]> granicus.if.org Git - clang/commitdiff
When two templates get merged together, also merge their pattern declarations
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 24 Apr 2014 02:25:27 +0000 (02:25 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 24 Apr 2014 02:25:27 +0000 (02:25 +0000)
together. This is extremely hairy, because in general we need to have loaded
both the template and the pattern before we can determine whether either should
be merged, so we temporarily violate the rule that all merging happens before
reading a decl ends, but *only* in the case where a template's pattern is being
loaded while loading the template itself.

In order to accomodate this for class templates, delay loading the injected
class name type for the pattern of the template until after we've loaded the
template itself, if we happen to load the template first.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@207063 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderDecl.cpp
test/Modules/Inputs/templates-left.h
test/Modules/Inputs/templates-right.h
test/Modules/cxx-templates.cpp
test/Modules/templates.mm

index 44e98f94c8f24072727bdd826e2e3601782c1183..834917de1d468b8705f8103adfb16816e9282cd6 100644 (file)
@@ -5315,8 +5315,14 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
     QualType TST = readType(*Loc.F, Record, Idx); // probably derivable
     // FIXME: ASTContext::getInjectedClassNameType is not currently suitable
     // for AST reading, too much interdependencies.
-    return
-      QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 0);
+    const Type *T;
+    if (const Type *Existing = D->getTypeForDecl())
+      T = Existing;
+    else if (auto *Prev = D->getPreviousDecl())
+      T = Prev->getTypeForDecl();
+    else
+      T = new (Context, TypeAlignment) InjectedClassNameType(D, TST);
+    return QualType(T, 0);
   }
 
   case TYPE_TEMPLATE_TYPE_PARM: {
index 4823cbcdfd9dcb4ce1b596a49b95ec4ce5df4c1f..96253ca301fa67b58ac40a0d3373a2bb8145083a 100644 (file)
@@ -267,7 +267,7 @@ namespace clang {
     void VisitImplicitParamDecl(ImplicitParamDecl *PD);
     void VisitParmVarDecl(ParmVarDecl *PD);
     void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
-    void VisitTemplateDecl(TemplateDecl *D);
+    DeclID VisitTemplateDecl(TemplateDecl *D);
     RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
     void VisitClassTemplateDecl(ClassTemplateDecl *D);
     void VisitVarTemplateDecl(VarTemplateDecl *D);
@@ -288,20 +288,26 @@ namespace clang {
     void VisitEmptyDecl(EmptyDecl *D);
 
     std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
-    
-    template<typename T> 
+
+    template<typename T>
     RedeclarableResult VisitRedeclarable(Redeclarable<T> *D);
 
     template<typename T>
-    void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl);
+    void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl,
+                           DeclID TemplatePatternID = 0);
 
     template<typename T>
     void mergeRedeclarable(Redeclarable<T> *D, T *Existing,
-                           RedeclarableResult &Redecl);
+                           RedeclarableResult &Redecl,
+                           DeclID TemplatePatternID = 0);
 
     template<typename T>
     void mergeMergeable(Mergeable<T> *D);
 
+    void mergeTemplatePattern(RedeclarableTemplateDecl *D,
+                              RedeclarableTemplateDecl *Existing,
+                              DeclID DsID);
+
     // FIXME: Reorder according to DeclNodes.td?
     void VisitObjCMethodDecl(ObjCMethodDecl *D);
     void VisitObjCContainerDecl(ObjCContainerDecl *D);
@@ -340,7 +346,7 @@ void ASTDeclReader::Visit(Decl *D) {
   }
 
   if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
-    // if we have a fully initialized TypeDecl, we can safely read its type now.
+    // We have a fully initialized TypeDecl. Read its type now.
     TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
   } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
     // if we have a fully initialized TypeDecl, we can safely read its type now.
@@ -985,10 +991,6 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
       VD->getLexicalDeclContext()->isFunctionOrMethod())
     VD->setLocalExternDecl();
 
-  // Only true variables (not parameters or implicit parameters) can be merged.
-  if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam)
-    mergeRedeclarable(VD, Redecl);
-  
   if (uint64_t Val = Record[Idx++]) {
     VD->setInit(Reader.ReadExpr(F));
     if (Val > 1) {
@@ -1003,8 +1005,12 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
   };
   switch ((VarKind)Record[Idx++]) {
   case VarNotTemplate:
+    // Only true variables (not parameters or implicit parameters) can be merged
+    if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam)
+      mergeRedeclarable(VD, Redecl);
     break;
   case VarTemplate:
+    // Merged when we merge the template.
     VD->setDescribedVarTemplate(ReadDeclAs<VarTemplateDecl>(Record, Idx));
     break;
   case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo.
@@ -1012,6 +1018,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
     TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
     SourceLocation POI = ReadSourceLocation(Record, Idx);
     Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
+    mergeRedeclarable(VD, Redecl);
     break;
   }
   }
