[llvm-branch-commits] [clang-tools-extra] 3228793 - Revert "[clang] fix getTemplateInstantiationArgs (#199528)"
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Jun 2 04:03:08 PDT 2026
Author: Hans Wennborg
Date: 2026-06-02T13:03:03+02:00
New Revision: 3228793fa61ef7dc2504028e321a6e53519ff32f
URL: https://github.com/llvm/llvm-project/commit/3228793fa61ef7dc2504028e321a6e53519ff32f
DIFF: https://github.com/llvm/llvm-project/commit/3228793fa61ef7dc2504028e321a6e53519ff32f.diff
LOG: Revert "[clang] fix getTemplateInstantiationArgs (#199528)"
This reverts commit ccd2606d0c30c58554cc11038a2160672ef529d5.
Added:
Modified:
clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
clang-tools-extra/clangd/SemanticHighlighting.cpp
clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/Decl.h
clang/include/clang/AST/DeclTemplate.h
clang/include/clang/AST/JSONNodeDumper.h
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/include/clang/ASTMatchers/ASTMatchersInternal.h
clang/include/clang/Basic/Specifiers.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ASTDumper.cpp
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/Comment.cpp
clang/lib/AST/Decl.cpp
clang/lib/AST/DeclPrinter.cpp
clang/lib/AST/DeclTemplate.cpp
clang/lib/AST/JSONNodeDumper.cpp
clang/lib/AST/TextNodeDumper.cpp
clang/lib/ASTMatchers/Dynamic/Registry.cpp
clang/lib/Analysis/ExprMutationAnalyzer.cpp
clang/lib/CodeGen/CGVTables.cpp
clang/lib/Index/IndexingContext.cpp
clang/lib/InstallAPI/Visitor.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Sema/HLSLExternalSemaSource.cpp
clang/lib/Sema/SemaConcept.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExprMember.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaTemplateDeductionGuide.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
clang/lib/Tooling/Syntax/BuildTree.cpp
clang/test/AST/ast-dump-templates-pattern.cpp
clang/test/CXX/basic/basic.link/p11.cpp
clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp
clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
clang/test/SemaTemplate/concepts-out-of-line-def.cpp
clang/test/SemaTemplate/friend-template.cpp
clang/test/SemaTemplate/instantiate-scope.cpp
clang/test/Templight/templight-default-func-arg.cpp
clang/test/Templight/templight-empty-entries-fix.cpp
clang/tools/libclang/CIndex.cpp
clang/unittests/AST/ASTImporterTest.cpp
clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp b/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
index a1a705dd043a0..ae063a19d779d 100644
--- a/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
@@ -106,7 +106,7 @@ void DefinitionsInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
return;
diag(FD->getLocation(), "mark the definition as 'inline'",
DiagnosticIDs::Note)
- << FixItHint::CreateInsertion(FD->getFunctionLocStart(), "inline ");
+ << FixItHint::CreateInsertion(FD->getInnerLocStart(), "inline ");
} else if (const auto *VD = dyn_cast<VarDecl>(ND)) {
// C++14 variable templates are allowed.
if (VD->getDescribedVarTemplate())
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index 856904bc810d1..d1ed3ea9bc88a 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -590,28 +590,28 @@ class CollectExtraHighlightings
bool
VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D) {
- if (const auto *Info = D->getExplicitInstantiationInfo()) {
- H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
- Info->TemplateArgsAsWritten->getRAngleLoc());
- } else if (const auto *Info = D->getExplicitSpecializationInfo()) {
- H.addAngleBracketTokens(Info->TemplateParams->getLAngleLoc(),
- Info->TemplateParams->getRAngleLoc());
- H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
- Info->TemplateArgsAsWritten->getRAngleLoc());
- }
+ if (auto *Args = D->getTemplateArgsAsWritten())
+ H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
+ return true;
+ }
+
+ bool VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ if (auto *TPL = D->getTemplateParameters())
+ H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
return true;
}
bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
- if (const auto *Info = D->getExplicitInstantiationInfo()) {
- H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
- Info->TemplateArgsAsWritten->getRAngleLoc());
- } else if (const auto *Info = D->getExplicitSpecializationInfo()) {
- H.addAngleBracketTokens(Info->TemplateParams->getLAngleLoc(),
- Info->TemplateParams->getRAngleLoc());
- H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
- Info->TemplateArgsAsWritten->getRAngleLoc());
- }
+ if (auto *Args = D->getTemplateArgsAsWritten())
+ H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
+ return true;
+ }
+
+ bool VisitVarTemplatePartialSpecializationDecl(
+ VarTemplatePartialSpecializationDecl *D) {
+ if (auto *TPL = D->getTemplateParameters())
+ H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
return true;
}
@@ -625,9 +625,6 @@ class CollectExtraHighlightings
}
bool VisitFunctionDecl(FunctionDecl *D) {
- if (const TemplateParameterList *TPL =
- D->getTemplateSpecializationParameters())
- H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
if (D->isOverloadedOperator()) {
const auto AddOpDeclToken = [&](SourceLocation Loc) {
auto &Token = H.addToken(Loc, HighlightingKind::Operator)
diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp
index 5fcb1a24448b8..c9704492bf1cd 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp
@@ -364,7 +364,7 @@ addInlineIfInHeader(const FunctionDecl *FD) {
if (!isHeaderFile(FileName, FD->getASTContext().getLangOpts()))
return std::nullopt;
- return tooling::Replacement(SM, FD->getFunctionLocStart(), 0, "inline ");
+ return tooling::Replacement(SM, FD->getInnerLocStart(), 0, "inline ");
}
/// Moves definition of a function/method to its declaration location.
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 35ffb37897007..132d9128a795b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -687,7 +687,6 @@ Bug Fixes to C++ Support
- Fixed an alias template CTAD crash.
- Correctly diagnose uses of ``co_await`` / ``co_yield`` in the default argument of nested function declarations. (#GH98923)
- Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741)
-- Fixed clang incorrectly rejecting several cases of out-of-line definitions. (#GH101330)
- Clang incorrectly instantiated variable specializations outside of the immediate context. (#GH54439)
- Fixed a crash when pack expansions are used as arguments for non-pack parameters of built-in templates. (#GH180307)
- Fixed crash instantiating class member specializations.
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index e3f513732e588..620206612f98f 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2122,6 +2122,34 @@ class FunctionDecl : public DeclaratorDecl,
/// the DeclaratorDecl base class.
DeclarationNameLoc DNLoc;
+ /// Specify that this function declaration is actually a function
+ /// template specialization.
+ ///
+ /// \param C the ASTContext.
+ ///
+ /// \param Template the function template that this function template
+ /// specialization specializes.
+ ///
+ /// \param TemplateArgs the template arguments that produced this
+ /// function template specialization from the template.
+ ///
+ /// \param InsertPos If non-NULL, the position in the function template
+ /// specialization set where the function template specialization data will
+ /// be inserted.
+ ///
+ /// \param TSK the kind of template specialization this is.
+ ///
+ /// \param TemplateArgsAsWritten location info of template arguments.
+ ///
+ /// \param PointOfInstantiation point at which the function template
+ /// specialization was first instantiated.
+ void setFunctionTemplateSpecialization(
+ ASTContext &C, FunctionTemplateDecl *Template,
+ TemplateArgumentList *TemplateArgs, void *InsertPos,
+ TemplateSpecializationKind TSK,
+ const TemplateArgumentListInfo *TemplateArgsAsWritten,
+ SourceLocation PointOfInstantiation);
+
/// Specify that this record is an instantiation of the
/// member function FD.
void setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD,
@@ -2217,8 +2245,6 @@ class FunctionDecl : public DeclaratorDecl,
return SourceLocation();
}
- SourceLocation getFunctionLocStart() const;
-
SourceRange getSourceRange() const override LLVM_READONLY;
// Function definitions.
@@ -3044,14 +3070,9 @@ class FunctionDecl : public DeclaratorDecl,
const ASTTemplateArgumentListInfo*
getTemplateSpecializationArgsAsWritten() const;
- /// Returns the template parameter list for an explicit specialization.
- const TemplateParameterList *getTemplateSpecializationParameters() const;
-
/// Specify that this function declaration is actually a function
/// template specialization.
///
- /// \param C the ASTContext.
- ///
/// \param Template the function template that this function template
/// specialization specializes.
///
@@ -3064,30 +3085,25 @@ class FunctionDecl : public DeclaratorDecl,
///
/// \param TSK the kind of template specialization this is.
///
- /// \param TemplateParams the template parameters if this is an explicit
- /// specialization.
- ///
/// \param TemplateArgsAsWritten location info of template arguments.
///
/// \param PointOfInstantiation point at which the function template
/// specialization was first instantiated.
- ///
- /// \param AddSpecialization whether to add this specialization to the
- /// template's specialization set.
- ///
void setFunctionTemplateSpecialization(
- ASTContext &C, FunctionTemplateDecl *Template,
- TemplateArgumentList *TemplateArgs, void *InsertPos,
- TemplateSpecializationKind TSK,
- const TemplateParameterList *TemplateParams,
- const TemplateArgumentListInfo *TemplateArgsAsWritten,
- SourceLocation PointOfInstantiation, bool AddSpecialization);
+ FunctionTemplateDecl *Template, TemplateArgumentList *TemplateArgs,
+ void *InsertPos,
+ TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
+ TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr,
+ SourceLocation PointOfInstantiation = SourceLocation()) {
+ setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs,
+ InsertPos, TSK, TemplateArgsAsWritten,
+ PointOfInstantiation);
+ }
/// Specifies that this function declaration is actually a
/// dependent function template specialization.
void setDependentTemplateSpecialization(
ASTContext &Context, const UnresolvedSetImpl &Templates,
- const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TemplateArgs);
DependentFunctionTemplateSpecializationInfo *
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 672648c3fc03c..4f5a4e1b7b8a6 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -73,7 +73,7 @@ class TemplateParameterList final
: private llvm::TrailingObjects<TemplateParameterList, NamedDecl *,
Expr *> {
/// The template argument list of the template parameter list.
- mutable TemplateArgument *InjectedArgs = nullptr;
+ TemplateArgument *InjectedArgs = nullptr;
/// The location of the 'template' keyword.
SourceLocation TemplateLoc;
@@ -200,8 +200,7 @@ class TemplateParameterList final
bool hasAssociatedConstraints() const;
/// Get the template argument list of the template parameter list.
- ArrayRef<TemplateArgument>
- getInjectedTemplateArgs(const ASTContext &Context) const;
+ ArrayRef<TemplateArgument> getInjectedTemplateArgs(const ASTContext &Context);
SourceLocation getTemplateLoc() const { return TemplateLoc; }
SourceLocation getLAngleLoc() const { return LAngleLoc; }
@@ -476,18 +475,14 @@ class FunctionTemplateSpecializationInfo final
/// The function template from which this function template
/// specialization was generated.
///
- /// The three bits contain the TemplateSpecializationKind.
- llvm::PointerIntPair<FunctionTemplateDecl *, 3> Template;
+ /// The two bits contain the top 4 values of TemplateSpecializationKind.
+ llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
public:
/// The template arguments used to produce the function template
/// specialization from the function template.
TemplateArgumentList *TemplateArguments;
- // The template parameters if this is an explicit specialization.
- /// FIXME: Normally null; tail-allocate this.
- const TemplateParameterList *TemplateParameters;
-
/// The template arguments as written in the sources, if provided.
/// FIXME: Normally null; tail-allocate this.
const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
@@ -500,14 +495,12 @@ class FunctionTemplateSpecializationInfo final
FunctionTemplateSpecializationInfo(
FunctionDecl *FD, FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
- const TemplateParameterList *TemplateParameters,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation POI, MemberSpecializationInfo *MSInfo)
: Function(FD, MSInfo ? true : false), Template(Template, TSK - 1),
- TemplateArguments(TemplateArgs), TemplateParameters(TemplateParameters),
+ TemplateArguments(TemplateArgs),
TemplateArgumentsAsWritten(TemplateArgsAsWritten),
PointOfInstantiation(POI) {
- assert(TemplateParameters == nullptr || TSK == TSK_ExplicitSpecialization);
if (MSInfo)
getTrailingObjects()[0] = MSInfo;
}
@@ -520,7 +513,6 @@ class FunctionTemplateSpecializationInfo final
static FunctionTemplateSpecializationInfo *
Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
- const TemplateParameterList *TemplateParameters,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation POI, MemberSpecializationInfo *MSInfo);
@@ -621,8 +613,8 @@ class FunctionTemplateSpecializationInfo final
/// member class or member enumeration.
class MemberSpecializationInfo {
// The member declaration from which this member was instantiated, and the
- // manner in which the instantiation occurred (in the lower three bits).
- llvm::PointerIntPair<NamedDecl *, 3> MemberAndTSK;
+ // manner in which the instantiation occurred (in the lower two bits).
+ llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK;
// The point at which this member was first instantiated.
SourceLocation PointOfInstantiation;
@@ -701,19 +693,14 @@ class DependentFunctionTemplateSpecializationInfo final
DependentFunctionTemplateSpecializationInfo(
const UnresolvedSetImpl &Candidates,
- const TemplateParameterList *TemplateParams,
const ASTTemplateArgumentListInfo *TemplateArgsWritten);
public:
- // The template parameters if this is an explicit specialization.
- const TemplateParameterList *TemplateParameters;
-
/// The template arguments as written in the sources, if provided.
const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
static DependentFunctionTemplateSpecializationInfo *
Create(ASTContext &Context, const UnresolvedSetImpl &Candidates,
- const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TemplateArgs);
/// Returns the candidates for the primary function template.
@@ -1018,6 +1005,11 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
return getTemplatedDecl()->isThisDeclarationADefinition();
}
+ bool isCompatibleWithDefinition() const {
+ return getTemplatedDecl()->isInstantiatedFromMemberTemplate() ||
+ isThisDeclarationADefinition();
+ }
+
// This bit closely tracks 'RedeclarableTemplateDecl::InstantiatedFromMember',
// except this is per declaration, while the redeclarable field is
// per chain. This indicates a template redeclaration which
@@ -1815,18 +1807,8 @@ struct ExplicitInstantiationInfo {
ExplicitInstantiationInfo() = default;
};
-struct ExplicitSpecializationInfo {
- /// The list of template parameters
- TemplateParameterList *TemplateParams = nullptr;
-
- /// The template arguments as written.
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten = nullptr;
-
- ExplicitSpecializationInfo() = default;
-};
-
using SpecializationOrInstantiationInfo =
- llvm::PointerUnion<ExplicitSpecializationInfo *,
+ llvm::PointerUnion<const ASTTemplateArgumentListInfo *,
ExplicitInstantiationInfo *>;
/// Represents a class template specialization, which refers to
@@ -2056,38 +2038,49 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
/// Retrieve the template argument list as written in the sources,
/// if any.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
- if (const auto *Info = getExplicitSpecializationInfo())
+ if (auto *Info =
+ dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
return Info->TemplateArgsAsWritten;
- if (const auto *Info = getExplicitInstantiationInfo())
- return Info->TemplateArgsAsWritten;
- return nullptr;
+ return cast<const ASTTemplateArgumentListInfo *>(ExplicitInfo);
+ }
+
+ /// Set the template argument list as written in the sources.
+ void
+ setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
+ if (auto *Info =
+ dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
+ Info->TemplateArgsAsWritten = ArgsWritten;
+ else
+ ExplicitInfo = ArgsWritten;
}
- /// Gets the explicit instantiation info, if present.
- const ExplicitInstantiationInfo *getExplicitInstantiationInfo() const {
- return dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
+ /// Set the template argument list as written in the sources.
+ void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
+ setTemplateArgsAsWritten(
+ ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
}
- /// Sets the explicit instantiation info.
- void setExplicitInstantiationInfo(
- SourceLocation ExternKeywordLoc, SourceLocation TemplateKeywordLoc,
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
- auto *Info = new (getASTContext()) ExplicitInstantiationInfo();
- Info->ExternKeywordLoc = ExternKeywordLoc;
- Info->TemplateKeywordLoc = TemplateKeywordLoc;
- Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
- ExplicitInfo = Info;
+ /// Gets the location of the extern keyword, if present.
+ SourceLocation getExternKeywordLoc() const {
+ if (auto *Info =
+ dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
+ return Info->ExternKeywordLoc;
+ return SourceLocation();
}
- /// Gets the explicit specialization info, if present.
- const ExplicitSpecializationInfo *getExplicitSpecializationInfo() const {
- return dyn_cast_if_present<ExplicitSpecializationInfo *>(ExplicitInfo);
+ /// Sets the location of the extern keyword.
+ void setExternKeywordLoc(SourceLocation Loc);
+
+ /// Gets the location of the template keyword, if present.
+ SourceLocation getTemplateKeywordLoc() const {
+ if (auto *Info =
+ dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
+ return Info->TemplateKeywordLoc;
+ return SourceLocation();
}
- /// Sets the explicit specialization info.
- void setExplicitSpecializationInfo(
- TemplateParameterList *TemplateParams,
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten);
+ /// Sets the location of the template keyword.
+ void setTemplateKeywordLoc(SourceLocation Loc);
SourceRange getSourceRange() const override LLVM_READONLY;
@@ -2112,7 +2105,10 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
};
class ClassTemplatePartialSpecializationDecl
- : public ClassTemplateSpecializationDecl {
+ : public ClassTemplateSpecializationDecl {
+ /// The list of template parameters
+ TemplateParameterList *TemplateParams = nullptr;
+
/// The class template partial specialization from which this
/// class template partial specialization was instantiated.
///
@@ -2126,7 +2122,6 @@ class ClassTemplatePartialSpecializationDecl
ClassTemplatePartialSpecializationDecl(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl);
@@ -2144,9 +2139,7 @@ class ClassTemplatePartialSpecializationDecl
static ClassTemplatePartialSpecializationDecl *
Create(ASTContext &Context, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
- TemplateParameterList *Params,
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
- ClassTemplateDecl *SpecializedTemplate,
+ TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args, CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl);
@@ -2161,10 +2154,7 @@ class ClassTemplatePartialSpecializationDecl
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
- auto *ExplicitSpecInfo = getExplicitSpecializationInfo();
- assert(ExplicitSpecInfo &&
- "A partial specialization is always an explicit specialization");
- return ExplicitSpecInfo->TemplateParams;
+ return TemplateParams;
}
/// \brief All associated constraints of this partial specialization,
@@ -2175,11 +2165,11 @@ class ClassTemplatePartialSpecializationDecl
/// conjunction ("and").
void getAssociatedConstraints(
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
- getTemplateParameters()->getAssociatedConstraints(AC);
+ TemplateParams->getAssociatedConstraints(AC);
}
bool hasAssociatedConstraints() const {
- return getTemplateParameters()->hasAssociatedConstraints();
+ return TemplateParams->hasAssociatedConstraints();
}
/// Retrieve the member class template partial specialization from
@@ -2816,38 +2806,49 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// Retrieve the template argument list as written in the sources,
/// if any.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
- if (const auto *Info = getExplicitSpecializationInfo())
- return Info->TemplateArgsAsWritten;
- if (const auto *Info = getExplicitInstantiationInfo())
+ if (auto *Info =
+ dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
return Info->TemplateArgsAsWritten;
- return nullptr;
+ return cast<const ASTTemplateArgumentListInfo *>(ExplicitInfo);
}
- /// Gets the explicit instantiation info, if present.
- const ExplicitInstantiationInfo *getExplicitInstantiationInfo() const {
- return dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
+ /// Set the template argument list as written in the sources.
+ void
+ setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
+ if (auto *Info =
+ dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
+ Info->TemplateArgsAsWritten = ArgsWritten;
+ else
+ ExplicitInfo = ArgsWritten;
}
- /// Sets the explicit instantiation info.
- void setExplicitInstantiationInfo(
- SourceLocation ExternKeywordLoc, SourceLocation TemplateKeywordLoc,
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
- auto *Info = new (getASTContext()) ExplicitInstantiationInfo();
- Info->ExternKeywordLoc = ExternKeywordLoc;
- Info->TemplateKeywordLoc = TemplateKeywordLoc;
- Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
- ExplicitInfo = Info;
+ /// Set the template argument list as written in the sources.
+ void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
+ setTemplateArgsAsWritten(
+ ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
}
- /// Gets the explicit specialization info, if present.
- const ExplicitSpecializationInfo *getExplicitSpecializationInfo() const {
- return dyn_cast_if_present<ExplicitSpecializationInfo *>(ExplicitInfo);
+ /// Gets the location of the extern keyword, if present.
+ SourceLocation getExternKeywordLoc() const {
+ if (auto *Info =
+ dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
+ return Info->ExternKeywordLoc;
+ return SourceLocation();
}
- /// Sets the explicit specialization info.
- void setExplicitSpecializationInfo(
- TemplateParameterList *TemplateParams,
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten);
+ /// Sets the location of the extern keyword.
+ void setExternKeywordLoc(SourceLocation Loc);
+
+ /// Gets the location of the template keyword, if present.
+ SourceLocation getTemplateKeywordLoc() const {
+ if (auto *Info =
+ dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
+ return Info->TemplateKeywordLoc;
+ return SourceLocation();
+ }
+
+ /// Sets the location of the template keyword.
+ void setTemplateKeywordLoc(SourceLocation Loc);
SourceRange getSourceRange() const override LLVM_READONLY;
@@ -2873,6 +2874,9 @@ class VarTemplateSpecializationDecl : public VarDecl,
class VarTemplatePartialSpecializationDecl
: public VarTemplateSpecializationDecl {
+ /// The list of template parameters
+ TemplateParameterList *TemplateParams = nullptr;
+
/// The variable template partial specialization from which this
/// variable template partial specialization was instantiated.
///
@@ -2884,7 +2888,6 @@ class VarTemplatePartialSpecializationDecl
VarTemplatePartialSpecializationDecl(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args);
@@ -2902,7 +2905,6 @@ class VarTemplatePartialSpecializationDecl
static VarTemplatePartialSpecializationDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
VarTemplateDecl *SpecializedTemplate, QualType T,
TypeSourceInfo *TInfo, StorageClass S,
ArrayRef<TemplateArgument> Args);
@@ -2918,10 +2920,7 @@ class VarTemplatePartialSpecializationDecl
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
- auto *ExplicitSpecInfo = getExplicitSpecializationInfo();
- assert(ExplicitSpecInfo &&
- "A partial specialization is always an explicit specialization");
- return ExplicitSpecInfo->TemplateParams;
+ return TemplateParams;
}
/// Get the template argument list of the template parameter list.
@@ -2938,11 +2937,11 @@ class VarTemplatePartialSpecializationDecl
/// conjunction ("and").
void getAssociatedConstraints(
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
- getTemplateParameters()->getAssociatedConstraints(AC);
+ TemplateParams->getAssociatedConstraints(AC);
}
bool hasAssociatedConstraints() const {
- return getTemplateParameters()->hasAssociatedConstraints();
+ return TemplateParams->hasAssociatedConstraints();
}
/// \brief Retrieve the member variable template partial specialization from
diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h
index 7c8496d6164fc..4e8d1649bbf8b 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -417,7 +417,6 @@ class JSONDumper : public ASTNodeTraverser<JSONDumper, JSONNodeDumper> {
Visit(Redecl);
DumpedAny = true;
break;
- case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization:
break;
}
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 3b9bafffe1bc1..febdf715698d9 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2002,7 +2002,6 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
case TSK_ExplicitSpecialization:
- case TSK_FriendDeclaration:
break;
}
}
@@ -2023,7 +2022,6 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
TRY_TO(TraverseDecl(RD));
break;
- case TSK_FriendDeclaration:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
case TSK_ExplicitSpecialization:
@@ -2058,7 +2056,6 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
TRY_TO(TraverseDecl(RD));
break;
- case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization:
break;
}
@@ -2225,11 +2222,12 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
handles traversal of template args and qualifier. \
For explicit specializations ("template<> set<int> {...};"), \
we traverse template args here since there is no EID. */ \
- if (const auto *Info = D->getExplicitSpecializationInfo()) { \
- const auto *ArgsWritten = Info->TemplateArgsAsWritten; \
- TRY_TO(TraverseTemplateParameterListHelper(Info->TemplateParams)); \
- TRY_TO(TraverseTemplateArgumentLocsHelper( \
- ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs)); \
+ if (const auto *ArgsWritten = D->getTemplateArgsAsWritten()) { \
+ assert(D->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); \
+ if (D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { \
+ TRY_TO(TraverseTemplateArgumentLocsHelper( \
+ ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs)); \
+ } \
} \
\
if (getDerived().shouldVisitTemplateInstantiations() || \
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index c35206fb41b92..bc0f35898a2c9 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5753,11 +5753,6 @@ AST_MATCHER_P(IfStmt, hasElse, internal::Matcher<Stmt>, InnerMatcher) {
return (Else != nullptr && InnerMatcher.matches(*Else, Finder, Builder));
}
-/// Matches a declaration if it declares the same entity as the node.
-AST_MATCHER_P(Decl, declaresSameEntityAsNode, const Decl *, Other) {
- return clang::declaresSameEntity(&Node, Other);
-}
-
/// Matches if a node equals a previously bound node.
///
/// Matches a node if it equals the node previously bound to \p ID.
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index d3daf2eb4781d..cb12d10d628b6 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1993,12 +1993,16 @@ getTemplateArgsWritten(const OverloadExpr &OE) {
inline unsigned
getNumTemplateArgsWritten(const ClassTemplateSpecializationDecl &D) {
- return getTemplateArgsWritten(D).size();
+ if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
+ return Args->getNumTemplateArgs();
+ return 0;
}
inline unsigned
getNumTemplateArgsWritten(const VarTemplateSpecializationDecl &D) {
- return getTemplateArgsWritten(D).size();
+ if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
+ return Args->getNumTemplateArgs();
+ return 0;
}
inline unsigned getNumTemplateArgsWritten(const FunctionDecl &FD) {
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index 1fe50760eff9a..8da6fd4cf454a 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -193,8 +193,6 @@ namespace clang {
/// This template specialization was implicitly instantiated from a
/// template. (C++ [temp.inst]).
TSK_ImplicitInstantiation,
- /// This template is a friend declaration.
- TSK_FriendDeclaration,
/// This template specialization was declared or defined by an
/// explicit specialization (C++ [temp.expl.spec]) or partial
/// specialization (C++ [temp.class.spec]).
@@ -229,7 +227,6 @@ namespace clang {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
- case TSK_FriendDeclaration:
return false;
}
llvm_unreachable("bad template specialization kind");
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ff474fdd99562..b8d760e7e0975 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11753,7 +11753,7 @@ class Sema final : public SemaBase {
TemplateParameterList *MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc,
const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,
- ArrayRef<TemplateParameterList *> &ParamLists, bool IsFriend,
+ ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
bool &IsMemberSpecialization, bool &Invalid,
bool SuppressDiagnostic = false);
@@ -11819,7 +11819,8 @@ class Sema final : public SemaBase {
DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation TemplateNameLoc,
- const TemplateArgumentListInfo &TemplateArgs);
+ const TemplateArgumentListInfo &TemplateArgs,
+ bool SetWrittenArgs);
/// Form a reference to the specialization of the given variable template
/// corresponding to the specified argument list, or a null-but-valid result
@@ -11903,7 +11904,7 @@ class Sema final : public SemaBase {
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
SourceLocation ModulePrivateLoc, CXXScopeSpec &SS,
TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr,
- MultiTemplateParamsArg &TemplateParameterLists,
+ MultiTemplateParamsArg TemplateParameterLists,
SkipBodyInfo *SkipBody = nullptr);
/// Check the non-type template arguments of a class template
@@ -11976,8 +11977,7 @@ class Sema final : public SemaBase {
/// There really isn't any useful analysis we can do here, so we
/// just store the information.
bool CheckDependentFunctionTemplateSpecialization(
- FunctionDecl *FD, const TemplateParameterList *TemplateParams,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
/// Perform semantic analysis for the given function template
@@ -12003,9 +12003,8 @@ class Sema final : public SemaBase {
/// declaration with no explicit template argument list that might be
/// befriending a function template specialization.
bool CheckFunctionTemplateSpecialization(
- FunctionDecl *FD, const TemplateParameterList *TemplateParams,
- TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous,
- bool QualifiedFriend = false);
+ FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
+ LookupResult &Previous, bool QualifiedFriend = false);
/// Perform semantic analysis for the given non-template member
/// specialization.
@@ -12271,6 +12270,46 @@ class Sema final : public SemaBase {
TPL_TemplateParamsEquivalent,
};
+ // A struct to represent the 'new' declaration, which is either itself just
+ // the named decl, or the important information we need about it in order to
+ // do constraint comparisons.
+ class TemplateCompareNewDeclInfo {
+ const NamedDecl *ND = nullptr;
+ const DeclContext *DC = nullptr;
+ const DeclContext *LexicalDC = nullptr;
+ SourceLocation Loc;
+
+ public:
+ TemplateCompareNewDeclInfo(const NamedDecl *ND) : ND(ND) {}
+ TemplateCompareNewDeclInfo(const DeclContext *DeclCtx,
+ const DeclContext *LexicalDeclCtx,
+ SourceLocation Loc)
+
+ : DC(DeclCtx), LexicalDC(LexicalDeclCtx), Loc(Loc) {
+ assert(DC && LexicalDC &&
+ "Constructor only for cases where we have the information to put "
+ "in here");
+ }
+
+ // If this was constructed with no information, we cannot do substitution
+ // for constraint comparison, so make sure we can check that.
+ bool isInvalid() const { return !ND && !DC; }
+
+ const NamedDecl *getDecl() const { return ND; }
+
+ bool ContainsDecl(const NamedDecl *ND) const { return this->ND == ND; }
+
+ const DeclContext *getLexicalDeclContext() const {
+ return ND ? ND->getLexicalDeclContext() : LexicalDC;
+ }
+
+ const DeclContext *getDeclContext() const {
+ return ND ? ND->getDeclContext() : DC;
+ }
+
+ SourceLocation getLocation() const { return ND ? ND->getLocation() : Loc; }
+ };
+
/// Determine whether the given template parameter lists are
/// equivalent.
///
@@ -12295,11 +12334,19 @@ class Sema final : public SemaBase {
/// \returns True if the template parameter lists are equal, false
/// otherwise.
bool TemplateParameterListsAreEqual(
- const Decl *NewInstFrom, TemplateParameterList *New,
- const Decl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+ const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
+ const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
TemplateParameterListEqualKind Kind,
SourceLocation TemplateArgLoc = SourceLocation());
+ bool TemplateParameterListsAreEqual(
+ TemplateParameterList *New, TemplateParameterList *Old, bool Complain,
+ TemplateParameterListEqualKind Kind,
+ SourceLocation TemplateArgLoc = SourceLocation()) {
+ return TemplateParameterListsAreEqual(nullptr, New, nullptr, Old, Complain,
+ Kind, TemplateArgLoc);
+ }
+
/// Check whether a template can be declared within this scope.
///
/// If the template declaration is valid in this scope, returns
@@ -13530,27 +13577,44 @@ class Sema final : public SemaBase {
/// Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
///
- /// \param D the declaration for which we are computing template
+ /// \param ND the declaration for which we are computing template
/// instantiation arguments.
///
- /// \param Innermost if present, specifies a template argument list for the
- /// template-like (TemplateDecl or PartialSpec) declaration passed as D.
+ /// \param DC In the event we don't HAVE a declaration yet, we instead provide
+ /// the decl context where it will be created. In this case, the `Innermost`
+ /// should likely be provided. If ND is non-null, this is ignored.
+ ///
+ /// \param Innermost if non-NULL, specifies a template argument list for the
+ /// template declaration passed as ND.
///
- /// \param NumLevels if present, specifies the maximum number of template
- /// levels of the result. This is useful for instantiating a pattern that has
- /// already had some levels instantiated. In that case, the Template Depth of
- /// the pattern can be passed here.
+ /// \param RelativeToPrimary true if we should get the template
+ /// arguments relative to the primary template, even when we're
+ /// dealing with a specialization. This is only relevant for function
+ /// template specializations.
///
- /// \param SkipInnerNonInstantiated Skips adding template-like levels to the
- /// result until hitting the first non-template-like level. This is a
- /// workaround for dealing with the instantiation of the definition of generic
- /// lambdas, which currently are eagerly substituted.
+ /// \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 Decl *D,
+ const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
- UnsignedOrNone NumLevels = std::nullopt,
- bool SkipInnerNonInstantiated = 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.
@@ -14970,13 +15034,14 @@ class Sema final : public SemaBase {
// for figuring out the relative 'depth' of the constraint. The depth of the
// 'primary template' and the 'instantiated from' templates aren't necessarily
// the same, such as a case when one is a 'friend' defined in a class.
- bool AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
- const Decl *New, const Expr *NewConstr);
+ bool AreConstraintExpressionsEqual(const NamedDecl *Old,
+ const Expr *OldConstr,
+ const TemplateCompareNewDeclInfo &New,
+ const Expr *NewConstr);
// Calculates whether the friend function depends on an enclosing template for
// the purposes of [temp.friend] p9.
- bool
- FriendConstraintsDependOnEnclosingTemplate(const FunctionTemplateDecl *FTD);
+ bool FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD);
/// \brief Ensure that the given template arguments satisfy the constraints
/// associated with the given template, emitting a diagnostic if they do not.
@@ -14997,19 +15062,10 @@ class Sema final : public SemaBase {
SourceRange TemplateIDRange);
bool CheckFunctionTemplateConstraints(SourceLocation PointOfInstantiation,
- FunctionTemplateDecl *Template,
+ FunctionDecl *Decl,
ArrayRef<TemplateArgument> TemplateArgs,
ConstraintSatisfaction &Satisfaction);
- // FIXME: Constraints should be always checked before the declaration is
- // specialized. This function exists to support a workaround for templated
- // lambdas, where handling the instantiation scope for the captures is not
- // implemented yet.
- bool
- CheckFunctionSpecializationConstraints(SourceLocation PointOfInstantiation,
- FunctionDecl *Decl,
- ConstraintSatisfaction &Satisfaction);
-
/// \brief Emit diagnostics explaining why a constraint expression was deemed
/// unsatisfied.
/// \param First whether this is the first time an unsatisfied constraint is
@@ -15090,16 +15146,19 @@ class Sema final : public SemaBase {
/// Used by SetupConstraintCheckingTemplateArgumentsAndScope to set up the
/// LocalInstantiationScope of the current non-lambda function. For lambdas,
/// use LambdaScopeForCallOperatorInstantiationRAII.
- bool SetupConstraintScope(FunctionDecl *FD,
- const MultiLevelTemplateArgumentList &MLTAL,
- LocalInstantiationScope &Scope);
+ bool
+ SetupConstraintScope(FunctionDecl *FD,
+ std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+ const MultiLevelTemplateArgumentList &MLTAL,
+ LocalInstantiationScope &Scope);
/// Used during constraint checking, sets up the constraint template argument
/// lists, and calls SetupConstraintScope to set up the
/// LocalInstantiationScope to have the proper set of ParVarDecls configured.
std::optional<MultiLevelTemplateArgumentList>
SetupConstraintCheckingTemplateArgumentsAndScope(
- FunctionDecl *FD, LocalInstantiationScope &Scope);
+ FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+ LocalInstantiationScope &Scope);
///@}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 8a8cbc3fa6a96..a401a7471e6fc 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -13048,7 +13048,6 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
case TSK_ExplicitInstantiationDeclaration:
return GVA_AvailableExternally;
- case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
External = GVA_DiscardableODR;
break;
@@ -13237,7 +13236,6 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
case TSK_ExplicitInstantiationDeclaration:
return GVA_AvailableExternally;
- case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
return GVA_DiscardableODR;
}
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 00c1140b538ec..b3071d83ed51f 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -134,7 +134,6 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
Visit(Redecl);
DumpedAny = true;
break;
- case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization:
break;
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 2aa83362d1070..f8c641789bd10 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -815,8 +815,6 @@ ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization(
template <>
Expected<TemplateParameterList *>
ASTNodeImporter::import(TemplateParameterList *From) {
- if (!From)
- return nullptr;
SmallVector<NamedDecl *, 4> To(From->size());
if (Error Err = ImportContainerChecked(*From, To))
return std::move(Err);
@@ -955,8 +953,7 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) {
ToInfo = TemplateArgumentLocInfo(*TSIOrErr);
else
return TSIOrErr.takeError();
- } else if (Arg.getKind() == TemplateArgument::Template ||
- Arg.getKind() == TemplateArgument::TemplateExpansion) {
+ } else {
auto ToTemplateKWLocOrErr = import(FromInfo.getTemplateKwLoc());
if (!ToTemplateKWLocOrErr)
return ToTemplateKWLocOrErr.takeError();
@@ -974,9 +971,6 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) {
Importer.getToContext(), *ToTemplateKWLocOrErr,
*ToTemplateQualifierLocOrErr, *ToTemplateNameLocOrErr,
*ToTemplateEllipsisLocOrErr);
- } else {
- ToInfo = TemplateArgumentLocInfo(Importer.getToContext(),
- FromInfo.getTrivialLoc());
}
return TemplateArgumentLoc(Arg, ToInfo);
@@ -3645,12 +3639,6 @@ Error ASTNodeImporter::ImportTemplateInformation(
Importer.getToContext(), std::get<1>(*FunctionAndArgsOrErr));
auto *FTSInfo = FromFD->getTemplateSpecializationInfo();
-
- Expected<TemplateParameterList *> TemplateParamsOrErr =
- import(FTSInfo->TemplateParameters);
- if (!TemplateParamsOrErr)
- return TemplateParamsOrErr.takeError();
-
TemplateArgumentListInfo ToTAInfo;
const auto *FromTAArgsAsWritten = FTSInfo->TemplateArgumentsAsWritten;
if (FromTAArgsAsWritten)
@@ -3667,10 +3655,8 @@ Error ASTNodeImporter::ImportTemplateInformation(
TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind();
ToFD->setFunctionTemplateSpecialization(
- Importer.getToContext(), std::get<0>(*FunctionAndArgsOrErr), ToTAList,
- /*InsertPos=*/nullptr, TSK, *TemplateParamsOrErr,
- FromTAArgsAsWritten ? &ToTAInfo : nullptr, *POIOrErr,
- /*AddSpecialization=*/true);
+ std::get<0>(*FunctionAndArgsOrErr), ToTAList, /* InsertPos= */ nullptr,
+ TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, *POIOrErr);
return Error::success();
}
@@ -3684,11 +3670,6 @@ Error ASTNodeImporter::ImportTemplateInformation(
return ToFTDOrErr.takeError();
}
- Expected<TemplateParameterList *> TemplateParamsOrErr =
- import(FromInfo->TemplateParameters);
- if (!TemplateParamsOrErr)
- return TemplateParamsOrErr.takeError();
-
// Import TemplateArgumentListInfo.
TemplateArgumentListInfo ToTAInfo;
const auto *FromTAArgsAsWritten = FromInfo->TemplateArgumentsAsWritten;
@@ -3698,7 +3679,7 @@ Error ASTNodeImporter::ImportTemplateInformation(
return Err;
ToFD->setDependentTemplateSpecialization(
- Importer.getToContext(), Candidates, *TemplateParamsOrErr,
+ Importer.getToContext(), Candidates,
FromTAArgsAsWritten ? &ToTAInfo : nullptr);
return Error::success();
}
@@ -6519,22 +6500,19 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (!IdLocOrErr)
return IdLocOrErr.takeError();
+ // Import TemplateArgumentListInfo.
+ TemplateArgumentListInfo ToTAInfo;
+ if (const auto *ASTTemplateArgs = D->getTemplateArgsAsWritten()) {
+ if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs, ToTAInfo))
+ return std::move(Err);
+ }
+
// Create the specialization.
ClassTemplateSpecializationDecl *D2 = nullptr;
if (PartialSpec) {
- TemplateArgumentListInfo ToTAInfo;
- if (Error Err = ImportTemplateArgumentListInfo(
- *cast<ClassTemplatePartialSpecializationDecl>(D)
- ->getTemplateArgsAsWritten(),
- ToTAInfo))
- return std::move(Err);
-
if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr,
- *IdLocOrErr, ToTPList,
- ASTTemplateArgumentListInfo::Create(Importer.getToContext(),
- ToTAInfo),
- ClassTemplate, ArrayRef(TemplateArgs),
+ *IdLocOrErr, ToTPList, ClassTemplate, ArrayRef(TemplateArgs),
/*CanonInjectedTST=*/CanQualType(),
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
return D2;
@@ -6565,34 +6543,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (!ClassTemplate->findSpecialization(TemplateArgs, InsertPos))
// Add this specialization to the class template.
ClassTemplate->AddSpecialization(D2, InsertPos);
-
- if (const auto *Info = D->getExplicitInstantiationInfo()) {
- auto ExternKeywordLocOrErr = import(Info->ExternKeywordLoc);
- if (!ExternKeywordLocOrErr)
- return ExternKeywordLocOrErr.takeError();
- auto TemplateKeywordLocOrErr = import(Info->TemplateKeywordLoc);
- if (!TemplateKeywordLocOrErr)
- return TemplateKeywordLocOrErr.takeError();
- TemplateArgumentListInfo ToTAInfo;
- if (Error Err = ImportTemplateArgumentListInfo(
- *Info->TemplateArgsAsWritten, ToTAInfo))
- return std::move(Err);
- D2->setExplicitInstantiationInfo(*ExternKeywordLocOrErr,
- *TemplateKeywordLocOrErr,
- ASTTemplateArgumentListInfo::Create(
- Importer.getToContext(), ToTAInfo));
- } else if (const auto *Info = D->getExplicitSpecializationInfo()) {
- auto ParamsOrErr = import(Info->TemplateParams);
- if (!ParamsOrErr)
- return ParamsOrErr.takeError();
- TemplateArgumentListInfo ToTAInfo;
- if (Error Err = ImportTemplateArgumentListInfo(
- *Info->TemplateArgsAsWritten, ToTAInfo))
- return std::move(Err);
- D2->setExplicitSpecializationInfo(*ParamsOrErr,
- ASTTemplateArgumentListInfo::Create(
- Importer.getToContext(), ToTAInfo));
- }
}
D2->setSpecializationKind(D->getSpecializationKind());
@@ -6619,6 +6569,19 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
else
return LocOrErr.takeError();
+ if (D->getTemplateArgsAsWritten())
+ D2->setTemplateArgsAsWritten(ToTAInfo);
+
+ if (auto LocOrErr = import(D->getTemplateKeywordLoc()))
+ D2->setTemplateKeywordLoc(*LocOrErr);
+ else
+ return LocOrErr.takeError();
+
+ if (auto LocOrErr = import(D->getExternKeywordLoc()))
+ D2->setExternKeywordLoc(*LocOrErr);
+ else
+ return LocOrErr.takeError();
+
if (D->getPointOfInstantiation().isValid()) {
if (auto POIOrErr = import(D->getPointOfInstantiation()))
D2->setPointOfInstantiation(*POIOrErr);
@@ -6836,6 +6799,12 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *D2 = nullptr;
+ TemplateArgumentListInfo ToTAInfo;
+ if (const auto *Args = D->getTemplateArgsAsWritten()) {
+ if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
+ return std::move(Err);
+ }
+
using PartVarSpecDecl = VarTemplatePartialSpecializationDecl;
// Create a new specialization.
if (auto *FromPartial = dyn_cast<PartVarSpecDecl>(D)) {
@@ -6843,16 +6812,9 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
if (!ToTPListOrErr)
return ToTPListOrErr.takeError();
- TemplateArgumentListInfo ToTAInfo;
- if (const auto *Args = D->getTemplateArgsAsWritten())
- if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
- return std::move(Err);
-
PartVarSpecDecl *ToPartial;
if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr,
- ASTTemplateArgumentListInfo::Create(
- Importer.getToContext(), ToTAInfo),
VarTemplate, QualType(), nullptr,
D->getStorageClass(), TemplateArgs))
return ToPartial;
@@ -6877,34 +6839,6 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
QualType(), nullptr, D->getStorageClass(),
TemplateArgs))
return D2;
-
- if (const auto *Info = D->getExplicitInstantiationInfo()) {
- auto ExternKeywordLocOrErr = import(Info->ExternKeywordLoc);
- if (!ExternKeywordLocOrErr)
- return ExternKeywordLocOrErr.takeError();
- auto TemplateKeywordLocOrErr = import(Info->TemplateKeywordLoc);
- if (!TemplateKeywordLocOrErr)
- return TemplateKeywordLocOrErr.takeError();
- TemplateArgumentListInfo ToTAInfo;
- if (Error Err = ImportTemplateArgumentListInfo(
- *Info->TemplateArgsAsWritten, ToTAInfo))
- return std::move(Err);
- D2->setExplicitInstantiationInfo(*ExternKeywordLocOrErr,
- *TemplateKeywordLocOrErr,
- ASTTemplateArgumentListInfo::Create(
- Importer.getToContext(), ToTAInfo));
- } else if (const auto *Info = D->getExplicitSpecializationInfo()) {
- auto ParamsOrErr = import(Info->TemplateParams);
- if (!ParamsOrErr)
- return ParamsOrErr.takeError();
- TemplateArgumentListInfo ToTAInfo;
- if (Error Err = ImportTemplateArgumentListInfo(
- *Info->TemplateArgsAsWritten, ToTAInfo))
- return std::move(Err);
- D2->setExplicitSpecializationInfo(*ParamsOrErr,
- ASTTemplateArgumentListInfo::Create(
- Importer.getToContext(), ToTAInfo));
- }
}
// Update InsertPos, because preceding import calls may have invalidated
@@ -6931,6 +6865,9 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
D2->setSpecializationKind(D->getSpecializationKind());
+ if (D->getTemplateArgsAsWritten())
+ D2->setTemplateArgsAsWritten(ToTAInfo);
+
if (auto LocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*LocOrErr);
else
diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp
index 6e107c87edb01..a1c73f9ec179b 100644
--- a/clang/lib/AST/Comment.cpp
+++ b/clang/lib/AST/Comment.cpp
@@ -233,13 +233,11 @@ void DeclInfo::fill() {
Kind = FunctionKind;
ParamVars = FD->parameters();
ReturnType = FD->getReturnType();
- TemplateParameters = FD->getTemplateSpecializationParameters();
- if (ArrayRef<TemplateParameterList *> TPLs =
- FD->getTemplateParameterLists();
- !TemplateParameters && !TPLs.empty())
- TemplateParameters = TPLs.back();
- if (TemplateParameters)
+ ArrayRef<TemplateParameterList *> TPLs = FD->getTemplateParameterLists();
+ if (!TPLs.empty()) {
TemplateKind = TemplateSpecialization;
+ TemplateParameters = TPLs.back();
+ }
if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
K == Decl::CXXDestructor || K == Decl::CXXConversion) {
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index a6de9959e0f62..b797ebfa1a7e1 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -51,7 +51,6 @@
#include "clang/Basic/TargetCXXABI.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Visibility.h"
-#include "clang/Lex/Lexer.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
@@ -4205,7 +4204,6 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
case TSK_ExplicitSpecialization:
return false;
- case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
return true;
@@ -4326,21 +4324,12 @@ FunctionDecl::getTemplateSpecializationArgsAsWritten() const {
return nullptr;
}
-const TemplateParameterList *
-FunctionDecl::getTemplateSpecializationParameters() const {
- if (const auto *Info = getTemplateSpecializationInfo())
- return Info->TemplateParameters;
- if (const auto *Info = getDependentSpecializationInfo())
- return Info->TemplateParameters;
- return nullptr;
-}
-
void FunctionDecl::setFunctionTemplateSpecialization(
ASTContext &C, FunctionTemplateDecl *Template,
TemplateArgumentList *TemplateArgs, void *InsertPos,
- TemplateSpecializationKind TSK, const TemplateParameterList *TemplateParams,
+ TemplateSpecializationKind TSK,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
- SourceLocation PointOfInstantiation, bool AddSpecialization) {
+ SourceLocation PointOfInstantiation) {
assert((TemplateOrSpecialization.isNull() ||
isa<MemberSpecializationInfo *>(TemplateOrSpecialization)) &&
"Member function is already a specialization");
@@ -4352,23 +4341,21 @@ void FunctionDecl::setFunctionTemplateSpecialization(
"Member specialization must be an explicit specialization");
FunctionTemplateSpecializationInfo *Info =
FunctionTemplateSpecializationInfo::Create(
- C, this, Template, TSK, TemplateArgs, TemplateParams,
- TemplateArgsAsWritten, PointOfInstantiation,
+ C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten,
+ PointOfInstantiation,
dyn_cast_if_present<MemberSpecializationInfo *>(
TemplateOrSpecialization));
TemplateOrSpecialization = Info;
- if (AddSpecialization)
- Template->addSpecialization(Info, InsertPos);
+ Template->addSpecialization(Info, InsertPos);
}
void FunctionDecl::setDependentTemplateSpecialization(
ASTContext &Context, const UnresolvedSetImpl &Templates,
- const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TemplateArgs) {
assert(TemplateOrSpecialization.isNull());
DependentFunctionTemplateSpecializationInfo *Info =
- DependentFunctionTemplateSpecializationInfo::Create(
- Context, Templates, TemplateParams, TemplateArgs);
+ DependentFunctionTemplateSpecializationInfo::Create(Context, Templates,
+ TemplateArgs);
TemplateOrSpecialization = Info;
}
@@ -4381,22 +4368,19 @@ FunctionDecl::getDependentSpecializationInfo() const {
DependentFunctionTemplateSpecializationInfo *
DependentFunctionTemplateSpecializationInfo::Create(
ASTContext &Context, const UnresolvedSetImpl &Candidates,
- const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TArgs) {
const auto *TArgsWritten =
TArgs ? ASTTemplateArgumentListInfo::Create(Context, *TArgs) : nullptr;
return new (Context.Allocate(
totalSizeToAlloc<FunctionTemplateDecl *>(Candidates.size())))
- DependentFunctionTemplateSpecializationInfo(Candidates, TemplateParams,
- TArgsWritten);
+ DependentFunctionTemplateSpecializationInfo(Candidates, TArgsWritten);
}
DependentFunctionTemplateSpecializationInfo::
DependentFunctionTemplateSpecializationInfo(
const UnresolvedSetImpl &Candidates,
- const TemplateParameterList *TemplateParams,
const ASTTemplateArgumentListInfo *TemplateArgsWritten)
- : NumCandidates(Candidates.size()), TemplateParameters(TemplateParams),
+ : NumCandidates(Candidates.size()),
TemplateArgumentsAsWritten(TemplateArgsWritten) {
std::transform(Candidates.begin(), Candidates.end(), getTrailingObjects(),
[](NamedDecl *ND) {
@@ -4556,17 +4540,6 @@ bool FunctionDecl::isOutOfLine() const {
return false;
}
-SourceLocation FunctionDecl::getFunctionLocStart() const {
- if (const TemplateParameterList *TemplateParams =
- getTemplateSpecializationParameters()) {
- const ASTContext &Ctx = getASTContext();
- return Lexer::findNextToken(TemplateParams->getSourceRange().getEnd(),
- Ctx.getSourceManager(), Ctx.getLangOpts())
- ->getLocation();
- }
- return getInnerLocStart();
-}
-
SourceRange FunctionDecl::getSourceRange() const {
return SourceRange(getOuterLocStart(), EndRangeLoc);
}
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 6a8046763c788..95591d3a09431 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -1105,7 +1105,6 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Out << *Attrs << ' ';
if (D->getIdentifier()) {
- // FIXME: Missing template parameter lists.
D->getQualifier().print(Out, Policy);
Out << *D;
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 861974848d6b3..275fe364e306d 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -245,8 +245,8 @@ bool TemplateParameterList::hasAssociatedConstraints() const {
return HasRequiresClause || HasConstrainedParameters;
}
-ArrayRef<TemplateArgument> TemplateParameterList::getInjectedTemplateArgs(
- const ASTContext &Context) const {
+ArrayRef<TemplateArgument>
+TemplateParameterList::getInjectedTemplateArgs(const ASTContext &Context) {
if (!InjectedArgs) {
InjectedArgs = new (Context) TemplateArgument[size()];
llvm::transform(*this, InjectedArgs, [&](NamedDecl *ND) {
@@ -946,7 +946,6 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
- const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation POI,
MemberSpecializationInfo *MSInfo) {
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
@@ -957,8 +956,7 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
void *Mem =
C.Allocate(totalSizeToAlloc<MemberSpecializationInfo *>(MSInfo ? 1 : 0));
return new (Mem) FunctionTemplateSpecializationInfo(
- FD, Template, TSK, TemplateArgs, TemplateParams, ArgsAsWritten, POI,
- MSInfo);
+ FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo);
}
//===----------------------------------------------------------------------===//
@@ -1052,38 +1050,54 @@ ClassTemplateSpecializationDecl::getSourceRange() const {
return CTPSD->getSourceRange();
return cast<ClassTemplateDecl *>(Pattern)->getSourceRange();
}
- case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization: {
- const auto *Info = getExplicitSpecializationInfo();
- auto TPLs = getTemplateParameterLists();
- return SourceRange(TPLs.empty() ? Info->TemplateParams->getTemplateLoc()
- : TPLs.front()->getTemplateLoc(),
- isThisDeclarationADefinition()
- ? CXXRecordDecl::getSourceRange().getEnd()
- : Info->TemplateArgsAsWritten->getRAngleLoc());
+ SourceRange Range = CXXRecordDecl::getSourceRange();
+ if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten();
+ !isThisDeclarationADefinition() && Args)
+ Range.setEnd(Args->getRAngleLoc());
+ return Range;
}
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition: {
- const auto *Info = getExplicitInstantiationInfo();
- return SourceRange(Info->ExternKeywordLoc.isValid()
- ? Info->ExternKeywordLoc
- : Info->TemplateKeywordLoc,
- Info->TemplateArgsAsWritten->getRAngleLoc());
+ SourceRange Range = CXXRecordDecl::getSourceRange();
+ if (SourceLocation ExternKW = getExternKeywordLoc(); ExternKW.isValid())
+ Range.setBegin(ExternKW);
+ else if (SourceLocation TemplateKW = getTemplateKeywordLoc();
+ TemplateKW.isValid())
+ Range.setBegin(TemplateKW);
+ if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten())
+ Range.setEnd(Args->getRAngleLoc());
+ return Range;
}
}
llvm_unreachable("unhandled template specialization kind");
}
-void ClassTemplateSpecializationDecl::setExplicitSpecializationInfo(
- TemplateParameterList *TemplateParams,
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
- auto *Info = new (getASTContext()) ExplicitSpecializationInfo();
- Info->TemplateParams = TemplateParams;
- Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
- ExplicitInfo = Info;
-
- if (AdoptTemplateParameterList(TemplateParams, this))
- setInvalidDecl();
+void ClassTemplateSpecializationDecl::setExternKeywordLoc(SourceLocation Loc) {
+ auto *Info = dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
+ if (!Info) {
+ // Don't allocate if the location is invalid.
+ if (Loc.isInvalid())
+ return;
+ Info = new (getASTContext()) ExplicitInstantiationInfo;
+ Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
+ ExplicitInfo = Info;
+ }
+ Info->ExternKeywordLoc = Loc;
+}
+
+void ClassTemplateSpecializationDecl::setTemplateKeywordLoc(
+ SourceLocation Loc) {
+ auto *Info = dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
+ if (!Info) {
+ // Don't allocate if the location is invalid.
+ if (Loc.isInvalid())
+ return;
+ Info = new (getASTContext()) ExplicitInstantiationInfo;
+ Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
+ ExplicitInfo = Info;
+ }
+ Info->TemplateKeywordLoc = Loc;
}
//===----------------------------------------------------------------------===//
@@ -1154,7 +1168,6 @@ void ClassTemplatePartialSpecializationDecl::anchor() {}
ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl)
@@ -1163,24 +1176,25 @@ ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
// Tracking StrictPackMatch for Partial
// Specializations is not needed.
SpecializedTemplate, Args, /*StrictPackMatch=*/false, PrevDecl),
- InstantiatedFromMember(nullptr, false),
+ TemplateParams(Params), InstantiatedFromMember(nullptr, false),
CanonInjectedTST(CanonInjectedTST) {
- setSpecializationKind(TSK_ExplicitSpecialization);
- setExplicitSpecializationInfo(Params, ArgsAsWritten);
+ if (AdoptTemplateParameterList(Params, this))
+ setInvalidDecl();
}
ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::Create(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl) {
assert(!Params->empty() && "template with no template parameters");
- return new (Context, DC) ClassTemplatePartialSpecializationDecl(
- Context, TK, DC, StartLoc, IdLoc, Params, ArgsAsWritten,
- SpecializedTemplate, Args, CanonInjectedTST, PrevDecl);
+ auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl(
+ Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args,
+ CanonInjectedTST, PrevDecl);
+ Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ return Result;
}
ClassTemplatePartialSpecializationDecl *
@@ -1207,7 +1221,11 @@ SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const {
getInstantiatedFromMember();
MT && !isMemberSpecialization())
return MT->getSourceRange();
- return ClassTemplateSpecializationDecl::getSourceRange();
+ SourceRange Range = ClassTemplateSpecializationDecl::getSourceRange();
+ if (const TemplateParameterList *TPL = getTemplateParameters();
+ TPL && getTemplateParameterLists().empty())
+ Range.setBegin(TPL->getTemplateLoc());
+ return Range;
}
//===----------------------------------------------------------------------===//
@@ -1466,11 +1484,8 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
}
return VTD->getCanonicalDecl()->getSourceRange();
}
- case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization: {
SourceRange Range = VarDecl::getSourceRange();
- if (const auto *Info = getExplicitSpecializationInfo())
- Range.setBegin(Info->TemplateParams->getTemplateLoc());
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten();
!hasInit() && Args)
Range.setEnd(Args->getRAngleLoc());
@@ -1478,11 +1493,10 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
}
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition: {
- const auto *Info = getExplicitInstantiationInfo();
SourceRange Range = VarDecl::getSourceRange();
- if (SourceLocation ExternKW = Info->ExternKeywordLoc; ExternKW.isValid())
+ if (SourceLocation ExternKW = getExternKeywordLoc(); ExternKW.isValid())
Range.setBegin(ExternKW);
- else if (SourceLocation TemplateKW = Info->TemplateKeywordLoc;
+ else if (SourceLocation TemplateKW = getTemplateKeywordLoc();
TemplateKW.isValid())
Range.setBegin(TemplateKW);
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten())
@@ -1493,16 +1507,30 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
llvm_unreachable("unhandled template specialization kind");
}
-void VarTemplateSpecializationDecl::setExplicitSpecializationInfo(
- TemplateParameterList *TemplateParams,
- const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
- auto *Info = new (getASTContext()) ExplicitSpecializationInfo();
- Info->TemplateParams = TemplateParams;
- Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
- ExplicitInfo = Info;
-
- if (AdoptTemplateParameterList(TemplateParams, getDeclContext()))
- setInvalidDecl();
+void VarTemplateSpecializationDecl::setExternKeywordLoc(SourceLocation Loc) {
+ auto *Info = dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
+ if (!Info) {
+ // Don't allocate if the location is invalid.
+ if (Loc.isInvalid())
+ return;
+ Info = new (getASTContext()) ExplicitInstantiationInfo;
+ Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
+ ExplicitInfo = Info;
+ }
+ Info->ExternKeywordLoc = Loc;
+}
+
+void VarTemplateSpecializationDecl::setTemplateKeywordLoc(SourceLocation Loc) {
+ auto *Info = dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
+ if (!Info) {
+ // Don't allocate if the location is invalid.
+ if (Loc.isInvalid())
+ return;
+ Info = new (getASTContext()) ExplicitInstantiationInfo;
+ Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
+ ExplicitInfo = Info;
+ }
+ Info->TemplateKeywordLoc = Loc;
}
//===----------------------------------------------------------------------===//
@@ -1514,28 +1542,28 @@ void VarTemplatePartialSpecializationDecl::anchor() {}
VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args)
: VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, Context,
DC, StartLoc, IdLoc, SpecializedTemplate, T,
TInfo, S, Args),
- InstantiatedFromMember(nullptr, false) {
- setSpecializationKind(TSK_ExplicitSpecialization);
- setExplicitSpecializationInfo(Params, ArgsAsWritten);
+ TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
+ if (AdoptTemplateParameterList(Params, DC))
+ setInvalidDecl();
}
VarTemplatePartialSpecializationDecl *
VarTemplatePartialSpecializationDecl::Create(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args) {
assert(!Params->empty() && "template with no template parameters");
- return new (Context, DC) VarTemplatePartialSpecializationDecl(
- Context, DC, StartLoc, IdLoc, Params, ArgsAsWritten, SpecializedTemplate,
- T, TInfo, S, Args);
+ auto *Result = new (Context, DC) VarTemplatePartialSpecializationDecl(
+ Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, S,
+ Args);
+ Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ return Result;
}
VarTemplatePartialSpecializationDecl *
@@ -1549,7 +1577,11 @@ SourceRange VarTemplatePartialSpecializationDecl::getSourceRange() const {
getInstantiatedFromMember();
MT && !isMemberSpecialization())
return MT->getSourceRange();
- return VarTemplateSpecializationDecl::getSourceRange();
+ SourceRange Range = VarTemplateSpecializationDecl::getSourceRange();
+ if (const TemplateParameterList *TPL = getTemplateParameters();
+ TPL && getTemplateParameterLists().empty())
+ Range.setBegin(TPL->getTemplateLoc());
+ return Range;
}
static TemplateParameterList *createBuiltinTemplateParameterList(
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index ffb3d74f6b9f4..8373dd8e373e0 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1131,9 +1131,6 @@ void JSONNodeDumper::VisitExplicitInstantiationDecl(
case TSK_ImplicitInstantiation:
JOS.attribute("templateSpecializationKind", "implicit_instantiation");
break;
- case TSK_FriendDeclaration:
- JOS.attribute("templateSpecializationKind", "friend_declaration");
- break;
case TSK_ExplicitSpecialization:
JOS.attribute("templateSpecializationKind", "explicit_specialization");
break;
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index abb6869a2b46e..2b1c0cac25b6d 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1044,9 +1044,6 @@ void clang::TextNodeDumper::dumpTemplateSpecializationKind(
case TSK_ImplicitInstantiation:
OS << " implicit_instantiation";
break;
- case TSK_FriendDeclaration:
- OS << " friend_declaration";
- break;
case TSK_ExplicitSpecialization:
OS << " explicit_specialization";
break;
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 8cb8d6ebf297f..a04070971f0eb 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -99,7 +99,6 @@ RegistryMaps::RegistryMaps() {
//
// Other:
// equalsNode
- // declaresSameEntityAsNode
registerMatcher("mapAnyOf",
std::make_unique<internal::MapAnyOfBuilderDescriptor>());
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index 45f0f0eaf7e70..3709fd0af3486 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -702,7 +702,7 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
canResolveToExpr(Exp),
parmVarDecl(hasType(nonConstReferenceType())).bind("parm"));
const auto IsInstantiated = hasDeclaration(isInstantiated());
- const auto FuncDecl = hasDeclaration(functionDecl());
+ const auto FuncDecl = hasDeclaration(functionDecl().bind("func"));
const auto Matches = match(
traverse(
TK_AsIs,
@@ -716,16 +716,13 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
Stm, Context);
for (const auto &Nodes : Matches) {
const auto *Exp = Nodes.getNodeAs<Expr>(NodeID<Expr>::value);
- const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
- const auto *Func =
- cast<FunctionDecl>(Parm->getDeclContext())->getDefinition();
- if (!Func || !Func->doesThisDeclarationHaveABody())
+ const auto *Func = Nodes.getNodeAs<FunctionDecl>("func");
+ if (!Func->getBody() || !Func->getPrimaryTemplate())
return Exp;
- Parm = Func->getParamDecl(Parm->getFunctionScopeIndex());
+ const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
const ArrayRef<ParmVarDecl *> AllParams =
- Func->getTemplateInstantiationPattern(/*ForDefinition=*/true)
- ->parameters();
+ Func->getPrimaryTemplate()->getTemplatedDecl()->parameters();
QualType ParmType =
AllParams[std::min<size_t>(Parm->getFunctionScopeIndex(),
AllParams.size() - 1)]
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index 40abf4570f219..64fdc0150ab8a 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -1143,22 +1143,21 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
return llvm::GlobalVariable::ExternalLinkage;
- case TSK_FriendDeclaration:
- case TSK_ImplicitInstantiation:
- return !Context.getLangOpts().AppleKext
- ? llvm::GlobalVariable::LinkOnceODRLinkage
- : llvm::Function::InternalLinkage;
-
- case TSK_ExplicitInstantiationDefinition:
- return !Context.getLangOpts().AppleKext
- ? llvm::GlobalVariable::WeakODRLinkage
- : llvm::Function::InternalLinkage;
-
- case TSK_ExplicitInstantiationDeclaration:
- return IsExternalDefinition
- ? llvm::GlobalVariable::AvailableExternallyLinkage
- : llvm::GlobalVariable::ExternalLinkage;
- }
+ case TSK_ImplicitInstantiation:
+ return !Context.getLangOpts().AppleKext ?
+ llvm::GlobalVariable::LinkOnceODRLinkage :
+ llvm::Function::InternalLinkage;
+
+ case TSK_ExplicitInstantiationDefinition:
+ return !Context.getLangOpts().AppleKext ?
+ llvm::GlobalVariable::WeakODRLinkage :
+ llvm::Function::InternalLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ return IsExternalDefinition
+ ? llvm::GlobalVariable::AvailableExternallyLinkage
+ : llvm::GlobalVariable::ExternalLinkage;
+ }
}
// -fapple-kext mode does not support weak linkage, so we must use
@@ -1183,7 +1182,6 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
- case TSK_FriendDeclaration:
return DiscardableODRLinkage;
case TSK_ExplicitInstantiationDeclaration:
diff --git a/clang/lib/Index/IndexingContext.cpp b/clang/lib/Index/IndexingContext.cpp
index ac532d6a2f5ef..bdd6c5acf1d34 100644
--- a/clang/lib/Index/IndexingContext.cpp
+++ b/clang/lib/Index/IndexingContext.cpp
@@ -185,7 +185,6 @@ bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
return isa<ClassTemplateSpecializationDecl>(D);
case TSK_ExplicitSpecialization:
return false;
- case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp
index 08d2e556ad57c..53fbc36ae7600 100644
--- a/clang/lib/InstallAPI/Visitor.cpp
+++ b/clang/lib/InstallAPI/Visitor.cpp
@@ -318,7 +318,6 @@ static bool hasVTable(const CXXRecordDecl *D) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
- case TSK_FriendDeclaration:
case TSK_ExplicitInstantiationDefinition:
return true;
case TSK_ExplicitInstantiationDeclaration:
@@ -335,7 +334,6 @@ static bool hasVTable(const CXXRecordDecl *D) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
- case TSK_FriendDeclaration:
return false;
case TSK_ExplicitInstantiationDeclaration:
@@ -363,7 +361,6 @@ static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) {
if (isInlined(KeyFunctionD))
return CXXLinkage::LinkOnceODRLinkage;
return CXXLinkage::ExternalLinkage;
- case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
llvm_unreachable("No external vtable for implicit instantiations");
case TSK_ExplicitInstantiationDefinition:
@@ -378,7 +375,6 @@ static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
- case TSK_FriendDeclaration:
return CXXLinkage::LinkOnceODRLinkage;
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
@@ -605,7 +601,6 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
break;
- case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
continue;
case TSK_ExplicitInstantiationDeclaration:
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 86f18d10f08b0..893989bd2398f 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2059,17 +2059,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateParams = &FakedParamLists;
}
}
- MultiTemplateParamsArg ParamLists(
- TemplateParams ? &(*TemplateParams)[0] : nullptr,
- TemplateParams ? TemplateParams->size() : 0);
+
// Build the class template specialization.
TagOrTempResult = Actions.ActOnClassTemplateSpecialization(
getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(),
- SS, *TemplateId, attrs, ParamLists, &SkipBody);
- // Some template parameter lists may have been dropped because they were
- // extraneous.
- if (TemplateParams)
- TemplateParams->resize(ParamLists.size());
+ SS, *TemplateId, attrs,
+ MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]
+ : nullptr,
+ TemplateParams ? TemplateParams->size() : 0),
+ &SkipBody);
}
} else if (TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation &&
TUK == TagUseKind::Declaration) {
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index e57bad6f5c548..f9fb7745721fe 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -312,6 +312,12 @@ addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
ElaboratedTypeKeyword::Class, TemplateName(TextureTemplate),
{TemplateArgument(VectorType)}, {}));
+ auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
+ AST, TagDecl::TagKind::Class, HLSLNamespace, SourceLocation(),
+ SourceLocation(), TemplateParams, TextureTemplate,
+ {TemplateArgument(VectorType)},
+ CanQualType::CreateUnsafe(CanonInjectedTST), nullptr);
+
// Set the template arguments as written.
TemplateArgument Arg(VectorType);
TemplateArgumentLoc ArgLoc =
@@ -319,13 +325,8 @@ addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
TemplateArgumentListInfo ArgsInfo =
TemplateArgumentListInfo(SourceLocation(), SourceLocation());
ArgsInfo.addArgument(ArgLoc);
-
- auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
- AST, TagDecl::TagKind::Class, HLSLNamespace, SourceLocation(),
- SourceLocation(), TemplateParams,
- ASTTemplateArgumentListInfo::Create(AST, ArgsInfo), TextureTemplate,
- {TemplateArgument(VectorType)},
- CanQualType::CreateUnsafe(CanonInjectedTST), nullptr);
+ PartialSpec->setTemplateArgsAsWritten(
+ ASTTemplateArgumentListInfo::Create(AST, ArgsInfo));
PartialSpec->setImplicit(true);
PartialSpec->setLexicalDeclContext(HLSLNamespace);
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 32a07b6266666..f41f37b8a3d19 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -200,10 +200,15 @@ static bool DiagRecursiveConstraintEval(
// Figure out the to-translation-unit depth for this function declaration for
// the purpose of seeing if they
diff er by constraints. This isn't the same as
// getTemplateDepth, because it includes already instantiated parents.
-static unsigned CalculateTemplateDepthForConstraints(Sema &S,
- const NamedDecl *ND) {
- // FIXME: This is a very expensive way to calculate this.
- MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(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,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true, SkipForSpecialization);
return MLTAL.getNumLevels();
}
@@ -1330,8 +1335,10 @@ bool Sema::CheckConstraintSatisfaction(
return false;
}
-static ExprResult SubstituteConceptsInConstraintExpression(
- Sema &S, const ConceptSpecializationExpr *CSE, UnsignedOrNone SubstIndex) {
+static ExprResult
+SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D,
+ const ConceptSpecializationExpr *CSE,
+ UnsignedOrNone SubstIndex) {
Sema::SFINAETrap Trap(S);
// [C++2c] [temp.constr.normal]
// Otherwise, to form CE, any non-dependent concept template argument Ai
@@ -1339,8 +1346,7 @@ static ExprResult SubstituteConceptsInConstraintExpression(
// If any such substitution results in an invalid concept-id,
// the program is ill-formed; no diagnostic is required.
- Expr *ConstraintExpr =
- CSE->getNamedConcept()->getCanonicalDecl()->getConstraintExpr();
+ ConceptDecl *Concept = CSE->getNamedConcept()->getCanonicalDecl();
Sema::ArgPackSubstIndexRAII _(S, SubstIndex);
const ASTTemplateArgumentListInfo *ArgsAsWritten =
@@ -1350,17 +1356,23 @@ static ExprResult SubstituteConceptsInConstraintExpression(
return !ArgLoc.getArgument().isDependent() &&
ArgLoc.getArgument().isConceptOrConceptTemplateParameter();
})) {
- return ConstraintExpr;
+ return Concept->getConstraintExpr();
}
- return S.SubstConceptTemplateArguments(
- CSE, ConstraintExpr,
- S.getTemplateInstantiationArgs(CSE->getSpecializationDecl()));
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ Concept, Concept->getLexicalDeclContext(),
+ /*Final=*/false, CSE->getTemplateArguments(),
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true);
+ return S.SubstConceptTemplateArguments(CSE, Concept->getConstraintExpr(),
+ MLTAL);
}
-bool Sema::SetupConstraintScope(FunctionDecl *FD,
- const MultiLevelTemplateArgumentList &MLTAL,
- LocalInstantiationScope &Scope) {
+bool Sema::SetupConstraintScope(
+ FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+ const MultiLevelTemplateArgumentList &MLTAL,
+ LocalInstantiationScope &Scope) {
assert(!isLambdaCallOperator(FD) &&
"Use LambdaScopeForCallOperatorInstantiationRAII to handle lambda "
"instantiations");
@@ -1369,7 +1381,8 @@ bool Sema::SetupConstraintScope(FunctionDecl *FD,
InstantiatingTemplate Inst(
*this, FD->getPointOfInstantiation(),
Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate,
- FD->getTemplateSpecializationArgs()->asArray(), SourceRange());
+ TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
+ SourceRange());
if (Inst.isInvalid())
return true;
@@ -1405,10 +1418,11 @@ bool Sema::SetupConstraintScope(FunctionDecl *FD,
? FD->getInstantiatedFromMemberFunction()
: FD->getInstantiatedFromDecl();
- InstantiatingTemplate Inst(*this, FD->getPointOfInstantiation(),
- Sema::InstantiatingTemplate::ConstraintsCheck{},
- InstantiatedFrom, ArrayRef<TemplateArgument>(),
- SourceRange());
+ InstantiatingTemplate Inst(
+ *this, FD->getPointOfInstantiation(),
+ Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
+ TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
+ SourceRange());
if (Inst.isInvalid())
return true;
@@ -1425,12 +1439,23 @@ bool Sema::SetupConstraintScope(FunctionDecl *FD,
// constraint-instantiation and checking.
std::optional<MultiLevelTemplateArgumentList>
Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
- FunctionDecl *FD, LocalInstantiationScope &Scope) {
- MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(FD);
+ FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+ LocalInstantiationScope &Scope) {
+ MultiLevelTemplateArgumentList MLTAL;
+
+ // Collect the list of template arguments relative to the 'primary' template.
+ // We need the entire list, since the constraint is completely uninstantiated
+ // at this point.
+ MLTAL =
+ getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
+ /*Final=*/false, /*Innermost=*/std::nullopt,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true);
// Lambdas are handled by LambdaScopeForCallOperatorInstantiationRAII.
if (isLambdaCallOperator(FD))
return MLTAL;
- if (SetupConstraintScope(FD, MLTAL, Scope))
+ if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
return std::nullopt;
return MLTAL;
@@ -1477,7 +1502,7 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
LocalInstantiationScope Scope(*this, !ForOverloadResolution);
std::optional<MultiLevelTemplateArgumentList> MLTAL =
SetupConstraintCheckingTemplateArgumentsAndScope(
- const_cast<FunctionDecl *>(FD), Scope);
+ const_cast<FunctionDecl *>(FD), {}, Scope);
if (!MLTAL)
return true;
@@ -1500,10 +1525,15 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
Satisfaction);
}
-static const Expr *
-SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
- const Expr *ConstrExpr) {
- MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(ND);
+static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
+ Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
+ const Expr *ConstrExpr) {
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ DeclInfo.getDecl(), DeclInfo.getDeclContext(), /*Final=*/false,
+ /*Innermost=*/std::nullopt,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
+ /*SkipForSpecialization*/ false);
if (MLTAL.getNumSubstitutedLevels() == 0)
return ConstrExpr;
@@ -1513,7 +1543,8 @@ SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
// this may happen while we're comparing two templates' constraint
// equivalence.
std::optional<LocalInstantiationScope> ScopeForParameters;
- if (ND->isFunctionOrFunctionTemplate()) {
+ if (const NamedDecl *ND = DeclInfo.getDecl();
+ ND && ND->isFunctionOrFunctionTemplate()) {
ScopeForParameters.emplace(S, /*CombineWithOuterScope=*/true);
const FunctionDecl *FD = ND->getAsFunction();
if (FunctionTemplateDecl *Template = FD->getDescribedFunctionTemplate();
@@ -1557,9 +1588,13 @@ SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
// possible that e.g. constraints involving C<Class<T>> and C<Class> are
// perceived identical.
std::optional<Sema::ContextRAII> ContextScope;
- const DeclContext *DC = ND->getFriendObjectKind()
- ? ND->getLexicalDeclContext()
- : ND->getDeclContext();
+ const DeclContext *DC = [&] {
+ if (!DeclInfo.getDecl())
+ return DeclInfo.getDeclContext();
+ return DeclInfo.getDecl()->getFriendObjectKind()
+ ? DeclInfo.getLexicalDeclContext()
+ : DeclInfo.getDeclContext();
+ }();
if (auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
ThisScope.emplace(S, const_cast<CXXRecordDecl *>(RD), Qualifiers());
ContextScope.emplace(S, const_cast<DeclContext *>(cast<DeclContext>(RD)),
@@ -1575,14 +1610,15 @@ SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
return SubstConstr.get();
}
-bool Sema::AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
- const Decl *New,
+bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
+ const Expr *OldConstr,
+ const TemplateCompareNewDeclInfo &New,
const Expr *NewConstr) {
if (OldConstr == NewConstr)
return true;
// C++ [temp.constr.decl]p4
- if (Old != New &&
- Old->getLexicalDeclContext() != New->getLexicalDeclContext()) {
+ if (Old && !New.isInvalid() && !New.ContainsDecl(Old) &&
+ Old->getLexicalDeclContext() != New.getLexicalDeclContext()) {
Sema::SFINAETrap _(*this);
if (const Expr *SubstConstr =
SubstituteConstraintExpressionWithoutSatisfaction(*this, Old,
@@ -1604,15 +1640,19 @@ bool Sema::AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
return ID1 == ID2;
}
-bool Sema::FriendConstraintsDependOnEnclosingTemplate(
- const FunctionTemplateDecl *FTD) {
- assert(FTD->getFriendObjectKind() && "Must be a friend!");
+bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
+ assert(FD->getFriendObjectKind() && "Must be a friend!");
+
+ // 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(FD->getDescribedFunctionTemplate() &&
+ "Non-function templates don't need to be checked");
SmallVector<AssociatedConstraint, 3> ACs;
- FTD->getAssociatedConstraints(ACs);
+ FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
- const FunctionDecl *FD = FTD->getTemplatedDecl();
- unsigned OldTemplateDepth = FTD->getTemplateDepth();
+ unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
for (const AssociatedConstraint &AC : ACs)
if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
AC.ConstraintExpr))
@@ -1648,9 +1688,9 @@ bool Sema::EnsureTemplateArgumentListConstraints(
return false;
}
-bool Sema::CheckFunctionTemplateConstraints(
- SourceLocation PointOfInstantiation, FunctionTemplateDecl *Template,
- ArrayRef<TemplateArgument> TemplateArgs,
+static bool CheckFunctionConstraintsWithoutInstantiation(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ FunctionTemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
ConstraintSatisfaction &Satisfaction) {
SmallVector<AssociatedConstraint, 3> TemplateAC;
Template->getAssociatedConstraints(TemplateAC);
@@ -1659,22 +1699,47 @@ bool Sema::CheckFunctionTemplateConstraints(
return false;
}
- LocalInstantiationScope Scope(*this);
+ LocalInstantiationScope Scope(SemaRef);
- MultiLevelTemplateArgumentList MLTAL =
- getTemplateInstantiationArgs(Template, TemplateArgs);
+ FunctionDecl *FD = Template->getTemplatedDecl();
+ // Collect the list of template arguments relative to the 'primary'
+ // template. We need the entire list, since the constraint is completely
+ // uninstantiated at this point.
- Sema::ContextRAII SavedContext(*this, Template->getTemplatedDecl());
- return CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
- PointOfInstantiation, Satisfaction);
+ MultiLevelTemplateArgumentList MLTAL;
+ {
+ // getTemplateInstantiationArgs uses this instantiation context to find out
+ // template arguments for uninstantiated functions.
+ // We don't want this RAII object to persist, because there would be
+ // otherwise duplicate diagnostic notes.
+ Sema::InstantiatingTemplate Inst(
+ SemaRef, PointOfInstantiation,
+ Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs,
+ PointOfInstantiation);
+ if (Inst.isInvalid())
+ return true;
+ MLTAL = SemaRef.getTemplateInstantiationArgs(
+ /*D=*/FD, FD,
+ /*Final=*/false, /*Innermost=*/{}, /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
+ }
+
+ Sema::ContextRAII SavedContext(SemaRef, FD);
+ return SemaRef.CheckConstraintSatisfaction(
+ Template, TemplateAC, MLTAL, PointOfInstantiation, Satisfaction);
}
-bool Sema::CheckFunctionSpecializationConstraints(
+bool Sema::CheckFunctionTemplateConstraints(
SourceLocation PointOfInstantiation, FunctionDecl *Decl,
+ ArrayRef<TemplateArgument> TemplateArgs,
ConstraintSatisfaction &Satisfaction) {
// In most cases we're not going to have constraints, so check for that first.
FunctionTemplateDecl *Template = Decl->getPrimaryTemplate();
- assert(Template && "Function is not a specialization");
+
+ if (!Template)
+ return ::CheckFunctionConstraintsWithoutInstantiation(
+ *this, PointOfInstantiation, Decl->getDescribedFunctionTemplate(),
+ TemplateArgs, Satisfaction);
// Note - code synthesis context for the constraints check is created
// inside CheckConstraintsSatisfaction.
@@ -1691,7 +1756,8 @@ bool Sema::CheckFunctionSpecializationConstraints(
LocalInstantiationScope Scope(*this);
std::optional<MultiLevelTemplateArgumentList> MLTAL =
- SetupConstraintCheckingTemplateArgumentsAndScope(Decl, Scope);
+ SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
+ Scope);
if (!MLTAL)
return true;
@@ -2275,8 +2341,12 @@ bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
InnerArgs = std::move(CTAI.SugaredConverted);
}
- MultiLevelTemplateArgumentList MLTAL =
- SemaRef.getTemplateInstantiationArgs(Concept, InnerArgs);
+ MultiLevelTemplateArgumentList MLTAL = SemaRef.getTemplateInstantiationArgs(
+ Concept, Concept->getLexicalDeclContext(),
+ /*Final=*/true, InnerArgs,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true);
return SubstituteParameterMappings(SemaRef, &MLTAL,
CSE->getTemplateArgsAsWritten(),
@@ -2357,7 +2427,7 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
// [...]
NormalizedConstraint *SubNF;
if (ExprResult Res =
- SubstituteConceptsInConstraintExpression(S, CSE, SubstIndex);
+ SubstituteConceptsInConstraintExpression(S, D, CSE, SubstIndex);
Res.isUsable())
// Use canonical declarations to merge ConceptDecls across
diff erent
// modules.
@@ -2507,8 +2577,8 @@ bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1,
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 --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 694067bea9e48..cddcf3a010279 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4750,10 +4750,10 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
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:
@@ -8023,8 +8023,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
if (IsVariableTemplateSpecialization) {
- // FIXME: This should be the template keyword location for the last
- // template parameter list.
SourceLocation TemplateKWLoc =
TemplateParamLists.size() > 0
? TemplateParamLists[0]->getTemplateLoc()
@@ -8067,8 +8065,10 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// If we have any template parameter lists that don't directly belong to
// the variable (matching the scope specifier), store them.
+ // An explicit variable template specialization does not own any template
+ // parameter lists.
unsigned VDTemplateParamLists =
- IsVariableTemplate || IsVariableTemplateSpecialization ? 1 : 0;
+ (TemplateParams && !IsExplicitSpecialization) ? 1 : 0;
if (TemplateParamLists.size() > VDTemplateParamLists)
NewVD->setTemplateParameterListsInfo(
Context, TemplateParamLists.drop_back(VDTemplateParamLists));
@@ -10119,7 +10119,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isMemberSpecialization = false;
bool isFunctionTemplateSpecialization = false;
- TemplateParameterList *TemplateParams = nullptr;
bool HasExplicitTemplateArgs = false;
TemplateArgumentListInfo TemplateArgs;
@@ -10204,14 +10203,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
? D.getName().TemplateId
: nullptr;
- TemplateParamListsRef = TemplateParamLists;
- TemplateParams = MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(), TemplateId, TemplateParamListsRef, isFriend,
- isMemberSpecialization, Invalid);
- // Some template parameter lists may have been dropped because they were
- // extraneous.
- TemplateParamLists.resize(TemplateParamListsRef.size());
+ TemplateParameterList *TemplateParams =
+ MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
+ D.getCXXScopeSpec(), TemplateId, TemplateParamLists, isFriend,
+ isMemberSpecialization, Invalid);
if (TemplateParams) {
// Check that we can declare a template here.
if (CheckTemplateDeclScope(S, TemplateParams))
@@ -10246,10 +10242,19 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD);
FunctionTemplate->setLexicalDeclContext(CurContext);
NewFD->setDescribedFunctionTemplate(FunctionTemplate);
+
+ // For source fidelity, store the other template param lists.
+ if (TemplateParamLists.size() > 1) {
+ NewFD->setTemplateParameterListsInfo(Context,
+ ArrayRef<TemplateParameterList *>(TemplateParamLists)
+ .drop_back(1));
+ }
} else {
// This is a function template specialization.
isFunctionTemplateSpecialization = true;
- NewFD->setInnerLocStart(TemplateParams->getTemplateLoc());
+ // For source fidelity, store all the template param lists.
+ if (TemplateParamLists.size() > 0)
+ NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists);
// C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
if (isFriend) {
@@ -10279,12 +10284,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TemplateArgs.setRAngleLoc(InsertLoc);
}
}
- // For source fidelity, store the other template param lists.
- if (TemplateParamLists.size() > 1) {
- NewFD->setTemplateParameterListsInfo(
- Context,
- ArrayRef<TemplateParameterList *>(TemplateParamLists).drop_back(1));
- }
} else {
// Check that we can declare a template here.
if (!TemplateParamLists.empty() && isMemberSpecialization &&
@@ -10886,11 +10885,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// template is instantiated. In such cases, we store the declarations
// found by name lookup and defer resolution until instantiation.
if (CheckDependentFunctionTemplateSpecialization(
- NewFD, TemplateParams, ExplicitTemplateArgs, Previous))
+ NewFD, ExplicitTemplateArgs, Previous))
NewFD->setInvalidDecl();
} else if (!NewFD->isInvalidDecl()) {
- if (CheckFunctionTemplateSpecialization(NewFD, TemplateParams,
- ExplicitTemplateArgs, Previous))
+ if (CheckFunctionTemplateSpecialization(NewFD, ExplicitTemplateArgs,
+ Previous))
NewFD->setInvalidDecl();
}
} else if (isMemberSpecialization && !FunctionTemplate) {
@@ -11194,7 +11193,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Precalculate whether this is a friend function template with a constraint
// that depends on an enclosing template, per [temp.friend]p9.
if (isFriend && FunctionTemplate &&
- FriendConstraintsDependOnEnclosingTemplate(FunctionTemplate)) {
+ FriendConstraintsDependOnEnclosingTemplate(NewFD)) {
NewFD->setFriendConstraintRefersToEnclosingTemplate(true);
// C++ [temp.friend]p9:
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 56ae96cae3e5b..9bbe99df064c3 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13938,13 +13938,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
}
if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) {
- // It's ok that we don't pass the declarations corresponding to the
- // template parameter lists here, because type alias templates cannot be
- // declared out-of-line.
- if (TemplateParameterListsAreEqual(
- /*NewInstFrom=*/nullptr, TemplateParams,
- /*OldInstFrom=*/nullptr, OldDecl->getTemplateParameters(),
- /*Complain=*/true, TPL_TemplateMatch))
+ if (TemplateParameterListsAreEqual(TemplateParams,
+ OldDecl->getTemplateParameters(),
+ /*Complain=*/true,
+ TPL_TemplateMatch))
OldTemplateParams =
OldDecl->getMostRecentDecl()->getTemplateParameters();
else
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 833e73922cfc9..851d58c49f7b9 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1129,8 +1129,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
return ExprError();
}
- DeclResult VDecl = CheckVarTemplateId(
- VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs);
+ DeclResult VDecl =
+ CheckVarTemplateId(VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(),
+ *TemplateArgs, /*SetWrittenArgs=*/false);
if (VDecl.isInvalid())
return ExprError();
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 83fde956e34b2..e11bbd7085798 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1325,10 +1325,8 @@ OverloadKind Sema::CheckOverload(Scope *S, FunctionDecl *New,
!New->getType()->isDependentType()) {
LookupResult TemplateSpecResult(LookupResult::Temporary, Old);
TemplateSpecResult.addAllDecls(Old);
- if (CheckFunctionTemplateSpecialization(New, /*TemplateParams=*/nullptr,
- /*ExplicitTemplateArgs=*/nullptr,
- TemplateSpecResult,
- /*QualifiedFriend*/ true)) {
+ if (CheckFunctionTemplateSpecialization(New, nullptr, TemplateSpecResult,
+ /*QualifiedFriend*/true)) {
New->setInvalidDecl();
return OverloadKind::Overload;
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 7228cc6ff4026..8c94a1ad39208 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2108,71 +2108,19 @@ DeclResult Sema::CheckClassTemplate(
}
}
- if (!PrevClassTemplate && PrevDecl) {
- // C++ [temp]p5:
- // A class template shall not have the same name as any other
- // template, class, function, object, enumeration, enumerator,
- // namespace, or type in the same scope (3.3), except as specified
- // in (14.5.4).
- Diag(NameLoc, diag::err_redefinition_
diff erent_kind) << Name;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- return true;
- }
-
- // If this is a templated friend in a dependent context we should not put it
- // on the redecl chain. In some cases, the templated friend can be the most
- // recent declaration tricking the template instantiator to make substitutions
- // there.
- // FIXME: Figure out how to combine with shouldLinkDependentDeclWithPrevious
- bool ShouldAddRedecl =
- !(TUK == TagUseKind::Friend && CurContext->isDependentContext());
-
- CXXRecordDecl *NewClass = CXXRecordDecl::Create(
- Context, Kind, SemanticContext, KWLoc, NameLoc, Name,
- /*PrevDecl=*/PrevClassTemplate && ShouldAddRedecl
- ? PrevClassTemplate->getTemplatedDecl()
- : nullptr);
- SetNestedNameSpecifier(*this, NewClass, SS);
- 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.
- if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) {
- if (LangOpts.HLSL)
- NewClass->addAttr(PackedAttr::CreateImplicit(Context));
- AddAlignmentAttributesForRecord(NewClass);
- AddMsStructLayoutForRecord(NewClass);
- }
-
- ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(
- Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams,
- NewClass);
-
- NewClass->setDescribedClassTemplate(NewTemplate);
-
- if (ModulePrivateLoc.isValid())
- NewTemplate->setModulePrivate();
-
- // Set the lexical context of these templates
- NewClass->setLexicalDeclContext(CurContext);
- NewTemplate->setLexicalDeclContext(CurContext);
-
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(
- NewTemplate, TemplateParams, PrevClassTemplate,
+ TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext
+ : CurContext,
+ CurContext, KWLoc),
+ TemplateParams, PrevClassTemplate,
PrevClassTemplate->getTemplateParameters(), /*Complain=*/true,
- TPL_TemplateMatch)) {
- NewTemplate->setInvalidDecl();
- NewClass->setInvalidDecl();
+ TPL_TemplateMatch))
return true;
- }
// C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit
@@ -2217,6 +2165,15 @@ DeclResult Sema::CheckClassTemplate(
}
}
}
+ } else if (PrevDecl) {
+ // C++ [temp]p5:
+ // A class template shall not have the same name as any other
+ // template, class, function, object, enumeration, enumerator,
+ // namespace, or type in the same scope (3.3), except as specified
+ // in (14.5.4).
+ Diag(NameLoc, diag::err_redefinition_
diff erent_kind) << Name;
+ Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ return true;
}
// Check the template parameter list of this declaration, possibly
@@ -2248,20 +2205,62 @@ DeclResult Sema::CheckClassTemplate(
}
}
- // Set the access specifier.
- if (!Invalid && TUK != TagUseKind::Friend &&
- NewTemplate->getDeclContext()->isRecord())
- SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
+ // If this is a templated friend in a dependent context we should not put it
+ // on the redecl chain. In some cases, the templated friend can be the most
+ // recent declaration tricking the template instantiator to make substitutions
+ // there.
+ // FIXME: Figure out how to combine with shouldLinkDependentDeclWithPrevious
+ bool ShouldAddRedecl =
+ !(TUK == TagUseKind::Friend && CurContext->isDependentContext());
- if (ShouldAddRedecl && PrevClassTemplate)
+ CXXRecordDecl *NewClass = CXXRecordDecl::Create(
+ Context, Kind, SemanticContext, KWLoc, NameLoc, Name,
+ PrevClassTemplate && ShouldAddRedecl
+ ? PrevClassTemplate->getTemplatedDecl()
+ : nullptr);
+ SetNestedNameSpecifier(*this, NewClass, SS);
+ 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.
+ if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) {
+ if (LangOpts.HLSL)
+ NewClass->addAttr(PackedAttr::CreateImplicit(Context));
+ AddAlignmentAttributesForRecord(NewClass);
+ AddMsStructLayoutForRecord(NewClass);
+ }
+
+ ClassTemplateDecl *NewTemplate
+ = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
+ DeclarationName(Name), TemplateParams,
+ NewClass);
+
+ if (ShouldAddRedecl)
NewTemplate->setPreviousDecl(PrevClassTemplate);
+ NewClass->setDescribedClassTemplate(NewTemplate);
+
+ if (ModulePrivateLoc.isValid())
+ NewTemplate->setModulePrivate();
+
if (IsMemberSpecialization) {
assert(PrevClassTemplate &&
"Member specialization without a primary template?");
NewTemplate->setMemberSpecialization();
}
+ // Set the access specifier.
+ if (!Invalid && TUK != TagUseKind::Friend &&
+ NewTemplate->getDeclContext()->isRecord())
+ SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
+
+ // Set the lexical context of these templates
+ NewClass->setLexicalDeclContext(CurContext);
+ NewTemplate->setLexicalDeclContext(CurContext);
+
if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
NewClass->startDefinition();
@@ -2834,7 +2833,7 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,
TemplateIdAnnotation *TemplateId,
- ArrayRef<TemplateParameterList *> &ParamLists, bool IsFriend,
+ ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) {
IsMemberSpecialization = false;
Invalid = false;
@@ -3100,12 +3099,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (ParamIdx < ParamLists.size()) {
// Check the template parameter list, if we can.
- // FIXME: Should pass the declaration corresponding to each list.
if (ExpectedTemplateParams &&
- !TemplateParameterListsAreEqual(
- /*NewInstFrom=*/nullptr, ParamLists[ParamIdx],
- /*OldInstFrom=*/nullptr, ExpectedTemplateParams,
- /*Complain=*/!SuppressDiagnostic, TPL_TemplateMatch))
+ !TemplateParameterListsAreEqual(ParamLists[ParamIdx],
+ ExpectedTemplateParams,
+ !SuppressDiagnostic, TPL_TemplateMatch))
Invalid = true;
if (!Invalid &&
@@ -3172,9 +3169,6 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
diag::note_explicit_template_spec_does_not_need_header)
<< NestedTypes.back();
- // Recover as if those extra template parameter lists weren't there.
- ParamLists = ParamLists.take_back(ParamIdx + 1);
-
// We have a template parameter list with no corresponding scope, which
// means that the resulting template declaration can't be instantiated
// properly (we'll end up with dependent nodes when we shouldn't).
@@ -4482,9 +4476,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplatePartialSpecializationDecl *Partial =
VarTemplatePartialSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
- TemplateNameLoc, TemplateParams,
- ASTTemplateArgumentListInfo::Create(Context, TemplateArgs),
- VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
+ TemplateNameLoc, TemplateParams, VarTemplate, TSI->getType(), TSI,
+ SC, CTAI.CanonicalConverted);
+ Partial->setTemplateArgsAsWritten(TemplateArgs);
if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
@@ -4497,9 +4491,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
Specialization = VarTemplateSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
- Specialization->setExplicitSpecializationInfo(
- TemplateParams,
- ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
+ Specialization->setTemplateArgsAsWritten(TemplateArgs);
if (!PrevDecl)
VarTemplate->AddSpecialization(Specialization, InsertPos);
@@ -4585,7 +4577,8 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) {
DeclResult
Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation TemplateNameLoc,
- const TemplateArgumentListInfo &TemplateArgs) {
+ const TemplateArgumentListInfo &TemplateArgs,
+ bool SetWrittenArgs) {
assert(Template && "A variable template id without template?");
// Check that the template argument list is well-formed for this template.
@@ -4784,6 +4777,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
TemplateNameLoc /*, LateAttrs, StartingScope*/);
if (!Decl)
return true;
+ if (SetWrittenArgs)
+ Decl->setTemplateArgsAsWritten(TemplateArgs);
if (VarTemplatePartialSpecializationDecl *D =
dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern))
@@ -4801,7 +4796,7 @@ ExprResult Sema::CheckVarTemplateId(
const TemplateArgumentListInfo *TemplateArgs) {
DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
- *TemplateArgs);
+ *TemplateArgs, /*SetWrittenArgs=*/false);
if (Decl.isInvalid())
return ExprError();
@@ -6193,8 +6188,7 @@ bool Sema::CheckTemplateArgumentList(
if (UpdateArgsWithConversions)
TemplateArgs = std::move(NewArgs);
- // Template template parameters can never have their constraints checked.
- if (!PartialTemplateArgs && !isa<TemplateTemplateParmDecl>(Template)) {
+ if (!PartialTemplateArgs) {
// Setup the context/ThisScope for the case where we are needing to
// re-instantiate constraints outside of normal instantiation.
DeclContext *NewContext = Template->getDeclContext();
@@ -6213,8 +6207,11 @@ bool Sema::CheckTemplateArgumentList(
ContextRAII Context(*this, NewContext);
CXXThisScopeRAII Scope(*this, RD, ThisQuals, RD != nullptr);
- MultiLevelTemplateArgumentList MLTAL =
- getTemplateInstantiationArgs(Template, CTAI.SugaredConverted);
+ MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
+ Template, NewContext, /*Final=*/true, CTAI.SugaredConverted,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConceptInstantiation=*/true);
if (!isa<ConceptDecl>(Template) &&
EnsureTemplateArgumentListConstraints(
Template, MLTAL,
@@ -8205,8 +8202,9 @@ Sema::BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
/// Match two template parameters within template parameter lists.
static bool MatchTemplateParameterKind(
- Sema &S, NamedDecl *New, const Decl *NewInstFrom, NamedDecl *Old,
- const Decl *OldInstFrom, bool Complain,
+ Sema &S, NamedDecl *New,
+ const Sema::TemplateCompareNewDeclInfo &NewInstFrom, NamedDecl *Old,
+ const NamedDecl *OldInstFrom, bool Complain,
Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
// Check the actual kind (type, non-type, template).
if (Old->getKind() != New->getKind()) {
@@ -8294,7 +8292,7 @@ static bool MatchTemplateParameterKind(
if (OldTTP->templateParameterKind() != NewTTP->templateParameterKind())
return false;
if (!S.TemplateParameterListsAreEqual(
- NewTTP, NewTTP->getTemplateParameters(), OldTTP,
+ NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
OldTTP->getTemplateParameters(), Complain,
(Kind == Sema::TPL_TemplateMatch
? Sema::TPL_TemplateTemplateParmMatch
@@ -8372,8 +8370,8 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
}
bool Sema::TemplateParameterListsAreEqual(
- const Decl *NewInstFrom, TemplateParameterList *New,
- const Decl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+ const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
+ const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
if (Old->size() != New->size()) {
if (Complain)
@@ -8755,7 +8753,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
SourceLocation ModulePrivateLoc, CXXScopeSpec &SS,
TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr,
- MultiTemplateParamsArg &TemplateParameterLists, SkipBodyInfo *SkipBody) {
+ MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) {
assert(TUK != TagUseKind::Reference && "References are not specializations");
SourceLocation TemplateNameLoc = TemplateId.TemplateNameLoc;
@@ -8953,13 +8951,15 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
Specialization = ClassTemplateSpecializationDecl::Create(
Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
ClassTemplate, CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl);
+ Specialization->setTemplateArgsAsWritten(TemplateArgs);
+ SetNestedNameSpecifier(*this, Specialization, SS);
+ if (TemplateParameterLists.size() > 0) {
+ Specialization->setTemplateParameterListsInfo(Context,
+ TemplateParameterLists);
+ }
if (!PrevDecl)
ClassTemplate->AddSpecialization(Specialization, InsertPos);
-
- Specialization->setExplicitSpecializationInfo(
- TemplateParams,
- ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
} else {
CanQualType CanonType = CanQualType::CreateUnsafe(
Context.getCanonicalTemplateSpecializationType(
@@ -8995,8 +8995,13 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplatePartialSpecializationDecl *Partial =
ClassTemplatePartialSpecializationDecl::Create(
Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
- ASTTemplateArgumentListInfo::Create(Context, TemplateArgs),
ClassTemplate, CTAI.CanonicalConverted, CanonType, PrevPartial);
+ Partial->setTemplateArgsAsWritten(TemplateArgs);
+ SetNestedNameSpecifier(*this, Partial, SS);
+ if (TemplateParameterLists.size() > 1 && SS.isSet()) {
+ Partial->setTemplateParameterListsInfo(
+ Context, TemplateParameterLists.drop_back(1));
+ }
if (!PrevPartial)
ClassTemplate->AddPartialSpecialization(Partial, InsertPos);
@@ -9006,18 +9011,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// template specialization, make a note of that.
if (isMemberSpecialization)
Partial->setMemberSpecialization();
- }
- SetNestedNameSpecifier(*this, Specialization, SS);
- if (TemplateParameterLists.size() > 1 && SS.isSet()) {
- Specialization->setTemplateParameterListsInfo(
- Context, TemplateParameterLists.drop_back(1));
+ CheckTemplatePartialSpecialization(Partial);
}
- if (isPartialSpecialization)
- CheckTemplatePartialSpecialization(
- cast<ClassTemplatePartialSpecializationDecl>(Specialization));
-
// C++ [temp.expl.spec]p6:
// If a template, a member template or the member of a class template is
// explicitly specialized then that specialization shall be declared
@@ -9377,7 +9374,6 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
switch (NewTSK) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
- case TSK_FriendDeclaration:
assert(
(PrevTSK == TSK_Undeclared || PrevTSK == TSK_ImplicitInstantiation) &&
"previous declaration must be implicit!");
@@ -9392,7 +9388,6 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// instantiation.
return false;
- case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
if (PrevPointOfInstantiation.isInvalid()) {
// The declaration itself has not actually been instantiated, so it is
@@ -9439,7 +9434,6 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
return false;
case TSK_Undeclared:
- case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
// We're explicitly instantiating something that may have already been
// implicitly instantiated; that's fine.
@@ -9475,7 +9469,6 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
case TSK_ExplicitInstantiationDefinition:
switch (PrevTSK) {
case TSK_Undeclared:
- case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
// We're explicitly instantiating something that may have already been
// implicitly instantiated; that's fine.
@@ -9535,8 +9528,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
}
bool Sema::CheckDependentFunctionTemplateSpecialization(
- FunctionDecl *FD, const TemplateParameterList *TemplateParams,
- const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous) {
// Remove anything from Previous that isn't a function template in
// the correct context.
@@ -9573,14 +9565,13 @@ bool Sema::CheckDependentFunctionTemplateSpecialization(
}
FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(),
- TemplateParams, ExplicitTemplateArgs);
+ ExplicitTemplateArgs);
return false;
}
bool Sema::CheckFunctionTemplateSpecialization(
- FunctionDecl *FD, const TemplateParameterList *TemplateParams,
- TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous,
- bool QualifiedFriend) {
+ FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
+ LookupResult &Previous, bool QualifiedFriend) {
// The set of function template specializations that could match this
// explicit function template specialization.
UnresolvedSet<8> Candidates;
@@ -9830,11 +9821,9 @@ bool Sema::CheckFunctionTemplateSpecialization(
TemplateArgumentList *TemplArgs = TemplateArgumentList::CreateCopy(
Context, Specialization->getTemplateSpecializationArgs()->asArray());
FD->setFunctionTemplateSpecialization(
- Context, Specialization->getPrimaryTemplate(), TemplArgs,
- /*InsertPos=*/nullptr, SpecInfo->getTemplateSpecializationKind(),
- TemplateParams,
- ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr,
- /*PointOfInstantiation=*/SourceLocation(), /*AddSpecialization=*/true);
+ Specialization->getPrimaryTemplate(), TemplArgs, /*InsertPos=*/nullptr,
+ SpecInfo->getTemplateSpecializationKind(),
+ ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr);
// A function template specialization inherits the target attributes
// of its template. (We require the attributes explicitly in the
@@ -9984,13 +9973,14 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
// FIXME: Is this really valid? Other compilers reject.
if (Member->getFriendObjectKind() != Decl::FOK_None) {
// Preserve instantiation information.
- if (InstantiatedFrom) {
- if (auto *MD = dyn_cast<CXXMethodDecl>(Member))
- MD->setInstantiationOfMemberFunction(
- cast<CXXMethodDecl>(InstantiatedFrom), TSK_FriendDeclaration);
- else if (auto *RD = dyn_cast<CXXRecordDecl>(Member))
- RD->setInstantiationOfMemberClass(cast<CXXRecordDecl>(InstantiatedFrom),
- TSK_FriendDeclaration);
+ if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) {
+ cast<CXXMethodDecl>(Member)->setInstantiationOfMemberFunction(
+ cast<CXXMethodDecl>(InstantiatedFrom),
+ cast<CXXMethodDecl>(Instantiation)->getTemplateSpecializationKind());
+ } else if (InstantiatedFrom && isa<CXXRecordDecl>(Member)) {
+ cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
+ cast<CXXRecordDecl>(InstantiatedFrom),
+ cast<CXXRecordDecl>(Instantiation)->getTemplateSpecializationKind());
}
Previous.clear();
@@ -10077,8 +10067,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
template<typename DeclT>
static void completeMemberSpecializationImpl(Sema &S, DeclT *OrigD,
SourceLocation Loc) {
- if (auto Kind = OrigD->getTemplateSpecializationKind();
- Kind != TSK_ImplicitInstantiation && Kind != TSK_FriendDeclaration)
+ if (OrigD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
return;
// FIXME: Inform AST mutation listeners of this AST mutation.
@@ -10408,6 +10397,7 @@ DeclResult Sema::ActOnExplicitInstantiation(
Specialization = ClassTemplateSpecializationDecl::Create(
Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
ClassTemplate, CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl);
+ SetNestedNameSpecifier(*this, Specialization, SS);
// A MSInheritanceAttr attached to the previous declaration must be
// propagated to the new node prior to instantiation.
@@ -10426,19 +10416,22 @@ DeclResult Sema::ActOnExplicitInstantiation(
}
}
- Specialization->setExplicitInstantiationInfo(
- ExternLoc, TemplateLoc,
- ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
+ Specialization->setTemplateArgsAsWritten(TemplateArgs);
+
+ // Set source locations for keywords.
+ Specialization->setExternKeywordLoc(ExternLoc);
+ Specialization->setTemplateKeywordLoc(TemplateLoc);
Specialization->setBraceRange(SourceRange());
bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>();
ProcessDeclAttributeList(S, Specialization, Attr);
ProcessAPINotes(Specialization);
- // Add the explicit instantiation into its lexical context.
- auto *LexicalDC = ClassTemplate->getLexicalDeclContext();
- Specialization->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDecl(Specialization);
+ // Add the explicit instantiation into its lexical context. However,
+ // since explicit instantiations are never found by name lookup, we
+ // just put it into the declaration context directly.
+ Specialization->setLexicalDeclContext(CurContext);
+ CurContext->addDecl(Specialization);
// Syntax is now OK, so return if it has no other effect on semantics.
if (HasNoEffect) {
@@ -10767,15 +10760,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
/*ObjectType=*/QualType());
- // If the declarator is a template-id, translate the parser's template
- // argument list into our AST format.
- bool HasExplicitTemplateArgs = false;
- TemplateArgumentListInfo TemplateArgs;
- if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) {
- TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
- HasExplicitTemplateArgs = true;
- }
-
if (!R->isFunctionType()) {
// C++ [temp.explicit]p1:
// A [...] static data member of a class template can be explicitly
@@ -10825,7 +10809,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}
- if (!HasExplicitTemplateArgs) {
+ if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
// C++1y [temp.explicit]p3:
// If the explicit instantiation is for a variable, the unqualified-id
// in the declaration shall be a template-id.
@@ -10837,8 +10821,13 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}
- DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
- D.getIdentifierLoc(), TemplateArgs);
+ // Translate the parser's template argument list into our AST format.
+ TemplateArgumentListInfo TemplateArgs =
+ makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
+
+ DeclResult Res =
+ CheckVarTemplateId(PrevTemplate, TemplateLoc, D.getIdentifierLoc(),
+ TemplateArgs, /*SetWrittenArgs=*/true);
if (Res.isInvalid())
return true;
@@ -10886,10 +10875,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// Instantiate static data member or variable template.
Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Prev)) {
- assert(HasExplicitTemplateArgs);
- VTSD->setExplicitInstantiationInfo(
- ExternLoc, TemplateLoc,
- ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
+ VTSD->setExternKeywordLoc(ExternLoc);
+ VTSD->setTemplateKeywordLoc(TemplateLoc);
}
// Merge attributes.
@@ -10918,6 +10905,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return (Decl *)nullptr;
}
+ // If the declarator is a template-id, translate the parser's template
+ // argument list into our AST format.
+ bool HasExplicitTemplateArgs = false;
+ TemplateArgumentListInfo TemplateArgs;
+ if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) {
+ TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
+ HasExplicitTemplateArgs = true;
+ }
+
// C++ [temp.explicit]p1:
// A [...] function [...] can be explicitly instantiated from its template.
// A member function [...] of a class template can be explicitly
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index b75abecefafd6..26c397afdd6ef 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3182,16 +3182,36 @@ CheckDeducedArgumentConstraints(Sema &S, NamedDecl *Template,
ArrayRef<TemplateArgument> CanonicalDeducedArgs,
TemplateDeductionInfo &Info) {
llvm::SmallVector<AssociatedConstraint, 3> AssociatedConstraints;
- if (auto *TD = dyn_cast<ClassTemplatePartialSpecializationDecl>(Template))
+ bool DeducedArgsNeedReplacement = false;
+ if (auto *TD = dyn_cast<ClassTemplatePartialSpecializationDecl>(Template)) {
TD->getAssociatedConstraints(AssociatedConstraints);
- else if (auto *TD = dyn_cast<VarTemplatePartialSpecializationDecl>(Template))
+ DeducedArgsNeedReplacement = !TD->isClassScopeExplicitSpecialization();
+ } else if (auto *TD =
+ dyn_cast<VarTemplatePartialSpecializationDecl>(Template)) {
TD->getAssociatedConstraints(AssociatedConstraints);
- else
+ DeducedArgsNeedReplacement = !TD->isClassScopeExplicitSpecialization();
+ } else {
cast<TemplateDecl>(Template)->getAssociatedConstraints(
AssociatedConstraints);
+ }
+
+ std::optional<ArrayRef<TemplateArgument>> 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)
+ Innermost = SugaredDeducedArgs;
- MultiLevelTemplateArgumentList MLTAL =
- S.getTemplateInstantiationArgs(Template, SugaredDeducedArgs);
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ 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, SugaredDeducedArgs);
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
Info.getLocation(),
@@ -3952,8 +3972,9 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
bool IsLambda = isLambdaCallOperator(FD) || isLambdaConversionOperator(FD);
if (!IsLambda && !IsIncomplete) {
if (CheckFunctionTemplateConstraints(
- Info.getLocation(), FunctionTemplate, CTAI.CanonicalConverted,
- Info.AssociatedConstraintsSatisfaction))
+ Info.getLocation(),
+ FunctionTemplate->getCanonicalDecl()->getTemplatedDecl(),
+ CTAI.CanonicalConverted, Info.AssociatedConstraintsSatisfaction))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
Info.reset(Info.takeSugared(), TemplateArgumentList::CreateCopy(
@@ -3999,8 +4020,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// ([temp.constr.constr]). If the constraints are not satisfied, type
// deduction fails.
if (IsLambda && !IsIncomplete) {
- if (CheckFunctionSpecializationConstraints(
- Info.getLocation(), Specialization,
+ if (CheckFunctionTemplateConstraints(
+ Info.getLocation(), Specialization, CTAI.CanonicalConverted,
Info.AssociatedConstraintsSatisfaction))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
@@ -6007,7 +6028,7 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
// function parameters that positionally correspond between the two
// templates are not of the same type, neither template is more specialized
// than the other.
- if (!TemplateParameterListsAreEqual(FT1, TPL1, FT2, TPL2, false,
+ if (!TemplateParameterListsAreEqual(TPL1, TPL2, false,
Sema::TPL_TemplateParamsEquivalent))
return nullptr;
@@ -6362,7 +6383,7 @@ getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1,
// function parameters that positionally correspond between the two
// templates are not of the same type, neither template is more specialized
// than the other.
- if (!S.TemplateParameterListsAreEqual(P1, TPL1, P2, TPL2, false,
+ if (!S.TemplateParameterListsAreEqual(TPL1, TPL2, false,
Sema::TPL_TemplateParamsEquivalent))
return nullptr;
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 15b6aea749584..fa740d5581e5f 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -65,9 +65,10 @@ static bool HaveSameAssociatedConstraints(
return true;
// General case: pairwise compare each associated constraint expression.
+ Sema::TemplateCompareNewDeclInfo NewInfo(New);
for (size_t I = 0, E = OldACs.size(); I != E; ++I)
- if (!SemaRef.AreConstraintExpressionsEqual(Old, OldACs[I].ConstraintExpr,
- New, NewACs[I].ConstraintExpr))
+ if (!SemaRef.AreConstraintExpressionsEqual(
+ Old, OldACs[I].ConstraintExpr, NewInfo, NewACs[I].ConstraintExpr))
return false;
return true;
@@ -502,7 +503,6 @@ struct ConvertConstructorToDeductionGuideTransform {
: SemaRef(S), Template(Template) {
// If the template is nested, then we need to use the original
// pattern to iterate over the constructors.
- // FIXME: Should this just use getTemplateInstantiationPattern?
ClassTemplateDecl *Pattern = Template;
while (Pattern->getInstantiatedFromMemberTemplate()) {
if (Pattern->isMemberSpecialization())
@@ -510,9 +510,9 @@ struct ConvertConstructorToDeductionGuideTransform {
Pattern = Pattern->getInstantiatedFromMemberTemplate();
NestedPattern = Pattern;
}
+
if (NestedPattern)
- OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(
- Decl::castFromDeclContext(Template->getDeclContext()));
+ OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template);
}
Sema &SemaRef;
@@ -1053,9 +1053,52 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
}
}
- MultiLevelTemplateArgumentList ArgsForBuildingRC =
- SemaRef.getTemplateInstantiationArgs(F, TemplateArgsForBuildingRC);
+ // 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.
+ //
+ // For example:
+ // template <typename T> // depth 0
+ // struct Outer {
+ // template <typename U>
+ // struct Foo { Foo(U); };
+ //
+ // template <typename U> // depth 1
+ // requires C<U>
+ // Foo(U) -> Foo<int>;
+ // };
+ // template <typename U>
+ // using AFoo = Outer<int>::Foo<U>;
+ //
+ // In this scenario, the deduction guide for `Foo` inside `Outer<int>`:
+ // - The occurrence of U in the require-expression is [depth:1, index:0]
+ // - 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<U>` 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.
+ // 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 --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 6df6d5505c61c..5309ec4430e9e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -49,6 +49,38 @@ using namespace sema;
//===----------------------------------------------------------------------===/
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.
@@ -136,197 +168,397 @@ bool isLambdaEnclosedByTypeAliasDecl(
.TraverseType(Underlying);
}
-} // namespace
+// 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<VarTemplatePartialSpecializationDecl>(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<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
+ Specialized = VarTemplSpec->getSpecializedTemplateOrPartial();
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ dyn_cast<VarTemplatePartialSpecializationDecl *>(Specialized)) {
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+ if (Partial->isMemberSpecialization())
+ return Response::Done();
+ } else {
+ VarTemplateDecl *Tmpl = cast<VarTemplateDecl *>(Specialized);
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+ if (Tmpl->isMemberSpecialization())
+ return Response::Done();
+ }
+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
+}
-MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
- const Decl *D, std::optional<ArrayRef<TemplateArgument>> Innermost,
- UnsignedOrNone NumLevels, bool SkipInnerNonInstantiated) {
- MultiLevelTemplateArgumentList TemplateArgs;
-
- // The scope being followed for an out-of-line-definition.
- NestedNameSpecifier Qualifier = std::nullopt;
- ArrayRef<TemplateParameterList *> TPLs;
-
- while (!NumLevels || *NumLevels != 0U) {
- bool Final = false;
- if (const TemplateParameterList *TPL =
- isa<TemplateDecl>(D)
- ? cast<TemplateDecl>(D)->getTemplateParameters()
- : D->getDescribedTemplateParams()) {
- // Template-like entities should always produce a final substitution
- // level, as they shouldn't be transformed again.
- Final = true;
- // If Innermost is provided, use that as the template arguments.
- if (!Innermost)
- Innermost = TPL->getInjectedTemplateArgs(Context);
- else
- SkipInnerNonInstantiated = false;
- } else {
- assert(!Innermost &&
- "Shouldn't provide innermost for a non-template-like declaration");
-
- if (isa<ClassTemplateSpecializationDecl, VarTemplateSpecializationDecl>(
- D)) {
- auto specCase = [&](const auto *ND) {
- if (ND->getSpecializationKind() == TSK_ExplicitSpecialization) {
- assert(TPLs.empty());
- return;
- }
- SkipInnerNonInstantiated = false;
- Innermost = ND->getTemplateInstantiationArgs().asArray();
- };
- if (isa<ClassTemplateSpecializationDecl>(D))
- specCase(cast<ClassTemplateSpecializationDecl>(D));
- else
- specCase(cast<VarTemplateSpecializationDecl>(D));
- } else if (isa<ImplicitConceptSpecializationDecl>(D)) {
- SkipInnerNonInstantiated = false;
- Innermost =
- cast<ImplicitConceptSpecializationDecl>(D)->getTemplateArguments();
- Final = true;
- } else if (const auto *ND = dyn_cast<FunctionDecl>(D)) {
- const FunctionTemplateSpecializationInfo *Info =
- ND->getTemplateSpecializationInfo();
- if (!Info || Info->getTemplateSpecializationKind() ==
- TSK_ExplicitSpecialization) {
- assert(TPLs.empty());
- } else {
- SkipInnerNonInstantiated = false;
- Innermost = Info->TemplateArguments->asArray();
- }
- } else if (const auto *ND = dyn_cast<CXXRecordDecl>(D);
- ND && ND->isLambda()) {
- assert(TPLs.empty() &&
- "lambdas can't be part of an out-of-line definition");
- // FIXME: If this lambda is enclosed by a type alias template, look
- // into the current CodeSynthesisContexts to find the template
- // arguments used to specialize it.
- if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef);
- TypeAlias &&
- isLambdaEnclosedByTypeAliasDecl(ND->getLambdaCallOperator(),
- TypeAlias.PrimaryTypeAliasDecl)) {
- Innermost = TypeAlias.AssociatedTemplateArguments;
- Final = true;
- D = TypeAlias.Template;
- continue;
- }
- if (const Decl *LCD = ND->getLambdaContextDecl()) {
- D = LCD;
- continue;
+// 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<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec))
+ return Response::Done();
+
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec),
+ ClassTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+
+ // 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<ClassTemplatePartialSpecializationDecl *>())
+ 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<FunctionDecl *>(Function),
+ TemplateArgs->asArray(),
+ /*Final=*/false);
+
+ 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();
+
+ } else if (auto *Template = Function->getDescribedFunctionTemplate()) {
+ assert(
+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+ "Outer template not instantiated?");
+ if (ForConstraintInstantiation) {
+ for (auto &Inst : llvm::reverse(SemaRef.CodeSynthesisContexts)) {
+ if (Inst.Kind == Sema::CodeSynthesisContext::ConstraintsCheck &&
+ Inst.Entity == Template) {
+ // After CWG2369, the outer templates are not instantiated when
+ // checking its associated constraints. So add them back through the
+ // synthesis context; this is useful for e.g. nested constraints
+ // involving lambdas.
+ Result.addOuterTemplateArguments(Template, Inst.template_arguments(),
+ /*Final=*/false);
+ break;
}
- } else if (isa<TranslationUnitDecl, NamespaceBaseDecl, ExportDecl,
- LinkageSpecDecl>(D)) {
- // The end of the line, there can't be any template arguments further.
- assert(TPLs.empty());
- assert(!NumLevels && "Declaration had less levels than expected");
- return TemplateArgs;
}
}
+ }
+ // 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());
+ }
- const Decl *CurDecl = D;
-
- // There is either a current qualifier for an out-of-line definition being
- // followed, in which case it should be advanced, or the next qualifier
- // and template parameter listss should be retrieved from the current
- // declaration, if any.
- bool InOutOfLineDefinition = Qualifier != std::nullopt;
- switch (Qualifier.getKind()) {
- case NestedNameSpecifier::Kind::Null: {
- // Get the current qualifier and template parameter lists.
- assert(TPLs.empty());
- if (auto *TD = dyn_cast<TemplateDecl>(D)) {
- D = TD->getTemplatedDecl();
- // One of the template entities which doesn't have a templated decl.
- if (!D)
- break;
- }
- if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
- TPLs = DD->getTemplateParameterLists();
- Qualifier = DD->getQualifier();
- } else if (const auto *TD = dyn_cast<TagDecl>(D)) {
- TPLs = TD->getTemplateParameterLists();
- Qualifier = TD->getQualifier();
+ if (ForConstraintInstantiation && Function->getFriendObjectKind())
+ return Response::ChangeDecl(Function->getLexicalDeclContext());
+ return Response::UseNextDecl(Function);
+}
+
+Response HandleFunctionTemplateDecl(Sema &SemaRef,
+ const FunctionTemplateDecl *FTD,
+ MultiLevelTemplateArgumentList &Result) {
+ if (!isa<ClassTemplateSpecializationDecl>(FTD->getDeclContext())) {
+ Result.addOuterTemplateArguments(
+ const_cast<FunctionTemplateDecl *>(FTD),
+ const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(
+ SemaRef.Context),
+ /*Final=*/false);
+
+ NestedNameSpecifier NNS = FTD->getTemplatedDecl()->getQualifier();
+
+ for (const Type *Ty = NNS.getKind() == NestedNameSpecifier::Kind::Type
+ ? NNS.getAsType()
+ : nullptr,
+ *NextTy = nullptr;
+ Ty && Ty->isInstantiationDependentType();
+ Ty = std::exchange(NextTy, nullptr)) {
+ if (NestedNameSpecifier P = Ty->getPrefix();
+ P.getKind() == NestedNameSpecifier::Kind::Type)
+ NextTy = P.getAsType();
+ const auto *TSTy = dyn_cast<TemplateSpecializationType>(Ty);
+ if (!TSTy)
+ continue;
+
+ ArrayRef<TemplateArgument> Arguments = TSTy->template_arguments();
+ // Prefer template arguments from the injected-class-type if possible.
+ // For example,
+ // ```cpp
+ // template <class... Pack> struct S {
+ // template <class T> void foo();
+ // };
+ // template <class... Pack> template <class T>
+ // ^^^^^^^^^^^^^ InjectedTemplateArgs
+ // They're of kind TemplateArgument::Pack, not of
+ // TemplateArgument::Type.
+ // void S<Pack...>::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<ClassTemplateSpecializationDecl>(RD))
+ Arguments = Specialization->getTemplateInstantiationArgs().asArray();
}
- assert((Qualifier || TPLs.empty()) &&
- "template parameter lists without qualifier");
- break;
- }
- case NestedNameSpecifier::Kind::Namespace:
- case NestedNameSpecifier::Kind::Global:
- llvm_unreachable("handled above");
- case NestedNameSpecifier::Kind::Type:
- Qualifier = Qualifier.getAsType()->getPrefix();
- break;
- case NestedNameSpecifier::Kind::MicrosoftSuper:
- Qualifier = std::nullopt;
- break;
+ Result.addOuterTemplateArguments(
+ TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
+ /*Final=*/false);
}
+ }
- // Get the next declaration from the current qualifier.
- switch (Qualifier.getKind()) {
- case NestedNameSpecifier::Kind::Null:
- // If there is no qualifier, the template context always follows
- // lexically.
- D = Decl::castFromDeclContext(CurDecl->getLexicalDeclContext());
- break;
- case NestedNameSpecifier::Kind::Namespace:
- case NestedNameSpecifier::Kind::Global:
- // Skip namespace, as they are never templated.
- D = Context.getTranslationUnitDecl();
- break;
- case NestedNameSpecifier::Kind::Type:
- if (const Type *T = Qualifier.getAsType();
- const auto *TT = T->getAs<TagType>())
- D = TT->getDecl();
- else if (const auto *TST = T->getAsNonAliasTemplateSpecializationType())
- D = TST->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true);
- else
- llvm_unreachable("unexpected type kind");
- break;
- case NestedNameSpecifier::Kind::MicrosoftSuper:
- D = Qualifier.getAsMicrosoftSuper();
- break;
- }
+ return Response::ChangeDecl(FTD->getLexicalDeclContext());
+}
- if (!Innermost)
- continue;
+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<CXXRecordDecl *>(Rec),
+ ClassTemplate->getInjectedTemplateArgs(SemaRef.Context),
+ /*Final=*/false);
+ }
- auto DeclArgs = *std::exchange(Innermost, std::nullopt);
- assert(!DeclArgs.empty());
-
- if (InOutOfLineDefinition) {
- // There either may or may not be a template parameter list corresponding
- // to the current qualifier chunk.
- // A template level only exists where there is a non-empty template
- // parameter list. Explicit specializations, ie `template <>` are never a
- // template level.
- TemplateParameterList *TPL =
- !TPLs.empty() ? TPLs.consume_back() : nullptr;
- if (!TPL || TPL->empty())
- continue;
+ 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 <class> using T = decltype([]<Concept> {} ());
+ // };
+ // 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 Response::UseNextDecl(Rec);
+}
+
+Response HandleImplicitConceptSpecializationDecl(
+ const ImplicitConceptSpecializationDecl *CSD,
+ MultiLevelTemplateArgumentList &Result) {
+ Result.addOuterTemplateArguments(
+ const_cast<ImplicitConceptSpecializationDecl *>(CSD),
+ CSD->getTemplateArguments(),
+ /*Final=*/false);
+ return Response::UseNextDecl(CSD);
+}
+
+Response HandleGenericDeclContext(const Decl *CurDecl) {
+ return Response::UseNextDecl(CurDecl);
+}
+} // namespace TemplateInstArgsHelpers
+} // namespace
- if (!SkipInnerNonInstantiated)
- TemplateArgs.addOuterTemplateArguments(const_cast<Decl *>(CurDecl),
- DeclArgs, Final);
-
- // A new level was just added. So if there is a level limit, decrement it.
- if (NumLevels)
- NumLevels = *NumLevels - 1U;
-
- // FIXME: Workaround for template template parameters on other template
- // template parameters and on type alias templates.
- if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
- unsigned ExtraLevels = TTP->getDepth() - D->getTemplateDepth() + 1;
- if (NumLevels) {
- ExtraLevels = std::min(ExtraLevels, *NumLevels);
- NumLevels = *NumLevels - ExtraLevels;
+MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
+ const NamedDecl *ND, const DeclContext *DC, bool Final,
+ std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
+ 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 (Innermost) {
+ Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost,
+ Final);
+ // Populate placeholder template arguments for TemplateTemplateParmDecls.
+ // This is essential for the case e.g.
+ //
+ // template <class> concept Concept = false;
+ // template <template <Concept C> class T> void foo(T<int>)
+ //
+ // where parameter C has a depth of 1 but the substituting argument `int`
+ // has a depth of 0.
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl))
+ HandleDefaultTempArgIntoTempTempParam(TTP, Result);
+ CurDecl = DC ? Decl::castFromDeclContext(DC)
+ : Response::UseNextDecl(CurDecl).NextDecl;
+ } else if (!CurDecl)
+ CurDecl = Decl::castFromDeclContext(DC);
+
+ while (!CurDecl->isFileContextDecl()) {
+ Response R;
+ if (const auto *VarTemplSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) {
+ R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization);
+ } else if (const auto *PartialClassTemplSpec =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(CurDecl)) {
+ R = HandlePartialClassTemplateSpec(PartialClassTemplSpec, Result,
+ SkipForSpecialization);
+ } else if (const auto *ClassTemplSpec =
+ dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) {
+ R = HandleClassTemplateSpec(ClassTemplSpec, Result,
+ SkipForSpecialization);
+ } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
+ R = HandleFunction(*this, Function, Result, Pattern, RelativeToPrimary,
+ ForConstraintInstantiation,
+ ForDefaultArgumentSubstitution);
+ } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
+ R = HandleRecordDecl(*this, Rec, Result, Context,
+ ForConstraintInstantiation);
+ } else if (const auto *CSD =
+ dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
+ R = HandleImplicitConceptSpecializationDecl(CSD, Result);
+ } else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CurDecl)) {
+ R = HandleFunctionTemplateDecl(*this, FTD, Result);
+ } else if (const auto *CTD = dyn_cast<ClassTemplateDecl>(CurDecl)) {
+ R = Response::ChangeDecl(CTD->getLexicalDeclContext());
+ } else if (!isa<DeclContext>(CurDecl)) {
+ R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
+ R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
}
- for (unsigned I = 0; I < ExtraLevels; ++I)
- TemplateArgs.addOuterTemplateArguments(std::nullopt);
+ } else {
+ R = HandleGenericDeclContext(CurDecl);
}
+
+ if (R.IsDone)
+ return Result;
+ if (R.ClearRelativeToPrimary)
+ RelativeToPrimary = false;
+ assert(R.NextDecl);
+ CurDecl = R.NextDecl;
}
- return TemplateArgs;
+ return Result;
}
bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
@@ -1509,8 +1741,10 @@ namespace {
CXXRecordDecl::LambdaDependencyKind
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
- if (auto TypeAlias = ::getEnclosingTypeAliasTemplateDecl(getSema());
- TypeAlias && ::isLambdaEnclosedByTypeAliasDecl(
+ if (auto TypeAlias =
+ TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
+ getSema());
+ TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
@@ -3851,9 +4085,6 @@ bool Sema::InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec,
TemplateSpecializationKind TSK, bool Complain,
bool PrimaryStrictPackMatch) {
- assert(ClassTemplateSpec->getTemplateDepth() == 0 &&
- "non-instantiated declaration");
-
// Perform the actual instantiation on the canonical declaration.
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
ClassTemplateSpec->getCanonicalDecl());
@@ -3877,12 +4108,9 @@ bool Sema::InstantiateClassTemplateSpecialization(
if (!Pattern.isUsable())
return Pattern.isInvalid();
- MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
- ClassTemplateSpec, /*Innermost=*/std::nullopt,
- /*NumLevels=*/Pattern.get()->getTemplateDepth());
-
- bool Err = InstantiateClassImpl(PointOfInstantiation, ClassTemplateSpec,
- Pattern.get(), TemplateArgs, TSK, Complain);
+ bool Err = InstantiateClassImpl(
+ PointOfInstantiation, ClassTemplateSpec, Pattern.get(),
+ getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain);
// If we haven't already warn on avaibility, consider the avaibility
// attributes of the partial specialization.
@@ -4244,7 +4472,14 @@ ExprResult Sema::SubstConceptTemplateArguments(
[](const TemplateArgumentLoc &Loc) { return Loc.getArgument(); });
MultiLevelTemplateArgumentList MLTALForConstraint =
- getTemplateInstantiationArgs(CSE->getNamedConcept(), NewArgList);
+ getTemplateInstantiationArgs(
+ CSE->getNamedConcept(),
+ CSE->getNamedConcept()->getLexicalDeclContext(),
+ /*Final=*/false,
+ /*Innermost=*/NewArgList,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true);
// Rebuild a constraint, only substituting non-dependent concept names
// and nothing else.
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index c3277748ab1f6..c9bc613a7c4ea 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -49,63 +49,40 @@ static bool isDeclWithinFunction(const Decl *D) {
return false;
}
-template <typename DeclT>
+template<typename DeclT>
static bool SubstQualifier(Sema &SemaRef, const DeclT *OldDecl, DeclT *NewDecl,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- DeclContext *Owner) {
- if (auto TPLs = OldDecl->getTemplateParameterLists(); !TPLs.empty()) {
- SmallVector<TemplateParameterList *, 4> TempParamLists(TPLs.size());
- MultiLevelTemplateArgumentList MLTAL;
-
- for (auto I = 0U; I < MLTAL.getNumRetainedOuterLevels(); ++I) {
- TemplateParameterList *InstParams = SemaRef.SubstTemplateParams(
- TPLs[I], Owner, MLTAL, /*EvaluateConstraints=*/true);
- assert(InstParams);
- TempParamLists[I] = InstParams;
- MLTAL.addOuterRetainedLevel();
- }
-
- auto *It = TemplateArgs.begin();
- for (unsigned I = 0; I != TPLs.size(); ++I) {
- TemplateParameterList *InstParams = SemaRef.SubstTemplateParams(
- TPLs[I], Owner, MLTAL, /*EvaluateConstraints=*/true);
- assert(InstParams);
- TempParamLists[I] = InstParams;
- if (It < TemplateArgs.end()) {
- auto [DeclAndFinal, Args] = *(It++);
- MLTAL.addOuterTemplateArguments(DeclAndFinal.getPointer(), Args,
- DeclAndFinal.getInt());
- }
- }
- NewDecl->setTemplateParameterListsInfo(SemaRef.Context, TempParamLists);
- }
- if (NestedNameSpecifierLoc QualifierLoc = OldDecl->getQualifierLoc()) {
- Sema::ContextRAII SavedContext(
- SemaRef,
- const_cast<DeclContext *>(NewDecl->getFriendObjectKind()
- ? NewDecl->getLexicalDeclContext()
- : OldDecl->getLexicalDeclContext()));
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (!OldDecl->getQualifierLoc())
+ return false;
- NestedNameSpecifierLoc NewQualifierLoc =
- SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
+ assert((NewDecl->getFriendObjectKind() ||
+ !OldDecl->getLexicalDeclContext()->isDependentContext()) &&
+ "non-friend with qualified name defined in dependent context");
+ Sema::ContextRAII SavedContext(
+ SemaRef,
+ const_cast<DeclContext *>(NewDecl->getFriendObjectKind()
+ ? NewDecl->getLexicalDeclContext()
+ : OldDecl->getLexicalDeclContext()));
+
+ NestedNameSpecifierLoc NewQualifierLoc
+ = SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
TemplateArgs);
- if (!NewQualifierLoc)
- return true;
+ if (!NewQualifierLoc)
+ return true;
- NewDecl->setQualifierInfo(NewQualifierLoc);
- }
+ NewDecl->setQualifierInfo(NewQualifierLoc);
return false;
}
bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
DeclaratorDecl *NewDecl) {
- return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs, Owner);
+ return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
}
bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl) {
- return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs, Owner);
+ return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
}
// Include attribute instantiation code.
@@ -1782,10 +1759,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false);
}
-Decl *
-TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
- bool InstantiatingVarTemplate,
- ArrayRef<BindingDecl *> *Bindings) {
+Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
+ bool InstantiatingVarTemplate,
+ ArrayRef<BindingDecl*> *Bindings) {
+
// Do substitution on the type of the declaration
TypeSourceInfo *TSI = SemaRef.SubstType(
D->getTypeSourceInfo(), TemplateArgs, D->getTypeSpecStartLoc(),
@@ -2419,8 +2396,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Make sure the parameter lists match.
if (!SemaRef.TemplateParameterListsAreEqual(
- RecordInst, InstParams, MostRecentPrevCT, PrevParams, true,
- Sema::TPL_TemplateMatch))
+ RecordInst, InstParams, MostRecentPrevCT->getTemplatedDecl(),
+ PrevParams, true, Sema::TPL_TemplateMatch))
return nullptr;
// Do some additional validation, then merge default arguments
@@ -2778,21 +2755,16 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
}
}
- FunctionDecl *PrevDecl = nullptr;
if (FunctionTemplate && !TemplateParams) {
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
void *InsertPos = nullptr;
- PrevDecl = FunctionTemplate->findSpecialization(Innermost, InsertPos);
- if (PrevDecl) {
- if (PrevDecl->getTemplateSpecializationInfo()->isExplicitSpecialization())
- return PrevDecl;
- for (FunctionDecl *F : PrevDecl->redecls())
- // If we already have a function template specialization for this
- // function template, return it.
- if (F->getPrimaryTemplate() == FunctionTemplate)
- return F;
- }
+ FunctionDecl *SpecFunc
+ = FunctionTemplate->findSpecialization(Innermost, InsertPos);
+
+ // If we already have a function template specialization, return it.
+ if (SpecFunc)
+ return SpecFunc;
}
bool MergeWithParentScope = (TemplateParams != nullptr) ||
@@ -2885,9 +2857,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
D->FriendConstraintRefersToEnclosingTemplate());
Function->setRangeEnd(D->getSourceRange().getEnd());
}
- Function->setPreviousDeclaration(PrevDecl);
- if (PrevDecl)
- SemaRef.mergeDeclAttributes(Function, PrevDecl);
if (D->isInlined())
Function->setImplicitlyInline();
@@ -2944,10 +2913,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
FunctionTemplate->setLexicalDeclContext(LexicalDC);
- if (PrevDecl)
- FunctionTemplate->setPreviousDecl(
- PrevDecl->getDescribedFunctionTemplate());
-
if (isFriend && D->isThisDeclarationADefinition()) {
FunctionTemplate->setInstantiatedFromMemberTemplate(
D->getDescribedFunctionTemplate());
@@ -2957,14 +2922,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
Sema::CodeSynthesisContext::BuildingDeductionGuides) {
// Record this function template specialization.
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
- Function->setFunctionTemplateSpecialization(
- SemaRef.Context, FunctionTemplate,
- TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost),
- /*InsertPos=*/nullptr, /*TSK=*/TSK_ImplicitInstantiation,
- /*TemplateParams=*/nullptr,
- /*TemplateArgsAsWritten=*/nullptr,
- /*PointOfInstantiation=*/SourceLocation(),
- /*AddSpecialization=*/PrevDecl == nullptr);
+ Function->setFunctionTemplateSpecialization(FunctionTemplate,
+ TemplateArgumentList::CreateCopy(SemaRef.Context,
+ Innermost),
+ /*InsertPos=*/nullptr);
} else if (FunctionRewriteKind == RewriteKind::None) {
if (isFriend && D->isThisDeclarationADefinition()) {
// Do not connect the friend to the template unless it's actually a
@@ -3022,7 +2983,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
}
if (SemaRef.CheckFunctionTemplateSpecialization(
- Function, DFTSI->TemplateParameters ? TemplateParams : nullptr,
+ Function,
DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Previous))
Function->setInvalidDecl();
@@ -3040,8 +3001,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
ExplicitArgs))
return nullptr;
- if (SemaRef.CheckFunctionTemplateSpecialization(Function, TemplateParams,
- &ExplicitArgs, Previous))
+ if (SemaRef.CheckFunctionTemplateSpecialization(Function,
+ &ExplicitArgs,
+ Previous))
Function->setInvalidDecl();
IsExplicitSpecialization = true;
@@ -3158,8 +3120,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
CXXMethodDecl *D, TemplateParameterList *TemplateParams,
RewriteKind FunctionRewriteKind) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
-
- FunctionDecl *PrevDecl = nullptr;
if (FunctionTemplate && !TemplateParams) {
// We are creating a function template specialization from a function
// template. Check whether there is already a function template
@@ -3167,16 +3127,12 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
void *InsertPos = nullptr;
- PrevDecl = FunctionTemplate->findSpecialization(Innermost, InsertPos);
- if (PrevDecl) {
- if (PrevDecl->getTemplateSpecializationInfo()->isExplicitSpecialization())
- return PrevDecl;
- for (FunctionDecl *F : PrevDecl->redecls())
- // If we already have a function template specialization for this
- // function template, return it.
- if (F->getPrimaryTemplate() == FunctionTemplate)
- return F;
- }
+ FunctionDecl *SpecFunc
+ = FunctionTemplate->findSpecialization(Innermost, InsertPos);
+
+ // If we already have a function template specialization, return it.
+ if (SpecFunc)
+ return SpecFunc;
}
bool isFriend;
@@ -3193,6 +3149,19 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
Sema::LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
SemaRef, D, TemplateArgs, Scope);
+ // Instantiate enclosing template arguments for friends.
+ SmallVector<TemplateParameterList *, 4> TempParamLists;
+ ArrayRef<TemplateParameterList *> TPLs = D->getTemplateParameterLists();
+ if (isFriend && !TPLs.empty()) {
+ TempParamLists.resize(TPLs.size());
+ for (unsigned I = 0; I != TPLs.size(); ++I) {
+ TemplateParameterList *InstParams = SubstTemplateParams(TPLs[I]);
+ if (!InstParams)
+ return nullptr;
+ TempParamLists[I] = InstParams;
+ }
+ }
+
auto InstantiatedExplicitSpecifier = ExplicitSpecifier::getFromDecl(D);
// deduction guides need this
const bool CouldInstantiate =
@@ -3318,9 +3287,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
D->UsesFPIntrin(), D->isInlineSpecified(), D->getConstexprKind(),
D->getEndLoc(), TrailingRequiresClause);
}
- Method->setPreviousDeclaration(PrevDecl);
- if (PrevDecl)
- SemaRef.mergeDeclAttributes(Method, PrevDecl);
if (D->isInlined())
Method->setImplicitlyInline();
@@ -3352,33 +3318,25 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
} else if (D->isOutOfLine())
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
-
- if (PrevDecl)
- FunctionTemplate->setPreviousDecl(
- PrevDecl->getDescribedFunctionTemplate());
} else if (FunctionTemplate) {
// Record this function template specialization.
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
- Method->setFunctionTemplateSpecialization(
- SemaRef.Context, FunctionTemplate,
- TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost),
- /*InsertPos=*/nullptr, /*TSK=*/TSK_ImplicitInstantiation,
- /*TemplateParams=*/nullptr,
- /*TemplateArgsAsWritten=*/nullptr,
- /*PointOfInstantiation=*/SourceLocation(),
- /*AddSpecialization=*/PrevDecl == nullptr);
+ Method->setFunctionTemplateSpecialization(FunctionTemplate,
+ TemplateArgumentList::CreateCopy(SemaRef.Context,
+ Innermost),
+ /*InsertPos=*/nullptr);
} else if (!isFriend && FunctionRewriteKind == RewriteKind::None) {
// Record that this is an instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
- if (SubstQualifier(D, Method))
- return nullptr;
-
// If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
if (isFriend) {
+ if (!TempParamLists.empty())
+ Method->setTemplateParameterListsInfo(SemaRef.Context, TempParamLists);
+
Method->setLexicalDeclContext(Owner);
Method->setObjectOfFriendDecl();
} else if (D->isOutOfLine())
@@ -3421,8 +3379,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
}
if (SemaRef.CheckFunctionTemplateSpecialization(
- Method, DFTSI->TemplateParameters,
- DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
+ Method, DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Previous))
Method->setInvalidDecl();
@@ -3438,8 +3395,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
ExplicitArgs))
return nullptr;
- if (SemaRef.CheckFunctionTemplateSpecialization(Method, TemplateParams,
- &ExplicitArgs, Previous))
+ if (SemaRef.CheckFunctionTemplateSpecialization(Method,
+ &ExplicitArgs,
+ Previous))
Method->setInvalidDecl();
IsExplicitSpecialization = true;
@@ -4569,22 +4527,16 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Substitute into the template arguments of the class template explicit
// specialization.
- // The template parameters list for an explicit specialization is always empty
- // and has no constraints, so there is nothing to substitute.
TemplateArgumentListInfo InstTemplateArgs;
- const ExplicitSpecializationInfo *ExplicitSpecInfo =
- D->getExplicitSpecializationInfo();
- if (ExplicitSpecInfo) {
- auto *Args = ExplicitSpecInfo->TemplateArgsAsWritten;
- InstTemplateArgs.setLAngleLoc(Args->getLAngleLoc());
- InstTemplateArgs.setRAngleLoc(Args->getRAngleLoc());
-
- if (SemaRef.SubstTemplateArguments(Args->arguments(), TemplateArgs,
- InstTemplateArgs))
+ if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
+ D->getTemplateArgsAsWritten()) {
+ InstTemplateArgs.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
+ InstTemplateArgs.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
+
+ if (SemaRef.SubstTemplateArguments(TemplateArgsInfo->arguments(),
+ TemplateArgs, InstTemplateArgs))
return nullptr;
}
- // Otherwise, an ExplicitInstantiation always occurs in a non-dependent
- // context, so there is nothing to substitute.
// Check that the template argument list is well-formed for this
// class template.
@@ -4639,14 +4591,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
D->getLocation(), InstClassTemplate, CTAI.CanonicalConverted,
CTAI.StrictPackMatch, PrevDecl);
- if (ExplicitSpecInfo)
- InstD->setExplicitSpecializationInfo(
- ExplicitSpecInfo->TemplateParams,
- ASTTemplateArgumentListInfo::Create(SemaRef.Context, InstTemplateArgs));
- else if (const auto *Info = D->getExplicitInstantiationInfo())
- InstD->setExplicitInstantiationInfo(Info->ExternKeywordLoc,
- Info->TemplateKeywordLoc,
- Info->TemplateArgsAsWritten);
+ InstD->setTemplateArgsAsWritten(InstTemplateArgs);
// Add this partial specialization to the set of class template partial
// specializations.
@@ -4660,6 +4605,8 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
InstD->setAccess(D->getAccess());
InstD->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
InstD->setSpecializationKind(D->getSpecializationKind());
+ InstD->setExternKeywordLoc(D->getExternKeywordLoc());
+ InstD->setTemplateKeywordLoc(D->getTemplateKeywordLoc());
Owner->addDecl(InstD);
@@ -4679,6 +4626,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *D) {
+ TemplateArgumentListInfo VarTemplateArgsInfo;
VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
assert(VarTemplate &&
"A template specialization without specialized template?");
@@ -4689,15 +4637,9 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
if (!InstVarTemplate)
return nullptr;
- assert(!D->getExplicitInstantiationInfo());
- const auto *ExplicitSpecializationInfo = D->getExplicitSpecializationInfo();
// Substitute the current template arguments.
- TemplateArgumentListInfo VarTemplateArgsInfo;
- if (ExplicitSpecializationInfo) {
- // The template parameters for an explicit specialization are empty and
- // never need to be transformed.
- const auto *TemplateArgsInfo =
- ExplicitSpecializationInfo->TemplateArgsAsWritten;
+ if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
+ D->getTemplateArgsAsWritten()) {
VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
@@ -4728,17 +4670,12 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
PrevDecl->getPointOfInstantiation(), Ignored))
return nullptr;
- VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
- InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl);
- if (!VTSD)
- return nullptr;
- if (ExplicitSpecializationInfo)
- VTSD->setExplicitSpecializationInfo(
- ExplicitSpecializationInfo->TemplateParams,
- ASTTemplateArgumentListInfo::Create(
- SemaRef.Context,
- ExplicitSpecializationInfo->TemplateArgsAsWritten));
- return VTSD;
+ if (VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
+ InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl)) {
+ VTSD->setTemplateArgsAsWritten(VarTemplateArgsInfo);
+ return VTSD;
+ }
+ return nullptr;
}
VarTemplateSpecializationDecl *
@@ -4747,8 +4684,6 @@ TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
ArrayRef<TemplateArgument> Converted,
VarTemplateSpecializationDecl *PrevDecl) {
- LocalInstantiationScope Scope(SemaRef);
-
// Do substitution on the type of the declaration
TypeSourceInfo *TSI =
SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
@@ -5004,17 +4939,16 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
InstParams, InsertPos);
// Create the class template partial specialization declaration.
- // FIXME: Avoid recreating the ASTTemplateArgumentListInfo if nothing changed.
ClassTemplatePartialSpecializationDecl *InstPartialSpec =
ClassTemplatePartialSpecializationDecl::Create(
SemaRef.Context, PartialSpec->getTagKind(), Owner,
PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
- ASTTemplateArgumentListInfo::Create(SemaRef.Context,
- InstTemplateArgs),
ClassTemplate, CTAI.CanonicalConverted,
/*CanonInjectedTST=*/CanQualType(),
/*PrevDecl=*/nullptr);
+ InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
+
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return nullptr;
@@ -5131,11 +5065,10 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
VarTemplatePartialSpecializationDecl *InstPartialSpec =
VarTemplatePartialSpecializationDecl::Create(
SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
- PartialSpec->getLocation(), InstParams,
- ASTTemplateArgumentListInfo::Create(SemaRef.Context,
- InstTemplateArgs),
- VarTemplate, TSI->getType(), TSI, PartialSpec->getStorageClass(),
- CTAI.CanonicalConverted);
+ PartialSpec->getLocation(), InstParams, VarTemplate, TSI->getType(),
+ TSI, PartialSpec->getStorageClass(), CTAI.CanonicalConverted);
+
+ InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
@@ -5370,11 +5303,8 @@ bool Sema::addInstantiatedParametersToScope(
bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param) {
- assert(FD->getTemplateDepth() == 0 && "function not instantiated");
assert(Param->hasUninstantiatedDefaultArg());
- const auto *PatternDecl =
- FD->getTemplateInstantiationPattern(/*ForDefinition=*/false);
// 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
@@ -5382,31 +5312,34 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
// purposes. [dcl.fct.default]p4:
// if a friend declaration D specifies a default argument expression,
// that declaration shall be a definition.
- if (!PatternDecl)
+ if (FD->getFriendObjectKind() != Decl::FOK_None &&
+ !FD->getTemplateInstantiationPattern())
return true;
- unsigned NumLevels = PatternDecl->getTemplateDepth();
- MultiLevelTemplateArgumentList TemplateArgs;
- // The default argument for a templated function must always be defined on
- // it's first declaration.
- if (const auto *Info = FD->getTemplateSpecializationInfo();
- Info &&
- Info->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
- TemplateArgs = getTemplateInstantiationArgs(
- Info->getTemplate()->getFirstDecl(), Info->TemplateArguments->asArray(),
- NumLevels);
- } else {
- if (Info)
- FD = InstantiateFunctionDeclaration(
- cast<FunctionTemplateDecl>(Info->getTemplate()->getFirstDecl()),
- Info->TemplateArguments, CallLoc);
- else
- FD = FD->getFirstDecl();
- TemplateArgs =
- getTemplateInstantiationArgs(FD, /*Innermost=*/std::nullopt, NumLevels);
- }
-
// Instantiate the expression.
+ //
+ // FIXME: Pass in a correct Pattern argument, otherwise
+ // getTemplateInstantiationArgs uses the lexical context of FD, e.g.
+ //
+ // template<typename T>
+ // struct A {
+ // static int FooImpl();
+ //
+ // template<typename Tp>
+ // // bug: default argument A<T>::FooImpl() is evaluated with 2-level
+ // // template argument list [[T], [Tp]], should be [[Tp]].
+ // friend A<Tp> Foo(int a);
+ // };
+ //
+ // template<typename T>
+ // A<T> Foo(int a = A<T>::FooImpl());
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ FD, FD->getLexicalDeclContext(),
+ /*Final=*/false, /*Innermost=*/std::nullopt,
+ /*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
+ /*ForDefaultArgumentSubstitution=*/true);
+
if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
@@ -5447,22 +5380,16 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Decl, Decl->getLexicalDeclContext(),
+ /*Final=*/false, /*Innermost=*/std::nullopt,
+ /*RelativeToPrimary*/ true);
+
// FIXME: We can't use getTemplateInstantiationPattern(false) in general
// here, because for a non-defining friend declaration in a class template,
// we don't store enough information to map back to the friend declaration in
// the template.
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
- unsigned NumLevels = Template->getTemplateDepth();
- MultiLevelTemplateArgumentList TemplateArgs;
- if (const auto *Info = Decl->getTemplateSpecializationInfo();
- Info &&
- Info->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- TemplateArgs = getTemplateInstantiationArgs(
- Info->getTemplate(), Info->TemplateArguments->asArray(), NumLevels);
- else
- TemplateArgs = getTemplateInstantiationArgs(
- Decl, /*Innermost=*/std::nullopt, NumLevels);
-
if (addInstantiatedParametersToScope(Decl, Template, Scope, TemplateArgs)) {
UpdateExceptionSpec(Decl, EST_None);
return;
@@ -5627,10 +5554,7 @@ FunctionDecl *Sema::InstantiateFunctionDeclaration(
MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray(),
/*Final=*/false);
- return cast_or_null<FunctionDecl>(SubstDecl(
- FD,
- isa<CXXMethodDecl>(FD) ? FD->getParent() : FD->getLexicalDeclContext(),
- MArgs));
+ return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs));
}
void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
@@ -5985,52 +5909,36 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
RebuildTypeSourceInfoForDefaultSpecialMembers();
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
- if (const FunctionTemplateSpecializationInfo *Info =
- Function->getTemplateSpecializationInfo();
- Info && !Info->isExplicitSpecialization()) {
- const FunctionDecl *TemplatedDecl =
- Info->getTemplate()->getTemplatedDecl();
- // Find the primary template redeclaration which corresponds to the
- // definition.
- auto Redecls = TemplatedDecl->redecls();
- auto It = llvm::find_if(Redecls, [](const FunctionDecl *FD) {
- return FD->isInstantiatedFromMemberTemplate() ||
- FD->isThisDeclarationADefinition();
- });
- assert(It != Redecls.end() && "Should't get here without a definition");
- if (*It != TemplatedDecl) {
- // If the primary template found is not the same as this function's
- // primary template, then instantiate that primary template and use it
- // instead.
- FunctionDecl *NewFunction = InstantiateFunctionDeclaration(
- (*It)->getDescribedFunctionTemplate(), Info->TemplateArguments,
- PointOfInstantiation);
- assert(NewFunction && "Failed to instantiate function template");
- assert(NewFunction != Function && "Expected a new specialization");
- assert(declaresSameEntity(NewFunction, Function));
- Function = NewFunction;
- }
- } else {
- for (FunctionDecl *F : Function->redecls()) {
- MemberSpecializationInfo *Info = F->getMemberSpecializationInfo();
- if (!Info)
- break;
- // Avoid friend member declarations, as they are never definitions
- // themselves and may not be declared in a template context compatible
- // with it.
- if (Info->getTemplateSpecializationKind() != TSK_FriendDeclaration) {
- Function = F;
- break;
- }
- }
- assert(Function->getTemplateSpecializationKind() !=
- TSK_FriendDeclaration &&
- "Expected to find an instantiation");
+ DeclContext *DC = Function->getLexicalDeclContext();
+ std::optional<ArrayRef<TemplateArgument>> Innermost;
+ if (auto *Primary = Function->getPrimaryTemplate();
+ Primary &&
+ !isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) &&
+ Function->getTemplateSpecializationKind() !=
+ TSK_ExplicitSpecialization) {
+ auto It = llvm::find_if(Primary->redecls(),
+ [](const RedeclarableTemplateDecl *RTD) {
+ return cast<FunctionTemplateDecl>(RTD)
+ ->isCompatibleWithDefinition();
+ });
+ assert(It != Primary->redecls().end() &&
+ "Should't get here without a definition");
+ if (FunctionDecl *Def = cast<FunctionTemplateDecl>(*It)
+ ->getTemplatedDecl()
+ ->getDefinition())
+ DC = Def->getLexicalDeclContext();
+ else
+ DC = (*It)->getLexicalDeclContext();
+ Innermost.emplace(Function->getTemplateSpecializationArgs()->asArray());
}
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
- Function, /*Innermost=*/std::nullopt,
- /*NumLevels=*/PatternDecl->getTemplateDepth(),
- /*SkipInnerNonInstantiated=*/true);
+ Function, DC, /*Final=*/false, Innermost, false, PatternDecl);
+
+ // Substitute into the qualifier; we can get a substitution failure here
+ // through evil use of alias templates.
+ // FIXME: Is CurContext correct for this? Should we go to the (instantiation
+ // of the) lexical context of the pattern?
+ SubstQualifier(*this, PatternDecl, Function, TemplateArgs);
ActOnStartOfFunctionDef(nullptr, Function);
@@ -6396,8 +6304,6 @@ void Sema::InstantiateVariableInitializer(
void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
VarDecl *Var, bool Recursive,
bool DefinitionRequired, bool AtEndOfTU) {
- assert(Var->getTemplateDepth() == 0 && "variable not already instantiated");
-
if (Var->isInvalidDecl())
return;
@@ -6415,9 +6321,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// Find the pattern and the arguments to substitute into it.
VarDecl *PatternDecl = Var->getTemplateInstantiationPattern();
assert(PatternDecl && "no pattern for templated variable");
- MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
- Var, /*Innermost=*/std::nullopt,
- /*NumLevels=*/PatternDecl->getTemplateDepth());
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Var);
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
@@ -6578,6 +6483,15 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(),
TemplateArgs);
+ TemplateArgumentListInfo TemplateArgInfo;
+ if (const ASTTemplateArgumentListInfo *ArgInfo =
+ VarSpec->getTemplateArgsAsWritten()) {
+ TemplateArgInfo.setLAngleLoc(ArgInfo->getLAngleLoc());
+ TemplateArgInfo.setRAngleLoc(ArgInfo->getRAngleLoc());
+ for (const TemplateArgumentLoc &Arg : ArgInfo->arguments())
+ TemplateArgInfo.addArgument(Arg);
+ }
+
VarTemplateSpecializationDecl *VTSD =
Instantiator.VisitVarTemplateSpecializationDecl(
VarSpec->getSpecializedTemplate(), Def,
@@ -6585,13 +6499,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
Var = VTSD;
if (Var) {
- if (const auto *Info = VarSpec->getExplicitInstantiationInfo())
- VTSD->setExplicitInstantiationInfo(Info->ExternKeywordLoc,
- Info->TemplateKeywordLoc,
- Info->TemplateArgsAsWritten);
- else if (const auto *Info = VarSpec->getExplicitSpecializationInfo())
- VTSD->setExplicitSpecializationInfo(Info->TemplateParams,
- Info->TemplateArgsAsWritten);
+ VTSD->setTemplateArgsAsWritten(TemplateArgInfo);
llvm::PointerUnion<VarTemplateDecl *,
VarTemplatePartialSpecializationDecl *> PatternPtr =
@@ -7381,7 +7289,6 @@ void Sema::PerformPendingInstantiations(bool LocalOnly, bool AtEndOfTU) {
if (Var != Var->getMostRecentDecl())
continue;
break;
- case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
break;
}
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index ea4e3f9204175..fb291a4b0f2c5 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -905,10 +905,9 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
if (Record.readInt()) { // hasExtInfo
auto *Info = new (Reader.getContext()) DeclaratorDecl::ExtInfo();
Record.readQualifierInfo(*Info);
- Expr *ConstraintExpr = Record.readExpr();
- UnsignedOrNone ArgPackSubstIndex = Record.readUnsignedOrNone();
- Info->TrailingRequiresClause =
- AssociatedConstraint(ConstraintExpr, ArgPackSubstIndex);
+ Info->TrailingRequiresClause = AssociatedConstraint(
+ Record.readExpr(),
+ UnsignedOrNone::fromInternalRepresentation(Record.readUInt32()));
DD->DeclInfo = Info;
}
QualType TSIType = Record.readType();
@@ -950,9 +949,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
SmallVector<TemplateArgument, 8> TemplArgs;
Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
- const TemplateParameterList *TemplateParams =
- Record.readBool() ? Record.readTemplateParameterList() : nullptr;
-
// Template args as written.
TemplateArgumentListInfo TemplArgsWritten;
bool HasTemplateArgumentsAsWritten = Record.readBool();
@@ -977,7 +973,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FunctionTemplateSpecializationInfo *FTInfo =
FunctionTemplateSpecializationInfo::Create(
- C, FD, Template, TSK, TemplArgList, TemplateParams,
+ C, FD, Template, TSK, TemplArgList,
HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr, POI,
MSInfo);
FD->TemplateOrSpecialization = FTInfo;
@@ -1012,9 +1008,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
while (NumCandidates--)
Candidates.addDecl(readDeclAs<NamedDecl>());
- const TemplateParameterList *TemplateParams =
- Record.readBool() ? Record.readTemplateParameterList() : nullptr;
-
// Templates args.
TemplateArgumentListInfo TemplArgsWritten;
bool HasTemplateArgumentsAsWritten = Record.readBool();
@@ -1022,7 +1015,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
Record.readTemplateArgumentListInfo(TemplArgsWritten);
FD->setDependentTemplateSpecialization(
- Reader.getContext(), Candidates, TemplateParams,
+ Reader.getContext(), Candidates,
HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr);
// These are not merged; we don't need to merge redeclarations of dependent
// template friends.
@@ -2555,20 +2548,6 @@ RedeclarableResult ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
D->StrictPackMatch = Record.readBool();
- // extern/template keyword locations for explicit instantiations
- if (auto K = D->SpecializationKind;
- K == TSK_ExplicitInstantiationDeclaration ||
- K == TSK_ExplicitInstantiationDefinition) {
- SourceLocation ExternKeywordLoc = readSourceLocation();
- SourceLocation TemplateKeywordLoc = readSourceLocation();
- D->setExplicitInstantiationInfo(ExternKeywordLoc, TemplateKeywordLoc,
- Record.readASTTemplateArgumentListInfo());
- } else if (K == TSK_ExplicitSpecialization) {
- auto *TemplateParams = Record.readTemplateParameterList();
- D->setExplicitSpecializationInfo(TemplateParams,
- Record.readASTTemplateArgumentListInfo());
- }
-
bool writtenAsCanonicalDecl = Record.readInt();
if (writtenAsCanonicalDecl) {
auto *CanonPattern = readDeclAs<ClassTemplateDecl>();
@@ -2599,11 +2578,27 @@ RedeclarableResult ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
}
}
+ // extern/template keyword locations for explicit instantiations
+ if (Record.readBool()) {
+ auto *ExplicitInfo = new (C) ExplicitInstantiationInfo;
+ ExplicitInfo->ExternKeywordLoc = readSourceLocation();
+ ExplicitInfo->TemplateKeywordLoc = readSourceLocation();
+ D->ExplicitInfo = ExplicitInfo;
+ }
+
+ if (Record.readBool())
+ D->setTemplateArgsAsWritten(Record.readASTTemplateArgumentListInfo());
+
return Redecl;
}
void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
- ClassTemplatePartialSpecializationDecl *D) {
+ ClassTemplatePartialSpecializationDecl *D) {
+ // We need to read the template params first because redeclarable is going to
+ // need them for profiling
+ TemplateParameterList *Params = Record.readTemplateParameterList();
+ D->TemplateParams = Params;
+
RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
// These are read/set from/to the first declaration.
@@ -2649,6 +2644,17 @@ RedeclarableResult ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
}
}
+ // extern/template keyword locations for explicit instantiations
+ if (Record.readBool()) {
+ auto *ExplicitInfo = new (C) ExplicitInstantiationInfo;
+ ExplicitInfo->ExternKeywordLoc = readSourceLocation();
+ ExplicitInfo->TemplateKeywordLoc = readSourceLocation();
+ D->ExplicitInfo = ExplicitInfo;
+ }
+
+ if (Record.readBool())
+ D->setTemplateArgsAsWritten(Record.readASTTemplateArgumentListInfo());
+
SmallVector<TemplateArgument, 8> TemplArgs;
Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
@@ -2656,20 +2662,6 @@ RedeclarableResult ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
D->IsCompleteDefinition = Record.readInt();
- // extern/template keyword locations for explicit instantiations
- if (auto K = D->SpecializationKind;
- K == TSK_ExplicitInstantiationDeclaration ||
- K == TSK_ExplicitInstantiationDefinition) {
- SourceLocation ExternKeywordLoc = readSourceLocation();
- SourceLocation TemplateKeywordLoc = readSourceLocation();
- D->setExplicitInstantiationInfo(ExternKeywordLoc, TemplateKeywordLoc,
- Record.readASTTemplateArgumentListInfo());
- } else if (K == TSK_ExplicitSpecialization) {
- auto *TemplateParams = Record.readTemplateParameterList();
- D->setExplicitSpecializationInfo(TemplateParams,
- Record.readASTTemplateArgumentListInfo());
- }
-
RedeclarableResult Redecl = VisitVarDeclImpl(D);
bool writtenAsCanonicalDecl = Record.readInt();
@@ -2700,6 +2692,9 @@ RedeclarableResult ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
/// using Template(Partial)SpecializationDecl as input type.
void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
+ TemplateParameterList *Params = Record.readTemplateParameterList();
+ D->TemplateParams = Params;
+
RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
// These are read/set from/to the first declaration.
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 1390bc7c8dc9a..7f5005aa666c7 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -805,10 +805,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// Template arguments.
Record.AddTemplateArgumentList(FTSInfo->TemplateArguments);
- Record.push_back(FTSInfo->TemplateParameters != nullptr);
- if (FTSInfo->TemplateParameters)
- Record.AddTemplateParameterList(FTSInfo->TemplateParameters);
-
// Template args as written.
Record.push_back(FTSInfo->TemplateArgumentsAsWritten != nullptr);
if (FTSInfo->TemplateArgumentsAsWritten)
@@ -843,10 +839,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
for (FunctionTemplateDecl *FTD : DFTSInfo->getCandidates())
Record.AddDeclRef(FTD);
- Record.push_back(DFTSInfo->TemplateParameters != nullptr);
- if (DFTSInfo->TemplateParameters)
- Record.AddTemplateParameterList(DFTSInfo->TemplateParameters);
-
// Templates args.
Record.push_back(DFTSInfo->TemplateArgumentsAsWritten != nullptr);
if (DFTSInfo->TemplateArgumentsAsWritten)
@@ -1754,7 +1746,6 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
if (FTSInfo->TemplateArguments->size() == 1) {
const TemplateArgument &TA = FTSInfo->TemplateArguments->get(0);
if (TA.getKind() == TemplateArgument::Type &&
- !FTSInfo->TemplateParameters &&
!FTSInfo->TemplateArgumentsAsWritten &&
!FTSInfo->getMemberSpecializationInfo())
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
@@ -1763,8 +1754,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
FunctionDecl::TK_DependentFunctionTemplateSpecialization) {
DependentFunctionTemplateSpecializationInfo *DFTSInfo =
D->getDependentSpecializationInfo();
- if (!DFTSInfo->TemplateArgumentsAsWritten &&
- !DFTSInfo->TemplateParameters)
+ if (!DFTSInfo->TemplateArgumentsAsWritten)
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
}
}
@@ -1945,36 +1935,29 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
Record.AddSourceLocation(D->getPointOfInstantiation());
Record.push_back(D->getSpecializationKind());
Record.push_back(D->hasStrictPackMatch());
-
- switch (D->getSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- case TSK_FriendDeclaration:
- assert(!D->getExplicitSpecializationInfo());
- assert(!D->getExplicitInstantiationInfo());
- break;
- case TSK_ExplicitSpecialization: {
- const auto *Info = D->getExplicitSpecializationInfo();
- Record.AddTemplateParameterList(Info->TemplateParams);
- Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
- break;
- }
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition: {
- const auto *Info = D->getExplicitInstantiationInfo();
- Record.AddSourceLocation(Info->ExternKeywordLoc);
- Record.AddSourceLocation(Info->TemplateKeywordLoc);
- Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
- break;
- }
- }
-
Record.push_back(D->isCanonicalDecl());
+
if (D->isCanonicalDecl()) {
// When reading, we'll add it to the folding set of the following template.
Record.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl());
}
+ bool ExplicitInstantiation =
+ D->getTemplateSpecializationKind() ==
+ TSK_ExplicitInstantiationDeclaration ||
+ D->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition;
+ Record.push_back(ExplicitInstantiation);
+ if (ExplicitInstantiation) {
+ Record.AddSourceLocation(D->getExternKeywordLoc());
+ Record.AddSourceLocation(D->getTemplateKeywordLoc());
+ }
+
+ const ASTTemplateArgumentListInfo *ArgsWritten =
+ D->getTemplateArgsAsWritten();
+ Record.push_back(!!ArgsWritten);
+ if (ArgsWritten)
+ Record.AddASTTemplateArgumentListInfo(ArgsWritten);
+
// Mention the implicitly generated C++ deduction guide to make sure the
// deduction guide will be rewritten as expected.
//
@@ -1996,7 +1979,9 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
}
void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
- ClassTemplatePartialSpecializationDecl *D) {
+ ClassTemplatePartialSpecializationDecl *D) {
+ Record.AddTemplateParameterList(D->getTemplateParameters());
+
VisitClassTemplateSpecializationDecl(D);
// These are read/set from/to the first declaration.
@@ -2029,34 +2014,27 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
Record.AddTemplateArgumentList(&D->getTemplateInstantiationArgs());
}
+ bool ExplicitInstantiation =
+ D->getTemplateSpecializationKind() ==
+ TSK_ExplicitInstantiationDeclaration ||
+ D->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition;
+ Record.push_back(ExplicitInstantiation);
+ if (ExplicitInstantiation) {
+ Record.AddSourceLocation(D->getExternKeywordLoc());
+ Record.AddSourceLocation(D->getTemplateKeywordLoc());
+ }
+
+ const ASTTemplateArgumentListInfo *ArgsWritten =
+ D->getTemplateArgsAsWritten();
+ Record.push_back(!!ArgsWritten);
+ if (ArgsWritten)
+ Record.AddASTTemplateArgumentListInfo(ArgsWritten);
+
Record.AddTemplateArgumentList(&D->getTemplateArgs());
Record.AddSourceLocation(D->getPointOfInstantiation());
Record.push_back(D->getSpecializationKind());
Record.push_back(D->IsCompleteDefinition);
- switch (D->getSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ImplicitInstantiation:
- case TSK_FriendDeclaration:
- assert(!D->getExplicitSpecializationInfo());
- assert(!D->getExplicitInstantiationInfo());
- break;
- case TSK_ExplicitSpecialization: {
- const auto *Info = D->getExplicitSpecializationInfo();
- Record.AddTemplateParameterList(Info->TemplateParams);
- Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
- break;
- }
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition: {
- const auto *Info = D->getExplicitInstantiationInfo();
- Record.AddSourceLocation(Info->ExternKeywordLoc);
- Record.AddSourceLocation(Info->TemplateKeywordLoc);
- Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
- break;
- }
- }
-
VisitVarDecl(D);
Record.push_back(D->isCanonicalDecl());
@@ -2075,6 +2053,8 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
+ Record.AddTemplateParameterList(D->getTemplateParameters());
+
VisitVarTemplateSpecializationDecl(D);
// These are read/set from/to the first declaration.
@@ -2451,7 +2431,6 @@ getFunctionDeclAbbrev(serialization::DeclCode Code) {
Abv->Add(
BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Template Argument Type
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Is Defaulted
- Abv->Add(BitCodeAbbrevOp(0)); // TemplateParams
Abv->Add(BitCodeAbbrevOp(0)); // TemplateArgumentsAsWritten
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
Abv->Add(BitCodeAbbrevOp(0));
@@ -2461,7 +2440,6 @@ getFunctionDeclAbbrev(serialization::DeclCode Code) {
TK_DependentFunctionTemplateSpecialization) {
// Candidates of specialization
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
- Abv->Add(BitCodeAbbrevOp(0)); // TemplateParams
Abv->Add(BitCodeAbbrevOp(0)); // TemplateArgumentsAsWritten
} else {
llvm_unreachable("Unknown templated kind?");
diff --git a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
index abc4b4179204b..6c1a55f79b908 100644
--- a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
@@ -166,6 +166,55 @@ bool BugSuppression::isSuppressed(const BugReport &R) {
isSuppressed(UniqueingLocation, DeclWithIssue, {});
}
+static const ClassTemplateDecl *
+walkInstantiatedFromChain(const ClassTemplateDecl *Tmpl) {
+ // For nested member templates (e.g., S2 inside S1<T>), getInstantiatedFrom
+ // may return the member template as instantiated within an outer
+ // specialization (e.g., S2 as it appears in S1<int>). That instantiated
+ // member template has no definition redeclaration itself; we need to walk
+ // up the member template chain to reach the primary template definition.
+ // \code
+ // template <class> struct S1 {
+ // template <class> struct S2 {
+ // int i;
+ // template <class T> int m(const S2<T>& s2) {
+ // return s2.i;
+ // }
+ // };
+ // }
+ // /code
+ const ClassTemplateDecl *MemberTmpl;
+ while ((MemberTmpl = Tmpl->getInstantiatedFromMemberTemplate())) {
+ if (Tmpl->isMemberSpecialization())
+ break;
+ Tmpl = MemberTmpl;
+ }
+ return Tmpl;
+}
+
+static const ClassTemplatePartialSpecializationDecl *walkInstantiatedFromChain(
+ const ClassTemplatePartialSpecializationDecl *PartialSpec) {
+ const ClassTemplatePartialSpecializationDecl *MemberPS;
+ while ((MemberPS = PartialSpec->getInstantiatedFromMember())) {
+ if (PartialSpec->isMemberSpecialization())
+ break;
+ PartialSpec = MemberPS;
+ }
+ return PartialSpec;
+}
+
+template <class T> static const T *chooseDefinitionRedecl(const T *Tmpl) {
+ static_assert(llvm::is_one_of<T, ClassTemplateDecl,
+ ClassTemplatePartialSpecializationDecl>::value);
+ for (const auto *Redecl : Tmpl->redecls()) {
+ if (const T *D = cast<T>(Redecl); D->isThisDeclarationADefinition()) {
+ return D;
+ }
+ }
+ assert(false && "This template must have a redecl that is a definition");
+ return Tmpl;
+}
+
// For template specializations, returns the primary template definition or
// partial specialization that was used to instantiate the specialization.
// This ensures suppression attributes on templates apply to their
@@ -180,19 +229,41 @@ bool BugSuppression::isSuppressed(const BugReport &R) {
// attribute.
//
// The function handles specializations (and partial specializations) of
-// class templates.
-// For any other decl, it returns the input unchanged.
+// class and function templates.
+// For any other decl, it returns the input unchagned.
static const Decl *
preferTemplateDefinitionForTemplateSpecializations(const Decl *D) {
- const auto *RD = dyn_cast<CXXRecordDecl>(D);
- if (!RD)
+ // For function template specializations (including instantiated friend
+ // function templates), map back to the primary template's FunctionDecl so
+ // that the lexical parent chain walk reaches the class where the template
+ // was defined inline.
+ //
+ // This handles the case where a friend function template is defined inline
+ // inside a [[clang::suppress]]-annotated class but was pre-declared at
+ // namespace scope. In that case the instantiation's lexical DC is the
+ // namespace (from the pre-declaration), not the class. Walking back to the
+ // primary template FunctionDecl — whose lexical DC IS the class — lets the
+ // existing parent-chain walk find the suppression attribute.
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
+ return Pattern->getDefinition();
+ }
+
+ const auto *SpecializationDecl = dyn_cast<ClassTemplateSpecializationDecl>(D);
+ if (!SpecializationDecl)
return D;
- if (const CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern())
- RD = Pattern;
- RD = RD->getDefinitionOrSelf();
- if (const auto *CTD = RD->getDescribedClassTemplate())
- return CTD;
- return RD;
+
+ auto InstantiatedFrom = SpecializationDecl->getInstantiatedFrom();
+ if (!InstantiatedFrom)
+ return D;
+
+ if (const auto *Tmpl = InstantiatedFrom.dyn_cast<ClassTemplateDecl *>()) {
+ // Interestingly, the source template might be a forward declaration, so we
+ // need to find the definition redeclaration.
+ return chooseDefinitionRedecl(walkInstantiatedFromChain(Tmpl));
+ }
+ return chooseDefinitionRedecl(walkInstantiatedFromChain(
+ cast<ClassTemplatePartialSpecializationDecl *>(InstantiatedFrom)));
}
bool BugSuppression::isSuppressed(const PathDiagnosticLocation &Location,
diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp
index c8088f622e185..3d3acea89d170 100644
--- a/clang/lib/Tooling/Syntax/BuildTree.cpp
+++ b/clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -726,14 +726,14 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
TraverseClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *C) {
if (!RecursiveASTVisitor::TraverseClassTemplateSpecializationDecl(C))
return false;
- const auto *Info = C->getExplicitInstantiationInfo();
- if (!Info)
+ if (C->isExplicitSpecialization())
return true; // we are only interested in explicit instantiations.
auto *Declaration =
cast<syntax::SimpleDeclaration>(handleFreeStandingTagDecl(C));
foldExplicitTemplateInstantiation(
- Builder.getTemplateRange(C), Builder.findToken(Info->ExternKeywordLoc),
- Builder.findToken(Info->TemplateKeywordLoc), Declaration, C);
+ Builder.getTemplateRange(C),
+ Builder.findToken(C->getExternKeywordLoc()),
+ Builder.findToken(C->getTemplateKeywordLoc()), Declaration, C);
return true;
}
@@ -778,9 +778,8 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
foldTemplateDeclaration(R, TemplateKW, DeclarationRange, nullptr);
DeclarationRange = R;
};
- if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(C))
- if (const auto *Info = S->getExplicitSpecializationInfo())
- ConsumeTemplateParameters(*Info->TemplateParams);
+ if (auto *S = dyn_cast<ClassTemplatePartialSpecializationDecl>(C))
+ ConsumeTemplateParameters(*S->getTemplateParameters());
for (TemplateParameterList *TPL : C->getTemplateParameterLists())
ConsumeTemplateParameters(*TPL);
return Result;
diff --git a/clang/test/AST/ast-dump-templates-pattern.cpp b/clang/test/AST/ast-dump-templates-pattern.cpp
index c16e0870639af..aec86664f9988 100644
--- a/clang/test/AST/ast-dump-templates-pattern.cpp
+++ b/clang/test/AST/ast-dump-templates-pattern.cpp
@@ -32,12 +32,11 @@ namespace TestFunctionRedecl {
// CHECK-LABEL: Dumping TestFunctionRedecl:
// CHECK: |-FunctionTemplateDecl 0x[[TestFunctionRedecl_T1:[^ ]+]] <line:[[@LINE-4]]:{{.+}} f external-linkage
// CHECK: | |-FunctionDecl 0x[[TestFunctionRedecl_D1:[^ ]+]] {{.+}} f 'void ()'
-// CHECK: | |-FunctionDecl {{.+}} prev 0x[[TestFunctionRedecl_S1:[^ ]+]] <col:22, col:32> col:27 f 'void ()' implicit_instantiation instantiated_from 0x[[TestFunctionRedecl_D1]] external-linkage
-// CHECK: | `-FunctionDecl 0x[[TestFunctionRedecl_S1]] {{.+}} f 'void ()' explicit_instantiation_definition instantiated_from 0x[[TestFunctionRedecl_D2:[^ ]+]] external-linkage
-// CHECK: |-FunctionTemplateDecl 0x[[TestFunctionRedecl_T2:[^ ]+]] prev 0x[[TestFunctionRedecl_T1]] <line:[[@LINE-7]]:{{.+}} f external-linkage
+// CHECK: | `-FunctionDecl 0x[[TestFunctionRedecl_S1:[^ ]+]] {{.+}} f 'void ()' explicit_instantiation_definition instantiated_from 0x[[TestFunctionRedecl_D2:[^ ]+]] external-linkage
+// CHECK: |-FunctionTemplateDecl 0x[[TestFunctionRedecl_T2:[^ ]+]] prev 0x[[TestFunctionRedecl_T1]] <line:[[@LINE-6]]:{{.+}} f external-linkage
// CHECK: | |-FunctionDecl 0x[[TestFunctionRedecl_D2]] prev 0x[[TestFunctionRedecl_D1]] {{.+}} f 'void ()'
// CHECK: | `-Function 0x[[TestFunctionRedecl_S1]] 'f' 'void ()'
-// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-9]]:{{.+}} 'f'
+// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-8]]:{{.+}} 'f'
// CHECK: |-Function 0x[[TestFunctionRedecl_S1]] 'f' 'void ()'
// CHECK: |-FunctionProtoTypeLoc {{.+}} 'void ()' cdecl
// CHECK: | `-BuiltinTypeLoc {{.+}} 'void'
@@ -77,15 +76,15 @@ namespace TestNestedClassRedecl {
// CHECK: | | `-ClassTemplateDecl 0x[[TestNestedClassRedecl_B_T1:[^ ]+]] <line:[[@LINE-8]]:{{.+}} B external-linkage
// CHECK: | | `-CXXRecordDecl 0x[[TestNestedClassRedecl_B_D1:[^ ]+]] {{.+}} struct B
// CHECK: | `-ClassTemplateSpecializationDecl 0x[[TestNestedClassRedecl_A_S1:[^ ]+]] <line:[[@LINE-8]]:{{.+}} line:[[@LINE-11]]:{{.+}} struct A definition external-linkage instantiated_from 0x[[TestNestedClassRedecl_A_D2:[^ ]+]] implicit_instantiation
-// CHECK: | |-ClassTemplateDecl 0x{{.+}} <line:[[@LINE-11]]:{{.+}} B external-linkage
-// CHECK: | | |-CXXRecordDecl 0x{{.+}} struct B
-// CHECK: | | `-ClassTemplateSpecialization 0x[[TestNestedClassRedecl_B_S1:[^ ]+]] 'B'
-// CHECK: | `-ClassTemplateSpecializationDecl 0x[[TestNestedClassRedecl_B_S1]] <line:[[@LINE-10]]:{{.+}} struct B definition external-linkage instantiated_from 0x[[TestNestedClassRedecl_B_D1]] explicit_instantiation_definition
-// CHECK: |-ClassTemplateDecl 0x{{.+}} prev 0x[[TestNestedClassRedecl_A_T1]] <line:[[@LINE-13]]:{{.+}} A external-linkage
+// CHECK: | `-ClassTemplateDecl 0x{{.+}} <line:[[@LINE-11]]:{{.+}} B external-linkage
+// CHECK: | |-CXXRecordDecl 0x{{.+}} struct B
+// CHECK: | `-ClassTemplateSpecialization 0x[[TestNestedClassRedecl_B_S1:[^ ]+]] 'B'
+// CHECK: |-ClassTemplateDecl 0x{{.+}} prev 0x[[TestNestedClassRedecl_A_T1]] <line:[[@LINE-12]]:{{.+}} A external-linkage
// CHECK: | |-CXXRecordDecl 0x[[TestNestedClassRedecl_A_D2]] prev 0x[[TestNestedClassRedecl_A_D1]] {{.+}} struct A
// CHECK: | `-ClassTemplateSpecialization 0x[[TestNestedClassRedecl_A_S1]] 'A'
-// CHECK: |-ClassTemplateDecl 0x{{.+}} parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_T1]] <line:[[@LINE-15]]:{{.+}} B external-linkage
+// CHECK: |-ClassTemplateDecl 0x{{.+}} parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_T1]] <line:[[@LINE-14]]:{{.+}} B external-linkage
// CHECK: | `-CXXRecordDecl 0x[[TestNestedClassRedecl_B_D2:[^ ]+]] parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_D1]] {{.+}} struct B definition
+// CHECK: |-ClassTemplateSpecializationDecl 0x[[TestNestedClassRedecl_B_S1]] parent 0x[[TestNestedClassRedecl_A_S1]] <line:[[@LINE-15]]:{{.+}} struct B definition external-linkage instantiated_from 0x[[TestNestedClassRedecl_B_D1]] explicit_instantiation_definition
// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-16]]:{{.+}} 'B'
// CHECK: |-NestedNameSpecifier TypeSpec {{.+}}
// CHECK: |-ClassTemplateSpecialization 0x[[TestNestedClassRedecl_B_S1]] 'B'
diff --git a/clang/test/CXX/basic/basic.link/p11.cpp b/clang/test/CXX/basic/basic.link/p11.cpp
index ab7b6cf99d0f6..7f6a88d4a63f1 100644
--- a/clang/test/CXX/basic/basic.link/p11.cpp
+++ b/clang/test/CXX/basic/basic.link/p11.cpp
@@ -5,6 +5,7 @@ namespace MemberSpecialization {
struct A {
template<bool B>
void f() noexcept(B);
+ // FIXME expected-note at -1 {{previous declaration is here}}
template<bool B>
void g() noexcept(B); // expected-note {{previous declaration is here}}
@@ -13,6 +14,7 @@ namespace MemberSpecialization {
template<>
template<bool B>
void A<int>::f() noexcept(B);
+ // FIXME expected-error at -1 {{exception specification in declaration does not match previous declaration}}
template<>
template<bool B>
diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
index ae8d5917a9664..342ffba53dbfa 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
@@ -73,15 +73,18 @@ template <class> struct S {};
template<template<True T> typename Wrapper>
using Test = Wrapper<int>;
-template<template<False T> typename Wrapper>
-using Test = Wrapper<int>;
+template<template<False T> typename Wrapper> // #TTP-Wrapper
+using Test = Wrapper<int>; // expected-error {{constraints not satisfied for template template parameter 'Wrapper' [with T = int]}}
+
+// expected-note@#TTP-Wrapper {{'int' does not satisfy 'False'}}
+// expected-note@#False {{evaluated to false}}
template <typename U, template<False> typename T>
void foo(T<U>); // #foo
void bar() {
- // FIXME: CWG2980: There is no way to check the constraints on the template template parameter.
- foo<int>(S<int>{});
+ foo<int>(S<int>{}); // expected-error {{no matching function for call to 'foo'}}
+ // expected-note@#foo {{substitution failure [with U = int]: constraints not satisfied for template template parameter 'T' [with $0 = int]}}
}
}
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
index 70064f867e18e..fefe86a448b18 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
@@ -1,11 +1,10 @@
// RUN: %clang_cc1 -std=c++20 -verify %s
-// expected-no-diagnostics
template<typename T>
concept D = true;
template<typename T>
-struct A {
+struct A { // expected-note {{defined here}}
template<typename U, bool V>
void f() requires V;
@@ -17,6 +16,7 @@ struct A {
template<typename U, bool V> requires V
struct B;
+ // expected-note at -2 {{previous template declaration is here}}
template<typename U, bool V> requires V
struct B<U*, V>;
@@ -26,12 +26,14 @@ struct A {
template<D U>
struct C;
+ // expected-note at -2 {{previous template declaration is here}}
template<D U>
struct C<U*>;
template<typename U, bool V> requires V
static int x;
+ // expected-note at -2 {{previous template declaration is here}}
template<typename U, bool V> requires V
static int x<U*, V>;
@@ -41,6 +43,7 @@ struct A {
template<D U>
static int y;
+ // expected-note at -2 {{previous template declaration is here}}
template<D U>
static int y<U*>;
@@ -94,9 +97,11 @@ template<typename T>
template<D U>
int A<T>::y<U*> = 0;
+// FIXME: This should be accepted.
template<>
template<typename U, bool V>
void A<short>::f() requires V;
+// expected-error at -1 {{out-of-line declaration of 'f' does not match any declaration in 'A<short>'}}
template<>
template<>
@@ -110,9 +115,11 @@ template<>
template<D U>
void A<short>::g();
+// FIXME: This should be accepted.
template<>
template<typename U, bool V> requires V
struct A<int>::B;
+// expected-error at -2 {{requires clause
diff ers in template redeclaration}}
template<>
template<>
@@ -130,9 +137,11 @@ template<>
template<typename U, bool V> requires V
struct A<int>::B<U&, V>;
+// FIXME: This should be accepted.
template<>
template<D U>
struct A<int>::C;
+// expected-error at -2 {{type constraint
diff ers in template redeclaration}}
template<>
template<D U>
@@ -142,9 +151,11 @@ template<>
template<D U>
struct A<int>::C<U&>;
+// FIXME: This should be accepted.
template<>
template<typename U, bool V> requires V
int A<long>::x;
+// expected-error at -2 {{requires clause
diff ers in template redeclaration}}
template<>
template<>
@@ -162,9 +173,11 @@ template<>
template<typename U, bool V> requires V
int A<long>::x<U&, V>;
+// FIXME: This should be accepted.
template<>
template<D U>
int A<long>::y;
+// expected-error at -2 {{type constraint
diff ers in template redeclaration}}
template<>
template<D U>
diff --git a/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp b/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp
index a39d3a8fea15d..20121d6cf5743 100644
--- a/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.spec.partial/temp.spec.partial.member/p2.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
-// expected-no-diagnostics
// expected-no-diagnostics
diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
index e7e4738032f64..af07024cb7af5 100644
--- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
+++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
@@ -180,20 +180,28 @@ namespace Defined {
namespace Constrained {
template<typename T>
struct A {
+ // FIXME expected-note at -1 2{{defined here}}
template<typename U, bool V> requires V
static constexpr int f(); // expected-note {{declared here}}
+ // FIXME expected-note at -1 {{declared here}}
template<typename U, bool V> requires V
static const int x; // expected-note {{declared here}}
+ // FIXME expected-note at -2 2{{previous template declaration is here}}
+ // FIXME expected-note at -2 {{declared here}}
template<typename U, bool V> requires V
static const int x<U*, V>; // expected-note {{declared here}}
+ // FIXME expected-note at -1 {{partial specialization matches}}
template<typename U, bool V> requires V
struct B; // expected-note {{template is declared here}}
+ // FIXME expected-note at -2 2{{previous template declaration is here}}
+ // FIXME expected-note at -2 {{template is declared here}}
template<typename U, bool V> requires V
struct B<U*, V>; // expected-note {{template is declared here}}
+ // FIXME expected-note at -1 {{partial specialization matches}}
};
template<>
@@ -201,36 +209,43 @@ namespace Constrained {
constexpr int A<short>::f() {
return A<long>::f<U, V>();
}
+ // FIXME expected-error at -3 {{out-of-line definition of 'f' does not match any declaration in 'Constrained::A<short>'}}
template<>
template<typename U, bool V> requires V
constexpr int A<short>::x = A<long>::x<U, V>;
+ // FIXME expected-error at -2 {{requires clause
diff ers in template redeclaration}}
template<>
template<typename U, bool V> requires V
constexpr int A<short>::x<U*, V> = A<long>::x<U*, V>;
+ // FIXME expected-note at -1 {{partial specialization matches}}
template<>
template<typename U, bool V> requires V
struct A<short>::B<U*, V> {
static constexpr int y = A<long>::B<U*, V>::y;
};
+ // FIXME expected-note at -3 {{partial specialization matches}}
template<>
template<typename U, bool V> requires V
struct A<short>::B {
static constexpr int y = A<long>::B<U, V>::y;
};
+ // FIXME expected-error at -4 {{requires clause
diff ers in template redeclaration}}
template<>
template<typename U, bool V> requires V
constexpr int A<long>::f() {
return 1;
}
+ // FIXME expected-error at -3 {{out-of-line definition of 'f' does not match any declaration in 'Constrained::A<long>'}}
template<>
template<typename U, bool V> requires V
constexpr int A<long>::x = 1;
+ // FIXME expected-error at -2 {{requires clause
diff ers in template redeclaration}}
template<>
template<typename U, bool V> requires V
@@ -241,6 +256,7 @@ namespace Constrained {
struct A<long>::B {
static constexpr int y = 1;
};
+ // FIXME expected-error at -4 {{requires clause
diff ers in template redeclaration}}
template<>
template<typename U, bool V> requires V
@@ -258,10 +274,17 @@ namespace Constrained {
static_assert(A<int>::B<int*, true>::y == 0); // expected-error {{implicit instantiation of undefined template 'Constrained::A<int>::B<int *, true>'}}
static_assert(A<short>::f<int, true>() == 1);
+ // FIXME expected-error at -1 {{static assertion expression is not an integral constant expression}}
+ // FIXME expected-note at -2 {{undefined function 'f<int, true>' cannot be used in a constant expression}}
static_assert(A<short>::x<int, true> == 1);
+ // FIXME expected-error at -1 {{static assertion expression is not an integral constant expression}}
+ // FIXME expected-note at -2 {{initializer of 'x<int, true>' is unknown}}
static_assert(A<short>::x<int*, true> == 2);
+ // FIXME expected-error at -1 {{ambiguous partial specializations of 'x'}}
static_assert(A<short>::B<int, true>::y == 1);
+ // FIXME expected-error at -1 {{implicit instantiation of undefined template 'Constrained::A<short>::B<int, true>'}}
static_assert(A<short>::B<int*, true>::y == 2);
+ // FIXME expected-error at -1 {{ambiguous partial specializations of 'B<int *, true>'}}
} // namespace Constrained
namespace Dependent {
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 01db2a54ae381..6c41853cf3b4f 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -840,7 +840,7 @@ namespace PackIndexExpr1 {
template <int... T>
concept C = true;
-template <typename...> struct TplClass {
+template <typename...> struct TplClass { // #PackIndexExpr1-TplClassDef
template <int... Ts>
requires C<Ts...[0]>
static auto buggy() -> void;
@@ -850,6 +850,9 @@ template <>
template <int... Ts>
requires C<Ts...[0]>
auto TplClass<int>::buggy() -> void {}
+// FIXME: These shouldn't diagnose, but are a result of a revert: #193558
+// expected-error at -2{{does not match any declaration in}}
+// expected-note@#PackIndexExpr1-TplClassDef{{TplClass defined here}}
} // namespace PackIndexExpr1
namespace PackIndexExpr2 {
@@ -900,16 +903,18 @@ namespace FuncTemplateInClass {
template <int T> concept C = true;
namespace t1 {
- template <int> struct TplClass {
+ template <int> struct TplClass { // expected-note {{defined here}}
template <int Ts>
requires C<Ts>
static auto buggy() -> void;
};
+ // FIXME: This should be accepted.
template <>
template <int Ts>
requires C<Ts>
auto TplClass<0>::buggy() -> void {}
+ // expected-error at -1 {{out-of-line definition of 'buggy' does not match any declaration}}
} //namespace t1
namespace t2 {
template <int> struct TplClass { // expected-note {{defined here}}
diff --git a/clang/test/SemaTemplate/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp
index 4321f1f073c77..2b5a226c3b33c 100644
--- a/clang/test/SemaTemplate/friend-template.cpp
+++ b/clang/test/SemaTemplate/friend-template.cpp
@@ -338,11 +338,3 @@ class Foo {
bool aux;
};
}
-
-namespace GH101330 {
- template <class T> struct A {
- template <int N> friend void f() noexcept(N == 0);
- };
- template <int N> void f() noexcept(N == 0) {}
- template struct A<int>;
-} // namespace GH101330
diff --git a/clang/test/SemaTemplate/instantiate-scope.cpp b/clang/test/SemaTemplate/instantiate-scope.cpp
index 7dca971470e6a..733105674b7a4 100644
--- a/clang/test/SemaTemplate/instantiate-scope.cpp
+++ b/clang/test/SemaTemplate/instantiate-scope.cpp
@@ -8,9 +8,10 @@ template<typename ...T> struct X {
template<typename T, typename U> using A = T;
-// FIXME: These definitions are not OK, X<A<T, decltype(...)>...> is not equivalent to X<T...>.
+// These definitions are OK, X<A<T, decltype(...)>...> is equivalent to X<T...>
+// so this defines the member of the primary template.
template<typename ...T>
-void X<A<T, decltype(f(T()))>...>::f(int) {}
+void X<A<T, decltype(f(T()))>...>::f(int) {} // expected-error {{undeclared}}
template<typename ...T>
int X<A<T, decltype(f(T()))>...>::n = 0; // expected-error {{undeclared}}
@@ -22,7 +23,8 @@ void g() {
X<Y>().f(0);
X<Y>::n = 1;
- // FIXME: There should be no substitutiton failure since the out-of-line definitions were not valid.
- X<void>().f(0);
+ // Error, substitution fails; this should not be treated as a SFINAE-able
+ // condition, so we don't select X<void>::f(...).
+ X<void>().f(0); // expected-note {{instantiation of}}
X<void>::n = 1; // expected-note {{instantiation of}}
}
diff --git a/clang/test/Templight/templight-default-func-arg.cpp b/clang/test/Templight/templight-default-func-arg.cpp
index f2533bffb9b99..19e6039379724 100644
--- a/clang/test/Templight/templight-default-func-arg.cpp
+++ b/clang/test/Templight/templight-default-func-arg.cpp
@@ -10,77 +10,64 @@ int main()
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+foo$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
//
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+foo$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+foo$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
//
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'foo<int>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'foo<int>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
-//
-// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+foo$}}
-// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
-// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
-// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+foo$}}
-// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
-// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
//
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+b$}}
// CHECK: {{^kind:[ ]+DefaultFunctionArgumentInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:12'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+b$}}
// CHECK: {{^kind:[ ]+DefaultFunctionArgumentInstantiation$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:12'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
//
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'foo<int>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'foo<int>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
foo<int>();
}
diff --git a/clang/test/Templight/templight-empty-entries-fix.cpp b/clang/test/Templight/templight-empty-entries-fix.cpp
index 43fcf2f50bbbc..7f34b10134929 100644
--- a/clang/test/Templight/templight-empty-entries-fix.cpp
+++ b/clang/test/Templight/templight-empty-entries-fix.cpp
@@ -207,18 +207,6 @@ template <bool = true> void d(int = 0) { d(); }
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:171:42'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+d$}}
-// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
-// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:171:42'$}}
-// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+d$}}
-// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
-// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:171:42'$}}
-// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'unnamed function parameter 0 of d<true>'$}}
// CHECK: {{^kind:[ ]+DefaultFunctionArgumentInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
@@ -237,41 +225,41 @@ void e() {
}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
template <template<typename> class>
@@ -287,71 +275,71 @@ void foo() {
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
// CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
// CHECK: {{^poi:[ ]+''$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
// CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
// CHECK: {{^poi:[ ]+''$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
// CHECK: {{^kind:[ ]+PartialOrderingTTP$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
// CHECK: {{^kind:[ ]+PartialOrderingTTP$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'d<C>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'d<C>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 0577c442e38d6..85760968cdbde 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -732,7 +732,6 @@ bool CursorVisitor::VisitClassTemplateSpecializationDecl(
switch (D->getSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
- case TSK_FriendDeclaration:
// Nothing to visit
return false;
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index aa92ee1173414..92085e30ace74 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -5289,13 +5289,11 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportTemplateParameterLists) {
Decl *FromTU = getTuDecl(Code, Lang_CXX03);
auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU,
functionDecl(hasName("f"), isExplicitTemplateSpecialization()));
- ASSERT_EQ(FromD->getTemplateSpecializationInfo()->TemplateParameters->size(),
- 0u);
+ ASSERT_EQ(FromD->getTemplateParameterLists().size(), 1u);
auto *ToD = Import(FromD, Lang_CXX03);
// The template parameter list should exist.
- ASSERT_EQ(ToD->getTemplateSpecializationInfo()->TemplateParameters->size(),
- 0u);
+ EXPECT_EQ(ToD->getTemplateParameterLists().size(), 1u);
}
const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateDecl>
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index 35d169fb1234d..a3281f948fdb7 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -6071,14 +6071,14 @@ class ForCallablePreservesBindingWithMultipleParentsTestCallback
FunDecl);
ExpectCorrectResult("ForCallable first",
- callExpr(forCallable(declaresSameEntityAsNode(FunDecl)),
+ callExpr(forCallable(equalsNode(FunDecl)),
callee(cxxMethodDecl().bind("callee")))
.bind("call"),
FunDecl);
ExpectCorrectResult("ForCallable second",
callExpr(callee(cxxMethodDecl().bind("callee")),
- forCallable(declaresSameEntityAsNode(FunDecl)))
+ forCallable(equalsNode(FunDecl)))
.bind("call"),
FunDecl);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 112901a05d641..74a5a414de67b 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1154,7 +1154,9 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::chrono::sys_seconds summary provider",
"^std::__[[:alnum:]]+::chrono::time_point<"
"std::__[[:alnum:]]+::chrono::system_clock, "
- "std::__[[:alnum:]]+::chrono::duration<[^,]*> >$",
+ "std::__[[:alnum:]]+::chrono::duration<.*, "
+ "std::__[[:alnum:]]+::ratio<1, 1> "
+ "> >$",
eTypeOptionHideChildren | eTypeOptionHideValue |
eTypeOptionCascade,
true);
@@ -1164,7 +1166,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"^std::__[[:alnum:]]+::chrono::time_point<"
"std::__[[:alnum:]]+::chrono::system_clock, "
"std::__[[:alnum:]]+::chrono::duration<int, "
- "std::__[[:alnum:]]+::ratio<86400> "
+ "std::__[[:alnum:]]+::ratio<86400, 1> "
"> >$",
eTypeOptionHideChildren | eTypeOptionHideValue |
eTypeOptionCascade,
@@ -1176,7 +1178,9 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::chrono::local_seconds summary provider",
"^std::__[[:alnum:]]+::chrono::time_point<"
"std::__[[:alnum:]]+::chrono::local_t, "
- "std::__[[:alnum:]]+::chrono::duration<[^,]*> >$",
+ "std::__[[:alnum:]]+::chrono::duration<.*, "
+ "std::__[[:alnum:]]+::ratio<1, 1> "
+ "> >$",
eTypeOptionHideChildren | eTypeOptionHideValue | eTypeOptionCascade,
true);
AddCXXSummary(cpp_category_sp,
@@ -1185,7 +1189,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"^std::__[[:alnum:]]+::chrono::time_point<"
"std::__[[:alnum:]]+::chrono::local_t, "
"std::__[[:alnum:]]+::chrono::duration<int, "
- "std::__[[:alnum:]]+::ratio<86400> "
+ "std::__[[:alnum:]]+::ratio<86400, 1> "
"> >$",
eTypeOptionHideChildren | eTypeOptionHideValue |
eTypeOptionCascade,
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 22ba62af26f3a..82fd9844cf96a 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -1449,11 +1449,8 @@ void TypeSystemClang::CreateFunctionTemplateSpecializationInfo(
TemplateArgumentList *template_args_ptr = TemplateArgumentList::CreateCopy(
func_decl->getASTContext(), infos.GetArgs());
- func_decl->setFunctionTemplateSpecialization(
- func_decl->getASTContext(), func_tmpl_decl, template_args_ptr,
- /*InsertPos=*/nullptr, TSK_ImplicitInstantiation,
- /*TemplateParams=*/nullptr, /*TemplateArgsAsWritten=*/nullptr,
- /*PointOfInstantiation=*/SourceLocation(), /*AddSpecialization=*/true);
+ func_decl->setFunctionTemplateSpecialization(func_tmpl_decl,
+ template_args_ptr, nullptr);
}
/// Returns true if the given template parameter can represent the given value.
@@ -1652,40 +1649,6 @@ TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) {
template_param_list);
}
-static const ASTTemplateArgumentListInfo *getTrivialTemplateArgumentListInfo(
- ASTContext &ast, ArrayRef<TemplateArgument> args, SourceLocation Loc) {
- TemplateArgumentListInfo Args(/*LAngleLoc=*/Loc, /*RAngleLoc=*/Loc);
- for (const auto &arg : args) {
- if (arg.getIsDefaulted())
- break;
- switch (arg.getKind()) {
- case TemplateArgument::Type:
- Args.addArgument(TemplateArgumentLoc(
- arg.getAsType(), ast.getTrivialTypeSourceInfo(arg.getAsType(), Loc)));
- break;
- case TemplateArgument::Expression:
- Args.addArgument(TemplateArgumentLoc(arg, arg.getAsExpr()));
- break;
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion:
- Args.addArgument(
- TemplateArgumentLoc(ast, arg, Loc, NestedNameSpecifierLoc(), Loc));
- break;
- case TemplateArgument::Declaration:
- case TemplateArgument::Integral:
- case TemplateArgument::NullPtr:
- case TemplateArgument::Pack:
- case TemplateArgument::StructuralValue:
- Args.addArgument(
- TemplateArgumentLoc(arg, TemplateArgumentLocInfo(ast, Loc)));
- break;
- case TemplateArgument::Null:
- llvm_unreachable("unexpected null template argument");
- }
- }
- return ASTTemplateArgumentListInfo::Create(ast, Args);
-}
-
ClassTemplateSpecializationDecl *
TypeSystemClang::CreateClassTemplateSpecializationDecl(
DeclContext *decl_ctx, OptionalClangModuleID owning_module,
@@ -1728,13 +1691,6 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl(
class_template_specialization_decl->setSpecializationKind(
TSK_ExplicitSpecialization);
- SourceLocation FakeLoc = class_template_specialization_decl->getLocation();
- auto *TemplateParams = TemplateParameterList::Create(
- ast, /*TemplateLoc=*/FakeLoc, /*LAngleLoc=*/FakeLoc,
- /*Params=*/ArrayRef<NamedDecl *>(), /*RAngleLoc=*/FakeLoc,
- /*RequiresClause=*/nullptr);
- class_template_specialization_decl->setExplicitSpecializationInfo(
- TemplateParams, ::getTrivialTemplateArgumentListInfo(ast, args, FakeLoc));
return class_template_specialization_decl;
}
More information about the llvm-branch-commits
mailing list