summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Serialization/ASTReader.cpp10
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp117
-rw-r--r--clang/test/Modules/Inputs/templates-left.h2
-rw-r--r--clang/test/Modules/Inputs/templates-right.h2
-rw-r--r--clang/test/Modules/cxx-templates.cpp12
-rw-r--r--clang/test/Modules/templates.mm6
6 files changed, 111 insertions, 38 deletions
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 44e98f94c8f..834917de1d4 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/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/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 4823cbcdfd9..96253ca301f 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/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<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())
diff --git a/clang/test/Modules/Inputs/templates-left.h b/clang/test/Modules/Inputs/templates-left.h
index 99e39bb5431..c61775b14fa 100644
--- a/clang/test/Modules/Inputs/templates-left.h
+++ b/clang/test/Modules/Inputs/templates-left.h
@@ -39,3 +39,5 @@ int defineListDoubleLeft() {
ld.push_back(0.0);
return ld.size;
}
+
+template<typename T> struct MergePatternDecl;
diff --git a/clang/test/Modules/Inputs/templates-right.h b/clang/test/Modules/Inputs/templates-right.h
index 7e18c95bd66..c8056d6539f 100644
--- a/clang/test/Modules/Inputs/templates-right.h
+++ b/clang/test/Modules/Inputs/templates-right.h
@@ -37,3 +37,5 @@ int defineListDoubleRight() {
ld.push_back(0.0);
return ld.size;
}
+
+template<typename T> struct MergePatternDecl;
diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp
index 291fabf0be5..82ecca31b56 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -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
diff --git a/clang/test/Modules/templates.mm b/clang/test/Modules/templates.mm
index 0f1bc43e829..fb4303f6a21 100644
--- a/clang/test/Modules/templates.mm
+++ b/clang/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<typename T> struct MergePatternDecl {
+ typedef int Type;
+ void f(Type);
+};
+template<typename T> void MergePatternDecl<T>::f(Type type) {}
OpenPOWER on IntegriCloud