Ensure that DIType is regenerated after we visited an implementation that adds ivars to an interface. Fixes rdar://13175234

llvm-svn: 176116
This commit is contained in:
Adrian Prantl 2013-02-26 20:01:46 +00:00
parent 37c777ecc0
commit 71510db7bc
7 changed files with 167 additions and 24 deletions

View File

@ -651,6 +651,10 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
/// completed by the external AST source when required.
mutable bool ExternallyCompleted : 1;
/// \brief Indicates that the ivar cache does not yet include ivars
/// declared in the implementation.
mutable bool IvarListMissingImplementation : 1;
/// \brief The location of the superclass, if any.
SourceLocation SuperClassLoc;
@ -660,7 +664,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
SourceLocation EndLoc;
DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(),
ExternallyCompleted() { }
ExternallyCompleted(),
IvarListMissingImplementation(true) { }
};
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,

View File

@ -1093,38 +1093,51 @@ namespace {
/// all_declared_ivar_begin - return first ivar declared in this class,
/// its extensions and its implementation. Lazily build the list on first
/// access.
///
/// Caveat: The list returned by this method reflects the current
/// state of the parser. The cache will be updated for every ivar
/// added by an extension or the implementation when they are
/// encountered.
/// See also ObjCIvarDecl::Create().
ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
if (data().IvarList)
return data().IvarList;
ObjCIvarDecl *curIvar = 0;
if (!ivar_empty()) {
ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
data().IvarList = *I; ++I;
for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
for (ObjCInterfaceDecl::known_extensions_iterator
Ext = known_extensions_begin(),
ExtEnd = known_extensions_end();
Ext != ExtEnd; ++Ext) {
if (!Ext->ivar_empty()) {
ObjCCategoryDecl::ivar_iterator I = Ext->ivar_begin(),E = Ext->ivar_end();
if (!data().IvarList) {
data().IvarList = *I; ++I;
curIvar = data().IvarList;
}
for ( ;I != E; curIvar = *I, ++I)
if (!data().IvarList) {
if (!ivar_empty()) {
ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
data().IvarList = *I; ++I;
for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
for (ObjCInterfaceDecl::known_extensions_iterator
Ext = known_extensions_begin(),
ExtEnd = known_extensions_end();
Ext != ExtEnd; ++Ext) {
if (!Ext->ivar_empty()) {
ObjCCategoryDecl::ivar_iterator
I = Ext->ivar_begin(),
E = Ext->ivar_end();
if (!data().IvarList) {
data().IvarList = *I; ++I;
curIvar = data().IvarList;
}
for ( ;I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
}
data().IvarListMissingImplementation = true;
}
// cached and complete!
if (!data().IvarListMissingImplementation)
return data().IvarList;
if (ObjCImplementationDecl *ImplDecl = getImplementation()) {
data().IvarListMissingImplementation = false;
if (!ImplDecl->ivar_empty()) {
SmallVector<SynthesizeIvarChunk, 16> layout;
for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),

View File

@ -1343,7 +1343,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
LexicalBlockStack.push_back(FwdDeclNode);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
// Add this to the completed types cache since we're completing it.
// Add this to the completed-type cache while we're completing it recursively.
CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Convert all the elements.
@ -1436,7 +1436,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// Otherwise, insert it into the CompletedTypeCache so that recursive uses
// will find it and we're emitting the complete type.
CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
QualType QualTy = QualType(Ty, 0);
CompletedTypeCache[QualTy.getAsOpaquePtr()] = RealDecl;
// Push the struct on region stack.
llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl);
@ -1561,6 +1562,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
FwdDeclNode->replaceOperandWith(10, Elements);
// If the implementation is not yet set, we do not want to mark it
// as complete. An implementation may declare additional
// private ivars that we would miss otherwise.
if (ID->getImplementation() == 0)
CompletedTypeCache.erase(QualTy.getAsOpaquePtr());
LexicalBlockStack.pop_back();
return llvm::DIType(FwdDeclNode);
@ -1824,6 +1831,10 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(),
static_cast<llvm::Value*>(TC)));
// Do not cache the type if it may be incomplete.
if (maybeIncompleteInterface(Ty))
return Res;
// And update the type cache.
TypeCache[Ty.getAsOpaquePtr()] = Res;
@ -1833,6 +1844,21 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
return Res;
}
/// clang::ParseAST handles each TopLevelDecl immediately after it was parsed.
/// A subsequent implementation may add more ivars to an interface, which is
/// why we cannot cache it yet.
bool CGDebugInfo::maybeIncompleteInterface(QualType Ty) {
switch (Ty->getTypeClass()) {
case Type::ObjCObjectPointer:
return maybeIncompleteInterface(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
case Type::ObjCInterface:
if (ObjCInterfaceDecl *Decl = cast<ObjCInterfaceType>(Ty)->getDecl())
return (Decl->getImplementation() == 0);
default:
return false;
}
}
/// CreateTypeNode - Create a new debug type node.
llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
// Handle qualifiers, which recursively handles what they refer to.

View File

@ -299,6 +299,10 @@ private:
/// CreateTypeNode - Create type metadata for a source language type.
llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
/// maybeIncompleteInterface - Determine if Ty may contain an
/// interface without an implementation
bool maybeIncompleteInterface(QualType Ty);
/// CreateLimitedTypeNode - Create type metadata for a source language
/// type, but only partial types for records.
llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F);

View File

@ -0,0 +1,28 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
// Debug symbols for private IVars
@interface I
{
@public int a;
}
@end
void foo(I* pi) {
// poking into pi for primary class ivars.
int _a = pi->a;
}
@interface I()
{
@public int b;
}
@end
void gorf (I* pg) {
// poking into pg for ivars for class extension
int _b = pg->b;
}
// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"a", metadata !{{[0-9]*}}, i32 7, i64 32, i64 32, i64 0, i32 0, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [a] [line 7, size 32, align 32, offset 0] [from int]
// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"b", metadata !{{[0-9]*}}, i32 18, i64 32, i64 32, i64 0, i32 0, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [b] [line 18, size 32, align 32, offset 0] [from int]

View File

@ -0,0 +1,31 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
// Debug symbols for private IVars
@interface I
{
@public int a;
}
@end
void foo(I* pi) {
int _a = pi->a;
}
// another layer of indirection
struct S
{
I* i;
};
@interface I()
{
@public int b;
}
@end
void gorf (struct S* s) {
int _b = s->i->b;
}
// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"b", metadata !{{[0-9]*}}, i32 23, i64 32, i64 32, i64 0, i32 0, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [b] [line 23, size 32, align 32, offset 0] [from int]

View File

@ -0,0 +1,36 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
// Debug symbols for private IVars. This test ensures that we are generating
// DI for ivars added ny the implementation.
__attribute((objc_root_class)) @interface NSObject {
id isa;
}
@end
@protocol Protocol
@end
@interface Delegate : NSObject<Protocol> {
@protected int foo;
}
@end
@interface Delegate(NSObject)
- (void)f;
@end
@implementation Delegate(NSObject)
- (void)f { return; }
@end
@implementation Delegate {
int bar;
}
- (void)g:(NSObject*) anObject {
bar = foo;
}
@end
// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"foo", metadata !{{[0-9]*}}, i32 14, i64 32, i64 32, i64 0, i32 2, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [foo] [line 14, size 32, align 32, offset 0] [protected] [from int]
// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"bar", metadata !{{[0-9]*}}, i32 27, i64 32, i64 32, i64 0, i32 1, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [bar] [line 27, size 32, align 32, offset 0] [private] [from int]