[clang] [clang-tools-extra] [lldb] [clang] Reland: fix getTemplateInstantiationArgs (PR #208601)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 9 18:55:20 PDT 2026
https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/208601
>From 3d3b8c952d85b204d23065dd1476df28d8f14208 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Wed, 29 Apr 2026 14:19:07 -0300
Subject: [PATCH 1/2] [clang] fix getTemplateInstantiationArgs
This implements a new strategy for collecting the template arguments, by
relying on the qualifiers and template parameter lists to navigate the template
context of out-of-line definitions.
This greatly simplifies the signature of that function, by removing a bunch
of workarounds, and simpliffying a couple that weren't removed yet.
Since this now relies on qualifiers and template parameter lists,
this patch expends most of its effort making sure these are placed,
transformed and propagated to template instantiations.
Also makes the explicit specialization AST nodes stop abusing the template
parameter lists by storing it's own template parameter list, creating a
dedicated field for them, similar to partial specializations.
---
.../misc/DefinitionsInHeadersCheck.cpp | 2 +-
.../clangd/SemanticHighlighting.cpp | 39 +-
.../clangd/refactor/tweaks/DefineInline.cpp | 2 +-
clang/docs/LibASTMatchersReference.html | 5 +
clang/docs/ReleaseNotes.md | 1 +
clang/include/clang/AST/Decl.h | 58 +-
clang/include/clang/AST/DeclTemplate.h | 191 +++---
clang/include/clang/AST/JSONNodeDumper.h | 1 +
clang/include/clang/AST/RecursiveASTVisitor.h | 8 +-
clang/include/clang/ASTMatchers/ASTMatchers.h | 5 +
.../clang/ASTMatchers/ASTMatchersInternal.h | 8 +-
clang/include/clang/Basic/Specifiers.h | 3 +
clang/include/clang/Sema/Sema.h | 143 ++--
clang/lib/AST/ASTContext.cpp | 2 +
clang/lib/AST/ASTDumper.cpp | 1 +
clang/lib/AST/ASTImporter.cpp | 131 +++-
clang/lib/AST/Comment.cpp | 10 +-
clang/lib/AST/Decl.cpp | 45 +-
clang/lib/AST/DeclPrinter.cpp | 1 +
clang/lib/AST/DeclTemplate.cpp | 156 ++---
clang/lib/AST/JSONNodeDumper.cpp | 3 +
clang/lib/AST/TextNodeDumper.cpp | 3 +
clang/lib/ASTMatchers/Dynamic/Registry.cpp | 1 +
clang/lib/Analysis/ExprMutationAnalyzer.cpp | 13 +-
clang/lib/CIR/CodeGen/CIRGenVTables.cpp | 2 +
clang/lib/CodeGen/CGVTables.cpp | 32 +-
clang/lib/Index/IndexingContext.cpp | 1 +
clang/lib/InstallAPI/Visitor.cpp | 5 +
clang/lib/Parse/ParseDeclCXX.cpp | 14 +-
clang/lib/Sema/HLSLExternalSemaSource.cpp | 15 +-
clang/lib/Sema/SemaConcept.cpp | 188 ++----
clang/lib/Sema/SemaDecl.cpp | 68 +-
clang/lib/Sema/SemaDeclCXX.cpp | 11 +-
clang/lib/Sema/SemaExprMember.cpp | 5 +-
clang/lib/Sema/SemaOverload.cpp | 6 +-
clang/lib/Sema/SemaTemplate.cpp | 296 ++++-----
clang/lib/Sema/SemaTemplateDeduction.cpp | 43 +-
clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 57 +-
clang/lib/Sema/SemaTemplateInstantiate.cpp | 611 ++++++------------
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 470 +++++++++-----
clang/lib/Serialization/ASTReaderDecl.cpp | 77 +--
clang/lib/Serialization/ASTWriterDecl.cpp | 100 +--
.../StaticAnalyzer/Core/BugSuppression.cpp | 91 +--
clang/lib/Tooling/Syntax/BuildTree.cpp | 13 +-
clang/test/AST/ast-dump-templates-pattern.cpp | 19 +-
clang/test/CXX/basic/basic.link/p11.cpp | 2 -
clang/test/CXX/drs/cwg18xx.cpp | 8 +-
clang/test/CXX/drs/cwg7xx.cpp | 3 +-
.../temp/temp.arg/temp.arg.template/p3-2a.cpp | 11 +-
.../temp/temp.constr/temp.constr.decl/p4.cpp | 17 +-
.../temp.spec.partial.member/p2.cpp | 1 +
.../CXX/temp/temp.spec/temp.expl.spec/p7.cpp | 23 -
clang/test/CodeGenCXX/default-arguments.cpp | 12 +
.../CodeGenCXX/explicit-instantiation.cpp | 7 +
clang/test/Modules/GH208100.cpp | 28 +
clang/test/SemaCXX/GH195416.cpp | 1 +
.../SemaCXX/constant-expression-cxx14.cpp | 7 +
.../SemaCXX/deduced-return-type-cxx14.cpp | 26 +
clang/test/SemaCXX/member-class-11.cpp | 20 +-
clang/test/SemaTemplate/GH202358.cpp | 12 +
.../SemaTemplate/concepts-out-of-line-def.cpp | 11 +-
clang/test/SemaTemplate/friend-template.cpp | 8 +
clang/test/SemaTemplate/instantiate-scope.cpp | 10 +-
.../Templight/templight-default-func-arg.cpp | 33 +-
.../Templight/templight-empty-entries-fix.cpp | 88 +--
clang/tools/libclang/CIndex.cpp | 1 +
clang/unittests/AST/ASTImporterTest.cpp | 6 +-
.../ASTMatchers/ASTMatchersTraversalTest.cpp | 4 +-
.../Language/CPlusPlus/CPlusPlusLanguage.cpp | 12 +-
.../TypeSystem/Clang/TypeSystemClang.cpp | 48 +-
70 files changed, 1625 insertions(+), 1730 deletions(-)
create mode 100644 clang/test/Modules/GH208100.cpp
create mode 100644 clang/test/SemaTemplate/GH202358.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp b/clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
index ae063a19d779d..a1a705dd043a0 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->getInnerLocStart(), "inline ");
+ << FixItHint::CreateInsertion(FD->getFunctionLocStart(), "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 5d9336fa6e53d..ffd0ed1b79b79 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 (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());
+ 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());
+ }
return true;
}
bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
- 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());
+ 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());
+ }
return true;
}
@@ -625,6 +625,9 @@ 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 c9704492bf1cd..5fcb1a24448b8 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->getInnerLocStart(), 0, "inline ");
+ return tooling::Replacement(SM, FD->getFunctionLocStart(), 0, "inline ");
}
/// Moves definition of a function/method to its declaration location.
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index 7e0bbbcb18938..675fb4a550ba8 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -4301,6 +4301,11 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('declaresSameEntityAsNode0')"><a name="declaresSameEntityAsNode0Anchor">declaresSameEntityAsNode</a></td><td>const Decl * Other</td></tr>
+<tr><td colspan="4" class="doc" id="declaresSameEntityAsNode0"><pre>Matches a declaration if it declares the same entity as the node.
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('equalsBoundNode1')"><a name="equalsBoundNode1Anchor">equalsBoundNode</a></td><td>std::string ID</td></tr>
<tr><td colspan="4" class="doc" id="equalsBoundNode1"><pre>Matches if a node equals a previously bound node.
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 449a3792eb4ba..84b0667d65edf 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -853,6 +853,7 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
- Improvements to typo correction involving template names. (#GH207498)
- 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 a6e9b3bcaa608..210a74ca66657 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2138,34 +2138,6 @@ 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,
@@ -2261,6 +2233,8 @@ class FunctionDecl : public DeclaratorDecl,
return SourceLocation();
}
+ SourceLocation getFunctionLocStart() const;
+
SourceRange getSourceRange() const override LLVM_READONLY;
// Function definitions.
@@ -3090,9 +3064,14 @@ 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.
///
@@ -3105,25 +3084,30 @@ 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(
- FunctionTemplateDecl *Template, TemplateArgumentList *TemplateArgs,
- void *InsertPos,
- TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
- TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr,
- SourceLocation PointOfInstantiation = SourceLocation()) {
- setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs,
- InsertPos, TSK, TemplateArgsAsWritten,
- PointOfInstantiation);
- }
+ ASTContext &C, FunctionTemplateDecl *Template,
+ TemplateArgumentList *TemplateArgs, void *InsertPos,
+ TemplateSpecializationKind TSK,
+ const TemplateParameterList *TemplateParams,
+ const TemplateArgumentListInfo *TemplateArgsAsWritten,
+ SourceLocation PointOfInstantiation, bool AddSpecialization);
/// 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 4f5a4e1b7b8a6..672648c3fc03c 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.
- TemplateArgument *InjectedArgs = nullptr;
+ mutable TemplateArgument *InjectedArgs = nullptr;
/// The location of the 'template' keyword.
SourceLocation TemplateLoc;
@@ -200,7 +200,8 @@ class TemplateParameterList final
bool hasAssociatedConstraints() const;
/// Get the template argument list of the template parameter list.
- ArrayRef<TemplateArgument> getInjectedTemplateArgs(const ASTContext &Context);
+ ArrayRef<TemplateArgument>
+ getInjectedTemplateArgs(const ASTContext &Context) const;
SourceLocation getTemplateLoc() const { return TemplateLoc; }
SourceLocation getLAngleLoc() const { return LAngleLoc; }
@@ -475,14 +476,18 @@ class FunctionTemplateSpecializationInfo final
/// The function template from which this function template
/// specialization was generated.
///
- /// The two bits contain the top 4 values of TemplateSpecializationKind.
- llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
+ /// The three bits contain the TemplateSpecializationKind.
+ llvm::PointerIntPair<FunctionTemplateDecl *, 3> 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;
@@ -495,12 +500,14 @@ 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),
+ TemplateArguments(TemplateArgs), TemplateParameters(TemplateParameters),
TemplateArgumentsAsWritten(TemplateArgsAsWritten),
PointOfInstantiation(POI) {
+ assert(TemplateParameters == nullptr || TSK == TSK_ExplicitSpecialization);
if (MSInfo)
getTrailingObjects()[0] = MSInfo;
}
@@ -513,6 +520,7 @@ 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);
@@ -613,8 +621,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 two bits).
- llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK;
+ // manner in which the instantiation occurred (in the lower three bits).
+ llvm::PointerIntPair<NamedDecl *, 3> MemberAndTSK;
// The point at which this member was first instantiated.
SourceLocation PointOfInstantiation;
@@ -693,14 +701,19 @@ 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.
@@ -1005,11 +1018,6 @@ 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
@@ -1807,8 +1815,18 @@ 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<const ASTTemplateArgumentListInfo *,
+ llvm::PointerUnion<ExplicitSpecializationInfo *,
ExplicitInstantiationInfo *>;
/// Represents a class template specialization, which refers to
@@ -2038,49 +2056,38 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
/// Retrieve the template argument list as written in the sources,
/// if any.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
- if (auto *Info =
- dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
+ if (const auto *Info = getExplicitSpecializationInfo())
return Info->TemplateArgsAsWritten;
- 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;
+ if (const auto *Info = getExplicitInstantiationInfo())
+ return Info->TemplateArgsAsWritten;
+ return nullptr;
}
- /// Set the template argument list as written in the sources.
- void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
- setTemplateArgsAsWritten(
- ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
+ /// Gets the explicit instantiation info, if present.
+ const ExplicitInstantiationInfo *getExplicitInstantiationInfo() const {
+ return dyn_cast_if_present<ExplicitInstantiationInfo *>(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 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;
}
- /// 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();
+ /// Gets the explicit specialization info, if present.
+ const ExplicitSpecializationInfo *getExplicitSpecializationInfo() const {
+ return dyn_cast_if_present<ExplicitSpecializationInfo *>(ExplicitInfo);
}
- /// Sets the location of the template keyword.
- void setTemplateKeywordLoc(SourceLocation Loc);
+ /// Sets the explicit specialization info.
+ void setExplicitSpecializationInfo(
+ TemplateParameterList *TemplateParams,
+ const ASTTemplateArgumentListInfo *TemplateArgsAsWritten);
SourceRange getSourceRange() const override LLVM_READONLY;
@@ -2105,10 +2112,7 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
};
class ClassTemplatePartialSpecializationDecl
- : public ClassTemplateSpecializationDecl {
- /// The list of template parameters
- TemplateParameterList *TemplateParams = nullptr;
-
+ : public ClassTemplateSpecializationDecl {
/// The class template partial specialization from which this
/// class template partial specialization was instantiated.
///
@@ -2122,6 +2126,7 @@ 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);
@@ -2139,7 +2144,9 @@ class ClassTemplatePartialSpecializationDecl
static ClassTemplatePartialSpecializationDecl *
Create(ASTContext &Context, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
- TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate,
+ TemplateParameterList *Params,
+ const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
+ ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args, CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl);
@@ -2154,7 +2161,10 @@ class ClassTemplatePartialSpecializationDecl
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
- return TemplateParams;
+ auto *ExplicitSpecInfo = getExplicitSpecializationInfo();
+ assert(ExplicitSpecInfo &&
+ "A partial specialization is always an explicit specialization");
+ return ExplicitSpecInfo->TemplateParams;
}
/// \brief All associated constraints of this partial specialization,
@@ -2165,11 +2175,11 @@ class ClassTemplatePartialSpecializationDecl
/// conjunction ("and").
void getAssociatedConstraints(
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
- TemplateParams->getAssociatedConstraints(AC);
+ getTemplateParameters()->getAssociatedConstraints(AC);
}
bool hasAssociatedConstraints() const {
- return TemplateParams->hasAssociatedConstraints();
+ return getTemplateParameters()->hasAssociatedConstraints();
}
/// Retrieve the member class template partial specialization from
@@ -2806,49 +2816,38 @@ class VarTemplateSpecializationDecl : public VarDecl,
/// Retrieve the template argument list as written in the sources,
/// if any.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
- if (auto *Info =
- dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
+ if (const auto *Info = getExplicitSpecializationInfo())
return Info->TemplateArgsAsWritten;
- 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;
+ if (const auto *Info = getExplicitInstantiationInfo())
+ return Info->TemplateArgsAsWritten;
+ return nullptr;
}
- /// Set the template argument list as written in the sources.
- void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
- setTemplateArgsAsWritten(
- ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
+ /// Gets the explicit instantiation info, if present.
+ const ExplicitInstantiationInfo *getExplicitInstantiationInfo() const {
+ return dyn_cast_if_present<ExplicitInstantiationInfo *>(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 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;
}
- /// 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();
+ /// Gets the explicit specialization info, if present.
+ const ExplicitSpecializationInfo *getExplicitSpecializationInfo() const {
+ return dyn_cast_if_present<ExplicitSpecializationInfo *>(ExplicitInfo);
}
- /// Sets the location of the template keyword.
- void setTemplateKeywordLoc(SourceLocation Loc);
+ /// Sets the explicit specialization info.
+ void setExplicitSpecializationInfo(
+ TemplateParameterList *TemplateParams,
+ const ASTTemplateArgumentListInfo *TemplateArgsAsWritten);
SourceRange getSourceRange() const override LLVM_READONLY;
@@ -2874,9 +2873,6 @@ 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.
///
@@ -2888,6 +2884,7 @@ 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);
@@ -2905,6 +2902,7 @@ 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);
@@ -2920,7 +2918,10 @@ class VarTemplatePartialSpecializationDecl
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
- return TemplateParams;
+ auto *ExplicitSpecInfo = getExplicitSpecializationInfo();
+ assert(ExplicitSpecInfo &&
+ "A partial specialization is always an explicit specialization");
+ return ExplicitSpecInfo->TemplateParams;
}
/// Get the template argument list of the template parameter list.
@@ -2937,11 +2938,11 @@ class VarTemplatePartialSpecializationDecl
/// conjunction ("and").
void getAssociatedConstraints(
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
- TemplateParams->getAssociatedConstraints(AC);
+ getTemplateParameters()->getAssociatedConstraints(AC);
}
bool hasAssociatedConstraints() const {
- return TemplateParams->hasAssociatedConstraints();
+ return getTemplateParameters()->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 4e8d1649bbf8b..7c8496d6164fc 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -417,6 +417,7 @@ 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 b77443f1fa0ab..222dbf5559e12 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2002,6 +2002,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
case TSK_ExplicitSpecialization:
+ case TSK_FriendDeclaration:
break;
}
}
@@ -2022,6 +2023,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
TRY_TO(TraverseDecl(RD));
break;
+ case TSK_FriendDeclaration:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
case TSK_ExplicitSpecialization:
@@ -2056,6 +2058,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
TRY_TO(TraverseDecl(RD));
break;
+ case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization:
break;
}
@@ -2222,8 +2225,9 @@ 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 (D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { \
- const auto *ArgsWritten = D->getTemplateArgsAsWritten(); \
+ if (const auto *Info = D->getExplicitSpecializationInfo()) { \
+ const auto *ArgsWritten = Info->TemplateArgsAsWritten; \
+ TRY_TO(TraverseTemplateParameterListHelper(Info->TemplateParams)); \
TRY_TO(TraverseTemplateArgumentLocsHelper( \
ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs)); \
} else if (!getDerived().shouldVisitTemplateInstantiations()) { \
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 8108ee559acea..7ef1033365630 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5753,6 +5753,11 @@ 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 cb12d10d628b6..d3daf2eb4781d 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1993,16 +1993,12 @@ getTemplateArgsWritten(const OverloadExpr &OE) {
inline unsigned
getNumTemplateArgsWritten(const ClassTemplateSpecializationDecl &D) {
- if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
- return Args->getNumTemplateArgs();
- return 0;
+ return getTemplateArgsWritten(D).size();
}
inline unsigned
getNumTemplateArgsWritten(const VarTemplateSpecializationDecl &D) {
- if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
- return Args->getNumTemplateArgs();
- return 0;
+ return getTemplateArgsWritten(D).size();
}
inline unsigned getNumTemplateArgsWritten(const FunctionDecl &FD) {
diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h
index 8da6fd4cf454a..1fe50760eff9a 100644
--- a/clang/include/clang/Basic/Specifiers.h
+++ b/clang/include/clang/Basic/Specifiers.h
@@ -193,6 +193,8 @@ 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]).
@@ -227,6 +229,7 @@ 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 f7d0d493e7081..631a680727fee 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11748,7 +11748,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);
@@ -11814,8 +11814,7 @@ class Sema final : public SemaBase {
DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation TemplateNameLoc,
- const TemplateArgumentListInfo &TemplateArgs,
- bool SetWrittenArgs);
+ const TemplateArgumentListInfo &TemplateArgs);
/// Form a reference to the specialization of the given variable template
/// corresponding to the specified argument list, or a null-but-valid result
@@ -11899,7 +11898,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
@@ -11972,7 +11971,8 @@ 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 TemplateArgumentListInfo *ExplicitTemplateArgs,
+ FunctionDecl *FD, const TemplateParameterList *TemplateParams,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
/// Perform semantic analysis for the given function template
@@ -11998,8 +11998,9 @@ class Sema final : public SemaBase {
/// declaration with no explicit template argument list that might be
/// befriending a function template specialization.
bool CheckFunctionTemplateSpecialization(
- FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
- LookupResult &Previous, bool QualifiedFriend = false);
+ FunctionDecl *FD, const TemplateParameterList *TemplateParams,
+ TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous,
+ bool QualifiedFriend = false);
/// Perform semantic analysis for the given non-template member
/// specialization.
@@ -12265,46 +12266,6 @@ 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.
///
@@ -12329,19 +12290,11 @@ class Sema final : public SemaBase {
/// \returns True if the template parameter lists are equal, false
/// otherwise.
bool TemplateParameterListsAreEqual(
- const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
- const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+ const Decl *NewInstFrom, TemplateParameterList *New,
+ const Decl *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
@@ -13572,44 +13525,27 @@ class Sema final : public SemaBase {
/// Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
///
- /// \param ND the declaration for which we are computing template
+ /// \param D the declaration for which we are computing template
/// instantiation arguments.
///
- /// \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 Innermost if present, specifies a template argument list for the
+ /// template-like (TemplateDecl or PartialSpec) declaration passed as D.
///
- /// \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 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 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 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 ForConstraintInstantiation when collecting arguments,
- /// ForConstraintInstantiation indicates we should continue looking when
- /// encountering a lambda generic call operator, and continue looking for
- /// arguments on an enclosing class template.
- ///
- /// \param SkipForSpecialization when specified, any template specializations
- /// in a traversal would be ignored.
- ///
- /// \param ForDefaultArgumentSubstitution indicates we should continue looking
- /// when encountering a specialized member function template, rather than
- /// returning immediately.
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
- const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
+ const Decl *D,
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
- bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
- bool ForConstraintInstantiation = false,
- bool SkipForSpecialization = false,
- bool ForDefaultArgumentSubstitution = false);
+ UnsignedOrNone NumLevels = std::nullopt,
+ bool SkipInnerNonInstantiated = false);
/// RAII object to handle the state changes required to synthesize
/// a function body.
@@ -15026,14 +14962,13 @@ 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 NamedDecl *Old,
- const Expr *OldConstr,
- const TemplateCompareNewDeclInfo &New,
- const Expr *NewConstr);
+ bool AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
+ const Decl *New, const Expr *NewConstr);
// Calculates whether the friend function depends on an enclosing template for
// the purposes of [temp.friend] p9.
- bool FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD);
+ bool
+ FriendConstraintsDependOnEnclosingTemplate(const FunctionTemplateDecl *FTD);
/// \brief Ensure that the given template arguments satisfy the constraints
/// associated with the given template, emitting a diagnostic if they do not.
@@ -15054,10 +14989,19 @@ class Sema final : public SemaBase {
SourceRange TemplateIDRange);
bool CheckFunctionTemplateConstraints(SourceLocation PointOfInstantiation,
- FunctionDecl *Decl,
+ FunctionTemplateDecl *Template,
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
@@ -15138,19 +15082,16 @@ 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,
- std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
- const MultiLevelTemplateArgumentList &MLTAL,
- LocalInstantiationScope &Scope);
+ bool SetupConstraintScope(FunctionDecl *FD,
+ 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, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
- LocalInstantiationScope &Scope);
+ FunctionDecl *FD, LocalInstantiationScope &Scope);
///@}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 2228811546c0f..2945a5bd03e43 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -13106,6 +13106,7 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
case TSK_ExplicitInstantiationDeclaration:
return GVA_AvailableExternally;
+ case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
External = GVA_DiscardableODR;
break;
@@ -13295,6 +13296,7 @@ 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 146fc5ea5caad..5c11336f20aa2 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -140,6 +140,7 @@ 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 d1de2dbac2a0e..fdadd545fd99a 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -816,6 +816,8 @@ 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);
@@ -954,7 +956,8 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) {
ToInfo = TemplateArgumentLocInfo(*TSIOrErr);
else
return TSIOrErr.takeError();
- } else {
+ } else if (Arg.getKind() == TemplateArgument::Template ||
+ Arg.getKind() == TemplateArgument::TemplateExpansion) {
auto ToTemplateKWLocOrErr = import(FromInfo.getTemplateKwLoc());
if (!ToTemplateKWLocOrErr)
return ToTemplateKWLocOrErr.takeError();
@@ -972,6 +975,9 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) {
Importer.getToContext(), *ToTemplateKWLocOrErr,
*ToTemplateQualifierLocOrErr, *ToTemplateNameLocOrErr,
*ToTemplateEllipsisLocOrErr);
+ } else {
+ ToInfo = TemplateArgumentLocInfo(Importer.getToContext(),
+ FromInfo.getTrivialLoc());
}
return TemplateArgumentLoc(Arg, ToInfo);
@@ -3664,6 +3670,12 @@ 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)
@@ -3680,8 +3692,10 @@ Error ASTNodeImporter::ImportTemplateInformation(
TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind();
ToFD->setFunctionTemplateSpecialization(
- std::get<0>(*FunctionAndArgsOrErr), ToTAList, /* InsertPos= */ nullptr,
- TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, *POIOrErr);
+ Importer.getToContext(), std::get<0>(*FunctionAndArgsOrErr), ToTAList,
+ /*InsertPos=*/nullptr, TSK, *TemplateParamsOrErr,
+ FromTAArgsAsWritten ? &ToTAInfo : nullptr, *POIOrErr,
+ /*AddSpecialization=*/true);
return Error::success();
}
@@ -3695,6 +3709,11 @@ 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;
@@ -3704,7 +3723,7 @@ Error ASTNodeImporter::ImportTemplateInformation(
return Err;
ToFD->setDependentTemplateSpecialization(
- Importer.getToContext(), Candidates,
+ Importer.getToContext(), Candidates, *TemplateParamsOrErr,
FromTAArgsAsWritten ? &ToTAInfo : nullptr);
return Error::success();
}
@@ -6537,19 +6556,22 @@ 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, ClassTemplate, ArrayRef(TemplateArgs),
+ *IdLocOrErr, ToTPList,
+ ASTTemplateArgumentListInfo::Create(Importer.getToContext(),
+ ToTAInfo),
+ ClassTemplate, ArrayRef(TemplateArgs),
/*CanonInjectedTST=*/CanQualType(),
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
return D2;
@@ -6580,6 +6602,34 @@ 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());
@@ -6606,19 +6656,6 @@ 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,12 +6873,6 @@ 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)) {
@@ -6849,9 +6880,16 @@ 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;
@@ -6876,6 +6914,34 @@ 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
@@ -6902,9 +6968,6 @@ 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 a1c73f9ec179b..6e107c87edb01 100644
--- a/clang/lib/AST/Comment.cpp
+++ b/clang/lib/AST/Comment.cpp
@@ -233,11 +233,13 @@ void DeclInfo::fill() {
Kind = FunctionKind;
ParamVars = FD->parameters();
ReturnType = FD->getReturnType();
- ArrayRef<TemplateParameterList *> TPLs = FD->getTemplateParameterLists();
- if (!TPLs.empty()) {
- TemplateKind = TemplateSpecialization;
+ TemplateParameters = FD->getTemplateSpecializationParameters();
+ if (ArrayRef<TemplateParameterList *> TPLs =
+ FD->getTemplateParameterLists();
+ !TemplateParameters && !TPLs.empty())
TemplateParameters = TPLs.back();
- }
+ if (TemplateParameters)
+ TemplateKind = TemplateSpecialization;
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 4eaef0d87f3e5..bea0e2c52116c 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -51,6 +51,7 @@
#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"
@@ -4208,6 +4209,7 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
case TSK_ExplicitSpecialization:
return false;
+ case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
return true;
@@ -4328,12 +4330,21 @@ 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,
+ TemplateSpecializationKind TSK, const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
- SourceLocation PointOfInstantiation) {
+ SourceLocation PointOfInstantiation, bool AddSpecialization) {
assert((TemplateOrSpecialization.isNull() ||
isa<MemberSpecializationInfo *>(TemplateOrSpecialization)) &&
"Member function is already a specialization");
@@ -4345,21 +4356,23 @@ void FunctionDecl::setFunctionTemplateSpecialization(
"Member specialization must be an explicit specialization");
FunctionTemplateSpecializationInfo *Info =
FunctionTemplateSpecializationInfo::Create(
- C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten,
- PointOfInstantiation,
+ C, this, Template, TSK, TemplateArgs, TemplateParams,
+ TemplateArgsAsWritten, PointOfInstantiation,
dyn_cast_if_present<MemberSpecializationInfo *>(
TemplateOrSpecialization));
TemplateOrSpecialization = Info;
- Template->addSpecialization(Info, InsertPos);
+ if (AddSpecialization)
+ 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,
- TemplateArgs);
+ DependentFunctionTemplateSpecializationInfo::Create(
+ Context, Templates, TemplateParams, TemplateArgs);
TemplateOrSpecialization = Info;
}
@@ -4372,19 +4385,22 @@ 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, TArgsWritten);
+ DependentFunctionTemplateSpecializationInfo(Candidates, TemplateParams,
+ TArgsWritten);
}
DependentFunctionTemplateSpecializationInfo::
DependentFunctionTemplateSpecializationInfo(
const UnresolvedSetImpl &Candidates,
+ const TemplateParameterList *TemplateParams,
const ASTTemplateArgumentListInfo *TemplateArgsWritten)
- : NumCandidates(Candidates.size()),
+ : NumCandidates(Candidates.size()), TemplateParameters(TemplateParams),
TemplateArgumentsAsWritten(TemplateArgsWritten) {
std::transform(Candidates.begin(), Candidates.end(), getTrailingObjects(),
[](NamedDecl *ND) {
@@ -4544,6 +4560,17 @@ 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 95591d3a09431..6a8046763c788 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -1105,6 +1105,7 @@ 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 275fe364e306d..861974848d6b3 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) {
+ArrayRef<TemplateArgument> TemplateParameterList::getInjectedTemplateArgs(
+ const ASTContext &Context) const {
if (!InjectedArgs) {
InjectedArgs = new (Context) TemplateArgument[size()];
llvm::transform(*this, InjectedArgs, [&](NamedDecl *ND) {
@@ -946,6 +946,7 @@ 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;
@@ -956,7 +957,8 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
void *Mem =
C.Allocate(totalSizeToAlloc<MemberSpecializationInfo *>(MSInfo ? 1 : 0));
return new (Mem) FunctionTemplateSpecializationInfo(
- FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo);
+ FD, Template, TSK, TemplateArgs, TemplateParams, ArgsAsWritten, POI,
+ MSInfo);
}
//===----------------------------------------------------------------------===//
@@ -1050,54 +1052,38 @@ ClassTemplateSpecializationDecl::getSourceRange() const {
return CTPSD->getSourceRange();
return cast<ClassTemplateDecl *>(Pattern)->getSourceRange();
}
+ case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization: {
- SourceRange Range = CXXRecordDecl::getSourceRange();
- if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten();
- !isThisDeclarationADefinition() && Args)
- Range.setEnd(Args->getRAngleLoc());
- return Range;
+ const auto *Info = getExplicitSpecializationInfo();
+ auto TPLs = getTemplateParameterLists();
+ return SourceRange(TPLs.empty() ? Info->TemplateParams->getTemplateLoc()
+ : TPLs.front()->getTemplateLoc(),
+ isThisDeclarationADefinition()
+ ? CXXRecordDecl::getSourceRange().getEnd()
+ : Info->TemplateArgsAsWritten->getRAngleLoc());
}
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition: {
- 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;
+ const auto *Info = getExplicitInstantiationInfo();
+ return SourceRange(Info->ExternKeywordLoc.isValid()
+ ? Info->ExternKeywordLoc
+ : Info->TemplateKeywordLoc,
+ Info->TemplateArgsAsWritten->getRAngleLoc());
}
}
llvm_unreachable("unhandled template specialization kind");
}
-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;
+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();
}
//===----------------------------------------------------------------------===//
@@ -1168,6 +1154,7 @@ 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)
@@ -1176,25 +1163,24 @@ ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
// Tracking StrictPackMatch for Partial
// Specializations is not needed.
SpecializedTemplate, Args, /*StrictPackMatch=*/false, PrevDecl),
- TemplateParams(Params), InstantiatedFromMember(nullptr, false),
+ InstantiatedFromMember(nullptr, false),
CanonInjectedTST(CanonInjectedTST) {
- if (AdoptTemplateParameterList(Params, this))
- setInvalidDecl();
+ setSpecializationKind(TSK_ExplicitSpecialization);
+ setExplicitSpecializationInfo(Params, ArgsAsWritten);
}
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");
- auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl(
- Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args,
- CanonInjectedTST, PrevDecl);
- Result->setSpecializationKind(TSK_ExplicitSpecialization);
- return Result;
+ return new (Context, DC) ClassTemplatePartialSpecializationDecl(
+ Context, TK, DC, StartLoc, IdLoc, Params, ArgsAsWritten,
+ SpecializedTemplate, Args, CanonInjectedTST, PrevDecl);
}
ClassTemplatePartialSpecializationDecl *
@@ -1221,11 +1207,7 @@ SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const {
getInstantiatedFromMember();
MT && !isMemberSpecialization())
return MT->getSourceRange();
- SourceRange Range = ClassTemplateSpecializationDecl::getSourceRange();
- if (const TemplateParameterList *TPL = getTemplateParameters();
- TPL && getTemplateParameterLists().empty())
- Range.setBegin(TPL->getTemplateLoc());
- return Range;
+ return ClassTemplateSpecializationDecl::getSourceRange();
}
//===----------------------------------------------------------------------===//
@@ -1484,8 +1466,11 @@ 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());
@@ -1493,10 +1478,11 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
}
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition: {
+ const auto *Info = getExplicitInstantiationInfo();
SourceRange Range = VarDecl::getSourceRange();
- if (SourceLocation ExternKW = getExternKeywordLoc(); ExternKW.isValid())
+ if (SourceLocation ExternKW = Info->ExternKeywordLoc; ExternKW.isValid())
Range.setBegin(ExternKW);
- else if (SourceLocation TemplateKW = getTemplateKeywordLoc();
+ else if (SourceLocation TemplateKW = Info->TemplateKeywordLoc;
TemplateKW.isValid())
Range.setBegin(TemplateKW);
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten())
@@ -1507,30 +1493,16 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
llvm_unreachable("unhandled template specialization kind");
}
-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;
+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();
}
//===----------------------------------------------------------------------===//
@@ -1542,28 +1514,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),
- TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
- if (AdoptTemplateParameterList(Params, DC))
- setInvalidDecl();
+ InstantiatedFromMember(nullptr, false) {
+ setSpecializationKind(TSK_ExplicitSpecialization);
+ setExplicitSpecializationInfo(Params, ArgsAsWritten);
}
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");
- auto *Result = new (Context, DC) VarTemplatePartialSpecializationDecl(
- Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, S,
- Args);
- Result->setSpecializationKind(TSK_ExplicitSpecialization);
- return Result;
+ return new (Context, DC) VarTemplatePartialSpecializationDecl(
+ Context, DC, StartLoc, IdLoc, Params, ArgsAsWritten, SpecializedTemplate,
+ T, TInfo, S, Args);
}
VarTemplatePartialSpecializationDecl *
@@ -1577,11 +1549,7 @@ SourceRange VarTemplatePartialSpecializationDecl::getSourceRange() const {
getInstantiatedFromMember();
MT && !isMemberSpecialization())
return MT->getSourceRange();
- SourceRange Range = VarTemplateSpecializationDecl::getSourceRange();
- if (const TemplateParameterList *TPL = getTemplateParameters();
- TPL && getTemplateParameterLists().empty())
- Range.setBegin(TPL->getTemplateLoc());
- return Range;
+ return VarTemplateSpecializationDecl::getSourceRange();
}
static TemplateParameterList *createBuiltinTemplateParameterList(
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 8373dd8e373e0..ffb3d74f6b9f4 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1131,6 +1131,9 @@ 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 f0064362abbc6..d90090b82fb7a 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1044,6 +1044,9 @@ 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 a04070971f0eb..8cb8d6ebf297f 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -99,6 +99,7 @@ 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 59fad2a41675c..b502870252119 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -690,7 +690,7 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
canResolveToExpr(Exp),
parmVarDecl(hasType(nonConstReferenceType())).bind("parm"));
const auto IsInstantiated = hasDeclaration(isInstantiated());
- const auto FuncDecl = hasDeclaration(functionDecl().bind("func"));
+ const auto FuncDecl = hasDeclaration(functionDecl());
const auto Matches = match(
traverse(
TK_AsIs,
@@ -704,13 +704,16 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
Stm, Context);
for (const auto &Nodes : Matches) {
const auto *Exp = Nodes.getNodeAs<Expr>(NodeID<Expr>::value);
- const auto *Func = Nodes.getNodeAs<FunctionDecl>("func");
- if (!Func->getBody() || !Func->getPrimaryTemplate())
+ const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
+ const auto *Func =
+ cast<FunctionDecl>(Parm->getDeclContext())->getDefinition();
+ if (!Func || !Func->doesThisDeclarationHaveABody())
return Exp;
+ Parm = Func->getParamDecl(Parm->getFunctionScopeIndex());
- const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
const ArrayRef<ParmVarDecl *> AllParams =
- Func->getPrimaryTemplate()->getTemplatedDecl()->parameters();
+ Func->getTemplateInstantiationPattern(/*ForDefinition=*/true)
+ ->parameters();
QualType ParmType =
AllParams[std::min<size_t>(Parm->getFunctionScopeIndex(),
AllParams.size() - 1)]
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
index 03d777cf7363a..cc2a1cfea8889 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
@@ -365,6 +365,7 @@ cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) {
: cir::GlobalLinkageKind::InternalLinkage;
return cir::GlobalLinkageKind::ExternalLinkage;
+ case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
return cir::GlobalLinkageKind::LinkOnceODRLinkage;
@@ -397,6 +398,7 @@ cir::GlobalLinkageKind CIRGenModule::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/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index 9e4218646669c..64fee965feda4 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -1152,21 +1152,22 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
return 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;
- }
+ 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;
+ }
}
// -fapple-kext mode does not support weak linkage, so we must use
@@ -1191,6 +1192,7 @@ 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 bdd6c5acf1d34..ac532d6a2f5ef 100644
--- a/clang/lib/Index/IndexingContext.cpp
+++ b/clang/lib/Index/IndexingContext.cpp
@@ -185,6 +185,7 @@ 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 53fbc36ae7600..08d2e556ad57c 100644
--- a/clang/lib/InstallAPI/Visitor.cpp
+++ b/clang/lib/InstallAPI/Visitor.cpp
@@ -318,6 +318,7 @@ 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:
@@ -334,6 +335,7 @@ static bool hasVTable(const CXXRecordDecl *D) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
+ case TSK_FriendDeclaration:
return false;
case TSK_ExplicitInstantiationDeclaration:
@@ -361,6 +363,7 @@ 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:
@@ -375,6 +378,7 @@ 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:
@@ -601,6 +605,7 @@ 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 893989bd2398f..86f18d10f08b0 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2059,15 +2059,17 @@ 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,
- MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]
- : nullptr,
- TemplateParams ? TemplateParams->size() : 0),
- &SkipBody);
+ SS, *TemplateId, attrs, ParamLists, &SkipBody);
+ // Some template parameter lists may have been dropped because they were
+ // extraneous.
+ if (TemplateParams)
+ TemplateParams->resize(ParamLists.size());
}
} else if (TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation &&
TUK == TagUseKind::Declaration) {
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 1d2a3983a639d..5006af55975ca 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -317,12 +317,6 @@ 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 =
@@ -330,8 +324,13 @@ addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
TemplateArgumentListInfo ArgsInfo =
TemplateArgumentListInfo(SourceLocation(), SourceLocation());
ArgsInfo.addArgument(ArgLoc);
- PartialSpec->setTemplateArgsAsWritten(
- ASTTemplateArgumentListInfo::Create(AST, ArgsInfo));
+
+ auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
+ AST, TagDecl::TagKind::Class, HLSLNamespace, SourceLocation(),
+ SourceLocation(), TemplateParams,
+ ASTTemplateArgumentListInfo::Create(AST, ArgsInfo), TextureTemplate,
+ {TemplateArgument(VectorType)},
+ CanQualType::CreateUnsafe(CanonInjectedTST), nullptr);
PartialSpec->setImplicit(true);
PartialSpec->setLexicalDeclContext(HLSLNamespace);
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index f41f37b8a3d19..32a07b6266666 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -200,15 +200,10 @@ static bool DiagRecursiveConstraintEval(
// Figure out the to-translation-unit depth for this function declaration for
// the purpose of seeing if they differ by constraints. This isn't the same as
// getTemplateDepth, because it includes already instantiated parents.
-static unsigned
-CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
- bool SkipForSpecialization = false) {
- MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
- ND, ND->getLexicalDeclContext(), /*Final=*/false,
- /*Innermost=*/std::nullopt,
- /*RelativeToPrimary=*/true,
- /*Pattern=*/nullptr,
- /*ForConstraintInstantiation=*/true, SkipForSpecialization);
+static unsigned CalculateTemplateDepthForConstraints(Sema &S,
+ const NamedDecl *ND) {
+ // FIXME: This is a very expensive way to calculate this.
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(ND);
return MLTAL.getNumLevels();
}
@@ -1335,10 +1330,8 @@ bool Sema::CheckConstraintSatisfaction(
return false;
}
-static ExprResult
-SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D,
- const ConceptSpecializationExpr *CSE,
- UnsignedOrNone SubstIndex) {
+static ExprResult SubstituteConceptsInConstraintExpression(
+ Sema &S, 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
@@ -1346,7 +1339,8 @@ SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D,
// If any such substitution results in an invalid concept-id,
// the program is ill-formed; no diagnostic is required.
- ConceptDecl *Concept = CSE->getNamedConcept()->getCanonicalDecl();
+ Expr *ConstraintExpr =
+ CSE->getNamedConcept()->getCanonicalDecl()->getConstraintExpr();
Sema::ArgPackSubstIndexRAII _(S, SubstIndex);
const ASTTemplateArgumentListInfo *ArgsAsWritten =
@@ -1356,23 +1350,17 @@ SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D,
return !ArgLoc.getArgument().isDependent() &&
ArgLoc.getArgument().isConceptOrConceptTemplateParameter();
})) {
- return Concept->getConstraintExpr();
+ return ConstraintExpr;
}
- MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
- Concept, Concept->getLexicalDeclContext(),
- /*Final=*/false, CSE->getTemplateArguments(),
- /*RelativeToPrimary=*/true,
- /*Pattern=*/nullptr,
- /*ForConstraintInstantiation=*/true);
- return S.SubstConceptTemplateArguments(CSE, Concept->getConstraintExpr(),
- MLTAL);
+ return S.SubstConceptTemplateArguments(
+ CSE, ConstraintExpr,
+ S.getTemplateInstantiationArgs(CSE->getSpecializationDecl()));
}
-bool Sema::SetupConstraintScope(
- FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
- const MultiLevelTemplateArgumentList &MLTAL,
- LocalInstantiationScope &Scope) {
+bool Sema::SetupConstraintScope(FunctionDecl *FD,
+ const MultiLevelTemplateArgumentList &MLTAL,
+ LocalInstantiationScope &Scope) {
assert(!isLambdaCallOperator(FD) &&
"Use LambdaScopeForCallOperatorInstantiationRAII to handle lambda "
"instantiations");
@@ -1381,8 +1369,7 @@ bool Sema::SetupConstraintScope(
InstantiatingTemplate Inst(
*this, FD->getPointOfInstantiation(),
Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate,
- TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
- SourceRange());
+ FD->getTemplateSpecializationArgs()->asArray(), SourceRange());
if (Inst.isInvalid())
return true;
@@ -1418,11 +1405,10 @@ bool Sema::SetupConstraintScope(
? FD->getInstantiatedFromMemberFunction()
: FD->getInstantiatedFromDecl();
- InstantiatingTemplate Inst(
- *this, FD->getPointOfInstantiation(),
- Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
- TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
- SourceRange());
+ InstantiatingTemplate Inst(*this, FD->getPointOfInstantiation(),
+ Sema::InstantiatingTemplate::ConstraintsCheck{},
+ InstantiatedFrom, ArrayRef<TemplateArgument>(),
+ SourceRange());
if (Inst.isInvalid())
return true;
@@ -1439,23 +1425,12 @@ bool Sema::SetupConstraintScope(
// constraint-instantiation and checking.
std::optional<MultiLevelTemplateArgumentList>
Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
- 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);
+ FunctionDecl *FD, LocalInstantiationScope &Scope) {
+ MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(FD);
// Lambdas are handled by LambdaScopeForCallOperatorInstantiationRAII.
if (isLambdaCallOperator(FD))
return MLTAL;
- if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
+ if (SetupConstraintScope(FD, MLTAL, Scope))
return std::nullopt;
return MLTAL;
@@ -1502,7 +1477,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;
@@ -1525,15 +1500,10 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
Satisfaction);
}
-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);
+static const Expr *
+SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
+ const Expr *ConstrExpr) {
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(ND);
if (MLTAL.getNumSubstitutedLevels() == 0)
return ConstrExpr;
@@ -1543,8 +1513,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
// this may happen while we're comparing two templates' constraint
// equivalence.
std::optional<LocalInstantiationScope> ScopeForParameters;
- if (const NamedDecl *ND = DeclInfo.getDecl();
- ND && ND->isFunctionOrFunctionTemplate()) {
+ if (ND->isFunctionOrFunctionTemplate()) {
ScopeForParameters.emplace(S, /*CombineWithOuterScope=*/true);
const FunctionDecl *FD = ND->getAsFunction();
if (FunctionTemplateDecl *Template = FD->getDescribedFunctionTemplate();
@@ -1588,13 +1557,9 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
// possible that e.g. constraints involving C<Class<T>> and C<Class> are
// perceived identical.
std::optional<Sema::ContextRAII> ContextScope;
- const DeclContext *DC = [&] {
- if (!DeclInfo.getDecl())
- return DeclInfo.getDeclContext();
- return DeclInfo.getDecl()->getFriendObjectKind()
- ? DeclInfo.getLexicalDeclContext()
- : DeclInfo.getDeclContext();
- }();
+ const DeclContext *DC = ND->getFriendObjectKind()
+ ? ND->getLexicalDeclContext()
+ : ND->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)),
@@ -1610,15 +1575,14 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
return SubstConstr.get();
}
-bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
- const Expr *OldConstr,
- const TemplateCompareNewDeclInfo &New,
+bool Sema::AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
+ const Decl *New,
const Expr *NewConstr) {
if (OldConstr == NewConstr)
return true;
// C++ [temp.constr.decl]p4
- if (Old && !New.isInvalid() && !New.ContainsDecl(Old) &&
- Old->getLexicalDeclContext() != New.getLexicalDeclContext()) {
+ if (Old != New &&
+ Old->getLexicalDeclContext() != New->getLexicalDeclContext()) {
Sema::SFINAETrap _(*this);
if (const Expr *SubstConstr =
SubstituteConstraintExpressionWithoutSatisfaction(*this, Old,
@@ -1640,19 +1604,15 @@ bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
return ID1 == ID2;
}
-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");
+bool Sema::FriendConstraintsDependOnEnclosingTemplate(
+ const FunctionTemplateDecl *FTD) {
+ assert(FTD->getFriendObjectKind() && "Must be a friend!");
SmallVector<AssociatedConstraint, 3> ACs;
- FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
+ FTD->getAssociatedConstraints(ACs);
- unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
+ const FunctionDecl *FD = FTD->getTemplatedDecl();
+ unsigned OldTemplateDepth = FTD->getTemplateDepth();
for (const AssociatedConstraint &AC : ACs)
if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
AC.ConstraintExpr))
@@ -1688,9 +1648,9 @@ bool Sema::EnsureTemplateArgumentListConstraints(
return false;
}
-static bool CheckFunctionConstraintsWithoutInstantiation(
- Sema &SemaRef, SourceLocation PointOfInstantiation,
- FunctionTemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
+bool Sema::CheckFunctionTemplateConstraints(
+ SourceLocation PointOfInstantiation, FunctionTemplateDecl *Template,
+ ArrayRef<TemplateArgument> TemplateArgs,
ConstraintSatisfaction &Satisfaction) {
SmallVector<AssociatedConstraint, 3> TemplateAC;
Template->getAssociatedConstraints(TemplateAC);
@@ -1699,47 +1659,22 @@ static bool CheckFunctionConstraintsWithoutInstantiation(
return false;
}
- LocalInstantiationScope Scope(SemaRef);
+ LocalInstantiationScope Scope(*this);
- 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.
+ MultiLevelTemplateArgumentList MLTAL =
+ getTemplateInstantiationArgs(Template, TemplateArgs);
- 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);
+ Sema::ContextRAII SavedContext(*this, Template->getTemplatedDecl());
+ return CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
+ PointOfInstantiation, Satisfaction);
}
-bool Sema::CheckFunctionTemplateConstraints(
+bool Sema::CheckFunctionSpecializationConstraints(
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();
-
- if (!Template)
- return ::CheckFunctionConstraintsWithoutInstantiation(
- *this, PointOfInstantiation, Decl->getDescribedFunctionTemplate(),
- TemplateArgs, Satisfaction);
+ assert(Template && "Function is not a specialization");
// Note - code synthesis context for the constraints check is created
// inside CheckConstraintsSatisfaction.
@@ -1756,8 +1691,7 @@ bool Sema::CheckFunctionTemplateConstraints(
LocalInstantiationScope Scope(*this);
std::optional<MultiLevelTemplateArgumentList> MLTAL =
- SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
- Scope);
+ SetupConstraintCheckingTemplateArgumentsAndScope(Decl, Scope);
if (!MLTAL)
return true;
@@ -2341,12 +2275,8 @@ bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
InnerArgs = std::move(CTAI.SugaredConverted);
}
- MultiLevelTemplateArgumentList MLTAL = SemaRef.getTemplateInstantiationArgs(
- Concept, Concept->getLexicalDeclContext(),
- /*Final=*/true, InnerArgs,
- /*RelativeToPrimary=*/true,
- /*Pattern=*/nullptr,
- /*ForConstraintInstantiation=*/true);
+ MultiLevelTemplateArgumentList MLTAL =
+ SemaRef.getTemplateInstantiationArgs(Concept, InnerArgs);
return SubstituteParameterMappings(SemaRef, &MLTAL,
CSE->getTemplateArgsAsWritten(),
@@ -2427,7 +2357,7 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
// [...]
NormalizedConstraint *SubNF;
if (ExprResult Res =
- SubstituteConceptsInConstraintExpression(S, D, CSE, SubstIndex);
+ SubstituteConceptsInConstraintExpression(S, CSE, SubstIndex);
Res.isUsable())
// Use canonical declarations to merge ConceptDecls across different
// modules.
@@ -2577,8 +2507,8 @@ bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1,
return false;
}
- unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
- unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
+ unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1);
+ unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2);
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 d1ddd3f6a1cc2..48ade20e0ddb3 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->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- /*Complain=*/true, TPL_TemplateMatch))
+ if (NewTemplate && !TemplateParameterListsAreEqual(
+ NewTemplate, NewTemplate->getTemplateParameters(),
+ OldTemplate, OldTemplate->getTemplateParameters(),
+ /*Complain=*/true, TPL_TemplateMatch))
return New->setInvalidDecl();
// C++ [class.mem]p1:
@@ -6414,20 +6414,7 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
return false;
// Cannot qualify members within a class.
- Diag(Loc, diag::err_member_qualification)
- << Name << SS.getRange();
- SS.clear();
-
- // C++ constructors and destructors with incorrect scopes can break
- // our AST invariants by having the wrong underlying types. If
- // that's the case, then drop this declaration entirely.
- if ((Name.getNameKind() == DeclarationName::CXXConstructorName ||
- Name.getNameKind() == DeclarationName::CXXDestructorName) &&
- !Context.hasSameType(
- Name.getCXXNameType(),
- Context.getCanonicalTagType(cast<CXXRecordDecl>(Cur))))
- return true;
-
+ Diag(Loc, diag::err_member_qualification) << Name << SS.getRange();
return false;
}
@@ -8029,6 +8016,8 @@ 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()
@@ -8071,10 +8060,8 @@ 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 =
- (TemplateParams && !IsExplicitSpecialization) ? 1 : 0;
+ IsVariableTemplate || IsVariableTemplateSpecialization ? 1 : 0;
if (TemplateParamLists.size() > VDTemplateParamLists)
NewVD->setTemplateParameterListsInfo(
Context, TemplateParamLists.drop_back(VDTemplateParamLists));
@@ -10125,6 +10112,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isMemberSpecialization = false;
bool isFunctionTemplateSpecialization = false;
+ TemplateParameterList *TemplateParams = nullptr;
bool HasExplicitTemplateArgs = false;
TemplateArgumentListInfo TemplateArgs;
@@ -10209,11 +10197,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
? D.getName().TemplateId
: nullptr;
- TemplateParameterList *TemplateParams =
- MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(), TemplateId, TemplateParamLists, isFriend,
- isMemberSpecialization, Invalid);
+ 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());
if (TemplateParams) {
// Check that we can declare a template here.
if (CheckTemplateDeclScope(S, TemplateParams))
@@ -10248,19 +10239,10 @@ 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;
- // For source fidelity, store all the template param lists.
- if (TemplateParamLists.size() > 0)
- NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists);
+ NewFD->setInnerLocStart(TemplateParams->getTemplateLoc());
// C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
if (isFriend) {
@@ -10290,6 +10272,12 @@ 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 &&
@@ -10891,11 +10879,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, ExplicitTemplateArgs, Previous))
+ NewFD, TemplateParams, ExplicitTemplateArgs, Previous))
NewFD->setInvalidDecl();
} else if (!NewFD->isInvalidDecl()) {
- if (CheckFunctionTemplateSpecialization(NewFD, ExplicitTemplateArgs,
- Previous))
+ if (CheckFunctionTemplateSpecialization(NewFD, TemplateParams,
+ ExplicitTemplateArgs, Previous))
NewFD->setInvalidDecl();
}
} else if (isMemberSpecialization && !FunctionTemplate) {
@@ -11218,7 +11206,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(NewFD)) {
+ FriendConstraintsDependOnEnclosingTemplate(FunctionTemplate)) {
NewFD->setFriendConstraintRefersToEnclosingTemplate(true);
// C++ [temp.friend]p9:
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 15c3b04942825..8a590e1def184 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13959,10 +13959,13 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
}
if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) {
- if (TemplateParameterListsAreEqual(TemplateParams,
- OldDecl->getTemplateParameters(),
- /*Complain=*/true,
- TPL_TemplateMatch))
+ // 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))
OldTemplateParams =
OldDecl->getMostRecentDecl()->getTemplateParameters();
else
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 62ecc52c0374b..0b819d05e72ef 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1129,9 +1129,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
return ExprError();
}
- DeclResult VDecl =
- CheckVarTemplateId(VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(),
- *TemplateArgs, /*SetWrittenArgs=*/false);
+ DeclResult VDecl = CheckVarTemplateId(
+ VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs);
if (VDecl.isInvalid())
return ExprError();
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index c8b05a9f94bd0..55ffdced0ea13 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -1325,8 +1325,10 @@ OverloadKind Sema::CheckOverload(Scope *S, FunctionDecl *New,
!New->getType()->isDependentType()) {
LookupResult TemplateSpecResult(LookupResult::Temporary, Old);
TemplateSpecResult.addAllDecls(Old);
- if (CheckFunctionTemplateSpecialization(New, nullptr, TemplateSpecResult,
- /*QualifiedFriend*/true)) {
+ if (CheckFunctionTemplateSpecialization(New, /*TemplateParams=*/nullptr,
+ /*ExplicitTemplateArgs=*/nullptr,
+ TemplateSpecResult,
+ /*QualifiedFriend*/ true)) {
New->setInvalidDecl();
return OverloadKind::Overload;
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 43bcd0bfb9e17..51eea4eedbf7a 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2131,19 +2131,71 @@ 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_different_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(
- TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext
- : CurContext,
- CurContext, KWLoc),
- TemplateParams, PrevClassTemplate,
+ NewTemplate, TemplateParams, PrevClassTemplate,
PrevClassTemplate->getTemplateParameters(), /*Complain=*/true,
- TPL_TemplateMatch))
+ TPL_TemplateMatch)) {
+ NewTemplate->setInvalidDecl();
+ NewClass->setInvalidDecl();
return true;
+ }
// C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit
@@ -2188,15 +2240,6 @@ 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_different_kind) << Name;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
- return true;
}
// Check the template parameter list of this declaration, possibly
@@ -2227,62 +2270,20 @@ DeclResult Sema::CheckClassTemplate(
<< SS.getRange();
}
- // 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,
- 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);
+ // Set the access specifier.
+ if (!Invalid && TUK != TagUseKind::Friend &&
+ NewTemplate->getDeclContext()->isRecord())
+ SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
- if (ShouldAddRedecl)
+ if (ShouldAddRedecl && PrevClassTemplate)
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();
@@ -2855,7 +2856,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;
@@ -3121,10 +3122,12 @@ 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(ParamLists[ParamIdx],
- ExpectedTemplateParams,
- !SuppressDiagnostic, TPL_TemplateMatch))
+ !TemplateParameterListsAreEqual(
+ /*NewInstFrom=*/nullptr, ParamLists[ParamIdx],
+ /*OldInstFrom=*/nullptr, ExpectedTemplateParams,
+ /*Complain=*/!SuppressDiagnostic, TPL_TemplateMatch))
Invalid = true;
if (!Invalid &&
@@ -3191,6 +3194,9 @@ 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).
@@ -4498,9 +4504,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplatePartialSpecializationDecl *Partial =
VarTemplatePartialSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
- TemplateNameLoc, TemplateParams, VarTemplate, TSI->getType(), TSI,
- SC, CTAI.CanonicalConverted);
- Partial->setTemplateArgsAsWritten(TemplateArgs);
+ TemplateNameLoc, TemplateParams,
+ ASTTemplateArgumentListInfo::Create(Context, TemplateArgs),
+ VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
@@ -4513,7 +4519,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
Specialization = VarTemplateSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
- Specialization->setTemplateArgsAsWritten(TemplateArgs);
+ Specialization->setExplicitSpecializationInfo(
+ TemplateParams,
+ ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
if (!PrevDecl)
VarTemplate->AddSpecialization(Specialization, InsertPos);
@@ -4599,8 +4607,7 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) {
DeclResult
Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation TemplateNameLoc,
- const TemplateArgumentListInfo &TemplateArgs,
- bool SetWrittenArgs) {
+ const TemplateArgumentListInfo &TemplateArgs) {
assert(Template && "A variable template id without template?");
// Check that the template argument list is well-formed for this template.
@@ -4799,8 +4806,6 @@ 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))
@@ -4818,7 +4823,7 @@ ExprResult Sema::CheckVarTemplateId(
const TemplateArgumentListInfo *TemplateArgs) {
DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
- *TemplateArgs, /*SetWrittenArgs=*/false);
+ *TemplateArgs);
if (Decl.isInvalid())
return ExprError();
@@ -6210,7 +6215,8 @@ bool Sema::CheckTemplateArgumentList(
if (UpdateArgsWithConversions)
TemplateArgs = std::move(NewArgs);
- if (!PartialTemplateArgs) {
+ // Template template parameters can never have their constraints checked.
+ if (!PartialTemplateArgs && !isa<TemplateTemplateParmDecl>(Template)) {
// Setup the context/ThisScope for the case where we are needing to
// re-instantiate constraints outside of normal instantiation.
DeclContext *NewContext = Template->getDeclContext();
@@ -6229,11 +6235,8 @@ bool Sema::CheckTemplateArgumentList(
ContextRAII Context(*this, NewContext);
CXXThisScopeRAII Scope(*this, RD, ThisQuals, RD != nullptr);
- MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
- Template, NewContext, /*Final=*/true, CTAI.SugaredConverted,
- /*RelativeToPrimary=*/true,
- /*Pattern=*/nullptr,
- /*ForConceptInstantiation=*/true);
+ MultiLevelTemplateArgumentList MLTAL =
+ getTemplateInstantiationArgs(Template, CTAI.SugaredConverted);
if (!isa<ConceptDecl>(Template) &&
EnsureTemplateArgumentListConstraints(
Template, MLTAL,
@@ -8224,9 +8227,8 @@ Sema::BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
/// Match two template parameters within template parameter lists.
static bool MatchTemplateParameterKind(
- Sema &S, NamedDecl *New,
- const Sema::TemplateCompareNewDeclInfo &NewInstFrom, NamedDecl *Old,
- const NamedDecl *OldInstFrom, bool Complain,
+ Sema &S, NamedDecl *New, const Decl *NewInstFrom, NamedDecl *Old,
+ const Decl *OldInstFrom, bool Complain,
Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
// Check the actual kind (type, non-type, template).
if (Old->getKind() != New->getKind()) {
@@ -8314,7 +8316,7 @@ static bool MatchTemplateParameterKind(
if (OldTTP->templateParameterKind() != NewTTP->templateParameterKind())
return false;
if (!S.TemplateParameterListsAreEqual(
- NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
+ NewTTP, NewTTP->getTemplateParameters(), OldTTP,
OldTTP->getTemplateParameters(), Complain,
(Kind == Sema::TPL_TemplateMatch
? Sema::TPL_TemplateTemplateParmMatch
@@ -8392,8 +8394,8 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
}
bool Sema::TemplateParameterListsAreEqual(
- const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
- const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+ const Decl *NewInstFrom, TemplateParameterList *New,
+ const Decl *OldInstFrom, TemplateParameterList *Old, bool Complain,
TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
if (Old->size() != New->size()) {
if (Complain)
@@ -8775,7 +8777,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;
@@ -8973,15 +8975,13 @@ 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(
@@ -9017,13 +9017,8 @@ 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);
@@ -9033,10 +9028,18 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// template specialization, make a note of that.
if (isMemberSpecialization)
Partial->setMemberSpecialization();
+ }
- CheckTemplatePartialSpecialization(Partial);
+ SetNestedNameSpecifier(*this, Specialization, SS);
+ if (TemplateParameterLists.size() > 1 && SS.isSet()) {
+ Specialization->setTemplateParameterListsInfo(
+ Context, TemplateParameterLists.drop_back(1));
}
+ 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
@@ -9396,6 +9399,7 @@ 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!");
@@ -9410,6 +9414,7 @@ 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
@@ -9456,6 +9461,7 @@ 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.
@@ -9491,6 +9497,7 @@ 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.
@@ -9550,7 +9557,8 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
}
bool Sema::CheckDependentFunctionTemplateSpecialization(
- FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
+ FunctionDecl *FD, const TemplateParameterList *TemplateParams,
+ const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous) {
// Remove anything from Previous that isn't a function template in
// the correct context.
@@ -9587,13 +9595,14 @@ bool Sema::CheckDependentFunctionTemplateSpecialization(
}
FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(),
- ExplicitTemplateArgs);
+ TemplateParams, ExplicitTemplateArgs);
return false;
}
bool Sema::CheckFunctionTemplateSpecialization(
- FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
- LookupResult &Previous, bool QualifiedFriend) {
+ FunctionDecl *FD, const TemplateParameterList *TemplateParams,
+ TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous,
+ bool QualifiedFriend) {
// The set of function template specializations that could match this
// explicit function template specialization.
UnresolvedSet<8> Candidates;
@@ -9843,9 +9852,11 @@ bool Sema::CheckFunctionTemplateSpecialization(
TemplateArgumentList *TemplArgs = TemplateArgumentList::CreateCopy(
Context, Specialization->getTemplateSpecializationArgs()->asArray());
FD->setFunctionTemplateSpecialization(
- Specialization->getPrimaryTemplate(), TemplArgs, /*InsertPos=*/nullptr,
- SpecInfo->getTemplateSpecializationKind(),
- ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr);
+ Context, Specialization->getPrimaryTemplate(), TemplArgs,
+ /*InsertPos=*/nullptr, SpecInfo->getTemplateSpecializationKind(),
+ TemplateParams,
+ ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr,
+ /*PointOfInstantiation=*/SourceLocation(), /*AddSpecialization=*/true);
// A function template specialization inherits the target attributes
// of its template. (We require the attributes explicitly in the
@@ -9995,14 +10006,13 @@ 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 && 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());
+ 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);
}
Previous.clear();
@@ -10089,7 +10099,8 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
template<typename DeclT>
static void completeMemberSpecializationImpl(Sema &S, DeclT *OrigD,
SourceLocation Loc) {
- if (OrigD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
+ if (auto Kind = OrigD->getTemplateSpecializationKind();
+ Kind != TSK_ImplicitInstantiation && Kind != TSK_FriendDeclaration)
return;
// FIXME: Inform AST mutation listeners of this AST mutation.
@@ -10419,7 +10430,6 @@ 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.
@@ -10438,22 +10448,19 @@ DeclResult Sema::ActOnExplicitInstantiation(
}
}
- Specialization->setTemplateArgsAsWritten(TemplateArgs);
-
- // Set source locations for keywords.
- Specialization->setExternKeywordLoc(ExternLoc);
- Specialization->setTemplateKeywordLoc(TemplateLoc);
+ Specialization->setExplicitInstantiationInfo(
+ ExternLoc, TemplateLoc,
+ ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
Specialization->setBraceRange(SourceRange());
bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>();
ProcessDeclAttributeList(S, Specialization, Attr);
ProcessAPINotes(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);
+ // Add the explicit instantiation into its lexical context.
+ auto *LexicalDC = ClassTemplate->getLexicalDeclContext();
+ Specialization->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDecl(Specialization);
// Syntax is now OK, so return if it has no other effect on semantics.
if (HasNoEffect) {
@@ -10782,6 +10789,15 @@ 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
@@ -10831,7 +10847,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}
- if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
+ if (!HasExplicitTemplateArgs) {
// C++1y [temp.explicit]p3:
// If the explicit instantiation is for a variable, the unqualified-id
// in the declaration shall be a template-id.
@@ -10843,13 +10859,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}
- // 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);
+ DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
+ D.getIdentifierLoc(), TemplateArgs);
if (Res.isInvalid())
return true;
@@ -10897,8 +10908,10 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// Instantiate static data member or variable template.
Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Prev)) {
- VTSD->setExternKeywordLoc(ExternLoc);
- VTSD->setTemplateKeywordLoc(TemplateLoc);
+ assert(HasExplicitTemplateArgs);
+ VTSD->setExplicitInstantiationInfo(
+ ExternLoc, TemplateLoc,
+ ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
}
// Merge attributes.
@@ -10927,15 +10940,6 @@ 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 d93b528facbcc..f57f60eb527ae 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3182,36 +3182,16 @@ CheckDeducedArgumentConstraints(Sema &S, NamedDecl *Template,
ArrayRef<TemplateArgument> CanonicalDeducedArgs,
TemplateDeductionInfo &Info) {
llvm::SmallVector<AssociatedConstraint, 3> AssociatedConstraints;
- bool DeducedArgsNeedReplacement = false;
- if (auto *TD = dyn_cast<ClassTemplatePartialSpecializationDecl>(Template)) {
+ if (auto *TD = dyn_cast<ClassTemplatePartialSpecializationDecl>(Template))
TD->getAssociatedConstraints(AssociatedConstraints);
- DeducedArgsNeedReplacement = !TD->isClassScopeExplicitSpecialization();
- } else if (auto *TD =
- dyn_cast<VarTemplatePartialSpecializationDecl>(Template)) {
+ else if (auto *TD = dyn_cast<VarTemplatePartialSpecializationDecl>(Template))
TD->getAssociatedConstraints(AssociatedConstraints);
- DeducedArgsNeedReplacement = !TD->isClassScopeExplicitSpecialization();
- } else {
+ 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, 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);
+ MultiLevelTemplateArgumentList MLTAL =
+ S.getTemplateInstantiationArgs(Template, SugaredDeducedArgs);
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
Info.getLocation(),
@@ -3974,9 +3954,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
bool IsLambda = isLambdaCallOperator(FD) || isLambdaConversionOperator(FD);
if (!IsLambda && !IsIncomplete) {
if (CheckFunctionTemplateConstraints(
- Info.getLocation(),
- FunctionTemplate->getCanonicalDecl()->getTemplatedDecl(),
- CTAI.CanonicalConverted, Info.AssociatedConstraintsSatisfaction))
+ Info.getLocation(), FunctionTemplate, CTAI.CanonicalConverted,
+ Info.AssociatedConstraintsSatisfaction))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
Info.reset(Info.takeSugared(), TemplateArgumentList::CreateCopy(
@@ -4022,8 +4001,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// ([temp.constr.constr]). If the constraints are not satisfied, type
// deduction fails.
if (IsLambda && !IsIncomplete) {
- if (CheckFunctionTemplateConstraints(
- Info.getLocation(), Specialization, CTAI.CanonicalConverted,
+ if (CheckFunctionSpecializationConstraints(
+ Info.getLocation(), Specialization,
Info.AssociatedConstraintsSatisfaction))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
@@ -6049,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(TPL1, TPL2, false,
+ if (!TemplateParameterListsAreEqual(FT1, TPL1, FT2, TPL2, false,
Sema::TPL_TemplateParamsEquivalent))
return nullptr;
@@ -6404,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(TPL1, TPL2, false,
+ if (!S.TemplateParameterListsAreEqual(P1, TPL1, P2, TPL2, false,
Sema::TPL_TemplateParamsEquivalent))
return nullptr;
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index fa740d5581e5f..15b6aea749584 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -65,10 +65,9 @@ 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, NewInfo, NewACs[I].ConstraintExpr))
+ if (!SemaRef.AreConstraintExpressionsEqual(Old, OldACs[I].ConstraintExpr,
+ New, NewACs[I].ConstraintExpr))
return false;
return true;
@@ -503,6 +502,7 @@ 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(Template);
+ OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(
+ Decl::castFromDeclContext(Template->getDeclContext()));
}
Sema &SemaRef;
@@ -1053,52 +1053,9 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
}
}
- // A list of template arguments for transforming the require-clause of F.
- // It must contain the entire set of template argument lists.
- MultiLevelTemplateArgumentList ArgsForBuildingRC;
+ MultiLevelTemplateArgumentList ArgsForBuildingRC =
+ SemaRef.getTemplateInstantiationArgs(F, TemplateArgsForBuildingRC);
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 4ba9414cfcdad..46571a188676e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -49,38 +49,6 @@ 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.
@@ -168,397 +136,197 @@ bool isLambdaEnclosedByTypeAliasDecl(
.TraverseType(Underlying);
}
-// 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);
-}
-
-// 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);
-}
+} // namespace
-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;
+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;
+ }
+ } 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());
- }
-
- 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();
+ 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;
}
- Result.addOuterTemplateArguments(
- TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
- /*Final=*/false);
- }
- }
-
- return Response::ChangeDecl(FTD->getLexicalDeclContext());
-}
-
-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);
- }
-
- 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());
+ 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();
}
+ 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;
}
- }
- return Response::UseNextDecl(Rec);
-}
+ // 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;
+ }
-Response HandleImplicitConceptSpecializationDecl(
- const ImplicitConceptSpecializationDecl *CSD,
- MultiLevelTemplateArgumentList &Result) {
- Result.addOuterTemplateArguments(
- const_cast<ImplicitConceptSpecializationDecl *>(CSD),
- CSD->getTemplateArguments(),
- /*Final=*/false);
- return Response::UseNextDecl(CSD);
-}
+ if (!Innermost)
+ continue;
-Response HandleGenericDeclContext(const Decl *CurDecl) {
- return Response::UseNextDecl(CurDecl);
-}
-} // namespace TemplateInstArgsHelpers
-} // namespace
+ 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;
+ }
-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);
+ 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;
}
- } else {
- R = HandleGenericDeclContext(CurDecl);
+ for (unsigned I = 0; I < ExtraLevels; ++I)
+ TemplateArgs.addOuterTemplateArguments(std::nullopt);
}
-
- if (R.IsDone)
- return Result;
- if (R.ClearRelativeToPrimary)
- RelativeToPrimary = false;
- assert(R.NextDecl);
- CurDecl = R.NextDecl;
}
- return Result;
+ return TemplateArgs;
}
bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
@@ -1741,10 +1509,8 @@ namespace {
CXXRecordDecl::LambdaDependencyKind
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
- if (auto TypeAlias =
- TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
- getSema());
- TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
+ if (auto TypeAlias = ::getEnclosingTypeAliasTemplateDecl(getSema());
+ TypeAlias && ::isLambdaEnclosedByTypeAliasDecl(
LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
@@ -4100,6 +3866,9 @@ 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());
@@ -4123,9 +3892,12 @@ bool Sema::InstantiateClassTemplateSpecialization(
if (!Pattern.isUsable())
return Pattern.isInvalid();
- bool Err = InstantiateClassImpl(
- PointOfInstantiation, ClassTemplateSpec, Pattern.get(),
- getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ ClassTemplateSpec, /*Innermost=*/std::nullopt,
+ /*NumLevels=*/Pattern.get()->getTemplateDepth());
+
+ bool Err = InstantiateClassImpl(PointOfInstantiation, ClassTemplateSpec,
+ Pattern.get(), TemplateArgs, TSK, Complain);
// If we haven't already warn on avaibility, consider the avaibility
// attributes of the partial specialization.
@@ -4487,14 +4259,7 @@ ExprResult Sema::SubstConceptTemplateArguments(
[](const TemplateArgumentLoc &Loc) { return Loc.getArgument(); });
MultiLevelTemplateArgumentList MLTALForConstraint =
- getTemplateInstantiationArgs(
- CSE->getNamedConcept(),
- CSE->getNamedConcept()->getLexicalDeclContext(),
- /*Final=*/false,
- /*Innermost=*/NewArgList,
- /*RelativeToPrimary=*/true,
- /*Pattern=*/nullptr,
- /*ForConstraintInstantiation=*/true);
+ getTemplateInstantiationArgs(CSE->getNamedConcept(), NewArgList);
// 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 a787d537f02f8..f18811c5beab5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -49,40 +49,63 @@ 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) {
- if (!OldDecl->getQualifierLoc())
- return false;
+ 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()));
- 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(),
+ 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);
+ return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs, Owner);
}
bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl) {
- return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
+ return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs, Owner);
}
// Include attribute instantiation code.
@@ -1736,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(),
@@ -2382,8 +2405,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Make sure the parameter lists match.
if (!SemaRef.TemplateParameterListsAreEqual(
- RecordInst, InstParams, MostRecentPrevCT->getTemplatedDecl(),
- PrevParams, true, Sema::TPL_TemplateMatch))
+ RecordInst, InstParams, MostRecentPrevCT, PrevParams, true,
+ Sema::TPL_TemplateMatch))
return nullptr;
// Do some additional validation, then merge default arguments
@@ -2711,6 +2734,23 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
NewFunc->getParamTypes(), NewEPI);
}
+static void mergeFunctionDecl(Sema &SemaRef, FunctionDecl *NewFD, QualType NewT,
+ FunctionDecl *OldFD) {
+ SemaRef.mergeDeclAttributes(NewFD, OldFD);
+
+ if (QualType OT = OldFD->getReturnType();
+ OT != NewT->castAs<FunctionType>()->getReturnType()) {
+ // If this function has a deduced return type and has already been
+ // defined, copy the deduced value from the old declaration.
+ if (AutoType *OldAT = OT->getContainedAutoType();
+ OldAT && OldAT->isDeduced()) {
+ QualType DT = OldAT->getDeducedType();
+ NewFD->setType(DT.isNull() ? SemaRef.SubstAutoTypeDependent(NewT)
+ : SemaRef.SubstAutoType(NewT, DT));
+ }
+ }
+}
+
/// Normal class members are of more specific types and therefore
/// don't make it here. This function serves three purposes:
/// 1) instantiating function templates
@@ -2741,16 +2781,21 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
}
}
+ FunctionDecl *PrevDecl = nullptr;
if (FunctionTemplate && !TemplateParams) {
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
void *InsertPos = nullptr;
- FunctionDecl *SpecFunc
- = FunctionTemplate->findSpecialization(Innermost, InsertPos);
-
- // If we already have a function template specialization, return it.
- if (SpecFunc)
- return SpecFunc;
+ 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;
+ }
}
bool MergeWithParentScope = (TemplateParams != nullptr) ||
@@ -2843,6 +2888,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
D->FriendConstraintRefersToEnclosingTemplate());
Function->setRangeEnd(D->getSourceRange().getEnd());
}
+ Function->setPreviousDeclaration(PrevDecl);
+ if (PrevDecl)
+ mergeFunctionDecl(SemaRef, Function, T, PrevDecl);
if (D->isInlined())
Function->setImplicitlyInline();
@@ -2899,6 +2947,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
FunctionTemplate->setLexicalDeclContext(LexicalDC);
+ if (PrevDecl)
+ FunctionTemplate->setPreviousDecl(
+ PrevDecl->getDescribedFunctionTemplate());
+
if (isFriend && D->isThisDeclarationADefinition()) {
FunctionTemplate->setInstantiatedFromMemberTemplate(
D->getDescribedFunctionTemplate());
@@ -2908,10 +2960,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
Sema::CodeSynthesisContext::BuildingDeductionGuides) {
// Record this function template specialization.
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
- Function->setFunctionTemplateSpecialization(FunctionTemplate,
- TemplateArgumentList::CreateCopy(SemaRef.Context,
- Innermost),
- /*InsertPos=*/nullptr);
+ Function->setFunctionTemplateSpecialization(
+ SemaRef.Context, FunctionTemplate,
+ TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost),
+ /*InsertPos=*/nullptr, /*TSK=*/TSK_ImplicitInstantiation,
+ /*TemplateParams=*/nullptr,
+ /*TemplateArgsAsWritten=*/nullptr,
+ /*PointOfInstantiation=*/SourceLocation(),
+ /*AddSpecialization=*/PrevDecl == nullptr);
} else if (FunctionRewriteKind == RewriteKind::None) {
if (isFriend && D->isThisDeclarationADefinition()) {
// Do not connect the friend to the template unless it's actually a
@@ -2969,7 +3025,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
}
if (SemaRef.CheckFunctionTemplateSpecialization(
- Function,
+ Function, DFTSI->TemplateParameters ? TemplateParams : nullptr,
DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Previous))
Function->setInvalidDecl();
@@ -2987,9 +3043,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
ExplicitArgs))
return nullptr;
- if (SemaRef.CheckFunctionTemplateSpecialization(Function,
- &ExplicitArgs,
- Previous))
+ if (SemaRef.CheckFunctionTemplateSpecialization(Function, TemplateParams,
+ &ExplicitArgs, Previous))
Function->setInvalidDecl();
IsExplicitSpecialization = true;
@@ -3106,6 +3161,8 @@ 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
@@ -3113,12 +3170,16 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
void *InsertPos = nullptr;
- FunctionDecl *SpecFunc
- = FunctionTemplate->findSpecialization(Innermost, InsertPos);
-
- // If we already have a function template specialization, return it.
- if (SpecFunc)
- return SpecFunc;
+ 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;
+ }
}
bool isFriend;
@@ -3135,19 +3196,6 @@ 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 =
@@ -3273,6 +3321,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
D->UsesFPIntrin(), D->isInlineSpecified(), D->getConstexprKind(),
D->getEndLoc(), TrailingRequiresClause);
}
+ Method->setPreviousDeclaration(PrevDecl);
+ if (PrevDecl)
+ mergeFunctionDecl(SemaRef, Method, T, PrevDecl);
if (D->isInlined())
Method->setImplicitlyInline();
@@ -3304,25 +3355,33 @@ 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(FunctionTemplate,
- TemplateArgumentList::CreateCopy(SemaRef.Context,
- Innermost),
- /*InsertPos=*/nullptr);
+ Method->setFunctionTemplateSpecialization(
+ SemaRef.Context, FunctionTemplate,
+ TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost),
+ /*InsertPos=*/nullptr, /*TSK=*/TSK_ImplicitInstantiation,
+ /*TemplateParams=*/nullptr,
+ /*TemplateArgsAsWritten=*/nullptr,
+ /*PointOfInstantiation=*/SourceLocation(),
+ /*AddSpecialization=*/PrevDecl == 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())
@@ -3365,7 +3424,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
}
if (SemaRef.CheckFunctionTemplateSpecialization(
- Method, DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
+ Method, DFTSI->TemplateParameters,
+ DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Previous))
Method->setInvalidDecl();
@@ -3381,9 +3441,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
ExplicitArgs))
return nullptr;
- if (SemaRef.CheckFunctionTemplateSpecialization(Method,
- &ExplicitArgs,
- Previous))
+ if (SemaRef.CheckFunctionTemplateSpecialization(Method, TemplateParams,
+ &ExplicitArgs, Previous))
Method->setInvalidDecl();
IsExplicitSpecialization = true;
@@ -4513,16 +4572,22 @@ 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;
- if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
- D->getTemplateArgsAsWritten()) {
- InstTemplateArgs.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
- InstTemplateArgs.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
-
- if (SemaRef.SubstTemplateArguments(TemplateArgsInfo->arguments(),
- TemplateArgs, 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))
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.
@@ -4577,7 +4642,14 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
D->getLocation(), InstClassTemplate, CTAI.CanonicalConverted,
CTAI.StrictPackMatch, PrevDecl);
- InstD->setTemplateArgsAsWritten(InstTemplateArgs);
+ 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);
// Add this partial specialization to the set of class template partial
// specializations.
@@ -4591,8 +4663,6 @@ 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);
@@ -4612,7 +4682,6 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *D) {
- TemplateArgumentListInfo VarTemplateArgsInfo;
VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
assert(VarTemplate &&
"A template specialization without specialized template?");
@@ -4623,9 +4692,15 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
if (!InstVarTemplate)
return nullptr;
+ assert(!D->getExplicitInstantiationInfo());
+ const auto *ExplicitSpecializationInfo = D->getExplicitSpecializationInfo();
// Substitute the current template arguments.
- if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
- D->getTemplateArgsAsWritten()) {
+ TemplateArgumentListInfo VarTemplateArgsInfo;
+ if (ExplicitSpecializationInfo) {
+ // The template parameters for an explicit specialization are empty and
+ // never need to be transformed.
+ const auto *TemplateArgsInfo =
+ ExplicitSpecializationInfo->TemplateArgsAsWritten;
VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
@@ -4656,12 +4731,17 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
PrevDecl->getPointOfInstantiation(), Ignored))
return nullptr;
- if (VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
- InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl)) {
- VTSD->setTemplateArgsAsWritten(VarTemplateArgsInfo);
- return VTSD;
- }
- 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;
}
VarTemplateSpecializationDecl *
@@ -4670,6 +4750,8 @@ 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,
@@ -4925,16 +5007,17 @@ 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;
@@ -5051,10 +5134,11 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
VarTemplatePartialSpecializationDecl *InstPartialSpec =
VarTemplatePartialSpecializationDecl::Create(
SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
- PartialSpec->getLocation(), InstParams, VarTemplate, TSI->getType(),
- TSI, PartialSpec->getStorageClass(), CTAI.CanonicalConverted);
-
- InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
+ PartialSpec->getLocation(), InstParams,
+ ASTTemplateArgumentListInfo::Create(SemaRef.Context,
+ InstTemplateArgs),
+ VarTemplate, TSI->getType(), TSI, PartialSpec->getStorageClass(),
+ CTAI.CanonicalConverted);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
@@ -5289,8 +5373,11 @@ 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
@@ -5298,37 +5385,51 @@ 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 (FD->getFriendObjectKind() != Decl::FOK_None &&
- !FD->getTemplateInstantiationPattern())
+ if (!PatternDecl)
return true;
- // 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);
+ ParmVarDecl *OrigParam = Param;
+
+ 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 {
+ FunctionDecl *OrigFD = FD;
+ if (Info) {
+ FD = InstantiateFunctionDeclaration(
+ cast<FunctionTemplateDecl>(Info->getTemplate()->getFirstDecl()),
+ Info->TemplateArguments, CallLoc);
+ // The above should always succeed for valid code, but may fail due to
+ // error recovery. For example, if both a fatal error and an uncompilable
+ // error occur, we stop instantiating templates at all.
+ if (!FD)
+ return true;
+ } else {
+ FD = FD->getFirstDecl();
+ }
+ if (FD != OrigFD)
+ Param =
+ cast<ParmVarDecl>(FD->getParamDecl(Param->getFunctionScopeIndex()));
- if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
+ TemplateArgs =
+ getTemplateInstantiationArgs(FD, /*Innermost=*/std::nullopt, NumLevels);
+ }
+
+ // Instantiate the expression.
+ if (Param->hasUninstantiatedDefaultArg() &&
+ SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
+ if (Param != OrigParam)
+ OrigParam->setDefaultArg(Param->getDefaultArg());
+
if (ASTMutationListener *L = getASTMutationListener())
L->DefaultArgumentInstantiated(Param);
@@ -5366,16 +5467,22 @@ 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;
@@ -5539,7 +5646,10 @@ FunctionDecl *Sema::InstantiateFunctionDeclaration(
MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray(),
/*Final=*/false);
- return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs));
+ return cast_or_null<FunctionDecl>(SubstDecl(
+ FD,
+ isa<CXXMethodDecl>(FD) ? FD->getParent() : FD->getLexicalDeclContext(),
+ MArgs));
}
void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
@@ -5894,36 +6004,61 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
RebuildTypeSourceInfoForDefaultSpecialMembers();
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
- 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());
+ 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);
+ // This should always succeed for well-formed code.
+ if (!NewFunction)
+ return;
+
+ assert(NewFunction != Function && "Expected a new specialization");
+ assert(declaresSameEntity(NewFunction, Function));
+ if (TemplateSpecializationKind TSK =
+ Info->getTemplateSpecializationKind();
+ TSK == TSK_ExplicitInstantiationDefinition ||
+ TSK == TSK_ExplicitInstantiationDeclaration)
+ NewFunction->setTemplateSpecializationKind(
+ TSK, Info->getPointOfInstantiation());
+ 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");
}
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
- 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);
+ Function, /*Innermost=*/std::nullopt,
+ /*NumLevels=*/PatternDecl->getTemplateDepth(),
+ /*SkipInnerNonInstantiated=*/true);
ActOnStartOfFunctionDef(nullptr, Function);
@@ -6290,6 +6425,8 @@ 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;
@@ -6307,8 +6444,9 @@ 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);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ Var, /*Innermost=*/std::nullopt,
+ /*NumLevels=*/PatternDecl->getTemplateDepth());
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
@@ -6469,15 +6607,6 @@ 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,
@@ -6485,7 +6614,13 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
Var = VTSD;
if (Var) {
- VTSD->setTemplateArgsAsWritten(TemplateArgInfo);
+ 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);
llvm::PointerUnion<VarTemplateDecl *,
VarTemplatePartialSpecializationDecl *> PatternPtr =
@@ -7275,6 +7410,7 @@ 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 f484bc7e0bf55..4a6208e0cece3 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -905,9 +905,10 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
if (Record.readInt()) { // hasExtInfo
auto *Info = new (Reader.getContext()) DeclaratorDecl::ExtInfo();
Record.readQualifierInfo(*Info);
- Info->TrailingRequiresClause = AssociatedConstraint(
- Record.readExpr(),
- UnsignedOrNone::fromInternalRepresentation(Record.readUInt32()));
+ Expr *ConstraintExpr = Record.readExpr();
+ UnsignedOrNone ArgPackSubstIndex = Record.readUnsignedOrNone();
+ Info->TrailingRequiresClause =
+ AssociatedConstraint(ConstraintExpr, ArgPackSubstIndex);
DD->DeclInfo = Info;
}
QualType TSIType = Record.readType();
@@ -949,6 +950,9 @@ 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();
@@ -973,7 +977,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FunctionTemplateSpecializationInfo *FTInfo =
FunctionTemplateSpecializationInfo::Create(
- C, FD, Template, TSK, TemplArgList,
+ C, FD, Template, TSK, TemplArgList, TemplateParams,
HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr, POI,
MSInfo);
FD->TemplateOrSpecialization = FTInfo;
@@ -1008,6 +1012,9 @@ 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();
@@ -1015,7 +1022,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
Record.readTemplateArgumentListInfo(TemplArgsWritten);
FD->setDependentTemplateSpecialization(
- Reader.getContext(), Candidates,
+ Reader.getContext(), Candidates, TemplateParams,
HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr);
// These are not merged; we don't need to merge redeclarations of dependent
// template friends.
@@ -2559,6 +2566,20 @@ 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>();
@@ -2589,27 +2610,11 @@ 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) {
- // We need to read the template params first because redeclarable is going to
- // need them for profiling
- TemplateParameterList *Params = Record.readTemplateParameterList();
- D->TemplateParams = Params;
-
+ ClassTemplatePartialSpecializationDecl *D) {
RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
// These are read/set from/to the first declaration.
@@ -2655,17 +2660,6 @@ 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);
@@ -2673,6 +2667,20 @@ 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();
@@ -2703,9 +2711,6 @@ 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 e3b81650d65a1..5e9ae27c9410f 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -805,6 +805,10 @@ 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)
@@ -839,6 +843,10 @@ 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)
@@ -1748,6 +1756,7 @@ 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());
@@ -1756,7 +1765,8 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
FunctionDecl::TK_DependentFunctionTemplateSpecialization) {
DependentFunctionTemplateSpecializationInfo *DFTSInfo =
D->getDependentSpecializationInfo();
- if (!DFTSInfo->TemplateArgumentsAsWritten)
+ if (!DFTSInfo->TemplateArgumentsAsWritten &&
+ !DFTSInfo->TemplateParameters)
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
}
}
@@ -1943,29 +1953,36 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
Record.AddSourceLocation(D->getPointOfInstantiation());
Record.push_back(D->getSpecializationKind());
Record.push_back(D->hasStrictPackMatch());
- Record.push_back(D->isCanonicalDecl());
+ 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.
//
@@ -1987,9 +2004,7 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
}
void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
- ClassTemplatePartialSpecializationDecl *D) {
- Record.AddTemplateParameterList(D->getTemplateParameters());
-
+ ClassTemplatePartialSpecializationDecl *D) {
VisitClassTemplateSpecializationDecl(D);
// These are read/set from/to the first declaration.
@@ -2022,27 +2037,34 @@ 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());
@@ -2061,8 +2083,6 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
- Record.AddTemplateParameterList(D->getTemplateParameters());
-
VisitVarTemplateSpecializationDecl(D);
// These are read/set from/to the first declaration.
@@ -2439,6 +2459,7 @@ 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));
@@ -2448,6 +2469,7 @@ 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 6c1a55f79b908..abc4b4179204b 100644
--- a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
@@ -166,55 +166,6 @@ 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
@@ -229,41 +180,19 @@ template <class T> static const T *chooseDefinitionRedecl(const T *Tmpl) {
// attribute.
//
// The function handles specializations (and partial specializations) of
-// class and function templates.
-// For any other decl, it returns the input unchagned.
+// class templates.
+// For any other decl, it returns the input unchanged.
static const Decl *
preferTemplateDefinitionForTemplateSpecializations(const Decl *D) {
- // 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)
+ const auto *RD = dyn_cast<CXXRecordDecl>(D);
+ if (!RD)
return D;
-
- 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)));
+ if (const CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern())
+ RD = Pattern;
+ RD = RD->getDefinitionOrSelf();
+ if (const auto *CTD = RD->getDescribedClassTemplate())
+ return CTD;
+ return RD;
}
bool BugSuppression::isSuppressed(const PathDiagnosticLocation &Location,
diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp
index 3d3acea89d170..c8088f622e185 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;
- if (C->isExplicitSpecialization())
+ const auto *Info = C->getExplicitInstantiationInfo();
+ if (!Info)
return true; // we are only interested in explicit instantiations.
auto *Declaration =
cast<syntax::SimpleDeclaration>(handleFreeStandingTagDecl(C));
foldExplicitTemplateInstantiation(
- Builder.getTemplateRange(C),
- Builder.findToken(C->getExternKeywordLoc()),
- Builder.findToken(C->getTemplateKeywordLoc()), Declaration, C);
+ Builder.getTemplateRange(C), Builder.findToken(Info->ExternKeywordLoc),
+ Builder.findToken(Info->TemplateKeywordLoc), Declaration, C);
return true;
}
@@ -778,8 +778,9 @@ class BuildTreeVisitor : public RecursiveASTVisitor<BuildTreeVisitor> {
foldTemplateDeclaration(R, TemplateKW, DeclarationRange, nullptr);
DeclarationRange = R;
};
- if (auto *S = dyn_cast<ClassTemplatePartialSpecializationDecl>(C))
- ConsumeTemplateParameters(*S->getTemplateParameters());
+ if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(C))
+ if (const auto *Info = S->getExplicitSpecializationInfo())
+ ConsumeTemplateParameters(*Info->TemplateParams);
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 aec86664f9988..705c9c967c7ef 100644
--- a/clang/test/AST/ast-dump-templates-pattern.cpp
+++ b/clang/test/AST/ast-dump-templates-pattern.cpp
@@ -32,11 +32,12 @@ 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 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 {{.+}} prev 0x[[TestFunctionRedecl_S1:[^ ]+]] <col:22, col:32> col:27 f 'void ()' explicit_instantiation_definition 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_D2]] prev 0x[[TestFunctionRedecl_D1]] {{.+}} f 'void ()'
// CHECK: | `-Function 0x[[TestFunctionRedecl_S1]] 'f' 'void ()'
-// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-8]]:{{.+}} 'f'
+// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-9]]:{{.+}} 'f'
// CHECK: |-Function 0x[[TestFunctionRedecl_S1]] 'f' 'void ()'
// CHECK: |-FunctionProtoTypeLoc {{.+}} 'void ()' cdecl
// CHECK: | `-BuiltinTypeLoc {{.+}} 'void'
@@ -76,15 +77,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: |-ClassTemplateDecl 0x{{.+}} prev 0x[[TestNestedClassRedecl_A_T1]] <line:[[@LINE-12]]:{{.+}} 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: | `-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: | |-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-14]]:{{.+}} B external-linkage
+// CHECK: |-ClassTemplateDecl 0x{{.+}} parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_T1]] <line:[[@LINE-15]]:{{.+}} 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 7f6a88d4a63f1..ab7b6cf99d0f6 100644
--- a/clang/test/CXX/basic/basic.link/p11.cpp
+++ b/clang/test/CXX/basic/basic.link/p11.cpp
@@ -5,7 +5,6 @@ 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}}
@@ -14,7 +13,6 @@ 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/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index f0424a1021abc..32c66282162b9 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -283,16 +283,20 @@ auto e = [] {
namespace cwg1821 { // cwg1821: 2.9
struct A {
template <typename> struct B {
- void f();
+ void f(); // #cwg1821-B-f
};
template <typename T> void B<T>::f(){};
// expected-error at -1 {{non-friend class member 'f' cannot have a qualified name}}
+ // expected-error at -2 {{class member cannot be redeclared}}
+ // expected-note@#cwg1821-B-f {{previous declaration is here}}
struct C {
- void f();
+ void f(); // #cwg1821-C-f
};
void C::f() {}
// expected-error at -1 {{non-friend class member 'f' cannot have a qualified name}}
+ // expected-error at -2 {{class member cannot be redeclared}}
+ // expected-note@#cwg1821-C-f {{previous declaration is here}}
};
} // namespace cwg1821
diff --git a/clang/test/CXX/drs/cwg7xx.cpp b/clang/test/CXX/drs/cwg7xx.cpp
index ca712333f9410..3c169c71ce3b4 100644
--- a/clang/test/CXX/drs/cwg7xx.cpp
+++ b/clang/test/CXX/drs/cwg7xx.cpp
@@ -138,7 +138,8 @@ namespace cwg727 { // cwg727: partial
// expected-note@#cwg727-C {{explicitly specialized declaration is here}}
template<> void A::f<double>();
// expected-error at -1 {{non-friend class member 'f' cannot have a qualified name}}
- // expected-error at -2 {{no function template matches function template specialization 'f'}}
+ // expected-error at -2 {{function template specialization of 'f' not in class 'A' or an enclosing namespace}}
+ // expected-note@#cwg727-f {{explicitly specialized declaration is here}}
template<> int A::N<double>;
// expected-error at -1 {{non-friend class member 'N' cannot have a qualified name}}
// expected-error at -2 {{variable template specialization of 'N' not in class 'A' or an enclosing namespace}}
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 342ffba53dbfa..ae8d5917a9664 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,18 +73,15 @@ template <class> struct S {};
template<template<True 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<template<False T> typename Wrapper>
+using Test = Wrapper<int>;
template <typename U, template<False> typename T>
void foo(T<U>); // #foo
void bar() {
- 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]}}
+ // FIXME: CWG2980: There is no way to check the constraints on the template template parameter.
+ foo<int>(S<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 fefe86a448b18..70064f867e18e 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,10 +1,11 @@
// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
template<typename T>
concept D = true;
template<typename T>
-struct A { // expected-note {{defined here}}
+struct A {
template<typename U, bool V>
void f() requires V;
@@ -16,7 +17,6 @@ struct A { // expected-note {{defined here}}
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,14 +26,12 @@ struct A { // expected-note {{defined here}}
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>;
@@ -43,7 +41,6 @@ struct A { // expected-note {{defined here}}
template<D U>
static int y;
- // expected-note at -2 {{previous template declaration is here}}
template<D U>
static int y<U*>;
@@ -97,11 +94,9 @@ 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<>
@@ -115,11 +110,9 @@ 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 differs in template redeclaration}}
template<>
template<>
@@ -137,11 +130,9 @@ 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 differs in template redeclaration}}
template<>
template<D U>
@@ -151,11 +142,9 @@ 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 differs in template redeclaration}}
template<>
template<>
@@ -173,11 +162,9 @@ 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 differs 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 20121d6cf5743..a39d3a8fea15d 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,4 +1,5 @@
// 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 af07024cb7af5..e7e4738032f64 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,28 +180,20 @@ 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<>
@@ -209,43 +201,36 @@ 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 differs 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 differs 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 differs in template redeclaration}}
template<>
template<typename U, bool V> requires V
@@ -256,7 +241,6 @@ namespace Constrained {
struct A<long>::B {
static constexpr int y = 1;
};
- // FIXME expected-error at -4 {{requires clause differs in template redeclaration}}
template<>
template<typename U, bool V> requires V
@@ -274,17 +258,10 @@ 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/CodeGenCXX/default-arguments.cpp b/clang/test/CodeGenCXX/default-arguments.cpp
index 2459ef1ad41fc..3881d7f04ccac 100644
--- a/clang/test/CodeGenCXX/default-arguments.cpp
+++ b/clang/test/CodeGenCXX/default-arguments.cpp
@@ -85,3 +85,15 @@ void f4() {
// CHECK: call void @_Z2g4ii(i32 noundef 5, i32 noundef 7)
g4();
}
+
+namespace LambdaTemplateRedecl1 {
+ struct A {
+ template <class T> A(T) {}
+ };
+ template <class> void f(A = []{});
+ void t1() { f<int>(); }
+ template <class> void f(A);
+ void t2() { f<int>(); }
+ // CHECK-LABEL: define internal void @"_ZN21LambdaTemplateRedecl11AC1IZNS_1fIiEEvS0_E3$_0EET_"
+ // CHECK-LABEL: define internal void @"_ZN21LambdaTemplateRedecl11AC2IZNS_1fIiEEvS0_E3$_0EET_"
+} // namespace LambdaTemplateRedecl1
diff --git a/clang/test/CodeGenCXX/explicit-instantiation.cpp b/clang/test/CodeGenCXX/explicit-instantiation.cpp
index b7fe82f4db921..c9768ef9c5249 100644
--- a/clang/test/CodeGenCXX/explicit-instantiation.cpp
+++ b/clang/test/CodeGenCXX/explicit-instantiation.cpp
@@ -171,6 +171,13 @@ void use() {
}
}
+namespace Redecl1 {
+ template <class> void f();
+ template void f<int>();
+ template <class> void f() {}
+ // CHECK-LABEL: define weak_odr void @_ZN7Redecl11fIiEEvv
+} // namespace Redecl1
+
namespace DefaultedMembers {
struct B { B(); B(const B&); ~B(); };
template<typename T> struct A : B {
diff --git a/clang/test/Modules/GH208100.cpp b/clang/test/Modules/GH208100.cpp
new file mode 100644
index 0000000000000..87e4c208be9f3
--- /dev/null
+++ b/clang/test/Modules/GH208100.cpp
@@ -0,0 +1,28 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+// RUN: cd %t
+//
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface B.cppm -o B.pcm
+// RUN: %clang_cc1 -std=c++20 -fmodule-file=B=B.pcm -fsyntax-only C.cpp
+
+//--- A.h
+struct deduced {
+ template<typename = void> auto operator()() const {}
+};
+
+//--- B.cppm
+module;
+
+#include "A.h"
+
+export module B;
+
+export template<class> void b() {
+ deduced()();
+}
+
+//--- C.cpp
+#include "A.h"
+import B;
+template void b<void>();
diff --git a/clang/test/SemaCXX/GH195416.cpp b/clang/test/SemaCXX/GH195416.cpp
index 85ed2961d0ef6..8b56faa1c187c 100644
--- a/clang/test/SemaCXX/GH195416.cpp
+++ b/clang/test/SemaCXX/GH195416.cpp
@@ -6,5 +6,6 @@ constexpr void gh195416() {
static constexpr S S::bar;
// expected-error at -1 {{non-friend class member 'bar' cannot have a qualified name}}
// expected-error at -2 {{static data member 'bar' not allowed in local struct 'S'}}
+ // expected-error at -3 {{no member named 'bar' in 'gh195416()::U::S'}}
};
}
diff --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp b/clang/test/SemaCXX/constant-expression-cxx14.cpp
index c64466700808a..6fc702f4d2aa8 100644
--- a/clang/test/SemaCXX/constant-expression-cxx14.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp
@@ -1466,3 +1466,10 @@ constexpr bool missingCase() {
1u: return false; // expected-error {{expected 'case' keyword before expression}}
}
}
+
+namespace GH202106 {
+ template <typename T> constexpr int foo(T);
+ template int foo<int>(int);
+ template <typename T> constexpr int foo(T) {}
+ // cxx14_20-error at -1 {{no return statement in constexpr function}}
+} // namespace GH202106
diff --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
index 10ea9e82f5327..725359c4af015 100644
--- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
+++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp
@@ -792,3 +792,29 @@ auto f() {
return c;
}
}
+
+namespace TemplateRedecl1 {
+ template <class> auto f();
+ template <class T> void g() { (void)+f<T>(); };
+ template <class> auto f() { return 0; }
+ template auto f<int>();
+ template void g<int>();
+} // namespace TemplateRedecl1
+
+namespace TemplateRedecl2 {
+ struct A {
+ template <class> auto f() const;
+ };
+ template <class T> void g() { (void)+A().f<T>(); };
+ template <class> auto A::f() const { return 0; }
+ template auto A::f<int>() const;
+ template void g<int>();
+} // namespace TemplateRedecl2
+
+namespace TemplateRedecl3 {
+ template <class> auto f() __attribute__((cdecl));
+ template <class T> void g() { (void)+f<T>(); };
+ template <class> auto f() { return 0; }
+ template auto f<int>();
+ template void g<int>();
+} // namespace TemplateRedecl3
diff --git a/clang/test/SemaCXX/member-class-11.cpp b/clang/test/SemaCXX/member-class-11.cpp
index 20d6bce954f19..085356fb2f948 100644
--- a/clang/test/SemaCXX/member-class-11.cpp
+++ b/clang/test/SemaCXX/member-class-11.cpp
@@ -3,9 +3,10 @@
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
struct rdar9677163 {
- struct Y { ~Y(); };
+ struct Y { ~Y(); }; // expected-note {{previous declaration is here}}
struct Z { ~Z(); };
Y::~Y() { } // expected-error{{non-friend class member '~Y' cannot have a qualified name}}
+ // expected-error at -1 {{destructor cannot be redeclared}}
~Z(); // expected-error{{expected the class name after '~' to name the enclosing class}}
};
@@ -79,3 +80,20 @@ struct Z2 {
};
}
+
+namespace GH202109 {
+ struct C {
+ template <class> struct S {
+ template <class> struct I;
+ };
+
+ template <class X> template <class Y> struct S<X>::I {
+ void f(X, Y); // expected-note {{previous declaration is here}}
+ };
+ // expected-error at -3 {{non-friend class member 'I' cannot have a qualified name}}
+
+ template <class X> template <class Y> void S<X>::I<Y>::f(X, Y) {}
+ // expected-error at -1 {{non-friend class member 'f' cannot have a qualified name}}
+ // expected-error at -2 {{class member cannot be redeclared}}
+ };
+} // namespace GH202109
diff --git a/clang/test/SemaTemplate/GH202358.cpp b/clang/test/SemaTemplate/GH202358.cpp
new file mode 100644
index 0000000000000..d1284e2536a39
--- /dev/null
+++ b/clang/test/SemaTemplate/GH202358.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -verify %s
+
+template <class> void foo(int = 0;
+// expected-error at -1 {{expected ')'}}
+// expected-note at -2 {{to match this '('}}
+
+void bar();
+
+#include "dadfoksbdsdldfafszcf.h"
+// expected-error at -1 {{file not found}}
+
+void baz() { foo<int>(); }
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 60ab6a4939282..580a25bc2fe70 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 { // #PackIndexExpr1-TplClassDef
+template <typename...> struct TplClass {
template <int... Ts>
requires C<Ts...[0]>
static auto buggy() -> void;
@@ -850,9 +850,6 @@ 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 {
@@ -903,19 +900,17 @@ namespace FuncTemplateInClass {
template <int T> concept C = true;
namespace t1 {
- template <int> struct TplClass { // expected-note {{defined here}}
+ template <int> struct TplClass {
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 t1
namespace t2 {
template <int> struct TplClass { // expected-note {{defined here}}
template <int Ts, int Us>
diff --git a/clang/test/SemaTemplate/friend-template.cpp b/clang/test/SemaTemplate/friend-template.cpp
index 2b5a226c3b33c..4321f1f073c77 100644
--- a/clang/test/SemaTemplate/friend-template.cpp
+++ b/clang/test/SemaTemplate/friend-template.cpp
@@ -338,3 +338,11 @@ 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 733105674b7a4..7dca971470e6a 100644
--- a/clang/test/SemaTemplate/instantiate-scope.cpp
+++ b/clang/test/SemaTemplate/instantiate-scope.cpp
@@ -8,10 +8,9 @@ template<typename ...T> struct X {
template<typename T, typename U> using A = T;
-// These definitions are OK, X<A<T, decltype(...)>...> is equivalent to X<T...>
-// so this defines the member of the primary template.
+// FIXME: These definitions are not OK, X<A<T, decltype(...)>...> is not equivalent to X<T...>.
template<typename ...T>
-void X<A<T, decltype(f(T()))>...>::f(int) {} // expected-error {{undeclared}}
+void X<A<T, decltype(f(T()))>...>::f(int) {}
template<typename ...T>
int X<A<T, decltype(f(T()))>...>::n = 0; // expected-error {{undeclared}}
@@ -23,8 +22,7 @@ void g() {
X<Y>().f(0);
X<Y>::n = 1;
- // 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}}
+ // FIXME: There should be no substitutiton failure since the out-of-line definitions were not valid.
+ X<void>().f(0);
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 19e6039379724..f2533bffb9b99 100644
--- a/clang/test/Templight/templight-default-func-arg.cpp
+++ b/clang/test/Templight/templight-default-func-arg.cpp
@@ -10,64 +10,77 @@ int main()
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
-// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
+// 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:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85: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:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85: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:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85: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:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85: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:72:3'$}}
+// 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-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:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85: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:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85: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:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85: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:72:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
foo<int>();
}
diff --git a/clang/test/Templight/templight-empty-entries-fix.cpp b/clang/test/Templight/templight-empty-entries-fix.cpp
index 7f34b10134929..43fcf2f50bbbc 100644
--- a/clang/test/Templight/templight-empty-entries-fix.cpp
+++ b/clang/test/Templight/templight-empty-entries-fix.cpp
@@ -207,6 +207,18 @@ 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$}}
@@ -225,41 +237,41 @@ void e() {
}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
// CHECK-LABEL: {{^---$}}
-// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
+// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
template <template<typename> class>
@@ -275,71 +287,71 @@ void foo() {
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283: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:265:35'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277: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:265:35'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277: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:265:35'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283: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:265:35'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:5'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'d<C>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'d<C>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+End$}}
-// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
-// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
+// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283: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:271:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283: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:271:3'$}}
+// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 0dbf315166696..a65605845c8df 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -732,6 +732,7 @@ 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 503f5da8af90f..aad3af2558bb7 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -5299,11 +5299,13 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportTemplateParameterLists) {
Decl *FromTU = getTuDecl(Code, Lang_CXX03);
auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU,
functionDecl(hasName("f"), isExplicitTemplateSpecialization()));
- ASSERT_EQ(FromD->getTemplateParameterLists().size(), 1u);
+ ASSERT_EQ(FromD->getTemplateSpecializationInfo()->TemplateParameters->size(),
+ 0u);
auto *ToD = Import(FromD, Lang_CXX03);
// The template parameter list should exist.
- EXPECT_EQ(ToD->getTemplateParameterLists().size(), 1u);
+ ASSERT_EQ(ToD->getTemplateSpecializationInfo()->TemplateParameters->size(),
+ 0u);
}
const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateDecl>
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index a3281f948fdb7..35d169fb1234d 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(equalsNode(FunDecl)),
+ callExpr(forCallable(declaresSameEntityAsNode(FunDecl)),
callee(cxxMethodDecl().bind("callee")))
.bind("call"),
FunDecl);
ExpectCorrectResult("ForCallable second",
callExpr(callee(cxxMethodDecl().bind("callee")),
- forCallable(equalsNode(FunDecl)))
+ forCallable(declaresSameEntityAsNode(FunDecl)))
.bind("call"),
FunDecl);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 8225c2141a84a..272d3f7a0a1a4 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1154,9 +1154,7 @@ 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:]]+::ratio<1, 1> "
- "> >$",
+ "std::__[[:alnum:]]+::chrono::duration<[^,]*> >$",
eTypeOptionHideChildren | eTypeOptionHideValue |
eTypeOptionCascade,
true);
@@ -1166,7 +1164,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, 1> "
+ "std::__[[:alnum:]]+::ratio<86400> "
"> >$",
eTypeOptionHideChildren | eTypeOptionHideValue |
eTypeOptionCascade,
@@ -1178,9 +1176,7 @@ 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:]]+::ratio<1, 1> "
- "> >$",
+ "std::__[[:alnum:]]+::chrono::duration<[^,]*> >$",
eTypeOptionHideChildren | eTypeOptionHideValue | eTypeOptionCascade,
true);
AddCXXSummary(cpp_category_sp,
@@ -1189,7 +1185,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, 1> "
+ "std::__[[:alnum:]]+::ratio<86400> "
"> >$",
eTypeOptionHideChildren | eTypeOptionHideValue |
eTypeOptionCascade,
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 2bfa187c009a7..18100a705a7a8 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -1449,8 +1449,11 @@ void TypeSystemClang::CreateFunctionTemplateSpecializationInfo(
TemplateArgumentList *template_args_ptr = TemplateArgumentList::CreateCopy(
func_decl->getASTContext(), infos.GetArgs());
- func_decl->setFunctionTemplateSpecialization(func_tmpl_decl,
- template_args_ptr, nullptr);
+ func_decl->setFunctionTemplateSpecialization(
+ func_decl->getASTContext(), func_tmpl_decl, template_args_ptr,
+ /*InsertPos=*/nullptr, TSK_ImplicitInstantiation,
+ /*TemplateParams=*/nullptr, /*TemplateArgsAsWritten=*/nullptr,
+ /*PointOfInstantiation=*/SourceLocation(), /*AddSpecialization=*/true);
}
/// Returns true if the given template parameter can represent the given value.
@@ -1649,6 +1652,40 @@ 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,
@@ -1691,6 +1728,13 @@ 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;
}
>From 33d1af52bfe20961677f3ebd066a2d2c7612091f Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Wed, 8 Jul 2026 22:42:40 -0300
Subject: [PATCH 2/2] fixup
---
clang/include/clang/Sema/Sema.h | 9 +++++----
clang/lib/Sema/SemaDecl.cpp | 27 +++++++++-----------------
clang/lib/Sema/SemaDeclCXX.cpp | 2 +-
clang/lib/Sema/SemaTemplate.cpp | 23 +++++++++++-----------
clang/test/SemaCXX/member-class-11.cpp | 8 ++++++++
5 files changed, 35 insertions(+), 34 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 631a680727fee..91af1764f48ed 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11803,10 +11803,11 @@ class Sema final : public SemaBase {
SourceLocation TemplateLoc, SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc);
- DeclResult ActOnVarTemplateSpecialization(
- Scope *S, Declarator &D, TypeSourceInfo *TSI, LookupResult &Previous,
- SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
- StorageClass SC, bool IsPartialSpecialization);
+ DeclResult
+ ActOnVarTemplateSpecialization(Scope *S, Declarator &D, TypeSourceInfo *TSI,
+ LookupResult &Previous,
+ TemplateParameterList *TemplateParams,
+ StorageClass SC, bool IsPartialSpecialization);
/// Get the specialization of the given variable template corresponding to
/// the specified argument list, or a null-but-valid result if the arguments
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 48ade20e0ddb3..32ae352bc7633 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -8016,15 +8016,8 @@ 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()
- : SourceLocation();
DeclResult Res = ActOnVarTemplateSpecialization(
- S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC,
- IsPartialSpecialization);
+ S, D, TInfo, Previous, TemplateParams, SC, IsPartialSpecialization);
if (Res.isInvalid())
return nullptr;
NewVD = cast<VarDecl>(Res.get());
@@ -8060,11 +8053,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// If we have any template parameter lists that don't directly belong to
// the variable (matching the scope specifier), store them.
- unsigned VDTemplateParamLists =
- IsVariableTemplate || IsVariableTemplateSpecialization ? 1 : 0;
- if (TemplateParamLists.size() > VDTemplateParamLists)
- NewVD->setTemplateParameterListsInfo(
- Context, TemplateParamLists.drop_back(VDTemplateParamLists));
+ if (!TemplateParamLists.empty())
+ NewVD->setTemplateParameterListsInfo(Context, TemplateParamLists);
}
if (D.getDeclSpec().isInlineSpecified()) {
@@ -10273,10 +10263,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
// For source fidelity, store the other template param lists.
- if (TemplateParamLists.size() > 1) {
- NewFD->setTemplateParameterListsInfo(
- Context,
- ArrayRef<TemplateParameterList *>(TemplateParamLists).drop_back(1));
+ if (!TemplateParamLists.empty()) {
+ NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists);
}
} else {
// Check that we can declare a template here.
@@ -14340,6 +14328,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
Diag(VDecl->getLocation(),
diag::ext_in_class_initializer_float_type_cxx11)
<< DclT << Init->getSourceRange();
+ // FIXME: This should use `getInnerLocStart()` instead of
+ // `getBeginLoc()`, because otherwise this will insert `constexpr`
+ // before the `template` keyword for template declarations.
Diag(VDecl->getBeginLoc(),
diag::note_in_class_initializer_float_type_cxx11)
<< FixItHint::CreateInsertion(VDecl->getBeginLoc(), "constexpr ");
@@ -18038,7 +18029,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
DeclResult Result = CheckClassTemplate(
S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams,
AS, ModulePrivateLoc,
- /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1,
+ /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size(),
TemplateParameterLists.data(), isMemberSpecialization, SkipBody);
return Result.get();
} else {
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 8a590e1def184..d12eb0d848b15 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18135,7 +18135,7 @@ DeclResult Sema::ActOnTemplatedFriendTag(
return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS,
Name, NameLoc, Attr, TemplateParams, AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
- FriendLoc, TempParamLists.size() - 1,
+ FriendLoc, TempParamLists.size(),
TempParamLists.data(), IsMemberSpecialization)
.get();
} else {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 51eea4eedbf7a..f17d82f9bb9bb 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3218,7 +3218,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// Return the last template parameter list, which corresponds to the
// entity being declared.
- return ParamLists.back();
+ return ParamLists.consume_back();
}
void Sema::NoteAllFoundTemplates(TemplateName Name) {
@@ -4379,8 +4379,8 @@ void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) {
DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *TSI, LookupResult &Previous,
- SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
- StorageClass SC, bool IsPartialSpecialization) {
+ TemplateParameterList *TemplateParams, StorageClass SC,
+ bool IsPartialSpecialization) {
// D must be variable template id.
assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
"Variable template specialization is declared with a template id.");
@@ -4503,8 +4503,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
cast_or_null<VarTemplatePartialSpecializationDecl>(PrevDecl);
VarTemplatePartialSpecializationDecl *Partial =
VarTemplatePartialSpecializationDecl::Create(
- Context, VarTemplate->getDeclContext(), TemplateKWLoc,
- TemplateNameLoc, TemplateParams,
+ Context, VarTemplate->getDeclContext(),
+ /*StartLoc=*/TemplateParams->getTemplateLoc(), TemplateNameLoc,
+ TemplateParams,
ASTTemplateArgumentListInfo::Create(Context, TemplateArgs),
VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
@@ -4517,7 +4518,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// Create a new class template specialization declaration node for
// this explicit specialization or friend declaration.
Specialization = VarTemplateSpecializationDecl::Create(
- Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
+ Context, VarTemplate->getDeclContext(),
+ /*StartLoc=*/TemplateParams->getTemplateLoc(), TemplateNameLoc,
VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
Specialization->setExplicitSpecializationInfo(
TemplateParams,
@@ -9007,7 +9009,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(),
TemplateNameLoc, Attr, TemplateParams, AS_none,
/*ModulePrivateLoc=*/SourceLocation(),
- /*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1,
+ /*FriendLoc=*/SourceLocation(), TemplateParameterLists.size(),
TemplateParameterLists.data(), isMemberSpecialization);
}
@@ -9031,10 +9033,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
}
SetNestedNameSpecifier(*this, Specialization, SS);
- if (TemplateParameterLists.size() > 1 && SS.isSet()) {
- Specialization->setTemplateParameterListsInfo(
- Context, TemplateParameterLists.drop_back(1));
- }
+ if (!TemplateParameterLists.empty())
+ Specialization->setTemplateParameterListsInfo(Context,
+ TemplateParameterLists);
if (isPartialSpecialization)
CheckTemplatePartialSpecialization(
diff --git a/clang/test/SemaCXX/member-class-11.cpp b/clang/test/SemaCXX/member-class-11.cpp
index 085356fb2f948..04bea7f75c19c 100644
--- a/clang/test/SemaCXX/member-class-11.cpp
+++ b/clang/test/SemaCXX/member-class-11.cpp
@@ -97,3 +97,11 @@ namespace GH202109 {
// expected-error at -2 {{class member cannot be redeclared}}
};
} // namespace GH202109
+
+namespace GH207911 {
+ template <class> struct A {
+ template <> static int foo;
+ // expected-error at -1 {{extraneous 'template<>' in declaration of variable 'foo'}}
+ };
+ int bar = A<int>::foo;
+} // namespace GH207911
More information about the cfe-commits
mailing list