diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 0ca3fd48e81cf42..a572e3380f16550 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -857,6 +857,16 @@ class RedeclarableTemplateDecl : public TemplateDecl, /// \endcode bool isMemberSpecialization() const { return Common.getInt(); } + /// Determines whether any redeclaration of this template was + /// a specialization of a member template. + bool hasMemberSpecialization() const { + for (const auto *D : redecls()) { + if (D->isMemberSpecialization()) + return true; + } + return false; + } + /// Note that this member template is a specialization. void setMemberSpecialization() { assert(!isMemberSpecialization() && "already a member specialization"); @@ -1955,7 +1965,13 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl, /// specialization which was specialized by this. llvm::PointerUnion - getSpecializedTemplateOrPartial() const; + getSpecializedTemplateOrPartial() const { + if (const auto *PartialSpec = + SpecializedTemplate.dyn_cast()) + return PartialSpec->PartialSpecialization; + + return SpecializedTemplate.get(); + } /// Retrieve the set of template arguments that should be used /// to instantiate members of the class template or class template partial @@ -2192,6 +2208,17 @@ class ClassTemplatePartialSpecializationDecl return InstantiatedFromMember.getInt(); } + /// Determines whether any redeclaration of this this class template partial + /// specialization was a specialization of a member partial specialization. + bool hasMemberSpecialization() const { + for (const auto *D : redecls()) { + if (cast(D) + ->isMemberSpecialization()) + return true; + } + return false; + } + /// Note that this member template is a specialization. void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } @@ -2713,7 +2740,13 @@ class VarTemplateSpecializationDecl : public VarDecl, /// Retrieve the variable template or variable template partial /// specialization which was specialized by this. llvm::PointerUnion - getSpecializedTemplateOrPartial() const; + getSpecializedTemplateOrPartial() const { + if (const auto *PartialSpec = + SpecializedTemplate.dyn_cast()) + return PartialSpec->PartialSpecialization; + + return SpecializedTemplate.get(); + } /// Retrieve the set of template arguments that should be used /// to instantiate the initializer of the variable template or variable @@ -2947,6 +2980,18 @@ class VarTemplatePartialSpecializationDecl return InstantiatedFromMember.getInt(); } + /// Determines whether any redeclaration of this this variable template + /// partial specialization was a specialization of a member partial + /// specialization. + bool hasMemberSpecialization() const { + for (const auto *D : redecls()) { + if (cast(D) + ->isMemberSpecialization()) + return true; + } + return false; + } + /// Note that this member template is a specialization. void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } @@ -3119,9 +3164,6 @@ class VarTemplateDecl : public RedeclarableTemplateDecl { return makeSpecIterator(getSpecializations(), true); } - /// Merge \p Prev with our RedeclarableTemplateDecl::Common. - void mergePrevDecl(VarTemplateDecl *Prev); - // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == VarTemplate; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 9d0b77566f6747d..6e31df691fa1048 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -6190,8 +6190,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D) { ClassTemplateDecl *ClassTemplate; - if (Error Err = importInto(ClassTemplate, - D->getSpecializedTemplate()->getCanonicalDecl())) + if (Error Err = importInto(ClassTemplate, D->getSpecializedTemplate())) return std::move(Err); // Import the context of this declaration. diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index cd173d17263792c..86913763ef9ff59 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2708,7 +2708,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const { if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) { auto From = VDTemplSpec->getInstantiatedFrom(); if (auto *VTD = From.dyn_cast()) { - while (!VTD->isMemberSpecialization()) { + while (!VTD->hasMemberSpecialization()) { if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) VTD = NewVTD; else @@ -2718,7 +2718,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const { } if (auto *VTPSD = From.dyn_cast()) { - while (!VTPSD->isMemberSpecialization()) { + while (!VTPSD->hasMemberSpecialization()) { if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) VTPSD = NewVTPSD; else @@ -2732,7 +2732,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const { // If this is the pattern of a variable template, find where it was // instantiated from. FIXME: Is this necessary? if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) { - while (!VTD->isMemberSpecialization()) { + while (!VTD->hasMemberSpecialization()) { if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) VTD = NewVTD; else @@ -4153,7 +4153,7 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const { if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { // If we hit a point where the user provided a specialization of this // template, we're done looking. - while (!ForDefinition || !Primary->isMemberSpecialization()) { + while (!ForDefinition || !Primary->hasMemberSpecialization()) { if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate()) Primary = NewPrimary; else @@ -4170,7 +4170,7 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization .dyn_cast()) { - return Info->getTemplate()->getMostRecentDecl(); + return Info->getTemplate(); } return nullptr; } diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 1c92fd9e3ff0676..db0ea62a2323eb0 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -2030,7 +2030,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { if (auto *TD = dyn_cast(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast()) { - while (!CTD->isMemberSpecialization()) { + while (!CTD->hasMemberSpecialization()) { if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) CTD = NewCTD; else @@ -2040,7 +2040,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { } if (auto *CTPSD = From.dyn_cast()) { - while (!CTPSD->isMemberSpecialization()) { + while (!CTPSD->hasMemberSpecialization()) { if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate()) CTPSD = NewCTPSD; else diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 1db02d0d04448ce..755ec72f00bf771 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -993,17 +993,7 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const { if (const auto *PartialSpec = SpecializedTemplate.dyn_cast()) return PartialSpec->PartialSpecialization->getSpecializedTemplate(); - return SpecializedTemplate.get()->getMostRecentDecl(); -} - -llvm::PointerUnion -ClassTemplateSpecializationDecl::getSpecializedTemplateOrPartial() const { - if (const auto *PartialSpec = - SpecializedTemplate.dyn_cast()) - return PartialSpec->PartialSpecialization->getMostRecentDecl(); - - return SpecializedTemplate.get()->getMostRecentDecl(); + return SpecializedTemplate.get(); } SourceRange @@ -1293,39 +1283,6 @@ VarTemplateDecl::newCommon(ASTContext &C) const { return CommonPtr; } -void VarTemplateDecl::mergePrevDecl(VarTemplateDecl *Prev) { - // If we haven't created a common pointer yet, then it can just be created - // with the usual method. - if (!getCommonPtrInternal()) - return; - - Common *ThisCommon = static_cast(getCommonPtrInternal()); - Common *PrevCommon = nullptr; - SmallVector PreviousDecls; - for (; Prev; Prev = Prev->getPreviousDecl()) { - if (CommonBase *C = Prev->getCommonPtrInternal()) { - PrevCommon = static_cast(C); - break; - } - PreviousDecls.push_back(Prev); - } - - // If the previous redecl chain hasn't created a common pointer yet, then just - // use this common pointer. - if (!PrevCommon) { - for (auto *D : PreviousDecls) - D->setCommonPtr(ThisCommon); - return; - } - - // Ensure we don't leak any important state. - assert(ThisCommon->Specializations.empty() && - ThisCommon->PartialSpecializations.empty() && - "Can't merge incompatible declarations!"); - - setCommonPtr(PrevCommon); -} - VarTemplateSpecializationDecl * VarTemplateDecl::findSpecialization(ArrayRef Args, void *&InsertPos) { @@ -1448,16 +1405,7 @@ VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const { if (const auto *PartialSpec = SpecializedTemplate.dyn_cast()) return PartialSpec->PartialSpecialization->getSpecializedTemplate(); - return SpecializedTemplate.get()->getMostRecentDecl(); -} - -llvm::PointerUnion -VarTemplateSpecializationDecl::getSpecializedTemplateOrPartial() const { - if (const auto *PartialSpec = - SpecializedTemplate.dyn_cast()) - return PartialSpec->PartialSpecialization->getMostRecentDecl(); - - return SpecializedTemplate.get()->getMostRecentDecl(); + return SpecializedTemplate.get(); } SourceRange VarTemplateSpecializationDecl::getSourceRange() const { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 00c8f871bbb38c1..acb1bee8cef319d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4694,10 +4694,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // Keep a chain of previous declarations. New->setPreviousDecl(Old); - if (NewTemplate) { - NewTemplate->mergePrevDecl(OldTemplate); + if (NewTemplate) NewTemplate->setPreviousDecl(OldTemplate); - } // Inherit access appropriately. New->setAccess(Old->getAccess()); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index f13355bb93cbebc..cba66d82406cddc 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -9957,7 +9957,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) { auto *Pattern = Template; while (Pattern->getInstantiatedFromMemberTemplate()) { - if (Pattern->isMemberSpecialization()) + if (Pattern->hasMemberSpecialization()) break; Pattern = Pattern->getInstantiatedFromMemberTemplate(); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index de0ec0128905ffc..b63063813f1b566 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -343,7 +343,7 @@ struct TemplateInstantiationArgumentCollecter // If this function was instantiated from a specialized member that is // a function template, we're done. assert(FD->getPrimaryTemplate() && "No function template?"); - if (FD->getPrimaryTemplate()->isMemberSpecialization()) + if (FD->getPrimaryTemplate()->hasMemberSpecialization()) return Done(); // If this function is a generic lambda specialization, we are done. @@ -442,11 +442,11 @@ struct TemplateInstantiationArgumentCollecter Specialized = CTSD->getSpecializedTemplateOrPartial(); if (auto *CTPSD = Specialized.dyn_cast()) { - if (CTPSD->isMemberSpecialization()) + if (CTPSD->hasMemberSpecialization()) return Done(); } else { auto *CTD = Specialized.get(); - if (CTD->isMemberSpecialization()) + if (CTD->hasMemberSpecialization()) return Done(); } return UseNextDecl(CTSD); @@ -478,11 +478,11 @@ struct TemplateInstantiationArgumentCollecter Specialized = VTSD->getSpecializedTemplateOrPartial(); if (auto *VTPSD = Specialized.dyn_cast()) { - if (VTPSD->isMemberSpecialization()) + if (VTPSD->hasMemberSpecialization()) return Done(); } else { auto *VTD = Specialized.get(); - if (VTD->isMemberSpecialization()) + if (VTD->hasMemberSpecialization()) return Done(); } return UseNextDecl(VTSD); @@ -4141,7 +4141,7 @@ getPatternForClassTemplateSpecialization( CXXRecordDecl *Pattern = nullptr; Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial(); if (auto *CTD = Specialized.dyn_cast()) { - while (!CTD->isMemberSpecialization()) { + while (!CTD->hasMemberSpecialization()) { if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) CTD = NewCTD; else @@ -4151,7 +4151,7 @@ getPatternForClassTemplateSpecialization( } else if (auto *CTPSD = Specialized .dyn_cast()) { - while (!CTPSD->isMemberSpecialization()) { + while (!CTPSD->hasMemberSpecialization()) { if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate()) CTPSD = NewCTPSD; else diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp index 7b998f20944f490..e84241cee922f59 100644 --- a/clang/test/AST/ast-dump-decl.cpp +++ b/clang/test/AST/ast-dump-decl.cpp @@ -530,7 +530,7 @@ namespace testCanonicalTemplate { // CHECK-NEXT: | `-ClassTemplateDecl 0x{{.+}} parent 0x{{.+}} col:40 friend_undeclared TestClassTemplate{{$}} // CHECK-NEXT: | |-TemplateTypeParmDecl 0x{{.+}} col:23 typename depth 1 index 0 T2{{$}} // CHECK-NEXT: | `-CXXRecordDecl 0x{{.+}} parent 0x{{.+}} col:40 class TestClassTemplate{{$}} - // CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} line:[[@LINE-19]]:31 class TestClassTemplate definition implicit_instantiation{{$}} + // CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} line:[[@LINE-19]]:31 class TestClassTemplate definition implicit_instantiation{{$}} // CHECK-NEXT: |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init{{$}} // CHECK-NEXT: | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr{{$}} // CHECK-NEXT: | |-CopyConstructor simple trivial has_const_param implicit_has_const_param{{$}} diff --git a/clang/test/ASTMerge/class-template-spec/Inputs/class-template-spec.cpp b/clang/test/ASTMerge/class-template-spec/Inputs/class-template-spec.cpp deleted file mode 100644 index 332bf24d25b29dc..000000000000000 --- a/clang/test/ASTMerge/class-template-spec/Inputs/class-template-spec.cpp +++ /dev/null @@ -1,47 +0,0 @@ -namespace N0 { - template - struct A { - template - friend struct A; - }; - - template struct A; -} // namespace N0 - -namespace N1 { - template - struct A; - - template - struct A { - template - friend struct A; - }; - - template struct A; -} // namespace N1 - -namespace N2 { - template - struct A { - template - friend struct A; - }; - - template - struct A; - - template struct A; -} // namespace N2 - -namespace N3 { - struct A { - template - friend struct B; - }; - - template - struct B { }; - - template struct B; -} // namespace N3 diff --git a/clang/test/ASTMerge/class-template-spec/test.cpp b/clang/test/ASTMerge/class-template-spec/test.cpp deleted file mode 100644 index adbce4835032788..000000000000000 --- a/clang/test/ASTMerge/class-template-spec/test.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/class-template-spec.cpp -// RUN: %clang_cc1 -ast-merge %t.1.ast -fsyntax-only -verify %s -// expected-no-diagnostics - -template struct N0::A; -template struct N1::A; -template struct N2::A; -template struct N3::B; diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp index e7e4738032f647f..87127366eb58a50 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp @@ -177,93 +177,6 @@ namespace Defined { static_assert(A::B::y == 2); } // namespace Defined -namespace Constrained { - template - struct A { - template requires V - static constexpr int f(); // expected-note {{declared here}} - - template requires V - static const int x; // expected-note {{declared here}} - - template requires V - static const int x; // expected-note {{declared here}} - - template requires V - struct B; // expected-note {{template is declared here}} - - template requires V - struct B; // expected-note {{template is declared here}} - }; - - template<> - template requires V - constexpr int A::f() { - return A::f(); - } - - template<> - template requires V - constexpr int A::x = A::x; - - template<> - template requires V - constexpr int A::x = A::x; - - template<> - template requires V - struct A::B { - static constexpr int y = A::B::y; - }; - - template<> - template requires V - struct A::B { - static constexpr int y = A::B::y; - }; - - template<> - template requires V - constexpr int A::f() { - return 1; - } - - template<> - template requires V - constexpr int A::x = 1; - - template<> - template requires V - constexpr int A::x = 2; - - template<> - template requires V - struct A::B { - static constexpr int y = 1; - }; - - template<> - template requires V - struct A::B { - static constexpr int y = 2; - }; - - static_assert(A::f() == 0); // expected-error {{static assertion expression is not an integral constant expression}} - // expected-note@-1 {{undefined function 'f' cannot be used in a constant expression}} - static_assert(A::x == 0); // expected-error {{static assertion expression is not an integral constant expression}} - // expected-note@-1 {{initializer of 'x' is unknown}} - static_assert(A::x == 0); // expected-error {{static assertion expression is not an integral constant expression}} - // expected-note@-1 {{initializer of 'x' is unknown}} - static_assert(A::B::y == 0); // expected-error {{implicit instantiation of undefined template 'Constrained::A::B'}} - static_assert(A::B::y == 0); // expected-error {{implicit instantiation of undefined template 'Constrained::A::B'}} - - static_assert(A::f() == 1); - static_assert(A::x == 1); - static_assert(A::x == 2); - static_assert(A::B::y == 1); - static_assert(A::B::y == 2); -} // namespace Constrained - namespace Dependent { template struct A {