diff --git a/third_party/llvm/generated.patch b/third_party/llvm/generated.patch index d31176550e8c1f..ca1e4ff4da13b0 100644 --- a/third_party/llvm/generated.patch +++ b/third_party/llvm/generated.patch @@ -1,616 +1,2926 @@ Auto generated patch. Do not edit or delete it, even if empty. -diff -ruN --strip-trailing-cr a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp ---- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp -+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp -@@ -7046,7 +7046,8 @@ - OrdersType Order; - SmallVector PointerOps; - // Segmented load detected - vectorize at maximum vector factor. -- if (TTI.isLegalInterleavedAccessType( -+ if (InterleaveFactor <= Slice.size() && -+ TTI.isLegalInterleavedAccessType( - getWidenedType(Slice.front()->getType(), VF), - InterleaveFactor, - cast(Slice.front())->getAlign(), -diff -ruN --strip-trailing-cr a/llvm/test/Transforms/SLPVectorizer/RISCV/interleave-greater-than-slice.ll b/llvm/test/Transforms/SLPVectorizer/RISCV/interleave-greater-than-slice.ll ---- a/llvm/test/Transforms/SLPVectorizer/RISCV/interleave-greater-than-slice.ll -+++ b/llvm/test/Transforms/SLPVectorizer/RISCV/interleave-greater-than-slice.ll -@@ -0,0 +1,74 @@ -+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 -+; RUN: opt -S --passes=slp-vectorizer -mtriple=riscv64-unknown-linux -mattr=+v,+zvl128b < %s | FileCheck %s -+ -+define void @test(ptr %a, float %0) { -+; CHECK-LABEL: define void @test( -+; CHECK-SAME: ptr [[A:%.*]], float [[TMP0:%.*]]) #[[ATTR0:[0-9]+]] { -+; CHECK-NEXT: [[ENTRY:.*:]] -+; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A]], align 8 -+; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr i8, ptr [[TMP1]], i64 84 -+; CHECK-NEXT: [[TMP2:%.*]] = load float, ptr [[ARRAYIDX]], align 4 -+; CHECK-NEXT: [[TMP3:%.*]] = tail call float @llvm.fmuladd.f32(float [[TMP2]], float 0.000000e+00, float 0.000000e+00) -+; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr i8, ptr [[TMP1]], i64 28 -+; CHECK-NEXT: [[TMP4:%.*]] = load float, ptr [[ARRAYIDX1]], align 4 -+; CHECK-NEXT: [[TMP5:%.*]] = tail call float @llvm.fmuladd.f32(float [[TMP4]], float 0.000000e+00, float [[TMP3]]) -+; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr i8, ptr [[TMP1]], i64 8 -+; CHECK-NEXT: [[TMP6:%.*]] = load float, ptr [[ARRAYIDX2]], align 4 -+; CHECK-NEXT: [[TMP7:%.*]] = tail call float @llvm.fmuladd.f32(float [[TMP6]], float 0.000000e+00, float 0.000000e+00) -+; CHECK-NEXT: [[ARRAYIDX3:%.*]] = getelementptr i8, ptr [[TMP1]], i64 68 -+; CHECK-NEXT: [[TMP8:%.*]] = load float, ptr [[ARRAYIDX3]], align 4 -+; CHECK-NEXT: [[TMP9:%.*]] = tail call float @llvm.fmuladd.f32(float [[TMP8]], float 0.000000e+00, float [[TMP5]]) -+; CHECK-NEXT: [[ARRAYIDX4:%.*]] = getelementptr i8, ptr [[TMP1]], i64 88 -+; CHECK-NEXT: [[TMP10:%.*]] = load float, ptr [[ARRAYIDX4]], align 4 -+; CHECK-NEXT: [[TMP11:%.*]] = tail call float @llvm.fmuladd.f32(float [[TMP10]], float 0.000000e+00, float [[TMP7]]) -+; CHECK-NEXT: [[ARRAYIDX5:%.*]] = getelementptr i8, ptr [[TMP1]], i64 92 -+; CHECK-NEXT: [[TMP12:%.*]] = load float, ptr [[ARRAYIDX5]], align 4 -+; CHECK-NEXT: [[TMP13:%.*]] = tail call float @llvm.fmuladd.f32(float [[TMP12]], float 0.000000e+00, float [[TMP11]]) -+; CHECK-NEXT: [[TMP14:%.*]] = tail call float @llvm.fmuladd.f32(float [[TMP0]], float 0.000000e+00, float [[TMP9]]) -+; CHECK-NEXT: [[ARRAYIDX6:%.*]] = getelementptr i8, ptr [[TMP1]], i64 96 -+; CHECK-NEXT: [[TMP15:%.*]] = load float, ptr [[ARRAYIDX6]], align 4 -+; CHECK-NEXT: [[TMP16:%.*]] = tail call float @llvm.fmuladd.f32(float [[TMP15]], float 0.000000e+00, float [[TMP13]]) -+; CHECK-NEXT: [[ARRAYIDX7:%.*]] = getelementptr i8, ptr [[TMP1]], i64 80 -+; CHECK-NEXT: [[TMP17:%.*]] = load float, ptr [[ARRAYIDX7]], align 4 -+; CHECK-NEXT: [[TMP18:%.*]] = tail call float @llvm.fmuladd.f32(float [[TMP0]], float [[TMP17]], float [[TMP16]]) -+; CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr i8, ptr [[TMP1]], i64 100 -+; CHECK-NEXT: [[TMP19:%.*]] = load float, ptr [[ARRAYIDX8]], align 4 -+; CHECK-NEXT: [[TMP20:%.*]] = tail call float @llvm.fmuladd.f32(float [[TMP19]], float 0.000000e+00, float [[TMP14]]) -+; CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP18]], [[TMP20]] -+; CHECK-NEXT: store float [[ADD]], ptr [[A]], align 4 -+; CHECK-NEXT: ret void -+; -+entry: -+ %1 = load ptr, ptr %a, align 8 -+ %arrayidx = getelementptr i8, ptr %1, i64 84 -+ %2 = load float, ptr %arrayidx, align 4 -+ %3 = tail call float @llvm.fmuladd.f32(float %2, float 0.000000e+00, float 0.000000e+00) -+ %arrayidx1 = getelementptr i8, ptr %1, i64 28 -+ %4 = load float, ptr %arrayidx1, align 4 -+ %5 = tail call float @llvm.fmuladd.f32(float %4, float 0.000000e+00, float %3) -+ %arrayidx2 = getelementptr i8, ptr %1, i64 8 -+ %6 = load float, ptr %arrayidx2, align 4 -+ %7 = tail call float @llvm.fmuladd.f32(float %6, float 0.000000e+00, float 0.000000e+00) -+ %arrayidx3 = getelementptr i8, ptr %1, i64 68 -+ %8 = load float, ptr %arrayidx3, align 4 -+ %9 = tail call float @llvm.fmuladd.f32(float %8, float 0.000000e+00, float %5) -+ %arrayidx4 = getelementptr i8, ptr %1, i64 88 -+ %10 = load float, ptr %arrayidx4, align 4 -+ %11 = tail call float @llvm.fmuladd.f32(float %10, float 0.000000e+00, float %7) -+ %arrayidx5 = getelementptr i8, ptr %1, i64 92 -+ %12 = load float, ptr %arrayidx5, align 4 -+ %13 = tail call float @llvm.fmuladd.f32(float %12, float 0.000000e+00, float %11) -+ %14 = tail call float @llvm.fmuladd.f32(float %0, float 0.000000e+00, float %9) -+ %arrayidx6 = getelementptr i8, ptr %1, i64 96 -+ %15 = load float, ptr %arrayidx6, align 4 -+ %16 = tail call float @llvm.fmuladd.f32(float %15, float 0.000000e+00, float %13) -+ %arrayidx7 = getelementptr i8, ptr %1, i64 80 -+ %17 = load float, ptr %arrayidx7, align 4 -+ %18 = tail call float @llvm.fmuladd.f32(float %0, float %17, float %16) -+ %arrayidx8 = getelementptr i8, ptr %1, i64 100 -+ %19 = load float, ptr %arrayidx8, align 4 -+ %20 = tail call float @llvm.fmuladd.f32(float %19, float 0.000000e+00, float %14) -+ %add = fadd float %18, %20 -+ store float %add, ptr %a, align 4 -+ ret void -+} -diff -ruN --strip-trailing-cr a/mlir/lib/Bindings/Python/IRAttributes.cpp b/mlir/lib/Bindings/Python/IRAttributes.cpp ---- a/mlir/lib/Bindings/Python/IRAttributes.cpp -+++ b/mlir/lib/Bindings/Python/IRAttributes.cpp -@@ -13,7 +13,6 @@ - #include "IRModule.h" - - #include "PybindUtils.h" --#include - - #include "llvm/ADT/ScopeExit.h" - #include "llvm/Support/raw_ostream.h" -@@ -758,10 +757,103 @@ - throw py::error_already_set(); +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; } - auto freeBuffer = llvm::make_scope_exit([&]() { PyBuffer_Release(&view); }); -+ SmallVector shape; -+ if (explicitShape) { -+ shape.append(explicitShape->begin(), explicitShape->end()); -+ } else { -+ shape.append(view.shape, view.shape + view.ndim); -+ } +- return getDefinitionOrSelf(VTD->getTemplatedDecl()); ++ ++ return getDefinitionOrSelf(VarTemplate->getTemplatedDecl()); + } -+ MlirAttribute encodingAttr = mlirAttributeGetNull(); - MlirContext context = contextWrapper->get(); -- MlirAttribute attr = getAttributeFromBuffer(view, signless, explicitType, -- explicitShape, context); -+ -+ // Detect format codes that are suitable for bulk loading. This includes -+ // all byte aligned integer and floating point types up to 8 bytes. -+ // Notably, this excludes, bool (which needs to be bit-packed) and -+ // other exotics which do not have a direct representation in the buffer -+ // protocol (i.e. complex, etc). -+ std::optional bulkLoadElementType; -+ if (explicitType) { -+ bulkLoadElementType = *explicitType; -+ } else { -+ std::string_view format(view.format); -+ if (format == "f") { -+ // f32 -+ assert(view.itemsize == 4 && "mismatched array itemsize"); -+ bulkLoadElementType = mlirF32TypeGet(context); -+ } else if (format == "d") { -+ // f64 -+ assert(view.itemsize == 8 && "mismatched array itemsize"); -+ bulkLoadElementType = mlirF64TypeGet(context); -+ } else if (format == "e") { -+ // f16 -+ assert(view.itemsize == 2 && "mismatched array itemsize"); -+ bulkLoadElementType = mlirF16TypeGet(context); -+ } else if (isSignedIntegerFormat(format)) { -+ if (view.itemsize == 4) { -+ // i32 -+ bulkLoadElementType = signless -+ ? mlirIntegerTypeGet(context, 32) -+ : mlirIntegerTypeSignedGet(context, 32); -+ } else if (view.itemsize == 8) { -+ // i64 -+ bulkLoadElementType = signless -+ ? mlirIntegerTypeGet(context, 64) -+ : mlirIntegerTypeSignedGet(context, 64); -+ } else if (view.itemsize == 1) { -+ // i8 -+ bulkLoadElementType = signless ? mlirIntegerTypeGet(context, 8) -+ : mlirIntegerTypeSignedGet(context, 8); -+ } else if (view.itemsize == 2) { -+ // i16 -+ bulkLoadElementType = signless -+ ? mlirIntegerTypeGet(context, 16) -+ : mlirIntegerTypeSignedGet(context, 16); -+ } -+ } else if (isUnsignedIntegerFormat(format)) { -+ if (view.itemsize == 4) { -+ // unsigned i32 -+ bulkLoadElementType = signless -+ ? mlirIntegerTypeGet(context, 32) -+ : mlirIntegerTypeUnsignedGet(context, 32); -+ } else if (view.itemsize == 8) { -+ // unsigned i64 -+ bulkLoadElementType = signless -+ ? mlirIntegerTypeGet(context, 64) -+ : mlirIntegerTypeUnsignedGet(context, 64); -+ } else if (view.itemsize == 1) { -+ // i8 -+ bulkLoadElementType = signless -+ ? mlirIntegerTypeGet(context, 8) -+ : mlirIntegerTypeUnsignedGet(context, 8); -+ } else if (view.itemsize == 2) { -+ // i16 -+ bulkLoadElementType = signless -+ ? mlirIntegerTypeGet(context, 16) -+ : mlirIntegerTypeUnsignedGet(context, 16); + 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; + } + } -+ if (!bulkLoadElementType) { -+ throw std::invalid_argument( -+ std::string("unimplemented array format conversion from format: ") + -+ std::string(format)); -+ } + } + } 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; + -+ MlirType shapedType; -+ if (mlirTypeIsAShaped(*bulkLoadElementType)) { -+ if (explicitShape) { -+ throw std::invalid_argument("Shape can only be specified explicitly " -+ "when the type is not a shaped type."); -+ } -+ shapedType = *bulkLoadElementType; -+ } else { -+ shapedType = mlirRankedTensorTypeGet(shape.size(), shape.data(), -+ *bulkLoadElementType, encodingAttr); -+ } -+ size_t rawBufferSize = view.len; -+ MlirAttribute attr = -+ mlirDenseElementsAttrRawBufferGet(shapedType, rawBufferSize, view.buf); - if (mlirAttributeIsNull(attr)) { - throw std::invalid_argument( - "DenseElementsAttr could not be constructed from the given buffer. " -@@ -871,13 +963,6 @@ - // unsigned i16 - return bufferInfo(shapedType); - } -- } else if (mlirTypeIsAInteger(elementType) && -- mlirIntegerTypeGetWidth(elementType) == 1) { -- // i1 / bool -- // We can not send the buffer directly back to Python, because the i1 -- // values are bitpacked within MLIR. We call numpy's unpackbits function -- // to convert the bytes. -- return getBooleanBufferFromBitpackedAttribute(); + 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()); } - // TODO: Currently crashes the program. -@@ -931,183 +1016,14 @@ - code == 'q'; + // 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(); ++} -- static MlirType -- getShapedType(std::optional bulkLoadElementType, -- std::optional> explicitShape, -- Py_buffer &view) { -- SmallVector shape; -- if (explicitShape) { -- shape.append(explicitShape->begin(), explicitShape->end()); -- } else { -- shape.append(view.shape, view.shape + view.ndim); + 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 (mlirTypeIsAShaped(*bulkLoadElementType)) { -- if (explicitShape) { -- throw std::invalid_argument("Shape can only be specified explicitly " -- "when the type is not a shaped type."); -- } -- return *bulkLoadElementType; -- } else { -- MlirAttribute encodingAttr = mlirAttributeGetNull(); -- return mlirRankedTensorTypeGet(shape.size(), shape.data(), -- *bulkLoadElementType, encodingAttr); +- 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); - } - -- static MlirAttribute getAttributeFromBuffer( -- Py_buffer &view, bool signless, std::optional explicitType, -- std::optional> explicitShape, MlirContext &context) { -- // Detect format codes that are suitable for bulk loading. This includes -- // all byte aligned integer and floating point types up to 8 bytes. -- // Notably, this excludes exotics types which do not have a direct -- // representation in the buffer protocol (i.e. complex, etc). -- std::optional bulkLoadElementType; -- if (explicitType) { -- bulkLoadElementType = *explicitType; -- } else { -- std::string_view format(view.format); -- if (format == "f") { -- // f32 -- assert(view.itemsize == 4 && "mismatched array itemsize"); -- bulkLoadElementType = mlirF32TypeGet(context); -- } else if (format == "d") { -- // f64 -- assert(view.itemsize == 8 && "mismatched array itemsize"); -- bulkLoadElementType = mlirF64TypeGet(context); -- } else if (format == "e") { -- // f16 -- assert(view.itemsize == 2 && "mismatched array itemsize"); -- bulkLoadElementType = mlirF16TypeGet(context); -- } else if (format == "?") { -- // i1 -- // The i1 type needs to be bit-packed, so we will handle it seperately -- return getBitpackedAttributeFromBooleanBuffer(view, explicitShape, -- context); -- } else if (isSignedIntegerFormat(format)) { -- if (view.itemsize == 4) { -- // i32 -- bulkLoadElementType = signless -- ? mlirIntegerTypeGet(context, 32) -- : mlirIntegerTypeSignedGet(context, 32); -- } else if (view.itemsize == 8) { -- // i64 -- bulkLoadElementType = signless -- ? mlirIntegerTypeGet(context, 64) -- : mlirIntegerTypeSignedGet(context, 64); -- } else if (view.itemsize == 1) { -- // i8 -- bulkLoadElementType = signless ? mlirIntegerTypeGet(context, 8) -- : mlirIntegerTypeSignedGet(context, 8); -- } else if (view.itemsize == 2) { -- // i16 -- bulkLoadElementType = signless -- ? mlirIntegerTypeGet(context, 16) -- : mlirIntegerTypeSignedGet(context, 16); -- } -- } else if (isUnsignedIntegerFormat(format)) { -- if (view.itemsize == 4) { -- // unsigned i32 -- bulkLoadElementType = signless -- ? mlirIntegerTypeGet(context, 32) -- : mlirIntegerTypeUnsignedGet(context, 32); -- } else if (view.itemsize == 8) { -- // unsigned i64 -- bulkLoadElementType = signless -- ? mlirIntegerTypeGet(context, 64) -- : mlirIntegerTypeUnsignedGet(context, 64); -- } else if (view.itemsize == 1) { -- // i8 -- bulkLoadElementType = signless -- ? mlirIntegerTypeGet(context, 8) -- : mlirIntegerTypeUnsignedGet(context, 8); -- } else if (view.itemsize == 2) { -- // i16 -- bulkLoadElementType = signless -- ? mlirIntegerTypeGet(context, 16) -- : mlirIntegerTypeUnsignedGet(context, 16); -- } -- } -- if (!bulkLoadElementType) { -- throw std::invalid_argument( -- std::string("unimplemented array format conversion from format: ") + -- std::string(format)); -- } +- 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); + } + } - } - -- MlirType type = getShapedType(bulkLoadElementType, explicitShape, view); -- return mlirDenseElementsAttrRawBufferGet(type, view.len, view.buf); +- return UseNextDecl(RD); - } - -- // There is a complication for boolean numpy arrays, as numpy represents them -- // as 8 bits (1 byte) per boolean, whereas MLIR bitpacks them into 8 booleans -- // per byte. -- static MlirAttribute getBitpackedAttributeFromBooleanBuffer( -- Py_buffer &view, std::optional> explicitShape, -- MlirContext &context) { -- if (llvm::endianness::native != llvm::endianness::little) { -- // Given we have no good way of testing the behavior on big-endian systems -- // we will throw -- throw py::type_error("Constructing a bit-packed MLIR attribute is " -- "unsupported on big-endian systems"); +- 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); - -- py::array_t unpackedArray(view.len, -- static_cast(view.buf)); +- // 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); - -- py::module numpy = py::module::import("numpy"); -- py::object packbits_func = numpy.attr("packbits"); -- py::object packed_booleans = -- packbits_func(unpackedArray, "bitorder"_a = "little"); -- py::buffer_info pythonBuffer = packed_booleans.cast().request(); +- // 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); +- } - -- MlirType bitpackedType = -- getShapedType(mlirIntegerTypeGet(context, 1), explicitShape, view); -- return mlirDenseElementsAttrRawBufferGet(bitpackedType, pythonBuffer.size, -- pythonBuffer.ptr); +- 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