From edc6f0f85a7e47a6556dcb333015e8d7a96dfa5b Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 24 Apr 2014 02:25:27 +0000 Subject: [PATCH] When two templates get merged together, also merge their pattern declarations 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 | 10 ++- lib/Serialization/ASTReaderDecl.cpp | 117 ++++++++++++++++++++------ test/Modules/Inputs/templates-left.h | 2 + test/Modules/Inputs/templates-right.h | 2 + test/Modules/cxx-templates.cpp | 12 +-- test/Modules/templates.mm | 6 ++ 6 files changed, 111 insertions(+), 38 deletions(-) diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 44e98f94c8..834917de1d 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -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: { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 4823cbcdfd..96253ca301 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -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 VisitDeclContext(DeclContext *DC); - - template + + template RedeclarableResult VisitRedeclarable(Redeclarable *D); template - void mergeRedeclarable(Redeclarable *D, RedeclarableResult &Redecl); + void mergeRedeclarable(Redeclarable *D, RedeclarableResult &Redecl, + DeclID TemplatePatternID = 0); template void mergeRedeclarable(Redeclarable *D, T *Existing, - RedeclarableResult &Redecl); + RedeclarableResult &Redecl, + DeclID TemplatePatternID = 0); template void mergeMergeable(Mergeable *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(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(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(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(Record, Idx); + case CXXRecTemplate: { + // Merged when we merge the template. + ClassTemplateDecl *Template = ReadDeclAs(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(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(Record, Idx); + DeclID PatternID = ReadDeclID(Record, Idx); + NamedDecl *TemplatedDecl = cast_or_null(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 *D) { /// of the same entity. template void ASTDeclReader::mergeRedeclarable(Redeclarable *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(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 static T assert_cast(T t) { return t; } +template 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(DPattern)) + // FIXME: Merge definitions here, if both declarations had definitions. + return mergeRedeclarable(DClass, cast(ExistingPattern), + Result); + if (auto *DFunction = dyn_cast(DPattern)) + return mergeRedeclarable(DFunction, cast(ExistingPattern), + Result); + if (auto *DVar = dyn_cast(DPattern)) + return mergeRedeclarable(DVar, cast(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 -void ASTDeclReader::mergeRedeclarable(Redeclarable *D, T *Existing, - RedeclarableResult &Redecl) { +void ASTDeclReader::mergeRedeclarable(Redeclarable *DBase, T *Existing, + RedeclarableResult &Redecl, + DeclID TemplatePatternID) { + T *D = static_cast(DBase); T *ExistingCanon = Existing->getCanonicalDecl(); - T *DCanon = static_cast(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 *D, T *Existing, D->RedeclLink = Redeclarable::PreviousDeclLink(ExistingCanon); // When we merge a namespace, update its pointer to the first namespace. - if (NamespaceDecl *Namespace - = dyn_cast(static_cast(D))) { + if (auto *Namespace = dyn_cast(D)) Namespace->AnonOrFirstNamespaceAndInline.setPointer( - static_cast(static_cast(ExistingCanon))); - } + assert_cast(ExistingCanon)); + + // When we merge a template, merge its pattern. + if (auto *DTemplate = dyn_cast(D)) + mergeTemplatePattern( + DTemplate, assert_cast(ExistingCanon), + TemplatePatternID); // Don't introduce DCanon into the set of pending declaration chains. Redecl.suppress(); @@ -2002,7 +2067,7 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable *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(D)) { + if (DCanon == D) { SmallVectorImpl &Merged = Reader.MergedDecls[ExistingCanon]; if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID()) == Merged.end()) diff --git a/test/Modules/Inputs/templates-left.h b/test/Modules/Inputs/templates-left.h index 99e39bb543..c61775b14f 100644 --- a/test/Modules/Inputs/templates-left.h +++ b/test/Modules/Inputs/templates-left.h @@ -39,3 +39,5 @@ int defineListDoubleLeft() { ld.push_back(0.0); return ld.size; } + +template struct MergePatternDecl; diff --git a/test/Modules/Inputs/templates-right.h b/test/Modules/Inputs/templates-right.h index 7e18c95bd6..c8056d6539 100644 --- a/test/Modules/Inputs/templates-right.h +++ b/test/Modules/Inputs/templates-right.h @@ -37,3 +37,5 @@ int defineListDoubleRight() { ld.push_back(0.0); return ld.size; } + +template struct MergePatternDecl; diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp index 291fabf0be..82ecca31b5 100644 --- a/test/Modules/cxx-templates.cpp +++ b/test/Modules/cxx-templates.cpp @@ -29,8 +29,8 @@ void g() { N::f(1.0); N::f(); 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(); // 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 diff --git a/test/Modules/templates.mm b/test/Modules/templates.mm index 0f1bc43e82..fb4303f6a2 100644 --- a/test/Modules/templates.mm +++ b/test/Modules/templates.mm @@ -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 struct MergePatternDecl { + typedef int Type; + void f(Type); +}; +template void MergePatternDecl::f(Type type) {} -- 2.40.0