r241556 - The AST importer had a bug where it would enter into an infinite recursion

Douglas Gregor dgregor at apple.com
Mon Jul 6 23:20:12 PDT 2015


Author: dgregor
Date: Tue Jul  7 01:20:12 2015
New Revision: 241556

URL: http://llvm.org/viewvc/llvm-project?rev=241556&view=rev
Log:
The AST importer had a bug where it would enter into an infinite recursion
when importing type parameter lists.  The reason is that type parameters
have their DeclContexts set to the interface that is parameterized with those
types, and the importer would follow that loop and blow the stack out.

I've changed the way this works so that the type parameters are only imported
after the interface that contains them has been registered via the Imported()
function.

This is tested by LLDB.

<rdar://problem/20315663>

Modified:
    cfe/trunk/include/clang/AST/DeclObjC.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/DeclObjC.cpp

Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=241556&r1=241555&r2=241556&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Tue Jul  7 01:20:12 2015
@@ -956,6 +956,12 @@ public:
   /// has type parameters, skipping any declarations that do not.
   ObjCTypeParamList *getTypeParamList() const;
 
+  /// Set the type parameters of this class.
+  ///
+  /// This function is used by the AST importer, which must import the type
+  /// parameters after creating their DeclContext to avoid loops.
+  void setTypeParamList(ObjCTypeParamList *TPL);
+
   /// Retrieve the type parameters written on this particular declaration of
   /// the class.
   ObjCTypeParamList *getTypeParamListAsWritten() const {
@@ -1963,6 +1969,13 @@ public:
   /// extension.
   ObjCTypeParamList *getTypeParamList() const { return TypeParamList; }
 
+  /// Set the type parameters of this category.
+  ///
+  /// This function is used by the AST importer, which must import the type
+  /// parameters after creating their DeclContext to avoid loops.
+  void setTypeParamList(ObjCTypeParamList *TPL);
+
+
   ObjCCategoryImplDecl *getImplementation() const;
   void setImplementation(ObjCCategoryImplDecl *ImplD);
 

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=241556&r1=241555&r2=241556&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Tue Jul  7 01:20:12 2015
@@ -3491,13 +3491,16 @@ Decl *ASTNodeImporter::VisitObjCCategory
                                        Importer.Import(D->getCategoryNameLoc()), 
                                           Name.getAsIdentifierInfo(),
                                           ToInterface,
-                                          ImportObjCTypeParamList(
-                                            D->getTypeParamList()),
+                                          /*TypeParamList=*/nullptr,
                                        Importer.Import(D->getIvarLBraceLoc()),
                                        Importer.Import(D->getIvarRBraceLoc()));
     ToCategory->setLexicalDeclContext(LexicalDC);
     LexicalDC->addDeclInternal(ToCategory);
     Importer.Imported(D, ToCategory);
+    // Import the type parameter list after calling Imported, to avoid
+    // loops when bringing in their DeclContext.
+    ToCategory->setTypeParamList(ImportObjCTypeParamList(
+                                   D->getTypeParamList()));
     
     // Import protocols
     SmallVector<ObjCProtocolDecl *, 4> Protocols;
@@ -3819,14 +3822,17 @@ Decl *ASTNodeImporter::VisitObjCInterfac
     ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
                                         Importer.Import(D->getAtStartLoc()),
                                         Name.getAsIdentifierInfo(),
-                                        ImportObjCTypeParamList(
-                                          D->getTypeParamListAsWritten()),
+                                        /*TypeParamList=*/nullptr,
                                         /*PrevDecl=*/nullptr, Loc,
                                         D->isImplicitInterfaceDecl());
     ToIface->setLexicalDeclContext(LexicalDC);
     LexicalDC->addDeclInternal(ToIface);
   }
   Importer.Imported(D, ToIface);
+  // Import the type parameter list after calling Imported, to avoid
+  // loops when bringing in their DeclContext.
+  ToIface->setTypeParamList(ImportObjCTypeParamList(
+                              D->getTypeParamListAsWritten()));
   
   if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToIface))
     return nullptr;

Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=241556&r1=241555&r2=241556&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Tue Jul  7 01:20:12 2015
@@ -259,6 +259,15 @@ ObjCTypeParamList *ObjCInterfaceDecl::ge
   return nullptr;
 }
 
+void ObjCInterfaceDecl::setTypeParamList(ObjCTypeParamList *TPL) {
+  TypeParamList = TPL;
+  if (!TPL)
+    return;
+  // Set the declaration context of each of the type parameters.
+  for (auto typeParam : *TypeParamList)
+    typeParam->setDeclContext(this);
+}
+
 ObjCInterfaceDecl *ObjCInterfaceDecl::getSuperClass() const {
   // FIXME: Should make sure no callers ever do this.
   if (!hasDefinition())
@@ -1302,7 +1311,7 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(con
                                      ObjCInterfaceDecl *PrevDecl,
                                      bool IsInternal)
     : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
-      redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(typeParamList),
+      redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(nullptr),
       Data() {
   setPreviousDecl(PrevDecl);
   
@@ -1312,11 +1321,7 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(con
   
   setImplicit(IsInternal);
 
-  // Update the declaration context of the type parameters.
-  if (typeParamList) {
-    for (auto typeParam : *typeParamList)
-      typeParam->setDeclContext(this);
-  }
+  setTypeParamList(typeParamList);
 }
 
 void ObjCInterfaceDecl::LoadExternalDefinition() const {
@@ -1799,16 +1804,11 @@ ObjCCategoryDecl::ObjCCategoryDecl(DeclC
                                    SourceLocation IvarLBraceLoc,
                                    SourceLocation IvarRBraceLoc)
   : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
-    ClassInterface(IDecl), TypeParamList(typeParamList),
+    ClassInterface(IDecl), TypeParamList(nullptr),
     NextClassCategory(nullptr), CategoryNameLoc(CategoryNameLoc),
     IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) 
 {
-  // Set the declaration context of each of the type parameters.
-  if (typeParamList) {
-    for (auto typeParam : *typeParamList) {
-      typeParam->setDeclContext(this);
-    }
-  }
+  setTypeParamList(typeParamList);
 }
 
 ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
@@ -1853,6 +1853,15 @@ void ObjCCategoryDecl::setImplementation
   getASTContext().setObjCImplementation(this, ImplD);
 }
 
+void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) {
+  TypeParamList = TPL;
+  if (!TPL)
+    return;
+  // Set the declaration context of each of the type parameters.
+  for (auto typeParam : *TypeParamList)
+    typeParam->setDeclContext(this);
+}
+
 
 //===----------------------------------------------------------------------===//
 // ObjCCategoryImplDecl





More information about the cfe-commits mailing list