@@ -1414,9 +1421,21 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
   case CXXRecNotTemplate:
     mergeRedeclarable(D, Redecl);
     break;
-  case CXXRecTemplate:
-    D->TemplateOrInstantiation = ReadDeclAs<ClassTemplateDecl>(Record, Idx);
+  case CXXRecTemplate: {
+    // Merged when we merge the template.
+    ClassTemplateDecl *Template = ReadDeclAs<ClassTemplateDecl>(Record, Idx);
+    D->TemplateOrInstantiation = Template;
+    if (!Template->getTemplatedDecl()) {
+      // We've not actually loaded the ClassTemplateDecl yet, because we're
+      // currently being loaded as its pattern. Rely on it to set up our
+      // TypeForDecl (see VisitClassTemplateDecl).
+      //
+      // Beware: we do not yet know our canonical declaration, and may still
+      // get merged once the surrounding class template has got off the ground.
+      TypeIDForTypeDecl = 0;
+    }
     break;
+  }
   case CXXRecMemberSpecialization: {
     CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(Record, Idx);
     TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
@@ -1522,16 +1541,19 @@ void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
   D->FriendLoc = ReadSourceLocation(Record, Idx);
 }
 
-void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
+DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
   VisitNamedDecl(D);
 
-  NamedDecl *TemplatedDecl = ReadDeclAs<NamedDecl>(Record, Idx);
+  DeclID PatternID = ReadDeclID(Record, Idx);
+  NamedDecl *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
   TemplateParameterList* TemplateParams
       = Reader.ReadTemplateParameterList(F, Record, Idx); 
   D->init(TemplatedDecl, TemplateParams);
 
   // FIXME: If this is a redeclaration of a template from another module, handle
   // inheritance of default template arguments.
+
+  return PatternID;
 }
 
 ASTDeclReader::RedeclarableResult 
@@ -1560,10 +1582,10 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
     }
   }
 
-  VisitTemplateDecl(D);
+  DeclID PatternID = VisitTemplateDecl(D);
   D->IdentifierNamespace = Record[Idx++];
 
-  mergeRedeclarable(D, Redecl);
+  mergeRedeclarable(D, Redecl, PatternID);
 
   // If we merged the template with a prior declaration chain, merge the common
   // pointer.
@@ -1607,6 +1629,14 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
     
     CommonPtr->InjectedClassNameType = Reader.readType(F, Record, Idx);
   }
+
+  if (D->getTemplatedDecl()->TemplateOrInstantiation) {
+    // We were loaded before our templated declaration was. We've not set up
+    // its corresponding type yet (see VisitCXXRecordDeclImpl), so reconstruct
+    // it now.
+    Reader.Context.getInjectedClassNameType(
+        D->getTemplatedDecl(), D->getCommonPtr()->InjectedClassNameType);
+  }
 }
 
 /// TODO: Unify with ClassTemplateDecl version?
@@ -1957,23 +1987,54 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
 /// of the same entity.
 template<typename T>
 void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
-                                      RedeclarableResult &Redecl) {
+                                      RedeclarableResult &Redecl,
+                                      DeclID TemplatePatternID) {
   // If modules are not available, there is no reason to perform this merge.
   if (!Reader.getContext().getLangOpts().Modules)
     return;
 
   if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
     if (T *Existing = ExistingRes)
-      mergeRedeclarable(D, Existing, Redecl);
+      mergeRedeclarable(D, Existing, Redecl, TemplatePatternID);
+}
+
+/// \brief "Cast" to type T, asserting if we don't have an implicit conversion.
+/// We use this to put code in a template that will only be valid for certain
+/// instantiations.
+template<typename T> static T assert_cast(T t) { return t; }
+template<typename T> static T assert_cast(...) {
+  llvm_unreachable("bad assert_cast");
+}
+
+/// \brief Merge together the pattern declarations from two template
+/// declarations.
+void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D,
+                                         RedeclarableTemplateDecl *Existing,
+                                         DeclID DsID) {
+  auto *DPattern = D->getTemplatedDecl();
+  auto *ExistingPattern = Existing->getTemplatedDecl();
+  RedeclarableResult Result(Reader, DsID, DPattern->getKind());
+  if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern))
+    // FIXME: Merge definitions here, if both declarations had definitions.
+    return mergeRedeclarable(DClass, cast<TagDecl>(ExistingPattern),
+                             Result);
+  if (auto *DFunction = dyn_cast<FunctionDecl>(DPattern))
+    return mergeRedeclarable(DFunction, cast<FunctionDecl>(ExistingPattern),
+                             Result);
+  if (auto *DVar = dyn_cast<VarDecl>(DPattern))
+    return mergeRedeclarable(DVar, cast<VarDecl>(ExistingPattern), Result);
+  llvm_unreachable("merged an unknown kind of redeclarable template");
 }
 
 /// \brief Attempts to merge the given declaration (D) with another declaration
 /// of the same entity.
 template<typename T>
