[PCH] Deserializing the DeclContext of a template parameter is not safe
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sat, 16 Feb 2013 00:48:59 +0000 (00:48 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sat, 16 Feb 2013 00:48:59 +0000 (00:48 +0000)
until recursive loading is finished.

Otherwise we may end up with a template trying to deserialize a template
parameter that is in the process of getting loaded.

rdar://13135282

llvm-svn: 175329

clang/include/clang/Serialization/ASTReader.h
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/test/PCH/cxx-templates.cpp
clang/test/PCH/cxx-templates.h

index ecb550e..69a012c 100644 (file)
@@ -833,6 +833,21 @@ private:
   /// \brief Keeps track of the elements added to PendingDeclChains.
   llvm::SmallSet<serialization::DeclID, 16> PendingDeclChainsKnown;
 
+  /// \brief The Decl IDs for the Sema/Lexical DeclContext of a Decl that has
+  /// been loaded but its DeclContext was not set yet.
+  struct PendingDeclContextInfo {
+    Decl *D;
+    serialization::GlobalDeclID SemaDC;
+    serialization::GlobalDeclID LexicalDC;
+  };
+
+  /// \brief The set of Decls that have been loaded but their DeclContexts are
+  /// not set yet.
+  ///
+  /// The DeclContexts for these Decls will be set once recursive loading has
+  /// been completed.
+  std::deque<PendingDeclContextInfo> PendingDeclContextInfos;
+
   /// \brief The set of Objective-C categories that have been deserialized
   /// since the last time the declaration chains were linked.
   llvm::SmallPtrSet<ObjCCategoryDecl *, 16> CategoriesDeserialized;
@@ -1076,6 +1091,14 @@ private:
 
   void finishPendingActions();
 
+  void addPendingDeclContextInfo(Decl *D,
+                                 serialization::GlobalDeclID SemaDC,
+                                 serialization::GlobalDeclID LexicalDC) {
+    assert(D);
+    PendingDeclContextInfo Info = { D, SemaDC, LexicalDC };
+    PendingDeclContextInfos.push_back(Info);
+  }
+
   /// \brief Produce an error diagnostic and return true.
   ///
   /// This routine should only be used for fatal errors that have to
index 6f0dcaa..ee558dc 100644 (file)
@@ -6986,7 +6986,7 @@ void ASTReader::ReadComments() {
 
 void ASTReader::finishPendingActions() {
   while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
-         !PendingMacroIDs.empty()) {
+         !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty()) {
     // If any identifiers with corresponding top-level declarations have
     // been loaded, load those declarations now.
     while (!PendingIdentifierInfos.empty()) {
@@ -7013,6 +7013,16 @@ void ASTReader::finishPendingActions() {
       }
     }
     PendingMacroIDs.clear();
+
+    // Wire up the DeclContexts for Decls that we delayed setting until
+    // recursive loading is completed.
+    while (!PendingDeclContextInfos.empty()) {
+      PendingDeclContextInfo Info = PendingDeclContextInfos.front();
+      PendingDeclContextInfos.pop_front();
+      DeclContext *SemaDC = cast<DeclContext>(GetDecl(Info.SemaDC));
+      DeclContext *LexicalDC = cast<DeclContext>(GetDecl(Info.LexicalDC));
+      Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext());
+    }
   }
   
   // If we deserialized any C++ or Objective-C class definitions, any
index 64b33b0..ea54939 100644 (file)
@@ -44,9 +44,6 @@ namespace clang {
     unsigned &Idx;
     TypeID TypeIDForTypeDecl;
     
-    DeclID DeclContextIDForTemplateParmDecl;
-    DeclID LexicalDeclContextIDForTemplateParmDecl;
-
     bool HasPendingBody;
 
     uint64_t GetCurrentCursorOffset();
@@ -329,14 +326,6 @@ void ASTDeclReader::Visit(Decl *D) {
       Reader.PendingBodies[FD] = GetCurrentCursorOffset();
       HasPendingBody = true;
     }
-  } else if (D->isTemplateParameter()) {
-    // If we have a fully initialized template parameter, we can now
-    // set its DeclContext.
-    DeclContext *SemaDC = cast<DeclContext>(
-                              Reader.GetDecl(DeclContextIDForTemplateParmDecl));
-    DeclContext *LexicalDC = cast<DeclContext>(
-                       Reader.GetDecl(LexicalDeclContextIDForTemplateParmDecl));
-    D->setDeclContextsImpl(SemaDC, LexicalDC, Reader.getContext());
   }
 }
 
@@ -346,8 +335,11 @@ void ASTDeclReader::VisitDecl(Decl *D) {
     // parameter immediately, because the template parameter might be
     // used in the formulation of its DeclContext. Use the translation
     // unit DeclContext as a placeholder.
-    DeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx);
-    LexicalDeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+    GlobalDeclID SemaDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+    GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+    Reader.addPendingDeclContextInfo(D,
+                                     SemaDCIDForTemplateParmDecl,
+                                     LexicalDCIDForTemplateParmDecl);
     D->setDeclContext(Reader.getContext().getTranslationUnitDecl()); 
   } else {
     DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx);
index d27e9ca..ddebae4 100644 (file)
@@ -79,3 +79,9 @@ namespace TestNestedExpansion {
   Int &g(Int, int, double);
   Int &test = NestedExpansion<char, char, char>().f(0, 1, 2, Int(3), 4, 5.0);
 }
+
+namespace rdar13135282 {
+  void test() {
+    __mt_alloc<> mt = __mt_alloc<>();
+  }
+}
index 756f208..3dda059 100644 (file)
@@ -220,3 +220,29 @@ template<typename...A> struct NestedExpansion {
   template<typename...B> auto f(A...a, B...b) -> decltype(g(a + b...));
 };
 template struct NestedExpansion<char, char, char>;
+
+namespace rdar13135282 {
+template < typename _Alloc >
+void foo(_Alloc = _Alloc());
+
+template < bool > class __pool;
+
+template < template < bool > class _PoolTp >
+struct __common_pool {
+  typedef _PoolTp < 0 > pool_type;
+};
+
+template < template < bool > class _PoolTp >
+struct __common_pool_base : __common_pool < _PoolTp > {};
+
+template < template < bool > class _PoolTp >
+struct A : __common_pool_base < _PoolTp > {};
+
+template < typename _Poolp = A < __pool > >
+struct __mt_alloc {
+  typedef typename _Poolp::pool_type __pool_type;
+  __mt_alloc() {
+    foo<__mt_alloc<> >();
+  }
+};
+}