diff --git a/third_party/llvm/generated.patch b/third_party/llvm/generated.patch index a044bffafbea7..d6aa9c0e2d027 100644 --- a/third_party/llvm/generated.patch +++ b/third_party/llvm/generated.patch @@ -1,65 +1,317 @@ Auto generated patch. Do not edit or delete it, even if empty. -diff -ruN --strip-trailing-cr a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel ---- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel -+++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel -@@ -2337,6 +2337,7 @@ - srcs = ["include/mlir/Dialect/AMX/AMX.td"], - includes = ["include"], - deps = [ -+ ":BuiltinDialectTdFiles", - ":LLVMOpsTdFiles", - ":SideEffectInterfacesTdFiles", - ], -@@ -2360,6 +2361,20 @@ - "include/mlir/Dialect/AMX/AMXDialect.cpp.inc", - ), - ( -+ [ -+ "-gen-typedef-decls", -+ "-typedefs-dialect=amx", -+ ], -+ "include/mlir/Dialect/AMX/AMXTypes.h.inc", -+ ), -+ ( -+ [ -+ "-gen-typedef-defs", -+ "-typedefs-dialect=amx", -+ ], -+ "include/mlir/Dialect/AMX/AMXTypes.cpp.inc", -+ ), -+ ( - ["-gen-op-decls"], - "include/mlir/Dialect/AMX/AMX.h.inc", - ), -@@ -2388,6 +2403,7 @@ - ":IR", - ":LLVMDialect", - ":SideEffectInterfaces", -+ "//llvm:Support", - ], - ) +diff -ruN --strip-trailing-cr a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst +--- a/clang/docs/ReleaseNotes.rst ++++ b/clang/docs/ReleaseNotes.rst +@@ -613,8 +613,6 @@ + an implicitly instantiated class template specialization. (#GH51051) + - Fixed an assertion failure caused by invalid enum forward declarations. (#GH112208) + - Name independent data members were not correctly initialized from default member initializers. (#GH114069) +-- Fixed an assertion failure caused by invalid default argument substitutions in non-defining +- friend declarations. (#GH113324). -@@ -2398,6 +2414,7 @@ - includes = ["include"], - deps = [ - ":AMXDialect", -+ ":ConvertToLLVMInterface", - ":IR", - ":LLVMCommonConversion", - ":LLVMDialect", -@@ -4858,6 +4875,7 @@ - deps = [ - ":AffineTransformOps", - ":ArithToLLVM", -+ ":AMXTransforms", - ":BufferizationTransformOps", - ":BuiltinToLLVMIRTranslation", - ":ComplexToLLVM", -@@ -5965,6 +5983,7 @@ - deps = [ - ":ArithDialect", - ":ConversionPassIncGen", -+ ":DialectUtils", - ":IR", - ":Pass", - ":SPIRVConversion", + Bug Fixes to AST Handling + ^^^^^^^^^^^^^^^^^^^^^^^^^ +diff -ruN --strip-trailing-cr a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp +--- a/clang/lib/Sema/SemaExpr.cpp ++++ b/clang/lib/Sema/SemaExpr.cpp +@@ -6018,17 +6018,6 @@ + } else { + assert(Param && "can't use default arguments without a known callee"); + +- // FIXME: We don't track member specialization info for non-defining +- // friend declarations, so we will not be able to later find the function +- // pattern. As a workaround, don't instantiate the default argument in +- // this case. This is correct per wording and only an error recovery +- // issue, as per [dcl.fct.default]p4: +- // if a friend declaration D specifies a default argument expression, +- // that declaration shall be a definition. +- if (FDecl->getFriendObjectKind() != Decl::FOK_None && +- FDecl->getMemberSpecializationInfo() == nullptr) +- return true; +- + ExprResult ArgExpr = BuildCXXDefaultArgExpr(CallLoc, FDecl, Param); + if (ArgExpr.isInvalid()) + return true; +diff -ruN --strip-trailing-cr a/clang/test/CXX/temp/temp.res/p4.cpp b/clang/test/CXX/temp/temp.res/p4.cpp +--- a/clang/test/CXX/temp/temp.res/p4.cpp ++++ b/clang/test/CXX/temp/temp.res/p4.cpp +@@ -185,22 +185,3 @@ + friend void X::f(T::type); + }; + } +- +-namespace GH113324 { +-template struct ct { +- friend void f1(ct, int = 0); // expected-error {{friend declaration specifying a default argument must be a definition}} +- friend void f2(ct a, ct = decltype(a){ }); // expected-error {{friend declaration specifying a default argument must be a definition}} +-}; +- +-template using alias = int; +-template struct C { +- // FIXME: We miss diagnosing the default argument instantiation failure (forming reference to void) +- friend void f3(C, int a = alias(1)); // expected-error {{friend declaration specifying a default argument must be a definition}} +-}; +- +-void test() { +- f1(ct<>{}); +- f2(ct<>{}); +- f3(C()); +-} +-} // namespace GH113324 +diff -ruN --strip-trailing-cr a/llvm/include/llvm/Transforms/Scalar/GVNExpression.h b/llvm/include/llvm/Transforms/Scalar/GVNExpression.h +--- a/llvm/include/llvm/Transforms/Scalar/GVNExpression.h ++++ b/llvm/include/llvm/Transforms/Scalar/GVNExpression.h +@@ -315,6 +315,12 @@ + return EB->getExpressionType() == ET_Call; + } + ++ bool equals(const Expression &Other) const override; ++ bool exactlyEquals(const Expression &Other) const override { ++ return Expression::exactlyEquals(Other) && ++ cast(Other).Call == Call; ++ } ++ + // Debugging support + void printInternal(raw_ostream &OS, bool PrintEType) const override { + if (PrintEType) +diff -ruN --strip-trailing-cr a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp +--- a/llvm/lib/Transforms/Scalar/GVN.cpp ++++ b/llvm/lib/Transforms/Scalar/GVN.cpp +@@ -143,6 +143,8 @@ + Type *type = nullptr; + SmallVector varargs; + ++ AttributeList attrs; ++ + Expression(uint32_t o = ~2U) : opcode(o) {} + + bool operator==(const Expression &other) const { +@@ -154,6 +156,9 @@ + return false; + if (varargs != other.varargs) + return false; ++ if (!attrs.isEmpty() && !other.attrs.isEmpty() && ++ !attrs.intersectWith(type->getContext(), other.attrs).has_value()) ++ return false; + return true; + } + +@@ -364,6 +369,8 @@ + } else if (auto *SVI = dyn_cast(I)) { + ArrayRef ShuffleMask = SVI->getShuffleMask(); + e.varargs.append(ShuffleMask.begin(), ShuffleMask.end()); ++ } else if (auto *CB = dyn_cast(I)) { ++ e.attrs = CB->getAttributes(); + } + + return e; +@@ -2136,16 +2143,6 @@ + return Changed; + } + +-// Return true iff V1 can be replaced with V2. +-static bool canBeReplacedBy(Value *V1, Value *V2) { +- if (auto *CB1 = dyn_cast(V1)) +- if (auto *CB2 = dyn_cast(V2)) +- return CB1->getAttributes() +- .intersectWith(CB2->getContext(), CB2->getAttributes()) +- .has_value(); +- return true; +-} +- + static void patchAndReplaceAllUsesWith(Instruction *I, Value *Repl) { + patchReplacementInstruction(I, Repl); + I->replaceAllUsesWith(Repl); +@@ -2690,7 +2687,7 @@ + // Perform fast-path value-number based elimination of values inherited from + // dominators. + Value *Repl = findLeader(I->getParent(), Num); +- if (!Repl || !canBeReplacedBy(I, Repl)) { ++ if (!Repl) { + // Failure, just remember this instance for future use. + LeaderTable.insert(Num, I, I->getParent()); + return false; +@@ -2956,7 +2953,7 @@ + + uint32_t TValNo = VN.phiTranslate(P, CurrentBlock, ValNo, *this); + Value *predV = findLeader(P, TValNo); +- if (!predV || !canBeReplacedBy(CurInst, predV)) { ++ if (!predV) { + predMap.push_back(std::make_pair(static_cast(nullptr), P)); + PREPred = P; + ++NumWithout; +diff -ruN --strip-trailing-cr a/llvm/lib/Transforms/Scalar/NewGVN.cpp b/llvm/lib/Transforms/Scalar/NewGVN.cpp +--- a/llvm/lib/Transforms/Scalar/NewGVN.cpp ++++ b/llvm/lib/Transforms/Scalar/NewGVN.cpp +@@ -945,6 +945,18 @@ + return true; + } + ++bool CallExpression::equals(const Expression &Other) const { ++ if (!MemoryExpression::equals(Other)) ++ return false; ++ ++ if (auto *RHS = dyn_cast(&Other)) ++ return Call->getAttributes() ++ .intersectWith(Call->getContext(), RHS->Call->getAttributes()) ++ .has_value(); ++ ++ return false; ++} ++ + // Determine if the edge From->To is a backedge + bool NewGVN::isBackedge(BasicBlock *From, BasicBlock *To) const { + return From == To || +@@ -3854,16 +3866,6 @@ + return nullptr; + } + +-// Return true iff V1 can be replaced with V2. +-static bool canBeReplacedBy(Value *V1, Value *V2) { +- if (auto *CB1 = dyn_cast(V1)) +- if (auto *CB2 = dyn_cast(V2)) +- return CB1->getAttributes() +- .intersectWith(CB2->getContext(), CB2->getAttributes()) +- .has_value(); +- return true; +-} +- + bool NewGVN::eliminateInstructions(Function &F) { + // This is a non-standard eliminator. The normal way to eliminate is + // to walk the dominator tree in order, keeping track of available +@@ -3973,8 +3975,6 @@ + MembersLeft.insert(Member); + continue; + } +- if (!canBeReplacedBy(Member, Leader)) +- continue; + + LLVM_DEBUG(dbgs() << "Found replacement " << *(Leader) << " for " + << *Member << "\n"); +@@ -4082,11 +4082,8 @@ + if (DominatingLeader != Def) { + // Even if the instruction is removed, we still need to update + // flags/metadata due to downstreams users of the leader. +- if (!match(DefI, m_Intrinsic())) { +- if (!canBeReplacedBy(DefI, DominatingLeader)) +- continue; ++ if (!match(DefI, m_Intrinsic())) + patchReplacementInstruction(DefI, DominatingLeader); +- } + + markInstructionForDeletion(DefI); + } +@@ -4134,11 +4131,8 @@ + // original operand, as we already know we can just drop it. + auto *ReplacedInst = cast(U->get()); + auto *PI = PredInfo->getPredicateInfoFor(ReplacedInst); +- if (!PI || DominatingLeader != PI->OriginalOp) { +- if (!canBeReplacedBy(ReplacedInst, DominatingLeader)) +- continue; ++ if (!PI || DominatingLeader != PI->OriginalOp) + patchReplacementInstruction(ReplacedInst, DominatingLeader); +- } + + LLVM_DEBUG(dbgs() + << "Found replacement " << *DominatingLeader << " for " +diff -ruN --strip-trailing-cr a/llvm/test/Transforms/GVN/pr113997.ll b/llvm/test/Transforms/GVN/pr113997.ll +--- a/llvm/test/Transforms/GVN/pr113997.ll ++++ b/llvm/test/Transforms/GVN/pr113997.ll +@@ -31,3 +31,39 @@ + if.then: + ret i1 false + } ++ ++; Make sure we don't merge these two users of the incompatible call pair. ++ ++define i1 @bucket2(i32 noundef %x) { ++; CHECK-LABEL: define i1 @bucket2( ++; CHECK-SAME: i32 noundef [[X:%.*]]) { ++; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], 0 ++; CHECK-NEXT: [[CTPOP1:%.*]] = tail call range(i32 1, 32) i32 @llvm.ctpop.i32(i32 zeroext [[X]]) ++; CHECK-NEXT: [[CTPOP1INC:%.*]] = add i32 [[CTPOP1]], 1 ++; CHECK-NEXT: [[CMP2:%.*]] = icmp samesign ult i32 [[CTPOP1INC]], 3 ++; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false ++; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]] ++; CHECK: [[IF_ELSE]]: ++; CHECK-NEXT: [[CTPOP2:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]]) ++; CHECK-NEXT: [[CTPOP2INC:%.*]] = add i32 [[CTPOP2]], 1 ++; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[CTPOP2INC]], 2 ++; CHECK-NEXT: ret i1 [[RES]] ++; CHECK: [[IF_THEN]]: ++; CHECK-NEXT: ret i1 false ++; ++ %cmp1 = icmp sgt i32 %x, 0 ++ %ctpop1 = tail call range(i32 1, 32) i32 @llvm.ctpop.i32(i32 zeroext %x) ++ %ctpop1inc = add i32 %ctpop1, 1 ++ %cmp2 = icmp samesign ult i32 %ctpop1inc, 3 ++ %cond = select i1 %cmp1, i1 %cmp2, i1 false ++ br i1 %cond, label %if.then, label %if.else ++ ++if.else: ++ %ctpop2 = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 %x) ++ %ctpop2inc = add i32 %ctpop2, 1 ++ %res = icmp eq i32 %ctpop2inc, 2 ++ ret i1 %res ++ ++if.then: ++ ret i1 false ++} +diff -ruN --strip-trailing-cr a/llvm/test/Transforms/NewGVN/pr113997.ll b/llvm/test/Transforms/NewGVN/pr113997.ll +--- a/llvm/test/Transforms/NewGVN/pr113997.ll ++++ b/llvm/test/Transforms/NewGVN/pr113997.ll +@@ -31,3 +31,39 @@ + if.then: + ret i1 false + } ++ ++; Make sure we don't merge these two users of the incompatible call pair. ++ ++define i1 @bucket2(i32 noundef %x) { ++; CHECK-LABEL: define i1 @bucket2( ++; CHECK-SAME: i32 noundef [[X:%.*]]) { ++; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], 0 ++; CHECK-NEXT: [[CTPOP1:%.*]] = tail call range(i32 1, 32) i32 @llvm.ctpop.i32(i32 zeroext [[X]]) ++; CHECK-NEXT: [[CTPOP1INC:%.*]] = add i32 [[CTPOP1]], 1 ++; CHECK-NEXT: [[CMP2:%.*]] = icmp samesign ult i32 [[CTPOP1INC]], 3 ++; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 false ++; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]] ++; CHECK: [[IF_ELSE]]: ++; CHECK-NEXT: [[CTPOP2:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]]) ++; CHECK-NEXT: [[CTPOP2INC:%.*]] = add i32 [[CTPOP2]], 1 ++; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[CTPOP2INC]], 2 ++; CHECK-NEXT: ret i1 [[RES]] ++; CHECK: [[IF_THEN]]: ++; CHECK-NEXT: ret i1 false ++; ++ %cmp1 = icmp sgt i32 %x, 0 ++ %ctpop1 = tail call range(i32 1, 32) i32 @llvm.ctpop.i32(i32 zeroext %x) ++ %ctpop1inc = add i32 %ctpop1, 1 ++ %cmp2 = icmp samesign ult i32 %ctpop1inc, 3 ++ %cond = select i1 %cmp1, i1 %cmp2, i1 false ++ br i1 %cond, label %if.then, label %if.else ++ ++if.else: ++ %ctpop2 = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 %x) ++ %ctpop2inc = add i32 %ctpop2, 1 ++ %res = icmp eq i32 %ctpop2inc, 2 ++ ret i1 %res ++ ++if.then: ++ ret i1 false ++} +diff -ruN --strip-trailing-cr a/mlir/lib/Dialect/Arith/IR/InferIntRangeInterfaceImpls.cpp b/mlir/lib/Dialect/Arith/IR/InferIntRangeInterfaceImpls.cpp +--- a/mlir/lib/Dialect/Arith/IR/InferIntRangeInterfaceImpls.cpp ++++ b/mlir/lib/Dialect/Arith/IR/InferIntRangeInterfaceImpls.cpp +@@ -40,11 +40,6 @@ + setResultRange(getResult(), ConstantIntRanges::constant(value)); + return; + } +- if (auto splatAttr = llvm::dyn_cast_or_null(getValue())) { +- setResultRange(getResult(), ConstantIntRanges::constant( +- splatAttr.getSplatValue())); +- return; +- } + if (auto arrayCstAttr = + llvm::dyn_cast_or_null(getValue())) { + std::optional result; diff --git a/third_party/llvm/workspace.bzl b/third_party/llvm/workspace.bzl index 897304c7fe808..0d1e8d208ea36 100644 --- a/third_party/llvm/workspace.bzl +++ b/third_party/llvm/workspace.bzl @@ -4,8 +4,8 @@ load("//third_party:repo.bzl", "tf_http_archive") def repo(name): """Imports LLVM.""" - LLVM_COMMIT = "f548d39c3c751446d124c08769080214680d53ba" - LLVM_SHA256 = "66872d95602de81098608858f799969579ac35122e028f30a82c53e4c68d9a7f" + LLVM_COMMIT = "e109c493210572535de25950e7b83f74b8d11a6a" + LLVM_SHA256 = "1df13ffa86d666994cd921bad34e449f8540b35f2f9ab3a4e160fd46191e73f9" tf_http_archive( name = name, diff --git a/third_party/shardy/temporary.patch b/third_party/shardy/temporary.patch index 25fe725209f3d..c4a8e446bb654 100644 --- a/third_party/shardy/temporary.patch +++ b/third_party/shardy/temporary.patch @@ -1,2996 +1,400 @@ diff --git a/third_party/llvm/generated.patch b/third_party/llvm/generated.patch -index ca1e4ff..a044bff 100644 +index a044bff..d6aa9c0 100644 --- a/third_party/llvm/generated.patch +++ b/third_party/llvm/generated.patch -@@ -1,2922 +1,61 @@ +@@ -1,65 +1,317 @@ Auto generated patch. Do not edit or delete it, even if empty. --diff -ruN --strip-trailing-cr a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst ----- a/clang/docs/ReleaseNotes.rst --+++ b/clang/docs/ReleaseNotes.rst --@@ -569,9 +569,6 @@ -- in certain friend declarations. (#GH93099) -- - Clang now instantiates the correct lambda call operator when a lambda's class type is -- merged across modules. (#GH110401) ---- Clang now uses the correct set of template argument lists when comparing the constraints of --- out-of-line definitions and member templates explicitly specialized for a given implicit instantiation of --- a class template. (#GH102320) -- - Fix a crash when parsing a pseudo destructor involving an invalid type. (#GH111460) -- - Fixed an assertion failure when invoking recovery call expressions with explicit attributes -- and undeclared templates. (#GH107047), (#GH49093) --diff -ruN --strip-trailing-cr a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h ----- a/clang/include/clang/AST/DeclTemplate.h --+++ b/clang/include/clang/AST/DeclTemplate.h --@@ -787,11 +787,15 @@ -- EntryType *Entry, void *InsertPos); -- -- struct CommonBase { --- CommonBase() {} --+ CommonBase() : InstantiatedFromMember(nullptr, false) {} -- -- /// The template from which this was most -- /// directly instantiated (or null). --- RedeclarableTemplateDecl *InstantiatedFromMember = nullptr; --+ /// --+ /// The boolean value indicates whether this template --+ /// was explicitly specialized. --+ llvm::PointerIntPair --+ InstantiatedFromMember; -- -- /// If non-null, points to an array of specializations (including -- /// partial specializations) known only by their external declaration IDs. --@@ -802,19 +806,14 @@ -- }; -- -- /// Pointer to the common data shared by all declarations of this --- /// template, and a flag indicating if the template is a member --- /// specialization. --- mutable llvm::PointerIntPair Common; --- --- CommonBase *getCommonPtrInternal() const { return Common.getPointer(); } --+ /// template. --+ mutable CommonBase *Common = nullptr; -- -- /// Retrieves the "common" pointer shared by all (re-)declarations of -- /// the same template. Calling this routine may implicitly allocate memory -- /// for the common pointer. -- CommonBase *getCommonPtr() const; -- --- void setCommonPtr(CommonBase *C) const { Common.setPointer(C); } --- -- virtual CommonBase *newCommon(ASTContext &C) const = 0; -- -- // Construct a template decl with name, parameters, and templated element. --@@ -855,12 +854,15 @@ -- /// template<> template -- /// struct X::Inner { /* ... */ }; -- /// \endcode --- bool isMemberSpecialization() const { return Common.getInt(); } --+ bool isMemberSpecialization() const { --+ return getCommonPtr()->InstantiatedFromMember.getInt(); --+ } -- -- /// Note that this member template is a specialization. -- void setMemberSpecialization() { --- assert(!isMemberSpecialization() && "already a member specialization"); --- Common.setInt(true); --+ assert(getCommonPtr()->InstantiatedFromMember.getPointer() && --+ "Only member templates can be member template specializations"); --+ getCommonPtr()->InstantiatedFromMember.setInt(true); -- } -- -- /// Retrieve the member template from which this template was --@@ -900,12 +902,12 @@ -- /// void X::f(T, U); -- /// \endcode -- RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const { --- return getCommonPtr()->InstantiatedFromMember; --+ return getCommonPtr()->InstantiatedFromMember.getPointer(); -- } -- -- void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) { --- assert(!getCommonPtr()->InstantiatedFromMember); --- getCommonPtr()->InstantiatedFromMember = TD; --+ assert(!getCommonPtr()->InstantiatedFromMember.getPointer()); --+ getCommonPtr()->InstantiatedFromMember.setPointer(TD); -- } -- -- /// Retrieve the "injected" template arguments that correspond to the --@@ -1955,7 +1957,13 @@ -- /// 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 --@@ -1981,8 +1989,6 @@ -- /// template arguments have been deduced. -- void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec, -- const TemplateArgumentList *TemplateArgs) { --- assert(!isa(this) && --- "A partial specialization cannot be instantiated from a template"); -- assert(!SpecializedTemplate.is() && -- "Already set to a class template partial specialization!"); -- auto *PS = new (getASTContext()) SpecializedPartialSpecialization(); --@@ -1994,8 +2000,6 @@ -- /// Note that this class template specialization is an instantiation -- /// of the given class template. -- void setInstantiationOf(ClassTemplateDecl *TemplDecl) { --- assert(!isa(this) && --- "A partial specialization cannot be instantiated from a template"); -- assert(!SpecializedTemplate.is() && -- "Previously set to a class template partial specialization!"); -- SpecializedTemplate = TemplDecl; --@@ -2189,11 +2193,18 @@ -- /// struct X::Inner { /* ... */ }; -- /// \endcode -- bool isMemberSpecialization() const { --- return InstantiatedFromMember.getInt(); --+ const auto *First = --+ cast(getFirstDecl()); --+ return First->InstantiatedFromMember.getInt(); -- } -- -- /// Note that this member template is a specialization. --- void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } --+ void setMemberSpecialization() { --+ auto *First = cast(getFirstDecl()); --+ assert(First->InstantiatedFromMember.getPointer() && --+ "Only member templates can be member template specializations"); --+ return First->InstantiatedFromMember.setInt(true); --+ } -- -- /// Retrieves the injected specialization type for this partial -- /// specialization. This is not the same as the type-decl-type for --@@ -2263,6 +2274,8 @@ -- return static_cast(RedeclarableTemplateDecl::getCommonPtr()); -- } -- --+ void setCommonPtr(Common *C) { RedeclarableTemplateDecl::Common = C; } --+ -- public: -- -- friend class ASTDeclReader; --@@ -2713,7 +2726,13 @@ -- /// 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 --@@ -2739,8 +2758,6 @@ -- /// template arguments have been deduced. -- void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec, -- const TemplateArgumentList *TemplateArgs) { --- assert(!isa(this) && --- "A partial specialization cannot be instantiated from a template"); -- assert(!SpecializedTemplate.is() && -- "Already set to a variable template partial specialization!"); -- auto *PS = new (getASTContext()) SpecializedPartialSpecialization(); --@@ -2752,8 +2769,6 @@ -- /// Note that this variable template specialization is an instantiation -- /// of the given variable template. -- void setInstantiationOf(VarTemplateDecl *TemplDecl) { --- assert(!isa(this) && --- "A partial specialization cannot be instantiated from a template"); -- assert(!SpecializedTemplate.is() && -- "Previously set to a variable template partial specialization!"); -- SpecializedTemplate = TemplDecl; --@@ -2944,11 +2959,18 @@ -- /// U* X::Inner = (T*)(0) + 1; -- /// \endcode -- bool isMemberSpecialization() const { --- return InstantiatedFromMember.getInt(); --+ const auto *First = --+ cast(getFirstDecl()); --+ return First->InstantiatedFromMember.getInt(); -- } -- -- /// Note that this member template is a specialization. --- void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); } --+ void setMemberSpecialization() { --+ auto *First = cast(getFirstDecl()); --+ assert(First->InstantiatedFromMember.getPointer() && --+ "Only member templates can be member template specializations"); --+ return First->InstantiatedFromMember.setInt(true); --+ } -- -- SourceRange getSourceRange() const override LLVM_READONLY; -- --@@ -3119,9 +3141,6 @@ -- 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 -ruN --strip-trailing-cr a/clang/include/clang/AST/SYCLKernelInfo.h b/clang/include/clang/AST/SYCLKernelInfo.h ----- a/clang/include/clang/AST/SYCLKernelInfo.h --+++ b/clang/include/clang/AST/SYCLKernelInfo.h --@@ -13,6 +13,7 @@ -- #ifndef LLVM_CLANG_AST_SYCLKERNELINFO_H -- #define LLVM_CLANG_AST_SYCLKERNELINFO_H -- --+#include "clang/AST/CanonicalType.h" -- #include "clang/AST/Decl.h" -- #include "clang/AST/Type.h" -- --diff -ruN --strip-trailing-cr a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h ----- a/clang/include/clang/Sema/Sema.h --+++ b/clang/include/clang/Sema/Sema.h --@@ -11328,9 +11328,9 @@ -- CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, -- const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, -- AccessSpecifier AS, SourceLocation ModulePrivateLoc, --- SourceLocation FriendLoc, --- ArrayRef OuterTemplateParamLists, --- bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr); --+ SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, --+ TemplateParameterList **OuterTemplateParamLists, --+ SkipBodyInfo *SkipBody = nullptr); -- -- /// Translates template arguments as provided by the parser -- /// into template arguments used by semantic analysis. --@@ -11369,8 +11369,7 @@ -- DeclResult ActOnVarTemplateSpecialization( -- Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous, -- SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, --- StorageClass SC, bool IsPartialSpecialization, --- bool IsMemberSpecialization); --+ StorageClass SC, bool IsPartialSpecialization); -- -- /// Get the specialization of the given variable template corresponding to -- /// the specified argument list, or a null-but-valid result if the arguments --@@ -13012,14 +13011,28 @@ -- /// dealing with a specialization. This is only relevant for function -- /// template specializations. -- /// --+ /// \param Pattern If non-NULL, indicates the pattern from which we will be --+ /// instantiating the definition of the given declaration, \p ND. This is --+ /// used to determine the proper set of template instantiation arguments for --+ /// friend function template specializations. --+ /// -- /// \param ForConstraintInstantiation when collecting arguments, -- /// ForConstraintInstantiation indicates we should continue looking when -- /// encountering a lambda generic call operator, and continue looking for -- /// arguments on an enclosing class template. --+ /// --+ /// \param SkipForSpecialization when specified, any template specializations --+ /// in a traversal would be ignored. --+ /// \param ForDefaultArgumentSubstitution indicates we should continue looking --+ /// when encountering a specialized member function template, rather than --+ /// returning immediately. -- MultiLevelTemplateArgumentList getTemplateInstantiationArgs( -- const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false, -- std::optional> Innermost = std::nullopt, --- bool RelativeToPrimary = false, bool ForConstraintInstantiation = false); --+ bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr, --+ bool ForConstraintInstantiation = false, --+ bool SkipForSpecialization = false, --+ bool ForDefaultArgumentSubstitution = false); -- -- /// RAII object to handle the state changes required to synthesize -- /// a function body. --diff -ruN --strip-trailing-cr a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp ----- a/clang/lib/AST/ASTImporter.cpp --+++ b/clang/lib/AST/ASTImporter.cpp --@@ -6190,8 +6190,7 @@ -- 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 -ruN --strip-trailing-cr a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp ----- a/clang/lib/AST/Decl.cpp --+++ b/clang/lib/AST/Decl.cpp --@@ -2709,20 +2709,20 @@ -- auto From = VDTemplSpec->getInstantiatedFrom(); -- if (auto *VTD = From.dyn_cast()) { -- while (!VTD->isMemberSpecialization()) { --- if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) --- VTD = NewVTD; --- else --+ auto *NewVTD = VTD->getInstantiatedFromMemberTemplate(); --+ if (!NewVTD) -- break; --+ VTD = NewVTD; -- } -- return getDefinitionOrSelf(VTD->getTemplatedDecl()); -- } -- if (auto *VTPSD = -- From.dyn_cast()) { -- while (!VTPSD->isMemberSpecialization()) { --- if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) --- VTPSD = NewVTPSD; --- else --+ auto *NewVTPSD = VTPSD->getInstantiatedFromMember(); --+ if (!NewVTPSD) -- break; --+ VTPSD = NewVTPSD; -- } -- return getDefinitionOrSelf(VTPSD); -- } --@@ -2731,14 +2731,15 @@ -- -- // 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()) { --- if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) --- VTD = NewVTD; --- else --+ if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) { --+ while (!VarTemplate->isMemberSpecialization()) { --+ auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate(); --+ if (!NewVT) -- break; --+ VarTemplate = NewVT; -- } --- return getDefinitionOrSelf(VTD->getTemplatedDecl()); --+ --+ return getDefinitionOrSelf(VarTemplate->getTemplatedDecl()); -- } -- -- if (VD == this) --@@ -4154,10 +4155,10 @@ -- // If we hit a point where the user provided a specialization of this -- // template, we're done looking. -- while (!ForDefinition || !Primary->isMemberSpecialization()) { --- if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate()) --- Primary = NewPrimary; --- else --+ auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate(); --+ if (!NewPrimary) -- break; --+ Primary = NewPrimary; -- } -- -- return getDefinitionOrSelf(Primary->getTemplatedDecl()); --@@ -4170,7 +4171,7 @@ -- if (FunctionTemplateSpecializationInfo *Info -- = TemplateOrSpecialization -- .dyn_cast()) { --- return Info->getTemplate()->getMostRecentDecl(); --+ return Info->getTemplate(); -- } -- return nullptr; -- } --diff -ruN --strip-trailing-cr a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp ----- a/clang/lib/AST/DeclCXX.cpp --+++ b/clang/lib/AST/DeclCXX.cpp --@@ -2030,21 +2030,19 @@ -- if (auto *TD = dyn_cast(this)) { -- auto From = TD->getInstantiatedFrom(); -- if (auto *CTD = From.dyn_cast()) { --- while (!CTD->isMemberSpecialization()) { --- if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) --- CTD = NewCTD; --- else --+ while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { --+ if (NewCTD->isMemberSpecialization()) -- break; --+ CTD = NewCTD; -- } -- return GetDefinitionOrSelf(CTD->getTemplatedDecl()); -- } -- if (auto *CTPSD = -- From.dyn_cast()) { --- while (!CTPSD->isMemberSpecialization()) { --- if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate()) --- CTPSD = NewCTPSD; --- else --+ while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { --+ if (NewCTPSD->isMemberSpecialization()) -- break; --+ CTPSD = NewCTPSD; -- } -- return GetDefinitionOrSelf(CTPSD); -- } --diff -ruN --strip-trailing-cr a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp ----- a/clang/lib/AST/DeclTemplate.cpp --+++ b/clang/lib/AST/DeclTemplate.cpp --@@ -320,16 +320,16 @@ -- void RedeclarableTemplateDecl::anchor() {} -- -- RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const { --- if (CommonBase *C = getCommonPtrInternal()) --- return C; --+ if (Common) --+ return Common; -- -- // Walk the previous-declaration chain until we either find a declaration -- // with a common pointer or we run out of previous declarations. -- SmallVector PrevDecls; -- for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev; -- Prev = Prev->getPreviousDecl()) { --- if (CommonBase *C = Prev->getCommonPtrInternal()) { --- setCommonPtr(C); --+ if (Prev->Common) { --+ Common = Prev->Common; -- break; -- } -- --@@ -337,18 +337,18 @@ -- } -- -- // If we never found a common pointer, allocate one now. --- if (!getCommonPtrInternal()) { --+ if (!Common) { -- // FIXME: If any of the declarations is from an AST file, we probably -- // need an update record to add the common data. -- --- setCommonPtr(newCommon(getASTContext())); --+ Common = newCommon(getASTContext()); -- } -- -- // Update any previous declarations we saw with the common pointer. -- for (const RedeclarableTemplateDecl *Prev : PrevDecls) --- Prev->setCommonPtr(getCommonPtrInternal()); --+ Prev->Common = Common; -- --- return getCommonPtrInternal(); --+ return Common; -- } -- -- void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { --@@ -458,17 +458,19 @@ -- } -- -- void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) { --+ using Base = RedeclarableTemplateDecl; --+ -- // If we haven't created a common pointer yet, then it can just be created -- // with the usual method. --- if (!getCommonPtrInternal()) --+ if (!Base::Common) -- return; -- --- Common *ThisCommon = static_cast(getCommonPtrInternal()); --+ Common *ThisCommon = static_cast(Base::Common); -- Common *PrevCommon = nullptr; -- SmallVector PreviousDecls; -- for (; Prev; Prev = Prev->getPreviousDecl()) { --- if (CommonBase *C = Prev->getCommonPtrInternal()) { --- PrevCommon = static_cast(C); --+ if (Prev->Base::Common) { --+ PrevCommon = static_cast(Prev->Base::Common); -- break; -- } -- PreviousDecls.push_back(Prev); --@@ -478,7 +480,7 @@ -- // use this common pointer. -- if (!PrevCommon) { -- for (auto *D : PreviousDecls) --- D->setCommonPtr(ThisCommon); --+ D->Base::Common = ThisCommon; -- return; -- } -- --@@ -486,7 +488,7 @@ -- assert(ThisCommon->Specializations.size() == 0 && -- "Can't merge incompatible declarations!"); -- --- setCommonPtr(PrevCommon); --+ Base::Common = PrevCommon; -- } -- -- //===----------------------------------------------------------------------===// --@@ -993,17 +995,7 @@ -- 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 +1285,6 @@ -- 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 +1407,7 @@ -- 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 -ruN --strip-trailing-cr a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp ----- a/clang/lib/Sema/SemaConcept.cpp --+++ b/clang/lib/Sema/SemaConcept.cpp --@@ -585,7 +585,7 @@ -- -- ArrayRef TemplateArgs = -- TemplateArgsLists.getNumSubstitutedLevels() > 0 --- ? TemplateArgsLists.getInnermost() --+ ? TemplateArgsLists.getOutermost() -- : ArrayRef{}; -- Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), -- Sema::InstantiatingTemplate::ConstraintsCheck{}, --@@ -834,6 +834,7 @@ -- getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(), -- /*Final=*/false, /*Innermost=*/std::nullopt, -- /*RelativeToPrimary=*/true, --+ /*Pattern=*/nullptr, -- /*ForConstraintInstantiation=*/true); -- if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope)) -- return std::nullopt; --@@ -909,13 +910,15 @@ -- // Figure out the to-translation-unit depth for this function declaration for -- // the purpose of seeing if they differ by constraints. This isn't the same as -- // getTemplateDepth, because it includes already instantiated parents. ---static unsigned CalculateTemplateDepthForConstraints(Sema &S, --- const NamedDecl *ND) { --+static unsigned --+CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND, --+ bool SkipForSpecialization = false) { -- MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( -- ND, ND->getLexicalDeclContext(), /*Final=*/false, -- /*Innermost=*/std::nullopt, -- /*RelativeToPrimary=*/true, --- /*ForConstraintInstantiation=*/true); --+ /*Pattern=*/nullptr, --+ /*ForConstraintInstantiation=*/true, SkipForSpecialization); -- return MLTAL.getNumLevels(); -- } -- --@@ -954,7 +957,8 @@ -- DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false, -- /*Innermost=*/std::nullopt, -- /*RelativeToPrimary=*/true, --- /*ForConstraintInstantiation=*/true); --+ /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true, --+ /*SkipForSpecialization*/ false); -- -- if (MLTAL.getNumSubstitutedLevels() == 0) -- return ConstrExpr; --@@ -1064,16 +1068,16 @@ -- bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) { -- assert(FD->getFriendObjectKind() && "Must be a friend!"); -- --- FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate(); -- // The logic for non-templates is handled in ASTContext::isSameEntity, so we -- // don't have to bother checking 'DependsOnEnclosingTemplate' for a -- // non-function-template. --- assert(FTD && "Non-function templates don't need to be checked"); --+ assert(FD->getDescribedFunctionTemplate() && --+ "Non-function templates don't need to be checked"); -- -- SmallVector ACs; --- FTD->getAssociatedConstraints(ACs); --+ FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs); -- --- unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth(); --+ unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD); -- for (const Expr *Constraint : ACs) -- if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth, -- Constraint)) --@@ -1520,6 +1524,7 @@ -- CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(), -- /*Final=*/false, CSE->getTemplateArguments(), -- /*RelativeToPrimary=*/true, --+ /*Pattern=*/nullptr, -- /*ForConstraintInstantiation=*/true); -- -- return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL, --@@ -1800,8 +1805,8 @@ -- return false; -- } -- --- unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1); --- unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2); --+ unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true); --+ unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true); -- -- for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) { -- if (Depth2 > Depth1) { --diff -ruN --strip-trailing-cr a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp ----- a/clang/lib/Sema/SemaDecl.cpp --+++ b/clang/lib/Sema/SemaDecl.cpp --@@ -4511,10 +4511,10 @@ -- adjustDeclContextForDeclaratorDecl(New, Old); -- -- // Ensure the template parameters are compatible. --- if (NewTemplate && !TemplateParameterListsAreEqual( --- NewTemplate, NewTemplate->getTemplateParameters(), --- OldTemplate, OldTemplate->getTemplateParameters(), --- /*Complain=*/true, TPL_TemplateMatch)) --+ if (NewTemplate && --+ !TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), --+ OldTemplate->getTemplateParameters(), --+ /*Complain=*/true, TPL_TemplateMatch)) -- return New->setInvalidDecl(); -- -- // C++ [class.mem]p1: --@@ -4694,10 +4694,8 @@ -- -- // 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()); --@@ -7678,7 +7676,7 @@ -- : SourceLocation(); -- DeclResult Res = ActOnVarTemplateSpecialization( -- S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC, --- IsPartialSpecialization, IsMemberSpecialization); --+ IsPartialSpecialization); -- if (Res.isInvalid()) -- return nullptr; -- NewVD = cast(Res.get()); --@@ -7697,10 +7695,6 @@ -- VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name, -- TemplateParams, NewVD); -- NewVD->setDescribedVarTemplate(NewTemplate); --- // If we are providing an explicit specialization of a static variable --- // template, make a note of that. --- if (IsMemberSpecialization) --- NewTemplate->setMemberSpecialization(); -- } -- -- // If this decl has an auto type in need of deduction, make a note of the --@@ -8081,6 +8075,12 @@ -- ? TPC_ClassTemplateMember -- : TPC_VarTemplate)) -- NewVD->setInvalidDecl(); --+ --+ // If we are providing an explicit specialization of a static variable --+ // template, make a note of that. --+ if (PrevVarTemplate && --+ PrevVarTemplate->getInstantiatedFromMemberTemplate()) --+ PrevVarTemplate->setMemberSpecialization(); -- } -- } -- --@@ -9887,8 +9887,6 @@ -- NewFD); -- FunctionTemplate->setLexicalDeclContext(CurContext); -- NewFD->setDescribedFunctionTemplate(FunctionTemplate); --- if (isMemberSpecialization) --- FunctionTemplate->setMemberSpecialization(); -- -- // For source fidelity, store the other template param lists. -- if (TemplateParamLists.size() > 1) { --@@ -12046,7 +12044,10 @@ -- -- // If this is an explicit specialization of a member that is a function -- // template, mark it as a member specialization. --- if (IsMemberSpecialization) { --+ if (IsMemberSpecialization && --+ NewTemplateDecl->getInstantiatedFromMemberTemplate()) { --+ NewTemplateDecl->setMemberSpecialization(); --+ assert(OldTemplateDecl->isMemberSpecialization()); -- // Explicit specializations of a member template do not inherit deleted -- // status from the parent member template that they are specializing. -- if (OldFD->isDeleted()) { --@@ -17120,8 +17121,8 @@ -- DeclResult Result = CheckClassTemplate( -- S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams, -- AS, ModulePrivateLoc, --- /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(), --- isMemberSpecialization, SkipBody); --+ /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1, --+ TemplateParameterLists.data(), SkipBody); -- return Result.get(); -- } else { -- // The "template<>" header is extraneous. --diff -ruN --strip-trailing-cr a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp ----- a/clang/lib/Sema/SemaDeclCXX.cpp --+++ b/clang/lib/Sema/SemaDeclCXX.cpp --@@ -17410,8 +17410,8 @@ -- return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS, -- Name, NameLoc, Attr, TemplateParams, AS_public, -- /*ModulePrivateLoc=*/SourceLocation(), --- FriendLoc, TempParamLists.drop_back(), --- IsMemberSpecialization) --+ FriendLoc, TempParamLists.size() - 1, --+ TempParamLists.data()) -- .get(); -- } else { -- // The "template<>" header is extraneous. --diff -ruN --strip-trailing-cr a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp ----- a/clang/lib/Sema/SemaTemplate.cpp --+++ b/clang/lib/Sema/SemaTemplate.cpp --@@ -1795,9 +1795,8 @@ -- CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, -- const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams, -- AccessSpecifier AS, SourceLocation ModulePrivateLoc, --- SourceLocation FriendLoc, --- ArrayRef OuterTemplateParamLists, --- bool IsMemberSpecialization, SkipBodyInfo *SkipBody) { --+ SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, --+ TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) { -- assert(TemplateParams && TemplateParams->size() > 0 && -- "No template parameters"); -- assert(TUK != TagUseKind::Reference && --@@ -1985,6 +1984,19 @@ -- } -- -- if (PrevClassTemplate) { --+ // Ensure that the template parameter lists are compatible. Skip this check --+ // for a friend in a dependent context: the template parameter list itself --+ // could be dependent. --+ if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) && --+ !TemplateParameterListsAreEqual( --+ TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext --+ : CurContext, --+ CurContext, KWLoc), --+ TemplateParams, PrevClassTemplate, --+ PrevClassTemplate->getTemplateParameters(), /*Complain=*/true, --+ TPL_TemplateMatch)) --+ return true; --+ -- // C++ [temp.class]p4: -- // In a redeclaration, partial specialization, explicit -- // specialization or explicit instantiation of a class template, --@@ -1999,6 +2011,30 @@ -- Diag(PrevRecordDecl->getLocation(), diag::note_previous_use); -- Kind = PrevRecordDecl->getTagKind(); -- } --+ --+ // Check for redefinition of this class template. --+ if (TUK == TagUseKind::Definition) { --+ if (TagDecl *Def = PrevRecordDecl->getDefinition()) { --+ // If we have a prior definition that is not visible, treat this as --+ // simply making that previous definition visible. --+ NamedDecl *Hidden = nullptr; --+ if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) { --+ SkipBody->ShouldSkip = true; --+ SkipBody->Previous = Def; --+ auto *Tmpl = cast(Hidden)->getDescribedClassTemplate(); --+ assert(Tmpl && "original definition of a class template is not a " --+ "class template?"); --+ makeMergedDefinitionVisible(Hidden); --+ makeMergedDefinitionVisible(Tmpl); --+ } else { --+ Diag(NameLoc, diag::err_redefinition) << Name; --+ Diag(Def->getLocation(), diag::note_previous_definition); --+ // FIXME: Would it make sense to try to "forget" the previous --+ // definition, as part of error recovery? --+ return true; --+ } --+ } --+ } -- } else if (PrevDecl) { -- // C++ [temp]p5: -- // A class template shall not have the same name as any other --@@ -2010,6 +2046,23 @@ -- return true; -- } -- --+ // Check the template parameter list of this declaration, possibly --+ // merging in the template parameter list from the previous class --+ // template declaration. Skip this check for a friend in a dependent --+ // context, because the template parameter list might be dependent. --+ if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) && --+ CheckTemplateParameterList( --+ TemplateParams, --+ PrevClassTemplate ? GetTemplateParameterList(PrevClassTemplate) --+ : nullptr, --+ (SS.isSet() && SemanticContext && SemanticContext->isRecord() && --+ SemanticContext->isDependentContext()) --+ ? TPC_ClassTemplateMember --+ : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate --+ : TPC_ClassTemplate, --+ SkipBody)) --+ Invalid = true; --+ -- if (SS.isSet()) { -- // If the name of the template was qualified, we must be defining the -- // template out-of-line. --@@ -2036,8 +2089,10 @@ -- PrevClassTemplate->getTemplatedDecl() : nullptr, -- /*DelayTypeCreation=*/true); -- SetNestedNameSpecifier(*this, NewClass, SS); --- if (!OuterTemplateParamLists.empty()) --- NewClass->setTemplateParameterListsInfo(Context, OuterTemplateParamLists); --+ if (NumOuterTemplateParamLists > 0) --+ NewClass->setTemplateParameterListsInfo( --+ Context, --+ llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists)); -- -- // Add alignment attributes if necessary; these attributes are checked when -- // the ASTContext lays out the structure. --@@ -2050,10 +2105,7 @@ -- = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, -- DeclarationName(Name), TemplateParams, -- NewClass); --- // If we are providing an explicit specialization of a member that is a --- // class template, make a note of that. --- if (IsMemberSpecialization) --- NewTemplate->setMemberSpecialization(); --+ -- if (ShouldAddRedecl) -- NewTemplate->setPreviousDecl(PrevClassTemplate); -- --@@ -2068,6 +2120,12 @@ -- assert(T->isDependentType() && "Class template type is not dependent?"); -- (void)T; -- --+ // If we are providing an explicit specialization of a member that is a --+ // class template, make a note of that. --+ if (PrevClassTemplate && --+ PrevClassTemplate->getInstantiatedFromMemberTemplate()) --+ PrevClassTemplate->setMemberSpecialization(); --+ -- // Set the access specifier. -- if (!Invalid && TUK != TagUseKind::Friend && -- NewTemplate->getDeclContext()->isRecord()) --@@ -2077,62 +2135,8 @@ -- NewClass->setLexicalDeclContext(CurContext); -- NewTemplate->setLexicalDeclContext(CurContext); -- --- // Ensure that the template parameter lists are compatible. Skip this check --- // for a friend in a dependent context: the template parameter list itself --- // could be dependent. --- if (ShouldAddRedecl && PrevClassTemplate && --- !TemplateParameterListsAreEqual( --- NewTemplate, TemplateParams, PrevClassTemplate, --- PrevClassTemplate->getTemplateParameters(), --- /*Complain=*/true, TPL_TemplateMatch)) --- return true; --- --- // Check the template parameter list of this declaration, possibly --- // merging in the template parameter list from the previous class --- // template declaration. Skip this check for a friend in a dependent --- // context, because the template parameter list might be dependent. --- if (ShouldAddRedecl && --- CheckTemplateParameterList( --- TemplateParams, --- PrevClassTemplate ? PrevClassTemplate->getTemplateParameters() --- : nullptr, --- (SS.isSet() && SemanticContext && SemanticContext->isRecord() && --- SemanticContext->isDependentContext()) --- ? TPC_ClassTemplateMember --- : TUK == TagUseKind::Friend ? TPC_FriendClassTemplate --- : TPC_ClassTemplate, --- SkipBody)) --- Invalid = true; --- --- if (TUK == TagUseKind::Definition) { --- if (PrevClassTemplate) { --- // Check for redefinition of this class template. --- if (TagDecl *Def = --- PrevClassTemplate->getTemplatedDecl()->getDefinition()) { --- // If we have a prior definition that is not visible, treat this as --- // simply making that previous definition visible. --- NamedDecl *Hidden = nullptr; --- if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) { --- SkipBody->ShouldSkip = true; --- SkipBody->Previous = Def; --- auto *Tmpl = cast(Hidden)->getDescribedClassTemplate(); --- assert(Tmpl && "original definition of a class template is not a " --- "class template?"); --- makeMergedDefinitionVisible(Hidden); --- makeMergedDefinitionVisible(Tmpl); --- } else { --- Diag(NameLoc, diag::err_redefinition) << Name; --- Diag(Def->getLocation(), diag::note_previous_definition); --- // FIXME: Would it make sense to try to "forget" the previous --- // definition, as part of error recovery? --- return true; --- } --- } --- } --- --- if (!SkipBody || !SkipBody->ShouldSkip) --- NewClass->startDefinition(); --- } --+ if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) --+ NewClass->startDefinition(); -- -- ProcessDeclAttributeList(S, NewClass, Attr); -- ProcessAPINotes(NewClass); --@@ -4129,8 +4133,7 @@ -- DeclResult Sema::ActOnVarTemplateSpecialization( -- Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous, -- SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, --- StorageClass SC, bool IsPartialSpecialization, --- bool IsMemberSpecialization) { --+ StorageClass SC, bool IsPartialSpecialization) { -- // D must be variable template id. -- assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId && -- "Variable template specialization is declared with a template id."); --@@ -4248,16 +4251,17 @@ -- Context, VarTemplate->getDeclContext(), TemplateKWLoc, -- TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC, -- CanonicalConverted); --- // If we are providing an explicit specialization of a member variable --- // template specialization, make a note of that. --- if (IsMemberSpecialization) --- Partial->setMemberSpecialization(); -- Partial->setTemplateArgsAsWritten(TemplateArgs); -- -- if (!PrevPartial) -- VarTemplate->AddPartialSpecialization(Partial, InsertPos); -- Specialization = Partial; -- --+ // If we are providing an explicit specialization of a member variable --+ // template specialization, make a note of that. --+ if (PrevPartial && PrevPartial->getInstantiatedFromMember()) --+ PrevPartial->setMemberSpecialization(); --+ -- CheckTemplatePartialSpecialization(Partial); -- } else { -- // Create a new class template specialization declaration node for --@@ -5784,7 +5788,9 @@ -- -- MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs( -- Template, NewContext, /*Final=*/false, CanonicalConverted, --- /*RelativeToPrimary=*/true, /*ForConceptInstantiation=*/true); --+ /*RelativeToPrimary=*/true, --+ /*Pattern=*/nullptr, --+ /*ForConceptInstantiation=*/true); -- if (EnsureTemplateArgumentListConstraints( -- Template, MLTAL, -- SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) { --@@ -8484,8 +8490,8 @@ -- S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(), -- TemplateNameLoc, Attr, TemplateParams, AS_none, -- /*ModulePrivateLoc=*/SourceLocation(), --- /*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(), --- isMemberSpecialization); --+ /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1, --+ TemplateParameterLists.data()); -- } -- -- // Create a new class template partial specialization declaration node. --@@ -8495,11 +8501,6 @@ -- ClassTemplatePartialSpecializationDecl::Create( -- Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams, -- ClassTemplate, CanonicalConverted, CanonType, PrevPartial); --- --- // If we are providing an explicit specialization of a member class --- // template specialization, make a note of that. --- if (isMemberSpecialization) --- Partial->setMemberSpecialization(); -- Partial->setTemplateArgsAsWritten(TemplateArgs); -- SetNestedNameSpecifier(*this, Partial, SS); -- if (TemplateParameterLists.size() > 1 && SS.isSet()) { --@@ -8511,6 +8512,11 @@ -- ClassTemplate->AddPartialSpecialization(Partial, InsertPos); -- Specialization = Partial; -- --+ // If we are providing an explicit specialization of a member class --+ // template specialization, make a note of that. --+ if (PrevPartial && PrevPartial->getInstantiatedFromMember()) --+ PrevPartial->setMemberSpecialization(); --+ -- CheckTemplatePartialSpecialization(Partial); -- } else { -- // Create a new class template specialization declaration node for --@@ -9110,8 +9116,8 @@ -- TemplateDeductionInfo Info(FailedCandidates.getLocation()); -- FunctionDecl *Specialization = nullptr; -- if (TemplateDeductionResult TDK = DeduceTemplateArguments( --- FunTmpl, ExplicitTemplateArgs ? &Args : nullptr, FT, --- Specialization, Info); --+ cast(FunTmpl->getFirstDecl()), --+ ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization, Info); -- TDK != TemplateDeductionResult::Success) { -- // Template argument deduction failed; record why it failed, so -- // that we can provide nifty diagnostics. --@@ -11309,8 +11315,8 @@ -- -- template -- void checkTemplate(TemplDecl *TD) { --- if (TD->getMostRecentDecl()->isMemberSpecialization()) { --- if (!CheckMemberSpecialization(TD->getMostRecentDecl())) --+ if (TD->isMemberSpecialization()) { --+ if (!CheckMemberSpecialization(TD)) -- diagnose(TD->getMostRecentDecl(), false); -- } -- } --diff -ruN --strip-trailing-cr a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp ----- a/clang/lib/Sema/SemaTemplateDeduction.cpp --+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp --@@ -3139,6 +3139,20 @@ -- struct IsPartialSpecialization { -- static constexpr bool value = true; -- }; --+template --+static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) { --+ return false; --+} --+template <> --+bool DeducedArgsNeedReplacement( --+ VarTemplatePartialSpecializationDecl *Spec) { --+ return !Spec->isClassScopeExplicitSpecialization(); --+} --+template <> --+bool DeducedArgsNeedReplacement( --+ ClassTemplatePartialSpecializationDecl *Spec) { --+ return !Spec->isClassScopeExplicitSpecialization(); --+} -- -- template -- static TemplateDeductionResult --@@ -3149,10 +3163,23 @@ -- llvm::SmallVector AssociatedConstraints; -- Template->getAssociatedConstraints(AssociatedConstraints); -- --+ std::optional> Innermost; --+ // If we don't need to replace the deduced template arguments, --+ // we can add them immediately as the inner-most argument list. --+ if (!DeducedArgsNeedReplacement(Template)) --+ Innermost = CanonicalDeducedArgs; --+ -- MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( --- Template, Template->getDeclContext(), /*Final=*/false, --- /*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true, --- /*ForConstraintInstantiation=*/true); --+ Template, Template->getDeclContext(), /*Final=*/false, Innermost, --+ /*RelativeToPrimary=*/true, /*Pattern=*/ --+ nullptr, /*ForConstraintInstantiation=*/true); --+ --+ // getTemplateInstantiationArgs picks up the non-deduced version of the --+ // template args when this is a variable template partial specialization and --+ // not class-scope explicit specialization, so replace with Deduced Args --+ // instead of adding to inner-most. --+ if (!Innermost) --+ MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs); -- -- if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL, -- Info.getLocation(), --diff -ruN --strip-trailing-cr a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp ----- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp --+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp --@@ -765,7 +765,7 @@ -- } -- // Template arguments used to transform the template arguments in -- // DeducedResults. --- SmallVector InnerArgsForBuildingRC( --+ SmallVector TemplateArgsForBuildingRC( -- F->getTemplateParameters()->size()); -- // Transform the transformed template args -- MultiLevelTemplateArgumentList Args; --@@ -778,30 +778,33 @@ -- NamedDecl *TP = F->getTemplateParameters()->getParam(Index); -- MultiLevelTemplateArgumentList Args; -- Args.setKind(TemplateSubstitutionKind::Rewrite); --- Args.addOuterTemplateArguments(InnerArgsForBuildingRC); --+ Args.addOuterTemplateArguments(TemplateArgsForBuildingRC); -- // Rebuild the template parameter with updated depth and index. -- NamedDecl *NewParam = -- transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args, -- /*NewIndex=*/FirstUndeducedParamIdx, -- getDepthAndIndex(TP).first + AdjustDepth); -- FirstUndeducedParamIdx += 1; --- assert(InnerArgsForBuildingRC[Index].isNull()); --- InnerArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam); --+ assert(TemplateArgsForBuildingRC[Index].isNull()); --+ TemplateArgsForBuildingRC[Index] = --+ Context.getInjectedTemplateArg(NewParam); -- continue; -- } -- TemplateArgumentLoc Input = -- SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{}); -- TemplateArgumentLoc Output; -- if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) { --- assert(InnerArgsForBuildingRC[Index].isNull() && --+ assert(TemplateArgsForBuildingRC[Index].isNull() && -- "InstantiatedArgs must be null before setting"); --- InnerArgsForBuildingRC[Index] = Output.getArgument(); --+ TemplateArgsForBuildingRC[Index] = Output.getArgument(); -- } -- } -- --- // A list of template arguments for transforming the require-clause using --- // the transformed template arguments as the template argument list of F. --- // --+ // A list of template arguments for transforming the require-clause of F. --+ // It must contain the entire set of template argument lists. --+ MultiLevelTemplateArgumentList ArgsForBuildingRC; --+ ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite); --+ ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC); -- // For 2), if the underlying deduction guide F is nested in a class template, -- // we need the entire template argument list, as the constraint AST in the -- // require-clause of F remains completely uninstantiated. --@@ -824,15 +827,25 @@ -- // - The occurrence of U in the function parameter is [depth:0, index:0] -- // - The template parameter of U is [depth:0, index:0] -- // --+ // We add the outer template arguments which is [int] to the multi-level arg --+ // list to ensure that the occurrence U in `C` will be replaced with int --+ // during the substitution. --+ // -- // NOTE: The underlying deduction guide F is instantiated -- either from an -- // explicitly-written deduction guide member, or from a constructor. --- MultiLevelTemplateArgumentList ArgsForBuildingRC = --- SemaRef.getTemplateInstantiationArgs(F, F->getLexicalDeclContext(), --- /*Final=*/false, --- /*Innermost=*/InnerArgsForBuildingRC, --- /*RelativeToPrimary=*/true, --- /*ForConstraintInstantiation=*/true); --- ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite); --+ // getInstantiatedFromMemberTemplate() can only handle the former case, so we --+ // check the DeclContext kind. --+ if (F->getLexicalDeclContext()->getDeclKind() == --+ clang::Decl::ClassTemplateSpecialization) { --+ auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs( --+ F, F->getLexicalDeclContext(), --+ /*Final=*/false, /*Innermost=*/std::nullopt, --+ /*RelativeToPrimary=*/true, --+ /*Pattern=*/nullptr, --+ /*ForConstraintInstantiation=*/true); --+ for (auto It : OuterLevelArgs) --+ ArgsForBuildingRC.addOuterTemplateArguments(It.Args); --+ } -- -- ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC); -- if (E.isInvalid()) --diff -ruN --strip-trailing-cr a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp ----- a/clang/lib/Sema/SemaTemplateInstantiate.cpp --+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp --@@ -52,6 +52,38 @@ -- //===----------------------------------------------------------------------===/ -- -- namespace { --+namespace TemplateInstArgsHelpers { --+struct Response { --+ const Decl *NextDecl = nullptr; --+ bool IsDone = false; --+ bool ClearRelativeToPrimary = true; --+ static Response Done() { --+ Response R; --+ R.IsDone = true; --+ return R; --+ } --+ static Response ChangeDecl(const Decl *ND) { --+ Response R; --+ R.NextDecl = ND; --+ return R; --+ } --+ static Response ChangeDecl(const DeclContext *Ctx) { --+ Response R; --+ R.NextDecl = Decl::castFromDeclContext(Ctx); --+ return R; --+ } --+ --+ static Response UseNextDecl(const Decl *CurDecl) { --+ return ChangeDecl(CurDecl->getDeclContext()); --+ } --+ --+ static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) { --+ Response R = Response::UseNextDecl(CurDecl); --+ R.ClearRelativeToPrimary = false; --+ return R; --+ } --+}; --+ -- // Retrieve the primary template for a lambda call operator. It's -- // unfortunate that we only have the mappings of call operators rather -- // than lambda classes. --@@ -139,398 +171,379 @@ -- .TraverseType(Underlying); -- } -- ---struct TemplateInstantiationArgumentCollecter --- : DeclVisitor { --- Sema &S; --- MultiLevelTemplateArgumentList &Result; --- std::optional> Innermost; --- bool RelativeToPrimary; --- bool ForConstraintInstantiation; --- --- TemplateInstantiationArgumentCollecter( --- Sema &S, MultiLevelTemplateArgumentList &Result, --- std::optional> Innermost, --- bool RelativeToPrimary, bool ForConstraintInstantiation) --- : S(S), Result(Result), Innermost(Innermost), --- RelativeToPrimary(RelativeToPrimary), --- ForConstraintInstantiation(ForConstraintInstantiation) {} --- --- Decl *Done() { return nullptr; } --- --- Decl *ChangeDecl(const Decl *D) { --- RelativeToPrimary = false; --- return const_cast(D); --- } --- --- Decl *ChangeDecl(const DeclContext *DC) { --- return ChangeDecl(Decl::castFromDeclContext(DC)); --- } --- --- Decl *UseNextDecl(const Decl *D) { return ChangeDecl(D->getDeclContext()); } --- --- void AddInnermostTemplateArguments(const Decl *D) { --- assert(Innermost); --- Result.addOuterTemplateArguments(const_cast(D), *Innermost, --- /*Final=*/false); --- Innermost.reset(); --- } --- --- void AddOuterTemplateArguments(const Decl *D, ArrayRef Args, --- bool Final) { --- Result.addOuterTemplateArguments(const_cast(D), Args, Final); --- } --- --- Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) { --- if (Innermost) --- AddInnermostTemplateArguments(TTPD); --- else if (ForConstraintInstantiation) --- AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false); --- --- for (unsigned Depth = TTPD->getDepth() + 1; Depth--;) --- AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false); --- --- return Done(); --- } --- --- Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) { --- assert( --- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && --- "outer template not instantiated?"); --- --- if (Innermost) --- AddInnermostTemplateArguments(FTD); --- else if (ForConstraintInstantiation) --- AddOuterTemplateArguments(FTD, FTD->getInjectedTemplateArgs(S.Context), --- /*Final=*/false); --- --- if (FTD->isMemberSpecialization()) --- return Done(); --- --- if (FTD->getFriendObjectKind()) --- return ChangeDecl(FTD->getLexicalDeclContext()); --- return UseNextDecl(FTD); --- } --- --- Decl *VisitVarTemplateDecl(VarTemplateDecl *VTD) { --- assert( --- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && --- "outer template not instantiated?"); --- --- if (Innermost) --- AddInnermostTemplateArguments(VTD); --- else if (ForConstraintInstantiation) --- AddOuterTemplateArguments(VTD, VTD->getInjectedTemplateArgs(S.Context), --- /*Final=*/false); --- --- if (VTD->isMemberSpecialization()) --- return Done(); --- --- return UseNextDecl(VTD); --- } --- --- Decl *VisitVarTemplatePartialSpecializationDecl( --- VarTemplatePartialSpecializationDecl *VTPSD) { --- assert( --- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && --- "outer template not instantiated?"); --- --- if (Innermost) --- AddInnermostTemplateArguments(VTPSD); --- else if (ForConstraintInstantiation) --- AddOuterTemplateArguments(VTPSD, --- VTPSD->getInjectedTemplateArgs(S.Context), --- /*Final=*/false); --- --- if (VTPSD->isMemberSpecialization()) --- return Done(); --- --- return UseNextDecl(VTPSD); --- } --- --- Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) { --- assert( --- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && --- "outer template not instantiated?"); --- --- if (Innermost) --- AddInnermostTemplateArguments(CTD); --- else if (ForConstraintInstantiation) --- AddOuterTemplateArguments(CTD, CTD->getInjectedTemplateArgs(S.Context), --- /*Final=*/false); --- --- if (CTD->isMemberSpecialization()) --- return Done(); --- --- if (CTD->getFriendObjectKind()) --- return ChangeDecl(CTD->getLexicalDeclContext()); --- return UseNextDecl(CTD); --- } --- --- Decl *VisitClassTemplatePartialSpecializationDecl( --- ClassTemplatePartialSpecializationDecl *CTPSD) { --- assert( --- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && --- "outer template not instantiated?"); --- --- if (Innermost) --- AddInnermostTemplateArguments(CTPSD); --- else if (ForConstraintInstantiation) --- AddOuterTemplateArguments(CTPSD, --- CTPSD->getInjectedTemplateArgs(S.Context), --- /*Final=*/false); --+// Add template arguments from a variable template instantiation. --+Response --+HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec, --+ MultiLevelTemplateArgumentList &Result, --+ bool SkipForSpecialization) { --+ // For a class-scope explicit specialization, there are no template arguments --+ // at this level, but there may be enclosing template arguments. --+ if (VarTemplSpec->isClassScopeExplicitSpecialization()) --+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); --+ --+ // We're done when we hit an explicit specialization. --+ if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && --+ !isa(VarTemplSpec)) --+ return Response::Done(); --+ --+ // If this variable template specialization was instantiated from a --+ // specialized member that is a variable template, we're done. --+ assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?"); --+ llvm::PointerUnion --+ Specialized = VarTemplSpec->getSpecializedTemplateOrPartial(); --+ if (VarTemplatePartialSpecializationDecl *Partial = --+ Specialized.dyn_cast()) { --+ if (!SkipForSpecialization) --+ Result.addOuterTemplateArguments( --+ Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(), --+ /*Final=*/false); --+ if (Partial->isMemberSpecialization()) --+ return Response::Done(); --+ } else { --+ VarTemplateDecl *Tmpl = Specialized.get(); --+ if (!SkipForSpecialization) --+ Result.addOuterTemplateArguments( --+ Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(), --+ /*Final=*/false); --+ if (Tmpl->isMemberSpecialization()) --+ return Response::Done(); --+ } --+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); --+} --+ --+// If we have a template template parameter with translation unit context, --+// then we're performing substitution into a default template argument of --+// this template template parameter before we've constructed the template --+// that will own this template template parameter. In this case, we --+// use empty template parameter lists for all of the outer templates --+// to avoid performing any substitutions. --+Response --+HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP, --+ MultiLevelTemplateArgumentList &Result) { --+ for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I) --+ Result.addOuterTemplateArguments(std::nullopt); --+ return Response::Done(); --+} --+ --+Response HandlePartialClassTemplateSpec( --+ const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec, --+ MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) { --+ if (!SkipForSpecialization) --+ Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth()); --+ return Response::Done(); --+} --+ --+// Add template arguments from a class template instantiation. --+Response --+HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, --+ MultiLevelTemplateArgumentList &Result, --+ bool SkipForSpecialization) { --+ if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) { --+ // We're done when we hit an explicit specialization. --+ if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && --+ !isa(ClassTemplSpec)) --+ return Response::Done(); --+ --+ if (!SkipForSpecialization) --+ Result.addOuterTemplateArguments( --+ const_cast(ClassTemplSpec), --+ ClassTemplSpec->getTemplateInstantiationArgs().asArray(), --+ /*Final=*/false); -- --- if (CTPSD->isMemberSpecialization()) --- return Done(); --+ // If this class template specialization was instantiated from a --+ // specialized member that is a class template, we're done. --+ assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?"); --+ if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization()) --+ return Response::Done(); --+ --+ // If this was instantiated from a partial template specialization, we need --+ // to get the next level of declaration context from the partial --+ // specialization, as the ClassTemplateSpecializationDecl's --+ // DeclContext/LexicalDeclContext will be for the primary template. --+ if (auto *InstFromPartialTempl = --+ ClassTemplSpec->getSpecializedTemplateOrPartial() --+ .dyn_cast()) --+ return Response::ChangeDecl( --+ InstFromPartialTempl->getLexicalDeclContext()); --+ } --+ return Response::UseNextDecl(ClassTemplSpec); --+} --+ --+Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function, --+ MultiLevelTemplateArgumentList &Result, --+ const FunctionDecl *Pattern, bool RelativeToPrimary, --+ bool ForConstraintInstantiation, --+ bool ForDefaultArgumentSubstitution) { --+ // Add template arguments from a function template specialization. --+ if (!RelativeToPrimary && --+ Function->getTemplateSpecializationKindForInstantiation() == --+ TSK_ExplicitSpecialization) --+ return Response::Done(); --+ --+ if (!RelativeToPrimary && --+ Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { --+ // This is an implicit instantiation of an explicit specialization. We --+ // don't get any template arguments from this function but might get --+ // some from an enclosing template. --+ return Response::UseNextDecl(Function); --+ } else if (const TemplateArgumentList *TemplateArgs = --+ Function->getTemplateSpecializationArgs()) { --+ // Add the template arguments for this specialization. --+ Result.addOuterTemplateArguments(const_cast(Function), --+ TemplateArgs->asArray(), --+ /*Final=*/false); -- --- return UseNextDecl(CTPSD); --- } --+ if (RelativeToPrimary && --+ (Function->getTemplateSpecializationKind() == --+ TSK_ExplicitSpecialization || --+ (Function->getFriendObjectKind() && --+ !Function->getPrimaryTemplate()->getFriendObjectKind()))) --+ return Response::UseNextDecl(Function); --+ --+ // If this function was instantiated from a specialized member that is --+ // a function template, we're done. --+ assert(Function->getPrimaryTemplate() && "No function template?"); --+ if (!ForDefaultArgumentSubstitution && --+ Function->getPrimaryTemplate()->isMemberSpecialization()) --+ return Response::Done(); --+ --+ // If this function is a generic lambda specialization, we are done. --+ if (!ForConstraintInstantiation && --+ isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) --+ return Response::Done(); -- --- Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *TATD) { --+ } else if (Function->getDescribedFunctionTemplate()) { -- assert( -- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && --- "outer template not instantiated?"); --- if (Innermost) --- AddInnermostTemplateArguments(TATD); --- else if (ForConstraintInstantiation) --- AddOuterTemplateArguments(TATD, TATD->getInjectedTemplateArgs(S.Context), --- /*Final=*/false); --- --- return UseNextDecl(TATD); --+ "Outer template not instantiated?"); -- } --- --- Decl *VisitConceptDecl(ConceptDecl *CD) { --- assert( --- (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && --- "outer template not instantiated?"); --- if (Innermost) --- AddInnermostTemplateArguments(CD); --- --- return UseNextDecl(CD); --- } --- --- Decl *VisitFunctionDecl(FunctionDecl *FD) { --- assert(!FD->getDescribedFunctionTemplate() && --- "not for templated declarations"); --- --- if (!RelativeToPrimary) { --- // Add template arguments from a function template specialization. --- if (const MemberSpecializationInfo *MSI = --- FD->getMemberSpecializationInfo(); --- MSI && --- MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) --- return Done(); --- --- // This is an implicit instantiation of an explicit specialization. We --- // don't get any template arguments from this function but might get --- // some from an enclosing template. --- if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) --- return UseNextDecl(FD); --- } --- --- if (const TemplateArgumentList *TemplateArgs = --- FD->getTemplateSpecializationArgs()) { --- // Add the template arguments for this specialization. --- if (Innermost) --- AddInnermostTemplateArguments(FD); --- else --- AddOuterTemplateArguments(FD, TemplateArgs->asArray(), /*Final=*/false); --- --- if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization || --- (FD->getFriendObjectKind() && --- !FD->getPrimaryTemplate()->getFriendObjectKind())) --- return UseNextDecl(FD); --- --- // 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()) --- return Done(); --- --- // If this function is a generic lambda specialization, we are done. --- if (!ForConstraintInstantiation && --- isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) --- return Done(); --- } --- --- // If this is a friend or local declaration and it declares an entity at --- // namespace scope, take arguments from its lexical parent --- // instead of its semantic parent, unless of course the pattern we're --- // instantiating actually comes from the file's context! --- if ((FD->getFriendObjectKind() || FD->isLocalExternDecl()) && --- FD->getNonTransparentDeclContext()->isFileContext()) { --- return ChangeDecl(FD->getLexicalDeclContext()); --- } --- --- if (ForConstraintInstantiation && FD->getFriendObjectKind()) --- return ChangeDecl(FD->getLexicalDeclContext()); --- return UseNextDecl(FD); --- } --- --- Decl *VisitCXXRecordDecl(CXXRecordDecl *RD) { --- assert(!RD->getDescribedClassTemplate() && --- "not for templated declarations"); --- --- if (const MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo(); --- MSI && --- MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) --- return Done(); --- --- if (ForConstraintInstantiation && RD->getFriendObjectKind() && --- RD->getNonTransparentDeclContext()->isFileContext()) { --- return ChangeDecl(RD->getLexicalDeclContext()); --- } --- --- // This is to make sure we pick up the VarTemplateSpecializationDecl or the --- // TypeAliasTemplateDecl that this lambda is defined inside of. --- if (RD->isLambda()) { --- if (Decl *LCD = RD->getLambdaContextDecl()) --- return ChangeDecl(LCD); --- // Retrieve the template arguments for a using alias declaration. --- // This is necessary for constraint checking, since we always keep --- // constraints relative to the primary template. --- if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(S); --- ForConstraintInstantiation && TypeAlias) { --- if (isLambdaEnclosedByTypeAliasDecl(RD->getLambdaCallOperator(), --- TypeAlias.PrimaryTypeAliasDecl)) { --- AddOuterTemplateArguments(TypeAlias.Template, --- TypeAlias.AssociatedTemplateArguments, --- /*Final=*/false); --- // Visit the parent of the current type alias declaration rather than --- // the lambda thereof. --- // E.g., in the following example: --- // struct S { --- // template using T = decltype([] {} ()); --+ // If this is a friend or local declaration and it declares an entity at --+ // namespace scope, take arguments from its lexical parent --+ // instead of its semantic parent, unless of course the pattern we're --+ // instantiating actually comes from the file's context! --+ if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) && --+ Function->getNonTransparentDeclContext()->isFileContext() && --+ (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { --+ return Response::ChangeDecl(Function->getLexicalDeclContext()); --+ } --+ --+ if (ForConstraintInstantiation && Function->getFriendObjectKind()) --+ return Response::ChangeDecl(Function->getLexicalDeclContext()); --+ return Response::UseNextDecl(Function); --+} --+ --+Response HandleFunctionTemplateDecl(Sema &SemaRef, --+ const FunctionTemplateDecl *FTD, --+ MultiLevelTemplateArgumentList &Result) { --+ if (!isa(FTD->getDeclContext())) { --+ Result.addOuterTemplateArguments( --+ const_cast(FTD), --+ const_cast(FTD)->getInjectedTemplateArgs( --+ SemaRef.Context), --+ /*Final=*/false); --+ --+ NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier(); --+ --+ while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { --+ if (NNS->isInstantiationDependent()) { --+ if (const auto *TSTy = Ty->getAs()) { --+ ArrayRef Arguments = TSTy->template_arguments(); --+ // Prefer template arguments from the injected-class-type if possible. --+ // For example, --+ // ```cpp --+ // template struct S { --+ // template void foo(); -- // }; --- // void foo() { --- // S::T var; --- // } --- // The instantiated lambda expression (which we're visiting at 'var') --- // has a function DeclContext 'foo' rather than the Record DeclContext --- // S. This seems to be an oversight to me that we may want to set a --- // Sema Context from the CXXScopeSpec before substituting into T. --- return ChangeDecl(TypeAlias.Template->getDeclContext()); --+ // template template --+ // ^^^^^^^^^^^^^ InjectedTemplateArgs --+ // They're of kind TemplateArgument::Pack, not of --+ // TemplateArgument::Type. --+ // void S::foo() {} --+ // ^^^^^^^ --+ // TSTy->template_arguments() (which are of PackExpansionType) --+ // ``` --+ // This meets the contract in --+ // TreeTransform::TryExpandParameterPacks that the template arguments --+ // for unexpanded parameters should be of a Pack kind. --+ if (TSTy->isCurrentInstantiation()) { --+ auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl(); --+ if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) --+ Arguments = CTD->getInjectedTemplateArgs(SemaRef.Context); --+ else if (auto *Specialization = --+ dyn_cast(RD)) --+ Arguments = --+ Specialization->getTemplateInstantiationArgs().asArray(); --+ } --+ Result.addOuterTemplateArguments( --+ TSTy->getTemplateName().getAsTemplateDecl(), Arguments, --+ /*Final=*/false); -- } -- } --- } --- --- return UseNextDecl(RD); --- } --- --- Decl * --- VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) { --- // For a class-scope explicit specialization, there are no template --- // arguments at this level, but there may be enclosing template arguments. --- if (CTSD->isClassScopeExplicitSpecialization()) --- return UseNextDecl(CTSD); -- --- // We're done when we hit an explicit specialization. --- if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization) --- return Done(); --- --- if (Innermost) --- AddInnermostTemplateArguments(CTSD); --- else --- AddOuterTemplateArguments(CTSD, --- CTSD->getTemplateInstantiationArgs().asArray(), --- /*Final=*/false); --- --- // If this class template specialization was instantiated from a --- // specialized member that is a class template, we're done. --- assert(CTSD->getSpecializedTemplate() && "No class template?"); --- llvm::PointerUnion --- Specialized = CTSD->getSpecializedTemplateOrPartial(); --- if (auto *CTPSD = --- Specialized.dyn_cast()) { --- if (CTPSD->isMemberSpecialization()) --- return Done(); --- } else { --- auto *CTD = Specialized.get(); --- if (CTD->isMemberSpecialization()) --- return Done(); --- } --- return UseNextDecl(CTSD); --+ NNS = NNS->getPrefix(); --+ } -- } -- --- Decl * --- VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *VTSD) { --- // For a class-scope explicit specialization, there are no template --- // arguments at this level, but there may be enclosing template arguments. --- if (VTSD->isClassScopeExplicitSpecialization()) --- return UseNextDecl(VTSD); --- --- // We're done when we hit an explicit specialization. --- if (VTSD->getSpecializationKind() == TSK_ExplicitSpecialization) --- return Done(); --+ return Response::ChangeDecl(FTD->getLexicalDeclContext()); --+} -- --- if (Innermost) --- AddInnermostTemplateArguments(VTSD); --- else --- AddOuterTemplateArguments(VTSD, --- VTSD->getTemplateInstantiationArgs().asArray(), --- /*Final=*/false); --- --- // If this variable template specialization was instantiated from a --- // specialized member that is a variable template, we're done. --- assert(VTSD->getSpecializedTemplate() && "No variable template?"); --- llvm::PointerUnion --- Specialized = VTSD->getSpecializedTemplateOrPartial(); --- if (auto *VTPSD = --- Specialized.dyn_cast()) { --- if (VTPSD->isMemberSpecialization()) --- return Done(); --- } else { --- auto *VTD = Specialized.get(); --- if (VTD->isMemberSpecialization()) --- return Done(); --+Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec, --+ MultiLevelTemplateArgumentList &Result, --+ ASTContext &Context, --+ bool ForConstraintInstantiation) { --+ if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { --+ assert( --+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && --+ "Outer template not instantiated?"); --+ if (ClassTemplate->isMemberSpecialization()) --+ return Response::Done(); --+ if (ForConstraintInstantiation) --+ Result.addOuterTemplateArguments( --+ const_cast(Rec), --+ ClassTemplate->getInjectedTemplateArgs(SemaRef.Context), --+ /*Final=*/false); --+ } --+ --+ if (const MemberSpecializationInfo *MSInfo = --+ Rec->getMemberSpecializationInfo()) --+ if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) --+ return Response::Done(); --+ --+ bool IsFriend = Rec->getFriendObjectKind() || --+ (Rec->getDescribedClassTemplate() && --+ Rec->getDescribedClassTemplate()->getFriendObjectKind()); --+ if (ForConstraintInstantiation && IsFriend && --+ Rec->getNonTransparentDeclContext()->isFileContext()) { --+ return Response::ChangeDecl(Rec->getLexicalDeclContext()); --+ } --+ --+ // This is to make sure we pick up the VarTemplateSpecializationDecl or the --+ // TypeAliasTemplateDecl that this lambda is defined inside of. --+ if (Rec->isLambda()) { --+ if (const Decl *LCD = Rec->getLambdaContextDecl()) --+ return Response::ChangeDecl(LCD); --+ // Retrieve the template arguments for a using alias declaration. --+ // This is necessary for constraint checking, since we always keep --+ // constraints relative to the primary template. --+ if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef); --+ ForConstraintInstantiation && TypeAlias) { --+ if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(), --+ TypeAlias.PrimaryTypeAliasDecl)) { --+ Result.addOuterTemplateArguments(TypeAlias.Template, --+ TypeAlias.AssociatedTemplateArguments, --+ /*Final=*/false); --+ // Visit the parent of the current type alias declaration rather than --+ // the lambda thereof. --+ // E.g., in the following example: --+ // struct S { --+ // template using T = decltype([] {} ()); --+ // }; --+ // void foo() { --+ // S::T var; --+ // } --+ // The instantiated lambda expression (which we're visiting at 'var') --+ // has a function DeclContext 'foo' rather than the Record DeclContext --+ // S. This seems to be an oversight to me that we may want to set a --+ // Sema Context from the CXXScopeSpec before substituting into T. --+ return Response::ChangeDecl(TypeAlias.Template->getDeclContext()); --+ } -- } --- return UseNextDecl(VTSD); -- } -- --- Decl *VisitImplicitConceptSpecializationDecl( --- ImplicitConceptSpecializationDecl *ICSD) { --- AddOuterTemplateArguments(ICSD, ICSD->getTemplateArguments(), --- /*Final=*/false); --- return UseNextDecl(ICSD); --- } --- --- Decl *VisitDecl(Decl *D) { --- if (D->isFileContextDecl()) --- return Done(); --- --- if (isa(D)) --- RelativeToPrimary = false; --- --- return UseNextDecl(D); --- } --+ return Response::UseNextDecl(Rec); --+} -- --- Decl *Visit(Decl *D) { --- if (TemplateDecl *TD = D->getDescribedTemplate()) --- D = TD; --- return DeclVisitor::Visit(D); --- } ---}; --+Response HandleImplicitConceptSpecializationDecl( --+ const ImplicitConceptSpecializationDecl *CSD, --+ MultiLevelTemplateArgumentList &Result) { --+ Result.addOuterTemplateArguments( --+ const_cast(CSD), --+ CSD->getTemplateArguments(), --+ /*Final=*/false); --+ return Response::UseNextDecl(CSD); --+} -- --+Response HandleGenericDeclContext(const Decl *CurDecl) { --+ return Response::UseNextDecl(CurDecl); --+} --+} // namespace TemplateInstArgsHelpers -- } // namespace -- -- MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( -- const NamedDecl *ND, const DeclContext *DC, bool Final, -- std::optional> Innermost, bool RelativeToPrimary, --- bool ForConstraintInstantiation) { --+ const FunctionDecl *Pattern, bool ForConstraintInstantiation, --+ bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) { -- assert((ND || DC) && "Can't find arguments for a decl if one isn't provided"); -- // Accumulate the set of template argument lists in this structure. -- MultiLevelTemplateArgumentList Result; --+ --+ using namespace TemplateInstArgsHelpers; -- const Decl *CurDecl = ND; -- -- if (!CurDecl) -- CurDecl = Decl::castFromDeclContext(DC); -- --- TemplateInstantiationArgumentCollecter Collecter( --- *this, Result, Innermost, RelativeToPrimary, ForConstraintInstantiation); --- do { --- CurDecl = Collecter.Visit(const_cast(CurDecl)); --- } while (CurDecl); --+ if (Innermost) { --+ Result.addOuterTemplateArguments(const_cast(ND), *Innermost, --+ Final); --+ // Populate placeholder template arguments for TemplateTemplateParmDecls. --+ // This is essential for the case e.g. --+ // --+ // template concept Concept = false; --+ // template