r190315 - C++ modules: if a class is defined in multiple modules (for instance, because
Richard Smith
richard-llvm at metafoo.co.uk
Mon Sep 9 09:55:27 PDT 2013
Author: rsmith
Date: Mon Sep 9 11:55:27 2013
New Revision: 190315
URL: http://llvm.org/viewvc/llvm-project?rev=190315&view=rev
Log:
C++ modules: if a class is defined in multiple modules (for instance, because
it is an implicit instantiation of a class template specialization), pick the
first-loaded definition to be the canonical definition, and merge all other
definitions into it.
This is still rather incomplete -- we need to extend every form of declaration
that can appear within a CXXRecordDecl to be redeclarable if it came from an
AST file (this includes fields, enumerators, ...).
Modified:
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/include/clang/Serialization/ASTReader.h
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
cfe/trunk/test/Modules/Inputs/cxx-templates-a.h
cfe/trunk/test/Modules/Inputs/cxx-templates-b.h
cfe/trunk/test/Modules/Inputs/templates-left.h
cfe/trunk/test/Modules/Inputs/templates-right.h
cfe/trunk/test/Modules/Inputs/templates-top.h
cfe/trunk/test/Modules/cxx-templates.cpp
cfe/trunk/test/Modules/templates.mm
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Mon Sep 9 11:55:27 2013
@@ -1450,7 +1450,7 @@ public:
ClassTemplateSpecializationDecl *getMostRecentDecl() {
CXXRecordDecl *Recent
= cast<CXXRecordDecl>(CXXRecordDecl::getMostRecentDecl());
- if (!isa<ClassTemplateSpecializationDecl>(Recent)) {
+ while (!isa<ClassTemplateSpecializationDecl>(Recent)) {
// FIXME: Does injected class name need to be in the redeclarations chain?
assert(Recent->isInjectedClassName() && Recent->getPreviousDecl());
Recent = Recent->getPreviousDecl();
Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Mon Sep 9 11:55:27 2013
@@ -912,6 +912,11 @@ private:
MergedDeclsMap::iterator
combineStoredMergedDecls(Decl *Canon, serialization::GlobalDeclID CanonID);
+ /// \brief A mapping from DeclContexts to the semantic DeclContext that we
+ /// are treating as the definition of the entity. This is used, for instance,
+ /// when merging implicit instantiations of class templates across modules.
+ llvm::DenseMap<DeclContext *, DeclContext *> MergedDeclContexts;
+
/// \brief When reading a Stmt tree, Stmt operands are placed in this stack.
SmallVector<Stmt *, 16> StmtStack;
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Mon Sep 9 11:55:27 2013
@@ -2506,7 +2506,7 @@ Sema::SpecialMemberOverloadResult *Sema:
SmallVector<NamedDecl *, 8> Candidates(R.begin(), R.end());
for (SmallVectorImpl<NamedDecl *>::iterator I = Candidates.begin(),
- E = Candidates.end();
+ E = Candidates.end();
I != E; ++I) {
NamedDecl *Cand = *I;
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Mon Sep 9 11:55:27 2013
@@ -291,7 +291,11 @@ namespace clang {
template<typename T>
void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl);
-
+
+ template<typename T>
+ void mergeRedeclarable(Redeclarable<T> *D, T *Existing,
+ RedeclarableResult &Redecl);
+
// FIXME: Reorder according to DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
@@ -363,9 +367,11 @@ void ASTDeclReader::VisitDecl(Decl *D) {
} else {
DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx);
DeclContext *LexicalDC = ReadDeclAs<DeclContext>(Record, Idx);
+ DeclContext *MergedSemaDC = Reader.MergedDeclContexts.lookup(SemaDC);
// Avoid calling setLexicalDeclContext() directly because it uses
// Decl::getASTContext() internally which is unsafe during derialization.
- D->setDeclContextsImpl(SemaDC, LexicalDC, Reader.getContext());
+ D->setDeclContextsImpl(MergedSemaDC ? MergedSemaDC : SemaDC, LexicalDC,
+ Reader.getContext());
}
D->setLocation(Reader.ReadSourceLocation(F, RawLocation));
D->setInvalidDecl(Record[Idx++]);
@@ -1230,7 +1236,8 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CX
RedeclarableResult Redecl = VisitRecordDeclImpl(D);
ASTContext &C = Reader.getContext();
- if (Record[Idx++]) {
+ bool WasDefinition = Record[Idx++];
+ if (WasDefinition) {
// Determine whether this is a lambda closure type, so that we can
// allocate the appropriate DefinitionData structure.
bool IsLambda = Record[Idx++];
@@ -1239,21 +1246,34 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CX
false);
else
D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
-
+
+ ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
+
// Propagate the DefinitionData pointer to the canonical declaration, so
// that all other deserialized declarations will see it.
- // FIXME: Complain if there already is a DefinitionData!
- D->getCanonicalDecl()->DefinitionData = D->DefinitionData;
-
- ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
-
- // Note that we have deserialized a definition. Any declarations
- // deserialized before this one will be be given the DefinitionData pointer
- // at the end.
- Reader.PendingDefinitions.insert(D);
+ CXXRecordDecl *Canon = D->getCanonicalDecl();
+ if (Canon == D) {
+ // Nothing to do.
+ } else if (!Canon->DefinitionData) {
+ Canon->DefinitionData = D->DefinitionData;
+
+ // Note that we have deserialized a definition. Any declarations
+ // deserialized before this one will be be given the DefinitionData
+ // pointer at the end.
+ Reader.PendingDefinitions.insert(D);
+ } else {
+ // We have already deserialized a definition of this record. This
+ // definition is no longer really a definition. Note that the pre-existing
+ // definition is the *real* definition.
+ // FIXME: Check DefinitionData for consistency with prior definition.
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(D, D->getCanonicalDecl()->DefinitionData->Definition));
+ D->IsCompleteDefinition = false;
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+ }
} else {
// Propagate DefinitionData pointer from the canonical declaration.
- D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
}
enum CXXRecKind {
@@ -1278,8 +1298,9 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CX
// Lazily load the key function to avoid deserializing every method so we can
// compute it.
- if (D->IsCompleteDefinition) {
- if (DeclID KeyFn = ReadDeclID(Record, Idx))
+ if (WasDefinition) {
+ DeclID KeyFn = ReadDeclID(Record, Idx);
+ if (KeyFn && D->IsCompleteDefinition)
C.KeyFunctions[D] = KeyFn;
}
@@ -1502,16 +1523,6 @@ ASTDeclReader::VisitClassTemplateSpecial
}
}
- // Explicit info.
- if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) {
- ClassTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo
- = new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo;
- ExplicitInfo->TypeAsWritten = TyInfo;
- ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx);
- ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx);
- D->ExplicitInfo = ExplicitInfo;
- }
-
SmallVector<TemplateArgument, 8> TemplArgs;
Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx);
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs.data(),
@@ -1523,16 +1534,48 @@ ASTDeclReader::VisitClassTemplateSpecial
if (writtenAsCanonicalDecl) {
ClassTemplateDecl *CanonPattern = ReadDeclAs<ClassTemplateDecl>(Record,Idx);
if (D->isCanonicalDecl()) { // It's kept in the folding set.
+ // Set this as, or find, the canonical declaration for this specialization
+ ClassTemplateSpecializationDecl *CanonSpec;
if (ClassTemplatePartialSpecializationDecl *Partial =
dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
- CanonPattern->getCommonPtr()->PartialSpecializations
+ CanonSpec = CanonPattern->getCommonPtr()->PartialSpecializations
.GetOrInsertNode(Partial);
} else {
- CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ CanonSpec =
+ CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
+ }
+ // If there was already a canonical specialization, merge into it.
+ if (CanonSpec != D) {
+ mergeRedeclarable<TagDecl>(D, CanonSpec, Redecl);
+
+ // This declaration might be a definition. Merge with any existing
+ // definition.
+ if (D->DefinitionData) {
+ if (!CanonSpec->DefinitionData) {
+ CanonSpec->DefinitionData = D->DefinitionData;
+ } else {
+ // FIXME: Check DefinitionData for consistency with prior definition
+ Reader.PendingDefinitions.erase(D);
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(D, CanonSpec->DefinitionData->Definition));
+ D->IsCompleteDefinition = false;
+ D->DefinitionData = CanonSpec->DefinitionData;
+ }
+ }
}
}
}
+ // Explicit info.
+ if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) {
+ ClassTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo
+ = new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo;
+ ExplicitInfo->TypeAsWritten = TyInfo;
+ ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx);
+ ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx);
+ D->ExplicitInfo = ExplicitInfo;
+ }
+
return Redecl;
}
@@ -1765,59 +1808,65 @@ ASTDeclReader::VisitRedeclarable(Redecla
/// \brief Attempts to merge the given declaration (D) with another declaration
/// of the same entity.
template<typename T>
-void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
RedeclarableResult &Redecl) {
// 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) {
- T *ExistingCanon = Existing->getCanonicalDecl();
- T *DCanon = static_cast<T*>(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
- // appropriate canonical declaration.
- 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))) {
- Namespace->AnonOrFirstNamespaceAndInline.setPointer(
- static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
- }
-
- // Don't introduce DCanon into the set of pending declaration chains.
- Redecl.suppress();
-
- // Introduce ExistingCanon into the set of pending declaration chains,
- // if in fact it came from a module file.
- if (ExistingCanon->isFromASTFile()) {
- GlobalDeclID ExistingCanonID = ExistingCanon->getGlobalID();
- assert(ExistingCanonID && "Unrecorded canonical declaration ID?");
- if (Reader.PendingDeclChainsKnown.insert(ExistingCanonID))
- Reader.PendingDeclChains.push_back(ExistingCanonID);
- }
-
- // 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)) {
- SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
- if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
- == Merged.end())
- Merged.push_back(Redecl.getFirstID());
-
- // If ExistingCanon did not come from a module file, introduce the
- // first declaration that *does* come from a module file to the
- // set of pending declaration chains, so that we merge this
- // declaration.
- if (!ExistingCanon->isFromASTFile() &&
- Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID()))
- Reader.PendingDeclChains.push_back(Merged[0]);
- }
- }
+
+ if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
+ if (T *Existing = ExistingRes)
+ mergeRedeclarable(D, Existing, Redecl);
+}
+
+/// \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) {
+ T *ExistingCanon = Existing->getCanonicalDecl();
+ T *DCanon = static_cast<T*>(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
+ // appropriate canonical declaration.
+ 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))) {
+ Namespace->AnonOrFirstNamespaceAndInline.setPointer(
+ static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
+ }
+
+ // Don't introduce DCanon into the set of pending declaration chains.
+ Redecl.suppress();
+
+ // Introduce ExistingCanon into the set of pending declaration chains,
+ // if in fact it came from a module file.
+ if (ExistingCanon->isFromASTFile()) {
+ GlobalDeclID ExistingCanonID = ExistingCanon->getGlobalID();
+ assert(ExistingCanonID && "Unrecorded canonical declaration ID?");
+ if (Reader.PendingDeclChainsKnown.insert(ExistingCanonID))
+ Reader.PendingDeclChains.push_back(ExistingCanonID);
+ }
+
+ // 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)) {
+ SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
+ if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
+ == Merged.end())
+ Merged.push_back(Redecl.getFirstID());
+
+ // If ExistingCanon did not come from a module file, introduce the
+ // first declaration that *does* come from a module file to the
+ // set of pending declaration chains, so that we merge this
+ // declaration.
+ if (!ExistingCanon->isFromASTFile() &&
+ Reader.PendingDeclChainsKnown.insert(Redecl.getFirstID()))
+ Reader.PendingDeclChains.push_back(Merged[0]);
}
}
}
@@ -1992,12 +2041,11 @@ static bool isSameEntity(NamedDecl *X, N
return true;
if (isa<ClassTemplateSpecializationDecl>(X)) {
- // FIXME: Deal with merging of template specializations.
- // For now, don't merge these; we need to check more than just the name to
- // determine if they refer to the same entity.
+ // No need to handle these here: we merge them when adding them to the
+ // template.
return false;
}
-
+
// Compatible tags match.
if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
TagDecl *TagY = cast<TagDecl>(Y);
@@ -2044,6 +2092,18 @@ static bool isSameEntity(NamedDecl *X, N
return false;
}
+/// Find the context in which we should search for previous declarations when
+/// looking for declarations to merge.
+static DeclContext *getPrimaryContextForMerging(DeclContext *DC) {
+ if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC))
+ return ND->getOriginalNamespace();
+
+ if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC))
+ return RD->getDefinition();
+
+ return 0;
+}
+
ASTDeclReader::FindExistingResult::~FindExistingResult() {
if (!AddResult || Existing)
return;
@@ -2051,11 +2111,10 @@ ASTDeclReader::FindExistingResult::~Find
DeclContext *DC = New->getDeclContext()->getRedeclContext();
if (DC->isTranslationUnit() && Reader.SemaObj) {
Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, New->getDeclName());
- } else if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
+ } else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) {
// Add the declaration to its redeclaration context so later merging
// lookups will find it.
- NS->getFirstDeclaration()->makeDeclVisibleInContextImpl(New,
- /*Internal*/true);
+ MergeDC->makeDeclVisibleInContextImpl(New, /*Internal*/true);
}
}
@@ -2069,9 +2128,6 @@ ASTDeclReader::FindExistingResult ASTDec
}
DeclContext *DC = D->getDeclContext()->getRedeclContext();
- if (!DC->isFileContext())
- return FindExistingResult(Reader);
-
if (DC->isTranslationUnit() && Reader.SemaObj) {
IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
@@ -2104,15 +2160,17 @@ ASTDeclReader::FindExistingResult ASTDec
if (isSameEntity(*I, D))
return FindExistingResult(Reader, D, *I);
}
- } else if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
- DeclContext::lookup_result R = NS->getFirstDeclaration()->noload_lookup(Name);
+ return FindExistingResult(Reader, D, /*Existing=*/0);
+ } else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) {
+ DeclContext::lookup_result R = MergeDC->noload_lookup(Name);
for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
if (isSameEntity(*I, D))
return FindExistingResult(Reader, D, *I);
}
+ return FindExistingResult(Reader, D, /*Existing=*/0);
}
-
- return FindExistingResult(Reader, D, /*Existing=*/0);
+
+ return FindExistingResult(Reader);
}
void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) {
Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Mon Sep 9 11:55:27 2013
@@ -1158,13 +1158,6 @@ void ASTDeclWriter::VisitClassTemplateSp
Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record);
}
- // Explicit info.
- Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record);
- if (D->getTypeAsWritten()) {
- Writer.AddSourceLocation(D->getExternLoc(), Record);
- Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record);
- }
-
Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record);
Writer.AddSourceLocation(D->getPointOfInstantiation(), Record);
Record.push_back(D->getSpecializationKind());
@@ -1175,6 +1168,13 @@ void ASTDeclWriter::VisitClassTemplateSp
Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record);
}
+ // Explicit info.
+ Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record);
+ if (D->getTypeAsWritten()) {
+ Writer.AddSourceLocation(D->getExternLoc(), Record);
+ Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record);
+ }
+
Code = serialization::DECL_CLASS_TEMPLATE_SPECIALIZATION;
}
Modified: cfe/trunk/test/Modules/Inputs/cxx-templates-a.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/cxx-templates-a.h?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/cxx-templates-a.h (original)
+++ cfe/trunk/test/Modules/Inputs/cxx-templates-a.h Mon Sep 9 11:55:27 2013
@@ -24,3 +24,9 @@ template<typename T> void PerformDelayed
template<typename T> void PerformDelayedLookupInDefaultArgument(T &t, int a = (FoundByADL(T()), 0)) {}
template<typename T> struct RedeclaredAsFriend {};
+
+void use_some_template_a() {
+ SomeTemplate<char[2]> a;
+ SomeTemplate<char[1]> b, c;
+ b = c;
+}
Modified: cfe/trunk/test/Modules/Inputs/cxx-templates-b.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/cxx-templates-b.h?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/cxx-templates-b.h (original)
+++ cfe/trunk/test/Modules/Inputs/cxx-templates-b.h Mon Sep 9 11:55:27 2013
@@ -35,6 +35,12 @@ struct RedeclareTemplateAsFriend {
friend struct RedeclaredAsFriend;
};
+void use_some_template_b() {
+ SomeTemplate<char[1]> a;
+ SomeTemplate<char[2]> b, c;
+ b = c;
+}
+
@import cxx_templates_a;
template<typename T> void UseDefinedInBImplIndirectly(T &v) {
PerformDelayedLookup(v);
Modified: cfe/trunk/test/Modules/Inputs/templates-left.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/templates-left.h?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/templates-left.h (original)
+++ cfe/trunk/test/Modules/Inputs/templates-left.h Mon Sep 9 11:55:27 2013
@@ -27,3 +27,5 @@ void triggerPendingInstantiation() {
}
void redeclDefinitionEmit(){}
+
+typedef Outer<int>::Inner OuterIntInner_left;
Modified: cfe/trunk/test/Modules/Inputs/templates-right.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/templates-right.h?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/templates-right.h (original)
+++ cfe/trunk/test/Modules/Inputs/templates-right.h Mon Sep 9 11:55:27 2013
@@ -25,3 +25,5 @@ void triggerPendingInstantiationToo() {
}
void redeclDefinitionEmit(){}
+
+typedef Outer<int>::Inner OuterIntInner_right;
Modified: cfe/trunk/test/Modules/Inputs/templates-top.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/templates-top.h?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/templates-top.h (original)
+++ cfe/trunk/test/Modules/Inputs/templates-top.h Mon Sep 9 11:55:27 2013
@@ -15,3 +15,7 @@ template <typename T> class A::WhereAmI
public:
static void func() {}
};
+
+template<typename T> struct Outer {
+ struct Inner {};
+};
Modified: cfe/trunk/test/Modules/cxx-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/cxx-templates.cpp?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/test/Modules/cxx-templates.cpp (original)
+++ cfe/trunk/test/Modules/cxx-templates.cpp Mon Sep 9 11:55:27 2013
@@ -82,6 +82,14 @@ typedef SomeTemplate<int&> SomeTemplateI
SomeTemplate<char*> some_template_char_ptr;
SomeTemplate<char&> some_template_char_ref;
+void testImplicitSpecialMembers(SomeTemplate<char[1]> &a,
+ const SomeTemplate<char[1]> &b,
+ SomeTemplate<char[2]> &c,
+ const SomeTemplate<char[2]> &d) {
+ a = b;
+ c = d;
+}
+
// CHECK-GLOBAL: DeclarationName 'f'
// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
// CHECK-GLOBAL-NEXT: `-FunctionTemplate {{.*}} 'f'
Modified: cfe/trunk/test/Modules/templates.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/templates.mm?rev=190315&r1=190314&r2=190315&view=diff
==============================================================================
--- cfe/trunk/test/Modules/templates.mm (original)
+++ cfe/trunk/test/Modules/templates.mm Mon Sep 9 11:55:27 2013
@@ -32,5 +32,10 @@ void testRedeclDefinition() {
redeclDefinitionEmit();
}
+// These three are all the same type.
+typedef OuterIntInner_left OuterIntInner;
+typedef OuterIntInner_right OuterIntInner;
+typedef Outer<int>::Inner OuterIntInner;
+
// CHECK: call {{.*pendingInstantiation}}
// CHECK: call {{.*redeclDefinitionEmit}}
More information about the cfe-commits
mailing list