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

Adrian Prantl aprantl at apple.com
Tue Feb 26 12:01:46 PST 2013


Author: adrian
Date: Tue Feb 26 14:01:46 2013
New Revision: 176116

URL: http://llvm.org/viewvc/llvm-project?rev=176116&view=rev
Log:
Ensure that DIType is regenerated after we visited an implementation that adds ivars to an interface. Fixes rdar://13175234

Added:
    cfe/trunk/test/CodeGenObjC/debug-info-ivars-2.m
    cfe/trunk/test/CodeGenObjC/debug-info-ivars-3.m
    cfe/trunk/test/CodeGenObjC/debug-info-ivars-private.m
Modified:
    cfe/trunk/include/clang/AST/DeclObjC.h
    cfe/trunk/lib/AST/DeclObjC.cpp
    cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
    cfe/trunk/lib/CodeGen/CGDebugInfo.h

Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=176116&r1=176115&r2=176116&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Tue Feb 26 14:01:46 2013
@@ -651,6 +651,10 @@ class ObjCInterfaceDecl : public ObjCCon
     /// 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 ObjCCon
     SourceLocation EndLoc; 
 
     DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(), 
-                       ExternallyCompleted() { }
+                       ExternallyCompleted(),
+                       IvarListMissingImplementation(true) { }
   };
 
   ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,

Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=176116&r1=176115&r2=176116&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Tue Feb 26 14:01:46 2013
@@ -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);
-  }
+  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 (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);
       }
-      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(),

Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=176116&r1=176115&r2=176116&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Tue Feb 26 14:01:46 2013
@@ -1343,7 +1343,7 @@ llvm::DIType CGDebugInfo::CreateType(con
   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(con
 
   // 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(con
 
   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::getOrCreateTyp
     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::getOrCreateTyp
   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.

Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.h?rev=176116&r1=176115&r2=176116&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDebugInfo.h (original)
+++ cfe/trunk/lib/CodeGen/CGDebugInfo.h Tue Feb 26 14:01:46 2013
@@ -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);

Added: cfe/trunk/test/CodeGenObjC/debug-info-ivars-2.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/debug-info-ivars-2.m?rev=176116&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/debug-info-ivars-2.m (added)
+++ cfe/trunk/test/CodeGenObjC/debug-info-ivars-2.m Tue Feb 26 14:01:46 2013
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
+
+// Debug symbols for private IVars
+
+ at interface I
+{
+    @public int a;
+}
+ at end
+
+void foo(I* pi) {
+    // poking into pi for primary class ivars.
+    int _a = pi->a;
+}
+
+ at interface I()
+{
+    @public int b;
+}
+ at 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]

Added: cfe/trunk/test/CodeGenObjC/debug-info-ivars-3.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/debug-info-ivars-3.m?rev=176116&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/debug-info-ivars-3.m (added)
+++ cfe/trunk/test/CodeGenObjC/debug-info-ivars-3.m Tue Feb 26 14:01:46 2013
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
+
+// Debug symbols for private IVars
+
+ at interface I
+{
+    @public int a;
+}
+ at end
+
+void foo(I* pi) {
+    int _a = pi->a;
+}
+
+// another layer of indirection
+struct S
+{
+    I* i;
+};
+
+ at interface I()
+{
+    @public int b;
+}
+ at 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]

Added: cfe/trunk/test/CodeGenObjC/debug-info-ivars-private.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/debug-info-ivars-private.m?rev=176116&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/debug-info-ivars-private.m (added)
+++ cfe/trunk/test/CodeGenObjC/debug-info-ivars-private.m Tue Feb 26 14:01:46 2013
@@ -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;
+}
+ at end
+
+ at protocol Protocol
+ at end
+
+ at interface Delegate : NSObject<Protocol> {
+  @protected int foo;
+}
+ at end
+
+ at interface Delegate(NSObject)
+  - (void)f;
+ at end
+
+ at implementation Delegate(NSObject)
+- (void)f { return; }
+ at end
+
+ at implementation Delegate {
+  int bar;
+}
+
+- (void)g:(NSObject*) anObject {
+  bar = foo;
+}
+ at 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]





More information about the cfe-commits mailing list