-void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, T *Existing,
-                                      RedeclarableResult &Redecl) {
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing,
+                                      RedeclarableResult &Redecl,
+                                      DeclID TemplatePatternID) {
+  T *D = static_cast<T*>(DBase);
   T *ExistingCanon = Existing->getCanonicalDecl();
-  T *DCanon = static_cast<T*>(D)->getCanonicalDecl();
+  T *DCanon = D->getCanonicalDecl();
   if (ExistingCanon != DCanon) {
     // Have our redeclaration link point back at the canonical declaration
     // of the existing declaration, so that this declaration has the 
@@ -1981,11 +2042,15 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, T *Existing,
     D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon);
 
     // When we merge a namespace, update its pointer to the first namespace.
-    if (NamespaceDecl *Namespace
-          = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
+    if (auto *Namespace = dyn_cast<NamespaceDecl>(D))
       Namespace->AnonOrFirstNamespaceAndInline.setPointer(
-        static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
-    }
+          assert_cast<NamespaceDecl*>(ExistingCanon));
+
+    // When we merge a template, merge its pattern.
+    if (auto *DTemplate = dyn_cast<RedeclarableTemplateDecl>(D))
+      mergeTemplatePattern(
+          DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon),
+          TemplatePatternID);
 
     // Don't introduce DCanon into the set of pending declaration chains.
     Redecl.suppress();
@@ -2002,7 +2067,7 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, T *Existing,
     // If this declaration was the canonical declaration, make a note of
     // that. We accept the linear algorithm here because the number of
     // unique canonical declarations of an entity should always be tiny.
-    if (DCanon == static_cast<T*>(D)) {
+    if (DCanon == D) {
       SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
       if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
             == Merged.end())
index 99e39bb54313e53a6c9937fb672a4b0c736ba69f..c61775b14fafe75a35f1bb13ebd68020d8bf1268 100644 (file)
@@ -39,3 +39,5 @@ int defineListDoubleLeft() {
   ld.push_back(0.0);
   return ld.size;
 }
+
+template<typename T> struct MergePatternDecl;
index 7e18c95bd66898b09009d2533e4613a97e6dfaa5..c8056d6539f5fc83b0c1af82dcf14ef422fcf0a9 100644 (file)
@@ -37,3 +37,5 @@ int defineListDoubleRight() {
   ld.push_back(0.0);
   return ld.size;
 }
+
+template<typename T> struct MergePatternDecl;
index 291fabf0be502e3f05b9177f5daedb14fec148ab..82ecca31b56760cc695778bb498c1418a8a56fdd 100644 (file)
@@ -29,8 +29,8 @@ void g() {
   N::f<double>(1.0);
   N::f<int>();
   N::f(); // expected-error {{no matching function}}
-  // expected-note@Inputs/cxx-templates-b.h:6 {{couldn't infer template argument}}
-  // expected-note@Inputs/cxx-templates-b.h:7 {{requires single argument 't'}}
+  // expected-note@Inputs/cxx-templates-a.h:6 {{couldn't infer template argument}}
+  // expected-note@Inputs/cxx-templates-a.h:7 {{requires 1 argument}}
 
   template_param_kinds_1<0>(); // ok, from cxx-templates-a.h
   template_param_kinds_1<int>(); // ok, from cxx-templates-b.h
@@ -126,20 +126,12 @@ namespace Std {
   // expected-note@cxx-templates-common.h:21 {{previous}}
 }
 
-// FIXME: We should only have two entries for each of these names (one for each
-// function template), but we don't attempt to deduplicate lookup results from
-// sibling modules yet.
-
 // CHECK-GLOBAL:      DeclarationName 'f'
 // CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
-// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
-// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
 // CHECK-GLOBAL-NEXT: `-FunctionTemplate {{.*}} 'f'
 
 // CHECK-NAMESPACE-N:      DeclarationName 'f'
 // CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
-// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
-// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
 // CHECK-NAMESPACE-N-NEXT: `-FunctionTemplate {{.*}} 'f'
 
 // CHECK-DUMP:      ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}>  col:{{.*}} in cxx_templates_common SomeTemplate
index 0f1bc43e829611e5d301d5e349648296937d7728..fb4303f6a21e8a85301da404f54f45211675417b 100644 (file)
@@ -70,3 +70,9 @@ unsigned testMixedStruct() {
   // CHECK: load i32* bitcast (i8* getelementptr inbounds (i8* bitcast ({{.*}}* @list_right to i8*), i64 8) to i32*)
   return list_left.*size_right + list_right.*size_left;
 }
+
+template<typename T> struct MergePatternDecl {
+  typedef int Type;
+  void f(Type);
+};
+template<typename T> void MergePatternDecl<T>::f(Type type) {}