Revert "[clang] Reland: fix getTemplateInstantiationArgs (#208285)" (#208426)

It caused various breakages; see comments on the PR.

This reverts commit 031b773b01.
This commit is contained in:
Hans Wennborg 2026-07-09 14:11:45 +02:00 committed by GitHub
parent 099ffad0a7
commit 092f4451ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
70 changed files with 1729 additions and 1624 deletions

View file

@ -106,7 +106,7 @@ void DefinitionsInHeadersCheck::check(const MatchFinder::MatchResult &Result) {
return;
diag(FD->getLocation(), "mark the definition as 'inline'",
DiagnosticIDs::Note)
<< FixItHint::CreateInsertion(FD->getFunctionLocStart(), "inline ");
<< FixItHint::CreateInsertion(FD->getInnerLocStart(), "inline ");
} else if (const auto *VD = dyn_cast<VarDecl>(ND)) {
// C++14 variable templates are allowed.
if (VD->getDescribedVarTemplate())

View file

@ -590,28 +590,28 @@ public:
bool
VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D) {
if (const auto *Info = D->getExplicitInstantiationInfo()) {
H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
Info->TemplateArgsAsWritten->getRAngleLoc());
} else if (const auto *Info = D->getExplicitSpecializationInfo()) {
H.addAngleBracketTokens(Info->TemplateParams->getLAngleLoc(),
Info->TemplateParams->getRAngleLoc());
H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
Info->TemplateArgsAsWritten->getRAngleLoc());
}
if (auto *Args = D->getTemplateArgsAsWritten())
H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
return true;
}
bool VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
if (auto *TPL = D->getTemplateParameters())
H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
return true;
}
bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
if (const auto *Info = D->getExplicitInstantiationInfo()) {
H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
Info->TemplateArgsAsWritten->getRAngleLoc());
} else if (const auto *Info = D->getExplicitSpecializationInfo()) {
H.addAngleBracketTokens(Info->TemplateParams->getLAngleLoc(),
Info->TemplateParams->getRAngleLoc());
H.addAngleBracketTokens(Info->TemplateArgsAsWritten->getLAngleLoc(),
Info->TemplateArgsAsWritten->getRAngleLoc());
}
if (auto *Args = D->getTemplateArgsAsWritten())
H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
return true;
}
bool VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
if (auto *TPL = D->getTemplateParameters())
H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
return true;
}
@ -625,9 +625,6 @@ public:
}
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)

View file

@ -364,7 +364,7 @@ addInlineIfInHeader(const FunctionDecl *FD) {
if (!isHeaderFile(FileName, FD->getASTContext().getLangOpts()))
return std::nullopt;
return tooling::Replacement(SM, FD->getFunctionLocStart(), 0, "inline ");
return tooling::Replacement(SM, FD->getInnerLocStart(), 0, "inline ");
}
/// Moves definition of a function/method to its declaration location.

View file

@ -4301,11 +4301,6 @@ bound to ID.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</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&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</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.

View file

@ -836,7 +836,6 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
- Fixed an alias template CTAD crash.
- Correctly diagnose uses of `co_await` / `co_yield` in the default argument of nested function declarations. (#GH98923)
- Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741)
- Fixed clang incorrectly rejecting several cases of out-of-line definitions. (#GH101330)
- Clang incorrectly instantiated variable specializations outside of the immediate context. (#GH54439)
- Fixed a crash when pack expansions are used as arguments for non-pack parameters of built-in templates. (#GH180307)
- Fixed crash instantiating class member specializations.

View file

@ -2131,6 +2131,34 @@ private:
/// 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,
@ -2226,8 +2254,6 @@ public:
return SourceLocation();
}
SourceLocation getFunctionLocStart() const;
SourceRange getSourceRange() const override LLVM_READONLY;
// Function definitions.
@ -3057,14 +3083,9 @@ public:
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.
///
@ -3077,30 +3098,25 @@ public:
///
/// \param TSK the kind of template specialization this is.
///
/// \param TemplateParams the template parameters if this is an explicit
/// specialization.
///
/// \param TemplateArgsAsWritten location info of template arguments.
///
/// \param PointOfInstantiation point at which the function template
/// specialization was first instantiated.
///
/// \param AddSpecialization whether to add this specialization to the
/// template's specialization set.
///
void setFunctionTemplateSpecialization(
ASTContext &C, FunctionTemplateDecl *Template,
TemplateArgumentList *TemplateArgs, void *InsertPos,
TemplateSpecializationKind TSK,
const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation PointOfInstantiation, bool AddSpecialization);
FunctionTemplateDecl *Template, TemplateArgumentList *TemplateArgs,
void *InsertPos,
TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr,
SourceLocation PointOfInstantiation = SourceLocation()) {
setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs,
InsertPos, TSK, TemplateArgsAsWritten,
PointOfInstantiation);
}
/// Specifies that this function declaration is actually a
/// dependent function template specialization.
void setDependentTemplateSpecialization(
ASTContext &Context, const UnresolvedSetImpl &Templates,
const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TemplateArgs);
DependentFunctionTemplateSpecializationInfo *

View file

@ -73,7 +73,7 @@ class TemplateParameterList final
: private llvm::TrailingObjects<TemplateParameterList, NamedDecl *,
Expr *> {
/// The template argument list of the template parameter list.
mutable TemplateArgument *InjectedArgs = nullptr;
TemplateArgument *InjectedArgs = nullptr;
/// The location of the 'template' keyword.
SourceLocation TemplateLoc;
@ -200,8 +200,7 @@ public:
bool hasAssociatedConstraints() const;
/// Get the template argument list of the template parameter list.
ArrayRef<TemplateArgument>
getInjectedTemplateArgs(const ASTContext &Context) const;
ArrayRef<TemplateArgument> getInjectedTemplateArgs(const ASTContext &Context);
SourceLocation getTemplateLoc() const { return TemplateLoc; }
SourceLocation getLAngleLoc() const { return LAngleLoc; }
@ -476,18 +475,14 @@ class FunctionTemplateSpecializationInfo final
/// The function template from which this function template
/// specialization was generated.
///
/// The three bits contain the TemplateSpecializationKind.
llvm::PointerIntPair<FunctionTemplateDecl *, 3> Template;
/// The two bits contain the top 4 values of TemplateSpecializationKind.
llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
public:
/// The template arguments used to produce the function template
/// specialization from the function template.
TemplateArgumentList *TemplateArguments;
// The template parameters if this is an explicit specialization.
/// FIXME: Normally null; tail-allocate this.
const TemplateParameterList *TemplateParameters;
/// The template arguments as written in the sources, if provided.
/// FIXME: Normally null; tail-allocate this.
const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
@ -500,14 +495,12 @@ private:
FunctionTemplateSpecializationInfo(
FunctionDecl *FD, FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
const TemplateParameterList *TemplateParameters,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation POI, MemberSpecializationInfo *MSInfo)
: Function(FD, MSInfo ? true : false), Template(Template, TSK - 1),
TemplateArguments(TemplateArgs), TemplateParameters(TemplateParameters),
TemplateArguments(TemplateArgs),
TemplateArgumentsAsWritten(TemplateArgsAsWritten),
PointOfInstantiation(POI) {
assert(TemplateParameters == nullptr || TSK == TSK_ExplicitSpecialization);
if (MSInfo)
getTrailingObjects()[0] = MSInfo;
}
@ -520,7 +513,6 @@ public:
static FunctionTemplateSpecializationInfo *
Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
const TemplateParameterList *TemplateParameters,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation POI, MemberSpecializationInfo *MSInfo);
@ -621,8 +613,8 @@ public:
/// member class or member enumeration.
class MemberSpecializationInfo {
// The member declaration from which this member was instantiated, and the
// manner in which the instantiation occurred (in the lower three bits).
llvm::PointerIntPair<NamedDecl *, 3> MemberAndTSK;
// manner in which the instantiation occurred (in the lower two bits).
llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK;
// The point at which this member was first instantiated.
SourceLocation PointOfInstantiation;
@ -701,19 +693,14 @@ class DependentFunctionTemplateSpecializationInfo final
DependentFunctionTemplateSpecializationInfo(
const UnresolvedSetImpl &Candidates,
const TemplateParameterList *TemplateParams,
const ASTTemplateArgumentListInfo *TemplateArgsWritten);
public:
// The template parameters if this is an explicit specialization.
const TemplateParameterList *TemplateParameters;
/// The template arguments as written in the sources, if provided.
const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
static DependentFunctionTemplateSpecializationInfo *
Create(ASTContext &Context, const UnresolvedSetImpl &Candidates,
const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TemplateArgs);
/// Returns the candidates for the primary function template.
@ -1018,6 +1005,11 @@ public:
return getTemplatedDecl()->isThisDeclarationADefinition();
}
bool isCompatibleWithDefinition() const {
return getTemplatedDecl()->isInstantiatedFromMemberTemplate() ||
isThisDeclarationADefinition();
}
// This bit closely tracks 'RedeclarableTemplateDecl::InstantiatedFromMember',
// except this is per declaration, while the redeclarable field is
// per chain. This indicates a template redeclaration which
@ -1815,18 +1807,8 @@ struct ExplicitInstantiationInfo {
ExplicitInstantiationInfo() = default;
};
struct ExplicitSpecializationInfo {
/// The list of template parameters
TemplateParameterList *TemplateParams = nullptr;
/// The template arguments as written.
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten = nullptr;
ExplicitSpecializationInfo() = default;
};
using SpecializationOrInstantiationInfo =
llvm::PointerUnion<ExplicitSpecializationInfo *,
llvm::PointerUnion<const ASTTemplateArgumentListInfo *,
ExplicitInstantiationInfo *>;
/// Represents a class template specialization, which refers to
@ -2056,38 +2038,49 @@ public:
/// Retrieve the template argument list as written in the sources,
/// if any.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
if (const auto *Info = getExplicitSpecializationInfo())
if (auto *Info =
dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
return Info->TemplateArgsAsWritten;
if (const auto *Info = getExplicitInstantiationInfo())
return Info->TemplateArgsAsWritten;
return nullptr;
return cast<const ASTTemplateArgumentListInfo *>(ExplicitInfo);
}
/// Gets the explicit instantiation info, if present.
const ExplicitInstantiationInfo *getExplicitInstantiationInfo() const {
return dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
/// Set the template argument list as written in the sources.
void
setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
if (auto *Info =
dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
Info->TemplateArgsAsWritten = ArgsWritten;
else
ExplicitInfo = ArgsWritten;
}
/// Sets the explicit instantiation info.
void setExplicitInstantiationInfo(
SourceLocation ExternKeywordLoc, SourceLocation TemplateKeywordLoc,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
auto *Info = new (getASTContext()) ExplicitInstantiationInfo();
Info->ExternKeywordLoc = ExternKeywordLoc;
Info->TemplateKeywordLoc = TemplateKeywordLoc;
Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
ExplicitInfo = Info;
/// Set the template argument list as written in the sources.
void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
setTemplateArgsAsWritten(
ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
}
/// Gets the explicit specialization info, if present.
const ExplicitSpecializationInfo *getExplicitSpecializationInfo() const {
return dyn_cast_if_present<ExplicitSpecializationInfo *>(ExplicitInfo);
/// Gets the location of the extern keyword, if present.
SourceLocation getExternKeywordLoc() const {
if (auto *Info =
dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
return Info->ExternKeywordLoc;
return SourceLocation();
}
/// Sets the explicit specialization info.
void setExplicitSpecializationInfo(
TemplateParameterList *TemplateParams,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten);
/// Sets the location of the extern keyword.
void setExternKeywordLoc(SourceLocation Loc);
/// Gets the location of the template keyword, if present.
SourceLocation getTemplateKeywordLoc() const {
if (auto *Info =
dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
return Info->TemplateKeywordLoc;
return SourceLocation();
}
/// Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -2112,7 +2105,10 @@ public:
};
class ClassTemplatePartialSpecializationDecl
: public ClassTemplateSpecializationDecl {
: public ClassTemplateSpecializationDecl {
/// The list of template parameters
TemplateParameterList *TemplateParams = nullptr;
/// The class template partial specialization from which this
/// class template partial specialization was instantiated.
///
@ -2126,7 +2122,6 @@ class ClassTemplatePartialSpecializationDecl
ClassTemplatePartialSpecializationDecl(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl);
@ -2144,9 +2139,7 @@ public:
static ClassTemplatePartialSpecializationDecl *
Create(ASTContext &Context, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
TemplateParameterList *Params,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
ClassTemplateDecl *SpecializedTemplate,
TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args, CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl);
@ -2161,10 +2154,7 @@ public:
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
auto *ExplicitSpecInfo = getExplicitSpecializationInfo();
assert(ExplicitSpecInfo &&
"A partial specialization is always an explicit specialization");
return ExplicitSpecInfo->TemplateParams;
return TemplateParams;
}
/// \brief All associated constraints of this partial specialization,
@ -2175,11 +2165,11 @@ public:
/// conjunction ("and").
void getAssociatedConstraints(
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
getTemplateParameters()->getAssociatedConstraints(AC);
TemplateParams->getAssociatedConstraints(AC);
}
bool hasAssociatedConstraints() const {
return getTemplateParameters()->hasAssociatedConstraints();
return TemplateParams->hasAssociatedConstraints();
}
/// Retrieve the member class template partial specialization from
@ -2816,38 +2806,49 @@ public:
/// Retrieve the template argument list as written in the sources,
/// if any.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
if (const auto *Info = getExplicitSpecializationInfo())
if (auto *Info =
dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
return Info->TemplateArgsAsWritten;
if (const auto *Info = getExplicitInstantiationInfo())
return Info->TemplateArgsAsWritten;
return nullptr;
return cast<const ASTTemplateArgumentListInfo *>(ExplicitInfo);
}
/// Gets the explicit instantiation info, if present.
const ExplicitInstantiationInfo *getExplicitInstantiationInfo() const {
return dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
/// Set the template argument list as written in the sources.
void
setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
if (auto *Info =
dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
Info->TemplateArgsAsWritten = ArgsWritten;
else
ExplicitInfo = ArgsWritten;
}
/// Sets the explicit instantiation info.
void setExplicitInstantiationInfo(
SourceLocation ExternKeywordLoc, SourceLocation TemplateKeywordLoc,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
auto *Info = new (getASTContext()) ExplicitInstantiationInfo();
Info->ExternKeywordLoc = ExternKeywordLoc;
Info->TemplateKeywordLoc = TemplateKeywordLoc;
Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
ExplicitInfo = Info;
/// Set the template argument list as written in the sources.
void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
setTemplateArgsAsWritten(
ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
}
/// Gets the explicit specialization info, if present.
const ExplicitSpecializationInfo *getExplicitSpecializationInfo() const {
return dyn_cast_if_present<ExplicitSpecializationInfo *>(ExplicitInfo);
/// Gets the location of the extern keyword, if present.
SourceLocation getExternKeywordLoc() const {
if (auto *Info =
dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
return Info->ExternKeywordLoc;
return SourceLocation();
}
/// Sets the explicit specialization info.
void setExplicitSpecializationInfo(
TemplateParameterList *TemplateParams,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten);
/// Sets the location of the extern keyword.
void setExternKeywordLoc(SourceLocation Loc);
/// Gets the location of the template keyword, if present.
SourceLocation getTemplateKeywordLoc() const {
if (auto *Info =
dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo))
return Info->TemplateKeywordLoc;
return SourceLocation();
}
/// Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -2873,6 +2874,9 @@ public:
class VarTemplatePartialSpecializationDecl
: public VarTemplateSpecializationDecl {
/// The list of template parameters
TemplateParameterList *TemplateParams = nullptr;
/// The variable template partial specialization from which this
/// variable template partial specialization was instantiated.
///
@ -2884,7 +2888,6 @@ class VarTemplatePartialSpecializationDecl
VarTemplatePartialSpecializationDecl(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args);
@ -2902,7 +2905,6 @@ public:
static VarTemplatePartialSpecializationDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
VarTemplateDecl *SpecializedTemplate, QualType T,
TypeSourceInfo *TInfo, StorageClass S,
ArrayRef<TemplateArgument> Args);
@ -2918,10 +2920,7 @@ public:
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
auto *ExplicitSpecInfo = getExplicitSpecializationInfo();
assert(ExplicitSpecInfo &&
"A partial specialization is always an explicit specialization");
return ExplicitSpecInfo->TemplateParams;
return TemplateParams;
}
/// Get the template argument list of the template parameter list.
@ -2938,11 +2937,11 @@ public:
/// conjunction ("and").
void getAssociatedConstraints(
llvm::SmallVectorImpl<AssociatedConstraint> &AC) const {
getTemplateParameters()->getAssociatedConstraints(AC);
TemplateParams->getAssociatedConstraints(AC);
}
bool hasAssociatedConstraints() const {
return getTemplateParameters()->hasAssociatedConstraints();
return TemplateParams->hasAssociatedConstraints();
}
/// \brief Retrieve the member variable template partial specialization from

View file

@ -417,7 +417,6 @@ class JSONDumper : public ASTNodeTraverser<JSONDumper, JSONNodeDumper> {
Visit(Redecl);
DumpedAny = true;
break;
case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization:
break;
}

View file

@ -2002,7 +2002,6 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
case TSK_ExplicitSpecialization:
case TSK_FriendDeclaration:
break;
}
}
@ -2023,7 +2022,6 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
TRY_TO(TraverseDecl(RD));
break;
case TSK_FriendDeclaration:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
case TSK_ExplicitSpecialization:
@ -2058,7 +2056,6 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateInstantiations(
TRY_TO(TraverseDecl(RD));
break;
case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization:
break;
}
@ -2225,9 +2222,8 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
handles traversal of template args and qualifier. \
For explicit specializations ("template<> set<int> {...};"), \
we traverse template args here since there is no EID. */ \
if (const auto *Info = D->getExplicitSpecializationInfo()) { \
const auto *ArgsWritten = Info->TemplateArgsAsWritten; \
TRY_TO(TraverseTemplateParameterListHelper(Info->TemplateParams)); \
if (D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { \
const auto *ArgsWritten = D->getTemplateArgsAsWritten(); \
TRY_TO(TraverseTemplateArgumentLocsHelper( \
ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs)); \
} else if (!getDerived().shouldVisitTemplateInstantiations()) { \

View file

@ -5753,11 +5753,6 @@ AST_MATCHER_P(IfStmt, hasElse, internal::Matcher<Stmt>, InnerMatcher) {
return (Else != nullptr && InnerMatcher.matches(*Else, Finder, Builder));
}
/// Matches a declaration if it declares the same entity as the node.
AST_MATCHER_P(Decl, declaresSameEntityAsNode, const Decl *, Other) {
return clang::declaresSameEntity(&Node, Other);
}
/// Matches if a node equals a previously bound node.
///
/// Matches a node if it equals the node previously bound to \p ID.

View file

@ -1993,12 +1993,16 @@ getTemplateArgsWritten(const OverloadExpr &OE) {
inline unsigned
getNumTemplateArgsWritten(const ClassTemplateSpecializationDecl &D) {
return getTemplateArgsWritten(D).size();
if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
return Args->getNumTemplateArgs();
return 0;
}
inline unsigned
getNumTemplateArgsWritten(const VarTemplateSpecializationDecl &D) {
return getTemplateArgsWritten(D).size();
if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
return Args->getNumTemplateArgs();
return 0;
}
inline unsigned getNumTemplateArgsWritten(const FunctionDecl &FD) {

View file

@ -193,8 +193,6 @@ namespace clang {
/// This template specialization was implicitly instantiated from a
/// template. (C++ [temp.inst]).
TSK_ImplicitInstantiation,
/// This template is a friend declaration.
TSK_FriendDeclaration,
/// This template specialization was declared or defined by an
/// explicit specialization (C++ [temp.expl.spec]) or partial
/// specialization (C++ [temp.class.spec]).
@ -229,7 +227,6 @@ namespace clang {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
case TSK_FriendDeclaration:
return false;
}
llvm_unreachable("bad template specialization kind");

View file

@ -11748,7 +11748,7 @@ public:
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,7 +11814,8 @@ public:
DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation TemplateNameLoc,
const TemplateArgumentListInfo &TemplateArgs);
const TemplateArgumentListInfo &TemplateArgs,
bool SetWrittenArgs);
/// Form a reference to the specialization of the given variable template
/// corresponding to the specified argument list, or a null-but-valid result
@ -11898,7 +11899,7 @@ public:
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
@ -11971,8 +11972,7 @@ public:
/// There really isn't any useful analysis we can do here, so we
/// just store the information.
bool CheckDependentFunctionTemplateSpecialization(
FunctionDecl *FD, const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
/// Perform semantic analysis for the given function template
@ -11998,9 +11998,8 @@ public:
/// declaration with no explicit template argument list that might be
/// befriending a function template specialization.
bool CheckFunctionTemplateSpecialization(
FunctionDecl *FD, const TemplateParameterList *TemplateParams,
TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous,
bool QualifiedFriend = false);
FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous, bool QualifiedFriend = false);
/// Perform semantic analysis for the given non-template member
/// specialization.
@ -12266,6 +12265,46 @@ public:
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.
///
@ -12290,11 +12329,19 @@ public:
/// \returns True if the template parameter lists are equal, false
/// otherwise.
bool TemplateParameterListsAreEqual(
const Decl *NewInstFrom, TemplateParameterList *New,
const Decl *OldInstFrom, TemplateParameterList *Old, bool Complain,
const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
TemplateParameterListEqualKind Kind,
SourceLocation TemplateArgLoc = SourceLocation());
bool TemplateParameterListsAreEqual(
TemplateParameterList *New, TemplateParameterList *Old, bool Complain,
TemplateParameterListEqualKind Kind,
SourceLocation TemplateArgLoc = SourceLocation()) {
return TemplateParameterListsAreEqual(nullptr, New, nullptr, Old, Complain,
Kind, TemplateArgLoc);
}
/// Check whether a template can be declared within this scope.
///
/// If the template declaration is valid in this scope, returns
@ -13525,27 +13572,44 @@ public:
/// Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
///
/// \param D the declaration for which we are computing template
/// \param ND the declaration for which we are computing template
/// instantiation arguments.
///
/// \param Innermost if present, specifies a template argument list for the
/// template-like (TemplateDecl or PartialSpec) declaration passed as D.
/// \param DC In the event we don't HAVE a declaration yet, we instead provide
/// the decl context where it will be created. In this case, the `Innermost`
/// should likely be provided. If ND is non-null, this is ignored.
///
/// \param 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 Innermost if non-NULL, specifies a template argument list for the
/// template declaration passed as ND.
///
/// \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 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 Pattern If non-NULL, indicates the pattern from which we will be
/// instantiating the definition of the given declaration, \p ND. This is
/// used to determine the proper set of template instantiation arguments for
/// friend function template specializations.
///
/// \param ForConstraintInstantiation when collecting arguments,
/// ForConstraintInstantiation indicates we should continue looking when
/// encountering a lambda generic call operator, and continue looking for
/// arguments on an enclosing class template.
///
/// \param SkipForSpecialization when specified, any template specializations
/// in a traversal would be ignored.
///
/// \param ForDefaultArgumentSubstitution indicates we should continue looking
/// when encountering a specialized member function template, rather than
/// returning immediately.
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
const Decl *D,
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
UnsignedOrNone NumLevels = std::nullopt,
bool SkipInnerNonInstantiated = false);
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
bool ForConstraintInstantiation = false,
bool SkipForSpecialization = false,
bool ForDefaultArgumentSubstitution = false);
/// RAII object to handle the state changes required to synthesize
/// a function body.
@ -14962,13 +15026,14 @@ public:
// for figuring out the relative 'depth' of the constraint. The depth of the
// 'primary template' and the 'instantiated from' templates aren't necessarily
// the same, such as a case when one is a 'friend' defined in a class.
bool AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
const Decl *New, const Expr *NewConstr);
bool AreConstraintExpressionsEqual(const NamedDecl *Old,
const Expr *OldConstr,
const TemplateCompareNewDeclInfo &New,
const Expr *NewConstr);
// Calculates whether the friend function depends on an enclosing template for
// the purposes of [temp.friend] p9.
bool
FriendConstraintsDependOnEnclosingTemplate(const FunctionTemplateDecl *FTD);
bool FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD);
/// \brief Ensure that the given template arguments satisfy the constraints
/// associated with the given template, emitting a diagnostic if they do not.
@ -14989,19 +15054,10 @@ public:
SourceRange TemplateIDRange);
bool CheckFunctionTemplateConstraints(SourceLocation PointOfInstantiation,
FunctionTemplateDecl *Template,
FunctionDecl *Decl,
ArrayRef<TemplateArgument> TemplateArgs,
ConstraintSatisfaction &Satisfaction);
// FIXME: Constraints should be always checked before the declaration is
// specialized. This function exists to support a workaround for templated
// lambdas, where handling the instantiation scope for the captures is not
// implemented yet.
bool
CheckFunctionSpecializationConstraints(SourceLocation PointOfInstantiation,
FunctionDecl *Decl,
ConstraintSatisfaction &Satisfaction);
/// \brief Emit diagnostics explaining why a constraint expression was deemed
/// unsatisfied.
/// \param First whether this is the first time an unsatisfied constraint is
@ -15082,16 +15138,19 @@ private:
/// Used by SetupConstraintCheckingTemplateArgumentsAndScope to set up the
/// LocalInstantiationScope of the current non-lambda function. For lambdas,
/// use LambdaScopeForCallOperatorInstantiationRAII.
bool SetupConstraintScope(FunctionDecl *FD,
const MultiLevelTemplateArgumentList &MLTAL,
LocalInstantiationScope &Scope);
bool
SetupConstraintScope(FunctionDecl *FD,
std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
const MultiLevelTemplateArgumentList &MLTAL,
LocalInstantiationScope &Scope);
/// Used during constraint checking, sets up the constraint template argument
/// lists, and calls SetupConstraintScope to set up the
/// LocalInstantiationScope to have the proper set of ParVarDecls configured.
std::optional<MultiLevelTemplateArgumentList>
SetupConstraintCheckingTemplateArgumentsAndScope(
FunctionDecl *FD, LocalInstantiationScope &Scope);
FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
LocalInstantiationScope &Scope);
///@}

View file

@ -13090,7 +13090,6 @@ static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
case TSK_ExplicitInstantiationDeclaration:
return GVA_AvailableExternally;
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
External = GVA_DiscardableODR;
break;
@ -13280,7 +13279,6 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
case TSK_ExplicitInstantiationDeclaration:
return GVA_AvailableExternally;
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
return GVA_DiscardableODR;
}

View file

@ -140,7 +140,6 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
Visit(Redecl);
DumpedAny = true;
break;
case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization:
break;
}

View file

@ -816,8 +816,6 @@ ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization(
template <>
Expected<TemplateParameterList *>
ASTNodeImporter::import(TemplateParameterList *From) {
if (!From)
return nullptr;
SmallVector<NamedDecl *, 4> To(From->size());
if (Error Err = ImportContainerChecked(*From, To))
return std::move(Err);
@ -956,8 +954,7 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) {
ToInfo = TemplateArgumentLocInfo(*TSIOrErr);
else
return TSIOrErr.takeError();
} else if (Arg.getKind() == TemplateArgument::Template ||
Arg.getKind() == TemplateArgument::TemplateExpansion) {
} else {
auto ToTemplateKWLocOrErr = import(FromInfo.getTemplateKwLoc());
if (!ToTemplateKWLocOrErr)
return ToTemplateKWLocOrErr.takeError();
@ -975,9 +972,6 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) {
Importer.getToContext(), *ToTemplateKWLocOrErr,
*ToTemplateQualifierLocOrErr, *ToTemplateNameLocOrErr,
*ToTemplateEllipsisLocOrErr);
} else {
ToInfo = TemplateArgumentLocInfo(Importer.getToContext(),
FromInfo.getTrivialLoc());
}
return TemplateArgumentLoc(Arg, ToInfo);
@ -3670,12 +3664,6 @@ Error ASTNodeImporter::ImportTemplateInformation(
Importer.getToContext(), std::get<1>(*FunctionAndArgsOrErr));
auto *FTSInfo = FromFD->getTemplateSpecializationInfo();
Expected<TemplateParameterList *> TemplateParamsOrErr =
import(FTSInfo->TemplateParameters);
if (!TemplateParamsOrErr)
return TemplateParamsOrErr.takeError();
TemplateArgumentListInfo ToTAInfo;
const auto *FromTAArgsAsWritten = FTSInfo->TemplateArgumentsAsWritten;
if (FromTAArgsAsWritten)
@ -3692,10 +3680,8 @@ Error ASTNodeImporter::ImportTemplateInformation(
TemplateSpecializationKind TSK = FTSInfo->getTemplateSpecializationKind();
ToFD->setFunctionTemplateSpecialization(
Importer.getToContext(), std::get<0>(*FunctionAndArgsOrErr), ToTAList,
/*InsertPos=*/nullptr, TSK, *TemplateParamsOrErr,
FromTAArgsAsWritten ? &ToTAInfo : nullptr, *POIOrErr,
/*AddSpecialization=*/true);
std::get<0>(*FunctionAndArgsOrErr), ToTAList, /* InsertPos= */ nullptr,
TSK, FromTAArgsAsWritten ? &ToTAInfo : nullptr, *POIOrErr);
return Error::success();
}
@ -3709,11 +3695,6 @@ Error ASTNodeImporter::ImportTemplateInformation(
return ToFTDOrErr.takeError();
}
Expected<TemplateParameterList *> TemplateParamsOrErr =
import(FromInfo->TemplateParameters);
if (!TemplateParamsOrErr)
return TemplateParamsOrErr.takeError();
// Import TemplateArgumentListInfo.
TemplateArgumentListInfo ToTAInfo;
const auto *FromTAArgsAsWritten = FromInfo->TemplateArgumentsAsWritten;
@ -3723,7 +3704,7 @@ Error ASTNodeImporter::ImportTemplateInformation(
return Err;
ToFD->setDependentTemplateSpecialization(
Importer.getToContext(), Candidates, *TemplateParamsOrErr,
Importer.getToContext(), Candidates,
FromTAArgsAsWritten ? &ToTAInfo : nullptr);
return Error::success();
}
@ -6544,22 +6525,19 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (!IdLocOrErr)
return IdLocOrErr.takeError();
// Import TemplateArgumentListInfo.
TemplateArgumentListInfo ToTAInfo;
if (const auto *ASTTemplateArgs = D->getTemplateArgsAsWritten()) {
if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs, ToTAInfo))
return std::move(Err);
}
// Create the specialization.
ClassTemplateSpecializationDecl *D2 = nullptr;
if (PartialSpec) {
TemplateArgumentListInfo ToTAInfo;
if (Error Err = ImportTemplateArgumentListInfo(
*cast<ClassTemplatePartialSpecializationDecl>(D)
->getTemplateArgsAsWritten(),
ToTAInfo))
return std::move(Err);
if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr,
*IdLocOrErr, ToTPList,
ASTTemplateArgumentListInfo::Create(Importer.getToContext(),
ToTAInfo),
ClassTemplate, ArrayRef(TemplateArgs),
*IdLocOrErr, ToTPList, ClassTemplate, ArrayRef(TemplateArgs),
/*CanonInjectedTST=*/CanQualType(),
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
return D2;
@ -6590,34 +6568,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
if (!ClassTemplate->findSpecialization(TemplateArgs, InsertPos))
// Add this specialization to the class template.
ClassTemplate->AddSpecialization(D2, InsertPos);
if (const auto *Info = D->getExplicitInstantiationInfo()) {
auto ExternKeywordLocOrErr = import(Info->ExternKeywordLoc);
if (!ExternKeywordLocOrErr)
return ExternKeywordLocOrErr.takeError();
auto TemplateKeywordLocOrErr = import(Info->TemplateKeywordLoc);
if (!TemplateKeywordLocOrErr)
return TemplateKeywordLocOrErr.takeError();
TemplateArgumentListInfo ToTAInfo;
if (Error Err = ImportTemplateArgumentListInfo(
*Info->TemplateArgsAsWritten, ToTAInfo))
return std::move(Err);
D2->setExplicitInstantiationInfo(*ExternKeywordLocOrErr,
*TemplateKeywordLocOrErr,
ASTTemplateArgumentListInfo::Create(
Importer.getToContext(), ToTAInfo));
} else if (const auto *Info = D->getExplicitSpecializationInfo()) {
auto ParamsOrErr = import(Info->TemplateParams);
if (!ParamsOrErr)
return ParamsOrErr.takeError();
TemplateArgumentListInfo ToTAInfo;
if (Error Err = ImportTemplateArgumentListInfo(
*Info->TemplateArgsAsWritten, ToTAInfo))
return std::move(Err);
D2->setExplicitSpecializationInfo(*ParamsOrErr,
ASTTemplateArgumentListInfo::Create(
Importer.getToContext(), ToTAInfo));
}
}
D2->setSpecializationKind(D->getSpecializationKind());
@ -6644,6 +6594,19 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
else
return LocOrErr.takeError();
if (D->getTemplateArgsAsWritten())
D2->setTemplateArgsAsWritten(ToTAInfo);
if (auto LocOrErr = import(D->getTemplateKeywordLoc()))
D2->setTemplateKeywordLoc(*LocOrErr);
else
return LocOrErr.takeError();
if (auto LocOrErr = import(D->getExternKeywordLoc()))
D2->setExternKeywordLoc(*LocOrErr);
else
return LocOrErr.takeError();
if (D->getPointOfInstantiation().isValid()) {
if (auto POIOrErr = import(D->getPointOfInstantiation()))
D2->setPointOfInstantiation(*POIOrErr);
@ -6861,6 +6824,12 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *D2 = nullptr;
TemplateArgumentListInfo ToTAInfo;
if (const auto *Args = D->getTemplateArgsAsWritten()) {
if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
return std::move(Err);
}
using PartVarSpecDecl = VarTemplatePartialSpecializationDecl;
// Create a new specialization.
if (auto *FromPartial = dyn_cast<PartVarSpecDecl>(D)) {
@ -6868,16 +6837,9 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
if (!ToTPListOrErr)
return ToTPListOrErr.takeError();
TemplateArgumentListInfo ToTAInfo;
if (const auto *Args = D->getTemplateArgsAsWritten())
if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
return std::move(Err);
PartVarSpecDecl *ToPartial;
if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr,
ASTTemplateArgumentListInfo::Create(
Importer.getToContext(), ToTAInfo),
VarTemplate, QualType(), nullptr,
D->getStorageClass(), TemplateArgs))
return ToPartial;
@ -6902,34 +6864,6 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
QualType(), nullptr, D->getStorageClass(),
TemplateArgs))
return D2;
if (const auto *Info = D->getExplicitInstantiationInfo()) {
auto ExternKeywordLocOrErr = import(Info->ExternKeywordLoc);
if (!ExternKeywordLocOrErr)
return ExternKeywordLocOrErr.takeError();
auto TemplateKeywordLocOrErr = import(Info->TemplateKeywordLoc);
if (!TemplateKeywordLocOrErr)
return TemplateKeywordLocOrErr.takeError();
TemplateArgumentListInfo ToTAInfo;
if (Error Err = ImportTemplateArgumentListInfo(
*Info->TemplateArgsAsWritten, ToTAInfo))
return std::move(Err);
D2->setExplicitInstantiationInfo(*ExternKeywordLocOrErr,
*TemplateKeywordLocOrErr,
ASTTemplateArgumentListInfo::Create(
Importer.getToContext(), ToTAInfo));
} else if (const auto *Info = D->getExplicitSpecializationInfo()) {
auto ParamsOrErr = import(Info->TemplateParams);
if (!ParamsOrErr)
return ParamsOrErr.takeError();
TemplateArgumentListInfo ToTAInfo;
if (Error Err = ImportTemplateArgumentListInfo(
*Info->TemplateArgsAsWritten, ToTAInfo))
return std::move(Err);
D2->setExplicitSpecializationInfo(*ParamsOrErr,
ASTTemplateArgumentListInfo::Create(
Importer.getToContext(), ToTAInfo));
}
}
// Update InsertPos, because preceding import calls may have invalidated
@ -6956,6 +6890,9 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
D2->setSpecializationKind(D->getSpecializationKind());
if (D->getTemplateArgsAsWritten())
D2->setTemplateArgsAsWritten(ToTAInfo);
if (auto LocOrErr = import(D->getQualifierLoc()))
D2->setQualifierInfo(*LocOrErr);
else

View file

@ -233,13 +233,11 @@ void DeclInfo::fill() {
Kind = FunctionKind;
ParamVars = FD->parameters();
ReturnType = FD->getReturnType();
TemplateParameters = FD->getTemplateSpecializationParameters();
if (ArrayRef<TemplateParameterList *> TPLs =
FD->getTemplateParameterLists();
!TemplateParameters && !TPLs.empty())
TemplateParameters = TPLs.back();
if (TemplateParameters)
ArrayRef<TemplateParameterList *> TPLs = FD->getTemplateParameterLists();
if (!TPLs.empty()) {
TemplateKind = TemplateSpecialization;
TemplateParameters = TPLs.back();
}
if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
K == Decl::CXXDestructor || K == Decl::CXXConversion) {

View file

@ -51,7 +51,6 @@
#include "clang/Basic/TargetCXXABI.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Visibility.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
@ -4208,7 +4207,6 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
case TSK_ExplicitSpecialization:
return false;
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
return true;
@ -4329,21 +4327,12 @@ FunctionDecl::getTemplateSpecializationArgsAsWritten() const {
return nullptr;
}
const TemplateParameterList *
FunctionDecl::getTemplateSpecializationParameters() const {
if (const auto *Info = getTemplateSpecializationInfo())
return Info->TemplateParameters;
if (const auto *Info = getDependentSpecializationInfo())
return Info->TemplateParameters;
return nullptr;
}
void FunctionDecl::setFunctionTemplateSpecialization(
ASTContext &C, FunctionTemplateDecl *Template,
TemplateArgumentList *TemplateArgs, void *InsertPos,
TemplateSpecializationKind TSK, const TemplateParameterList *TemplateParams,
TemplateSpecializationKind TSK,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation PointOfInstantiation, bool AddSpecialization) {
SourceLocation PointOfInstantiation) {
assert((TemplateOrSpecialization.isNull() ||
isa<MemberSpecializationInfo *>(TemplateOrSpecialization)) &&
"Member function is already a specialization");
@ -4355,23 +4344,21 @@ void FunctionDecl::setFunctionTemplateSpecialization(
"Member specialization must be an explicit specialization");
FunctionTemplateSpecializationInfo *Info =
FunctionTemplateSpecializationInfo::Create(
C, this, Template, TSK, TemplateArgs, TemplateParams,
TemplateArgsAsWritten, PointOfInstantiation,
C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten,
PointOfInstantiation,
dyn_cast_if_present<MemberSpecializationInfo *>(
TemplateOrSpecialization));
TemplateOrSpecialization = Info;
if (AddSpecialization)
Template->addSpecialization(Info, InsertPos);
Template->addSpecialization(Info, InsertPos);
}
void FunctionDecl::setDependentTemplateSpecialization(
ASTContext &Context, const UnresolvedSetImpl &Templates,
const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TemplateArgs) {
assert(TemplateOrSpecialization.isNull());
DependentFunctionTemplateSpecializationInfo *Info =
DependentFunctionTemplateSpecializationInfo::Create(
Context, Templates, TemplateParams, TemplateArgs);
DependentFunctionTemplateSpecializationInfo::Create(Context, Templates,
TemplateArgs);
TemplateOrSpecialization = Info;
}
@ -4384,22 +4371,19 @@ FunctionDecl::getDependentSpecializationInfo() const {
DependentFunctionTemplateSpecializationInfo *
DependentFunctionTemplateSpecializationInfo::Create(
ASTContext &Context, const UnresolvedSetImpl &Candidates,
const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TArgs) {
const auto *TArgsWritten =
TArgs ? ASTTemplateArgumentListInfo::Create(Context, *TArgs) : nullptr;
return new (Context.Allocate(
totalSizeToAlloc<FunctionTemplateDecl *>(Candidates.size())))
DependentFunctionTemplateSpecializationInfo(Candidates, TemplateParams,
TArgsWritten);
DependentFunctionTemplateSpecializationInfo(Candidates, TArgsWritten);
}
DependentFunctionTemplateSpecializationInfo::
DependentFunctionTemplateSpecializationInfo(
const UnresolvedSetImpl &Candidates,
const TemplateParameterList *TemplateParams,
const ASTTemplateArgumentListInfo *TemplateArgsWritten)
: NumCandidates(Candidates.size()), TemplateParameters(TemplateParams),
: NumCandidates(Candidates.size()),
TemplateArgumentsAsWritten(TemplateArgsWritten) {
std::transform(Candidates.begin(), Candidates.end(), getTrailingObjects(),
[](NamedDecl *ND) {
@ -4559,17 +4543,6 @@ bool FunctionDecl::isOutOfLine() const {
return false;
}
SourceLocation FunctionDecl::getFunctionLocStart() const {
if (const TemplateParameterList *TemplateParams =
getTemplateSpecializationParameters()) {
const ASTContext &Ctx = getASTContext();
return Lexer::findNextToken(TemplateParams->getSourceRange().getEnd(),
Ctx.getSourceManager(), Ctx.getLangOpts())
->getLocation();
}
return getInnerLocStart();
}
SourceRange FunctionDecl::getSourceRange() const {
return SourceRange(getOuterLocStart(), EndRangeLoc);
}

View file

@ -1105,7 +1105,6 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Out << *Attrs << ' ';
if (D->getIdentifier()) {
// FIXME: Missing template parameter lists.
D->getQualifier().print(Out, Policy);
Out << *D;

View file

@ -245,8 +245,8 @@ bool TemplateParameterList::hasAssociatedConstraints() const {
return HasRequiresClause || HasConstrainedParameters;
}
ArrayRef<TemplateArgument> TemplateParameterList::getInjectedTemplateArgs(
const ASTContext &Context) const {
ArrayRef<TemplateArgument>
TemplateParameterList::getInjectedTemplateArgs(const ASTContext &Context) {
if (!InjectedArgs) {
InjectedArgs = new (Context) TemplateArgument[size()];
llvm::transform(*this, InjectedArgs, [&](NamedDecl *ND) {
@ -946,7 +946,6 @@ TemplateArgumentList::CreateCopy(ASTContext &Context,
FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation POI,
MemberSpecializationInfo *MSInfo) {
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
@ -957,8 +956,7 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
void *Mem =
C.Allocate(totalSizeToAlloc<MemberSpecializationInfo *>(MSInfo ? 1 : 0));
return new (Mem) FunctionTemplateSpecializationInfo(
FD, Template, TSK, TemplateArgs, TemplateParams, ArgsAsWritten, POI,
MSInfo);
FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo);
}
//===----------------------------------------------------------------------===//
@ -1052,38 +1050,54 @@ ClassTemplateSpecializationDecl::getSourceRange() const {
return CTPSD->getSourceRange();
return cast<ClassTemplateDecl *>(Pattern)->getSourceRange();
}
case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization: {
const auto *Info = getExplicitSpecializationInfo();
auto TPLs = getTemplateParameterLists();
return SourceRange(TPLs.empty() ? Info->TemplateParams->getTemplateLoc()
: TPLs.front()->getTemplateLoc(),
isThisDeclarationADefinition()
? CXXRecordDecl::getSourceRange().getEnd()
: Info->TemplateArgsAsWritten->getRAngleLoc());
SourceRange Range = CXXRecordDecl::getSourceRange();
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten();
!isThisDeclarationADefinition() && Args)
Range.setEnd(Args->getRAngleLoc());
return Range;
}
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition: {
const auto *Info = getExplicitInstantiationInfo();
return SourceRange(Info->ExternKeywordLoc.isValid()
? Info->ExternKeywordLoc
: Info->TemplateKeywordLoc,
Info->TemplateArgsAsWritten->getRAngleLoc());
SourceRange Range = CXXRecordDecl::getSourceRange();
if (SourceLocation ExternKW = getExternKeywordLoc(); ExternKW.isValid())
Range.setBegin(ExternKW);
else if (SourceLocation TemplateKW = getTemplateKeywordLoc();
TemplateKW.isValid())
Range.setBegin(TemplateKW);
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten())
Range.setEnd(Args->getRAngleLoc());
return Range;
}
}
llvm_unreachable("unhandled template specialization kind");
}
void ClassTemplateSpecializationDecl::setExplicitSpecializationInfo(
TemplateParameterList *TemplateParams,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
auto *Info = new (getASTContext()) ExplicitSpecializationInfo();
Info->TemplateParams = TemplateParams;
Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
ExplicitInfo = Info;
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;
}
if (AdoptTemplateParameterList(TemplateParams, this))
setInvalidDecl();
void ClassTemplateSpecializationDecl::setTemplateKeywordLoc(
SourceLocation Loc) {
auto *Info = dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
if (!Info) {
// Don't allocate if the location is invalid.
if (Loc.isInvalid())
return;
Info = new (getASTContext()) ExplicitInstantiationInfo;
Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
ExplicitInfo = Info;
}
Info->TemplateKeywordLoc = Loc;
}
//===----------------------------------------------------------------------===//
@ -1154,7 +1168,6 @@ void ClassTemplatePartialSpecializationDecl::anchor() {}
ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl)
@ -1163,24 +1176,25 @@ ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
// Tracking StrictPackMatch for Partial
// Specializations is not needed.
SpecializedTemplate, Args, /*StrictPackMatch=*/false, PrevDecl),
InstantiatedFromMember(nullptr, false),
TemplateParams(Params), InstantiatedFromMember(nullptr, false),
CanonInjectedTST(CanonInjectedTST) {
setSpecializationKind(TSK_ExplicitSpecialization);
setExplicitSpecializationInfo(Params, ArgsAsWritten);
if (AdoptTemplateParameterList(Params, this))
setInvalidDecl();
}
ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::Create(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl) {
assert(!Params->empty() && "template with no template parameters");
return new (Context, DC) ClassTemplatePartialSpecializationDecl(
Context, TK, DC, StartLoc, IdLoc, Params, ArgsAsWritten,
SpecializedTemplate, Args, CanonInjectedTST, PrevDecl);
auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl(
Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args,
CanonInjectedTST, PrevDecl);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
return Result;
}
ClassTemplatePartialSpecializationDecl *
@ -1207,7 +1221,11 @@ SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const {
getInstantiatedFromMember();
MT && !isMemberSpecialization())
return MT->getSourceRange();
return ClassTemplateSpecializationDecl::getSourceRange();
SourceRange Range = ClassTemplateSpecializationDecl::getSourceRange();
if (const TemplateParameterList *TPL = getTemplateParameters();
TPL && getTemplateParameterLists().empty())
Range.setBegin(TPL->getTemplateLoc());
return Range;
}
//===----------------------------------------------------------------------===//
@ -1466,11 +1484,8 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
}
return VTD->getCanonicalDecl()->getSourceRange();
}
case TSK_FriendDeclaration:
case TSK_ExplicitSpecialization: {
SourceRange Range = VarDecl::getSourceRange();
if (const auto *Info = getExplicitSpecializationInfo())
Range.setBegin(Info->TemplateParams->getTemplateLoc());
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten();
!hasInit() && Args)
Range.setEnd(Args->getRAngleLoc());
@ -1478,11 +1493,10 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
}
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition: {
const auto *Info = getExplicitInstantiationInfo();
SourceRange Range = VarDecl::getSourceRange();
if (SourceLocation ExternKW = Info->ExternKeywordLoc; ExternKW.isValid())
if (SourceLocation ExternKW = getExternKeywordLoc(); ExternKW.isValid())
Range.setBegin(ExternKW);
else if (SourceLocation TemplateKW = Info->TemplateKeywordLoc;
else if (SourceLocation TemplateKW = getTemplateKeywordLoc();
TemplateKW.isValid())
Range.setBegin(TemplateKW);
if (const ASTTemplateArgumentListInfo *Args = getTemplateArgsAsWritten())
@ -1493,16 +1507,30 @@ SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
llvm_unreachable("unhandled template specialization kind");
}
void VarTemplateSpecializationDecl::setExplicitSpecializationInfo(
TemplateParameterList *TemplateParams,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten) {
auto *Info = new (getASTContext()) ExplicitSpecializationInfo();
Info->TemplateParams = TemplateParams;
Info->TemplateArgsAsWritten = TemplateArgsAsWritten;
ExplicitInfo = Info;
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;
}
if (AdoptTemplateParameterList(TemplateParams, getDeclContext()))
setInvalidDecl();
void VarTemplateSpecializationDecl::setTemplateKeywordLoc(SourceLocation Loc) {
auto *Info = dyn_cast_if_present<ExplicitInstantiationInfo *>(ExplicitInfo);
if (!Info) {
// Don't allocate if the location is invalid.
if (Loc.isInvalid())
return;
Info = new (getASTContext()) ExplicitInstantiationInfo;
Info->TemplateArgsAsWritten = getTemplateArgsAsWritten();
ExplicitInfo = Info;
}
Info->TemplateKeywordLoc = Loc;
}
//===----------------------------------------------------------------------===//
@ -1514,28 +1542,28 @@ void VarTemplatePartialSpecializationDecl::anchor() {}
VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args)
: VarTemplateSpecializationDecl(VarTemplatePartialSpecialization, Context,
DC, StartLoc, IdLoc, SpecializedTemplate, T,
TInfo, S, Args),
InstantiatedFromMember(nullptr, false) {
setSpecializationKind(TSK_ExplicitSpecialization);
setExplicitSpecializationInfo(Params, ArgsAsWritten);
TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
if (AdoptTemplateParameterList(Params, DC))
setInvalidDecl();
}
VarTemplatePartialSpecializationDecl *
VarTemplatePartialSpecializationDecl::Create(
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args) {
assert(!Params->empty() && "template with no template parameters");
return new (Context, DC) VarTemplatePartialSpecializationDecl(
Context, DC, StartLoc, IdLoc, Params, ArgsAsWritten, SpecializedTemplate,
T, TInfo, S, Args);
auto *Result = new (Context, DC) VarTemplatePartialSpecializationDecl(
Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, S,
Args);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
return Result;
}
VarTemplatePartialSpecializationDecl *
@ -1549,7 +1577,11 @@ SourceRange VarTemplatePartialSpecializationDecl::getSourceRange() const {
getInstantiatedFromMember();
MT && !isMemberSpecialization())
return MT->getSourceRange();
return VarTemplateSpecializationDecl::getSourceRange();
SourceRange Range = VarTemplateSpecializationDecl::getSourceRange();
if (const TemplateParameterList *TPL = getTemplateParameters();
TPL && getTemplateParameterLists().empty())
Range.setBegin(TPL->getTemplateLoc());
return Range;
}
static TemplateParameterList *createBuiltinTemplateParameterList(

View file

@ -1131,9 +1131,6 @@ void JSONNodeDumper::VisitExplicitInstantiationDecl(
case TSK_ImplicitInstantiation:
JOS.attribute("templateSpecializationKind", "implicit_instantiation");
break;
case TSK_FriendDeclaration:
JOS.attribute("templateSpecializationKind", "friend_declaration");
break;
case TSK_ExplicitSpecialization:
JOS.attribute("templateSpecializationKind", "explicit_specialization");
break;

View file

@ -1044,9 +1044,6 @@ void clang::TextNodeDumper::dumpTemplateSpecializationKind(
case TSK_ImplicitInstantiation:
OS << " implicit_instantiation";
break;
case TSK_FriendDeclaration:
OS << " friend_declaration";
break;
case TSK_ExplicitSpecialization:
OS << " explicit_specialization";
break;

View file

@ -99,7 +99,6 @@ RegistryMaps::RegistryMaps() {
//
// Other:
// equalsNode
// declaresSameEntityAsNode
registerMatcher("mapAnyOf",
std::make_unique<internal::MapAnyOfBuilderDescriptor>());

View file

@ -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());
const auto FuncDecl = hasDeclaration(functionDecl().bind("func"));
const auto Matches = match(
traverse(
TK_AsIs,
@ -704,16 +704,13 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
Stm, Context);
for (const auto &Nodes : Matches) {
const auto *Exp = Nodes.getNodeAs<Expr>(NodeID<Expr>::value);
const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
const auto *Func =
cast<FunctionDecl>(Parm->getDeclContext())->getDefinition();
if (!Func || !Func->doesThisDeclarationHaveABody())
const auto *Func = Nodes.getNodeAs<FunctionDecl>("func");
if (!Func->getBody() || !Func->getPrimaryTemplate())
return Exp;
Parm = Func->getParamDecl(Parm->getFunctionScopeIndex());
const auto *Parm = Nodes.getNodeAs<ParmVarDecl>("parm");
const ArrayRef<ParmVarDecl *> AllParams =
Func->getTemplateInstantiationPattern(/*ForDefinition=*/true)
->parameters();
Func->getPrimaryTemplate()->getTemplatedDecl()->parameters();
QualType ParmType =
AllParams[std::min<size_t>(Parm->getFunctionScopeIndex(),
AllParams.size() - 1)]

View file

@ -365,7 +365,6 @@ cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) {
: cir::GlobalLinkageKind::InternalLinkage;
return cir::GlobalLinkageKind::ExternalLinkage;
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
return cir::GlobalLinkageKind::LinkOnceODRLinkage;
@ -398,7 +397,6 @@ cir::GlobalLinkageKind CIRGenModule::getVTableLinkage(const CXXRecordDecl *rd) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
case TSK_FriendDeclaration:
return discardableODRLinkage;
case TSK_ExplicitInstantiationDeclaration:

View file

@ -1149,22 +1149,21 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
return llvm::GlobalVariable::ExternalLinkage;
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
return !Context.getLangOpts().AppleKext
? llvm::GlobalVariable::LinkOnceODRLinkage
: llvm::Function::InternalLinkage;
case TSK_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_ExplicitInstantiationDefinition:
return !Context.getLangOpts().AppleKext ?
llvm::GlobalVariable::WeakODRLinkage :
llvm::Function::InternalLinkage;
case TSK_ExplicitInstantiationDeclaration:
return IsExternalDefinition
? llvm::GlobalVariable::AvailableExternallyLinkage
: llvm::GlobalVariable::ExternalLinkage;
}
case TSK_ExplicitInstantiationDeclaration:
return IsExternalDefinition
? llvm::GlobalVariable::AvailableExternallyLinkage
: llvm::GlobalVariable::ExternalLinkage;
}
}
// -fapple-kext mode does not support weak linkage, so we must use
@ -1189,7 +1188,6 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
case TSK_FriendDeclaration:
return DiscardableODRLinkage;
case TSK_ExplicitInstantiationDeclaration:

View file

@ -185,7 +185,6 @@ bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
return isa<ClassTemplateSpecializationDecl>(D);
case TSK_ExplicitSpecialization:
return false;
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:

View file

@ -318,7 +318,6 @@ static bool hasVTable(const CXXRecordDecl *D) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
case TSK_FriendDeclaration:
case TSK_ExplicitInstantiationDefinition:
return true;
case TSK_ExplicitInstantiationDeclaration:
@ -335,7 +334,6 @@ static bool hasVTable(const CXXRecordDecl *D) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
case TSK_FriendDeclaration:
return false;
case TSK_ExplicitInstantiationDeclaration:
@ -363,7 +361,6 @@ static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) {
if (isInlined(KeyFunctionD))
return CXXLinkage::LinkOnceODRLinkage;
return CXXLinkage::ExternalLinkage;
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
llvm_unreachable("No external vtable for implicit instantiations");
case TSK_ExplicitInstantiationDefinition:
@ -378,7 +375,6 @@ static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
case TSK_ImplicitInstantiation:
case TSK_FriendDeclaration:
return CXXLinkage::LinkOnceODRLinkage;
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
@ -605,7 +601,6 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
break;
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
continue;
case TSK_ExplicitInstantiationDeclaration:

View file

@ -2059,17 +2059,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateParams = &FakedParamLists;
}
}
MultiTemplateParamsArg ParamLists(
TemplateParams ? &(*TemplateParams)[0] : nullptr,
TemplateParams ? TemplateParams->size() : 0);
// Build the class template specialization.
TagOrTempResult = Actions.ActOnClassTemplateSpecialization(
getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(),
SS, *TemplateId, attrs, ParamLists, &SkipBody);
// Some template parameter lists may have been dropped because they were
// extraneous.
if (TemplateParams)
TemplateParams->resize(ParamLists.size());
SS, *TemplateId, attrs,
MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]
: nullptr,
TemplateParams ? TemplateParams->size() : 0),
&SkipBody);
}
} else if (TemplateInfo.Kind == ParsedTemplateKind::ExplicitInstantiation &&
TUK == TagUseKind::Declaration) {

View file

@ -317,6 +317,12 @@ addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
ElaboratedTypeKeyword::Class, TemplateName(TextureTemplate),
{TemplateArgument(VectorType)}, {}));
auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
AST, TagDecl::TagKind::Class, HLSLNamespace, SourceLocation(),
SourceLocation(), TemplateParams, TextureTemplate,
{TemplateArgument(VectorType)},
CanQualType::CreateUnsafe(CanonInjectedTST), nullptr);
// Set the template arguments as written.
TemplateArgument Arg(VectorType);
TemplateArgumentLoc ArgLoc =
@ -324,13 +330,8 @@ addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
TemplateArgumentListInfo ArgsInfo =
TemplateArgumentListInfo(SourceLocation(), SourceLocation());
ArgsInfo.addArgument(ArgLoc);
auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
AST, TagDecl::TagKind::Class, HLSLNamespace, SourceLocation(),
SourceLocation(), TemplateParams,
ASTTemplateArgumentListInfo::Create(AST, ArgsInfo), TextureTemplate,
{TemplateArgument(VectorType)},
CanQualType::CreateUnsafe(CanonInjectedTST), nullptr);
PartialSpec->setTemplateArgsAsWritten(
ASTTemplateArgumentListInfo::Create(AST, ArgsInfo));
PartialSpec->setImplicit(true);
PartialSpec->setLexicalDeclContext(HLSLNamespace);

View file

@ -200,10 +200,15 @@ static bool DiagRecursiveConstraintEval(
// Figure out the to-translation-unit depth for this function declaration for
// the purpose of seeing if they differ by constraints. This isn't the same as
// getTemplateDepth, because it includes already instantiated parents.
static unsigned CalculateTemplateDepthForConstraints(Sema &S,
const NamedDecl *ND) {
// FIXME: This is a very expensive way to calculate this.
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(ND);
static unsigned
CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
bool SkipForSpecialization = false) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
ND, ND->getLexicalDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true, SkipForSpecialization);
return MLTAL.getNumLevels();
}
@ -1330,8 +1335,10 @@ bool Sema::CheckConstraintSatisfaction(
return false;
}
static ExprResult SubstituteConceptsInConstraintExpression(
Sema &S, const ConceptSpecializationExpr *CSE, UnsignedOrNone SubstIndex) {
static ExprResult
SubstituteConceptsInConstraintExpression(Sema &S, const NamedDecl *D,
const ConceptSpecializationExpr *CSE,
UnsignedOrNone SubstIndex) {
Sema::SFINAETrap Trap(S);
// [C++2c] [temp.constr.normal]
// Otherwise, to form CE, any non-dependent concept template argument Ai
@ -1339,8 +1346,7 @@ static ExprResult SubstituteConceptsInConstraintExpression(
// If any such substitution results in an invalid concept-id,
// the program is ill-formed; no diagnostic is required.
Expr *ConstraintExpr =
CSE->getNamedConcept()->getCanonicalDecl()->getConstraintExpr();
ConceptDecl *Concept = CSE->getNamedConcept()->getCanonicalDecl();
Sema::ArgPackSubstIndexRAII _(S, SubstIndex);
const ASTTemplateArgumentListInfo *ArgsAsWritten =
@ -1350,17 +1356,23 @@ static ExprResult SubstituteConceptsInConstraintExpression(
return !ArgLoc.getArgument().isDependent() &&
ArgLoc.getArgument().isConceptOrConceptTemplateParameter();
})) {
return ConstraintExpr;
return Concept->getConstraintExpr();
}
return S.SubstConceptTemplateArguments(
CSE, ConstraintExpr,
S.getTemplateInstantiationArgs(CSE->getSpecializationDecl()));
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
Concept, Concept->getLexicalDeclContext(),
/*Final=*/false, CSE->getTemplateArguments(),
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
return S.SubstConceptTemplateArguments(CSE, Concept->getConstraintExpr(),
MLTAL);
}
bool Sema::SetupConstraintScope(FunctionDecl *FD,
const MultiLevelTemplateArgumentList &MLTAL,
LocalInstantiationScope &Scope) {
bool Sema::SetupConstraintScope(
FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
const MultiLevelTemplateArgumentList &MLTAL,
LocalInstantiationScope &Scope) {
assert(!isLambdaCallOperator(FD) &&
"Use LambdaScopeForCallOperatorInstantiationRAII to handle lambda "
"instantiations");
@ -1369,7 +1381,8 @@ bool Sema::SetupConstraintScope(FunctionDecl *FD,
InstantiatingTemplate Inst(
*this, FD->getPointOfInstantiation(),
Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate,
FD->getTemplateSpecializationArgs()->asArray(), SourceRange());
TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
SourceRange());
if (Inst.isInvalid())
return true;
@ -1405,10 +1418,11 @@ bool Sema::SetupConstraintScope(FunctionDecl *FD,
? FD->getInstantiatedFromMemberFunction()
: FD->getInstantiatedFromDecl();
InstantiatingTemplate Inst(*this, FD->getPointOfInstantiation(),
Sema::InstantiatingTemplate::ConstraintsCheck{},
InstantiatedFrom, ArrayRef<TemplateArgument>(),
SourceRange());
InstantiatingTemplate Inst(
*this, FD->getPointOfInstantiation(),
Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
SourceRange());
if (Inst.isInvalid())
return true;
@ -1425,12 +1439,23 @@ bool Sema::SetupConstraintScope(FunctionDecl *FD,
// constraint-instantiation and checking.
std::optional<MultiLevelTemplateArgumentList>
Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
FunctionDecl *FD, LocalInstantiationScope &Scope) {
MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(FD);
FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
LocalInstantiationScope &Scope) {
MultiLevelTemplateArgumentList MLTAL;
// Collect the list of template arguments relative to the 'primary' template.
// We need the entire list, since the constraint is completely uninstantiated
// at this point.
MLTAL =
getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
// Lambdas are handled by LambdaScopeForCallOperatorInstantiationRAII.
if (isLambdaCallOperator(FD))
return MLTAL;
if (SetupConstraintScope(FD, MLTAL, Scope))
if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
return std::nullopt;
return MLTAL;
@ -1477,7 +1502,7 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
LocalInstantiationScope Scope(*this, !ForOverloadResolution);
std::optional<MultiLevelTemplateArgumentList> MLTAL =
SetupConstraintCheckingTemplateArgumentsAndScope(
const_cast<FunctionDecl *>(FD), Scope);
const_cast<FunctionDecl *>(FD), {}, Scope);
if (!MLTAL)
return true;
@ -1500,10 +1525,15 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
Satisfaction);
}
static const Expr *
SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
const Expr *ConstrExpr) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(ND);
static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
Sema &S, const Sema::TemplateCompareNewDeclInfo &DeclInfo,
const Expr *ConstrExpr) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
DeclInfo.getDecl(), DeclInfo.getDeclContext(), /*Final=*/false,
/*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
/*SkipForSpecialization*/ false);
if (MLTAL.getNumSubstitutedLevels() == 0)
return ConstrExpr;
@ -1513,7 +1543,8 @@ SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
// this may happen while we're comparing two templates' constraint
// equivalence.
std::optional<LocalInstantiationScope> ScopeForParameters;
if (ND->isFunctionOrFunctionTemplate()) {
if (const NamedDecl *ND = DeclInfo.getDecl();
ND && ND->isFunctionOrFunctionTemplate()) {
ScopeForParameters.emplace(S, /*CombineWithOuterScope=*/true);
const FunctionDecl *FD = ND->getAsFunction();
if (FunctionTemplateDecl *Template = FD->getDescribedFunctionTemplate();
@ -1557,9 +1588,13 @@ SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
// possible that e.g. constraints involving C<Class<T>> and C<Class> are
// perceived identical.
std::optional<Sema::ContextRAII> ContextScope;
const DeclContext *DC = ND->getFriendObjectKind()
? ND->getLexicalDeclContext()
: ND->getDeclContext();
const DeclContext *DC = [&] {
if (!DeclInfo.getDecl())
return DeclInfo.getDeclContext();
return DeclInfo.getDecl()->getFriendObjectKind()
? DeclInfo.getLexicalDeclContext()
: DeclInfo.getDeclContext();
}();
if (auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
ThisScope.emplace(S, const_cast<CXXRecordDecl *>(RD), Qualifiers());
ContextScope.emplace(S, const_cast<DeclContext *>(cast<DeclContext>(RD)),
@ -1575,14 +1610,15 @@ SubstituteConstraintExpressionWithoutSatisfaction(Sema &S, const Decl *ND,
return SubstConstr.get();
}
bool Sema::AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
const Decl *New,
bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
const Expr *OldConstr,
const TemplateCompareNewDeclInfo &New,
const Expr *NewConstr) {
if (OldConstr == NewConstr)
return true;
// C++ [temp.constr.decl]p4
if (Old != New &&
Old->getLexicalDeclContext() != New->getLexicalDeclContext()) {
if (Old && !New.isInvalid() && !New.ContainsDecl(Old) &&
Old->getLexicalDeclContext() != New.getLexicalDeclContext()) {
Sema::SFINAETrap _(*this);
if (const Expr *SubstConstr =
SubstituteConstraintExpressionWithoutSatisfaction(*this, Old,
@ -1604,15 +1640,19 @@ bool Sema::AreConstraintExpressionsEqual(const Decl *Old, const Expr *OldConstr,
return ID1 == ID2;
}
bool Sema::FriendConstraintsDependOnEnclosingTemplate(
const FunctionTemplateDecl *FTD) {
assert(FTD->getFriendObjectKind() && "Must be a friend!");
bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
assert(FD->getFriendObjectKind() && "Must be a friend!");
// The logic for non-templates is handled in ASTContext::isSameEntity, so we
// don't have to bother checking 'DependsOnEnclosingTemplate' for a
// non-function-template.
assert(FD->getDescribedFunctionTemplate() &&
"Non-function templates don't need to be checked");
SmallVector<AssociatedConstraint, 3> ACs;
FTD->getAssociatedConstraints(ACs);
FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
const FunctionDecl *FD = FTD->getTemplatedDecl();
unsigned OldTemplateDepth = FTD->getTemplateDepth();
unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
for (const AssociatedConstraint &AC : ACs)
if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
AC.ConstraintExpr))
@ -1648,9 +1688,9 @@ bool Sema::EnsureTemplateArgumentListConstraints(
return false;
}
bool Sema::CheckFunctionTemplateConstraints(
SourceLocation PointOfInstantiation, FunctionTemplateDecl *Template,
ArrayRef<TemplateArgument> TemplateArgs,
static bool CheckFunctionConstraintsWithoutInstantiation(
Sema &SemaRef, SourceLocation PointOfInstantiation,
FunctionTemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
ConstraintSatisfaction &Satisfaction) {
SmallVector<AssociatedConstraint, 3> TemplateAC;
Template->getAssociatedConstraints(TemplateAC);
@ -1659,22 +1699,47 @@ bool Sema::CheckFunctionTemplateConstraints(
return false;
}
LocalInstantiationScope Scope(*this);
LocalInstantiationScope Scope(SemaRef);
MultiLevelTemplateArgumentList MLTAL =
getTemplateInstantiationArgs(Template, TemplateArgs);
FunctionDecl *FD = Template->getTemplatedDecl();
// Collect the list of template arguments relative to the 'primary'
// template. We need the entire list, since the constraint is completely
// uninstantiated at this point.
Sema::ContextRAII SavedContext(*this, Template->getTemplatedDecl());
return CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
PointOfInstantiation, Satisfaction);
MultiLevelTemplateArgumentList MLTAL;
{
// getTemplateInstantiationArgs uses this instantiation context to find out
// template arguments for uninstantiated functions.
// We don't want this RAII object to persist, because there would be
// otherwise duplicate diagnostic notes.
Sema::InstantiatingTemplate Inst(
SemaRef, PointOfInstantiation,
Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs,
PointOfInstantiation);
if (Inst.isInvalid())
return true;
MLTAL = SemaRef.getTemplateInstantiationArgs(
/*D=*/FD, FD,
/*Final=*/false, /*Innermost=*/{}, /*RelativeToPrimary=*/true,
/*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
}
Sema::ContextRAII SavedContext(SemaRef, FD);
return SemaRef.CheckConstraintSatisfaction(
Template, TemplateAC, MLTAL, PointOfInstantiation, Satisfaction);
}
bool Sema::CheckFunctionSpecializationConstraints(
bool Sema::CheckFunctionTemplateConstraints(
SourceLocation PointOfInstantiation, FunctionDecl *Decl,
ArrayRef<TemplateArgument> TemplateArgs,
ConstraintSatisfaction &Satisfaction) {
// In most cases we're not going to have constraints, so check for that first.
FunctionTemplateDecl *Template = Decl->getPrimaryTemplate();
assert(Template && "Function is not a specialization");
if (!Template)
return ::CheckFunctionConstraintsWithoutInstantiation(
*this, PointOfInstantiation, Decl->getDescribedFunctionTemplate(),
TemplateArgs, Satisfaction);
// Note - code synthesis context for the constraints check is created
// inside CheckConstraintsSatisfaction.
@ -1691,7 +1756,8 @@ bool Sema::CheckFunctionSpecializationConstraints(
LocalInstantiationScope Scope(*this);
std::optional<MultiLevelTemplateArgumentList> MLTAL =
SetupConstraintCheckingTemplateArgumentsAndScope(Decl, Scope);
SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
Scope);
if (!MLTAL)
return true;
@ -2275,8 +2341,12 @@ bool SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
InnerArgs = std::move(CTAI.SugaredConverted);
}
MultiLevelTemplateArgumentList MLTAL =
SemaRef.getTemplateInstantiationArgs(Concept, InnerArgs);
MultiLevelTemplateArgumentList MLTAL = SemaRef.getTemplateInstantiationArgs(
Concept, Concept->getLexicalDeclContext(),
/*Final=*/true, InnerArgs,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
return SubstituteParameterMappings(SemaRef, &MLTAL,
CSE->getTemplateArgsAsWritten(),
@ -2357,7 +2427,7 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr(
// [...]
NormalizedConstraint *SubNF;
if (ExprResult Res =
SubstituteConceptsInConstraintExpression(S, CSE, SubstIndex);
SubstituteConceptsInConstraintExpression(S, D, CSE, SubstIndex);
Res.isUsable())
// Use canonical declarations to merge ConceptDecls across different
// modules.
@ -2507,8 +2577,8 @@ bool Sema::IsAtLeastAsConstrained(const NamedDecl *D1,
return false;
}
unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1);
unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2);
unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
if (Depth2 > Depth1) {

View file

@ -4750,10 +4750,10 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
adjustDeclContextForDeclaratorDecl(New, Old);
// Ensure the template parameters are compatible.
if (NewTemplate && !TemplateParameterListsAreEqual(
NewTemplate, NewTemplate->getTemplateParameters(),
OldTemplate, OldTemplate->getTemplateParameters(),
/*Complain=*/true, TPL_TemplateMatch))
if (NewTemplate &&
!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
OldTemplate->getTemplateParameters(),
/*Complain=*/true, TPL_TemplateMatch))
return New->setInvalidDecl();
// C++ [class.mem]p1:
@ -6414,7 +6414,20 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
return false;
// Cannot qualify members within a class.
Diag(Loc, diag::err_member_qualification) << Name << SS.getRange();
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;
return false;
}
@ -8016,8 +8029,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
if (IsVariableTemplateSpecialization) {
// FIXME: This should be the template keyword location for the last
// template parameter list.
SourceLocation TemplateKWLoc =
TemplateParamLists.size() > 0
? TemplateParamLists[0]->getTemplateLoc()
@ -8060,8 +8071,10 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// If we have any template parameter lists that don't directly belong to
// the variable (matching the scope specifier), store them.
// An explicit variable template specialization does not own any template
// parameter lists.
unsigned VDTemplateParamLists =
IsVariableTemplate || IsVariableTemplateSpecialization ? 1 : 0;
(TemplateParams && !IsExplicitSpecialization) ? 1 : 0;
if (TemplateParamLists.size() > VDTemplateParamLists)
NewVD->setTemplateParameterListsInfo(
Context, TemplateParamLists.drop_back(VDTemplateParamLists));
@ -10112,7 +10125,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isMemberSpecialization = false;
bool isFunctionTemplateSpecialization = false;
TemplateParameterList *TemplateParams = nullptr;
bool HasExplicitTemplateArgs = false;
TemplateArgumentListInfo TemplateArgs;
@ -10197,14 +10209,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
? D.getName().TemplateId
: nullptr;
TemplateParamListsRef = TemplateParamLists;
TemplateParams = MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
D.getCXXScopeSpec(), TemplateId, TemplateParamListsRef, isFriend,
isMemberSpecialization, Invalid);
// Some template parameter lists may have been dropped because they were
// extraneous.
TemplateParamLists.resize(TemplateParamListsRef.size());
TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
D.getCXXScopeSpec(), TemplateId, TemplateParamLists, isFriend,
isMemberSpecialization, Invalid);
if (TemplateParams) {
// Check that we can declare a template here.
if (CheckTemplateDeclScope(S, TemplateParams))
@ -10239,10 +10248,19 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD);
FunctionTemplate->setLexicalDeclContext(CurContext);
NewFD->setDescribedFunctionTemplate(FunctionTemplate);
// For source fidelity, store the other template param lists.
if (TemplateParamLists.size() > 1) {
NewFD->setTemplateParameterListsInfo(Context,
ArrayRef<TemplateParameterList *>(TemplateParamLists)
.drop_back(1));
}
} else {
// This is a function template specialization.
isFunctionTemplateSpecialization = true;
NewFD->setInnerLocStart(TemplateParams->getTemplateLoc());
// For source fidelity, store all the template param lists.
if (TemplateParamLists.size() > 0)
NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists);
// C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
if (isFriend) {
@ -10272,12 +10290,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TemplateArgs.setRAngleLoc(InsertLoc);
}
}
// For source fidelity, store the other template param lists.
if (TemplateParamLists.size() > 1) {
NewFD->setTemplateParameterListsInfo(
Context,
ArrayRef<TemplateParameterList *>(TemplateParamLists).drop_back(1));
}
} else {
// Check that we can declare a template here.
if (!TemplateParamLists.empty() && isMemberSpecialization &&
@ -10879,11 +10891,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// template is instantiated. In such cases, we store the declarations
// found by name lookup and defer resolution until instantiation.
if (CheckDependentFunctionTemplateSpecialization(
NewFD, TemplateParams, ExplicitTemplateArgs, Previous))
NewFD, ExplicitTemplateArgs, Previous))
NewFD->setInvalidDecl();
} else if (!NewFD->isInvalidDecl()) {
if (CheckFunctionTemplateSpecialization(NewFD, TemplateParams,
ExplicitTemplateArgs, Previous))
if (CheckFunctionTemplateSpecialization(NewFD, ExplicitTemplateArgs,
Previous))
NewFD->setInvalidDecl();
}
} else if (isMemberSpecialization && !FunctionTemplate) {
@ -11187,7 +11199,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Precalculate whether this is a friend function template with a constraint
// that depends on an enclosing template, per [temp.friend]p9.
if (isFriend && FunctionTemplate &&
FriendConstraintsDependOnEnclosingTemplate(FunctionTemplate)) {
FriendConstraintsDependOnEnclosingTemplate(NewFD)) {
NewFD->setFriendConstraintRefersToEnclosingTemplate(true);
// C++ [temp.friend]p9:

View file

@ -13938,13 +13938,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
}
if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) {
// It's ok that we don't pass the declarations corresponding to the
// template parameter lists here, because type alias templates cannot be
// declared out-of-line.
if (TemplateParameterListsAreEqual(
/*NewInstFrom=*/nullptr, TemplateParams,
/*OldInstFrom=*/nullptr, OldDecl->getTemplateParameters(),
/*Complain=*/true, TPL_TemplateMatch))
if (TemplateParameterListsAreEqual(TemplateParams,
OldDecl->getTemplateParameters(),
/*Complain=*/true,
TPL_TemplateMatch))
OldTemplateParams =
OldDecl->getMostRecentDecl()->getTemplateParameters();
else

View file

@ -1129,8 +1129,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
return ExprError();
}
DeclResult VDecl = CheckVarTemplateId(
VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs);
DeclResult VDecl =
CheckVarTemplateId(VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(),
*TemplateArgs, /*SetWrittenArgs=*/false);
if (VDecl.isInvalid())
return ExprError();

View file

@ -1325,10 +1325,8 @@ OverloadKind Sema::CheckOverload(Scope *S, FunctionDecl *New,
!New->getType()->isDependentType()) {
LookupResult TemplateSpecResult(LookupResult::Temporary, Old);
TemplateSpecResult.addAllDecls(Old);
if (CheckFunctionTemplateSpecialization(New, /*TemplateParams=*/nullptr,
/*ExplicitTemplateArgs=*/nullptr,
TemplateSpecResult,
/*QualifiedFriend*/ true)) {
if (CheckFunctionTemplateSpecialization(New, nullptr, TemplateSpecResult,
/*QualifiedFriend*/true)) {
New->setInvalidDecl();
return OverloadKind::Overload;
}

View file

@ -2113,71 +2113,19 @@ DeclResult Sema::CheckClassTemplate(
}
}
if (!PrevClassTemplate && PrevDecl) {
// C++ [temp]p5:
// A class template shall not have the same name as any other
// template, class, function, object, enumeration, enumerator,
// namespace, or type in the same scope (3.3), except as specified
// in (14.5.4).
Diag(NameLoc, diag::err_redefinition_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(
NewTemplate, TemplateParams, PrevClassTemplate,
TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext
: CurContext,
CurContext, KWLoc),
TemplateParams, PrevClassTemplate,
PrevClassTemplate->getTemplateParameters(), /*Complain=*/true,
TPL_TemplateMatch)) {
NewTemplate->setInvalidDecl();
NewClass->setInvalidDecl();
TPL_TemplateMatch))
return true;
}
// C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit
@ -2222,6 +2170,15 @@ DeclResult Sema::CheckClassTemplate(
}
}
}
} else if (PrevDecl) {
// C++ [temp]p5:
// A class template shall not have the same name as any other
// template, class, function, object, enumeration, enumerator,
// namespace, or type in the same scope (3.3), except as specified
// in (14.5.4).
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
return true;
}
// Check the template parameter list of this declaration, possibly
@ -2252,20 +2209,62 @@ DeclResult Sema::CheckClassTemplate(
<< SS.getRange();
}
// Set the access specifier.
if (!Invalid && TUK != TagUseKind::Friend &&
NewTemplate->getDeclContext()->isRecord())
SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
// If this is a templated friend in a dependent context we should not put it
// on the redecl chain. In some cases, the templated friend can be the most
// recent declaration tricking the template instantiator to make substitutions
// there.
// FIXME: Figure out how to combine with shouldLinkDependentDeclWithPrevious
bool ShouldAddRedecl =
!(TUK == TagUseKind::Friend && CurContext->isDependentContext());
if (ShouldAddRedecl && PrevClassTemplate)
CXXRecordDecl *NewClass = CXXRecordDecl::Create(
Context, Kind, SemanticContext, KWLoc, NameLoc, Name,
PrevClassTemplate && ShouldAddRedecl
? PrevClassTemplate->getTemplatedDecl()
: nullptr);
SetNestedNameSpecifier(*this, NewClass, SS);
if (NumOuterTemplateParamLists > 0)
NewClass->setTemplateParameterListsInfo(
Context,
llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) {
if (LangOpts.HLSL)
NewClass->addAttr(PackedAttr::CreateImplicit(Context));
AddAlignmentAttributesForRecord(NewClass);
AddMsStructLayoutForRecord(NewClass);
}
ClassTemplateDecl *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams,
NewClass);
if (ShouldAddRedecl)
NewTemplate->setPreviousDecl(PrevClassTemplate);
NewClass->setDescribedClassTemplate(NewTemplate);
if (ModulePrivateLoc.isValid())
NewTemplate->setModulePrivate();
if (IsMemberSpecialization) {
assert(PrevClassTemplate &&
"Member specialization without a primary template?");
NewTemplate->setMemberSpecialization();
}
// Set the access specifier.
if (!Invalid && TUK != TagUseKind::Friend &&
NewTemplate->getDeclContext()->isRecord())
SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
// Set the lexical context of these templates
NewClass->setLexicalDeclContext(CurContext);
NewTemplate->setLexicalDeclContext(CurContext);
if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
NewClass->startDefinition();
@ -2838,7 +2837,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;
@ -3104,12 +3103,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (ParamIdx < ParamLists.size()) {
// Check the template parameter list, if we can.
// FIXME: Should pass the declaration corresponding to each list.
if (ExpectedTemplateParams &&
!TemplateParameterListsAreEqual(
/*NewInstFrom=*/nullptr, ParamLists[ParamIdx],
/*OldInstFrom=*/nullptr, ExpectedTemplateParams,
/*Complain=*/!SuppressDiagnostic, TPL_TemplateMatch))
!TemplateParameterListsAreEqual(ParamLists[ParamIdx],
ExpectedTemplateParams,
!SuppressDiagnostic, TPL_TemplateMatch))
Invalid = true;
if (!Invalid &&
@ -3176,9 +3173,6 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
diag::note_explicit_template_spec_does_not_need_header)
<< NestedTypes.back();
// Recover as if those extra template parameter lists weren't there.
ParamLists = ParamLists.take_back(ParamIdx + 1);
// We have a template parameter list with no corresponding scope, which
// means that the resulting template declaration can't be instantiated
// properly (we'll end up with dependent nodes when we shouldn't).
@ -4486,9 +4480,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplatePartialSpecializationDecl *Partial =
VarTemplatePartialSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
TemplateNameLoc, TemplateParams,
ASTTemplateArgumentListInfo::Create(Context, TemplateArgs),
VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
TemplateNameLoc, TemplateParams, VarTemplate, TSI->getType(), TSI,
SC, CTAI.CanonicalConverted);
Partial->setTemplateArgsAsWritten(TemplateArgs);
if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
@ -4501,9 +4495,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
Specialization = VarTemplateSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
VarTemplate, TSI->getType(), TSI, SC, CTAI.CanonicalConverted);
Specialization->setExplicitSpecializationInfo(
TemplateParams,
ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
Specialization->setTemplateArgsAsWritten(TemplateArgs);
if (!PrevDecl)
VarTemplate->AddSpecialization(Specialization, InsertPos);
@ -4589,7 +4581,8 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) {
DeclResult
Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation TemplateNameLoc,
const TemplateArgumentListInfo &TemplateArgs) {
const TemplateArgumentListInfo &TemplateArgs,
bool SetWrittenArgs) {
assert(Template && "A variable template id without template?");
// Check that the template argument list is well-formed for this template.
@ -4788,6 +4781,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
TemplateNameLoc /*, LateAttrs, StartingScope*/);
if (!Decl)
return true;
if (SetWrittenArgs)
Decl->setTemplateArgsAsWritten(TemplateArgs);
if (VarTemplatePartialSpecializationDecl *D =
dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern))
@ -4805,7 +4800,7 @@ ExprResult Sema::CheckVarTemplateId(
const TemplateArgumentListInfo *TemplateArgs) {
DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
*TemplateArgs);
*TemplateArgs, /*SetWrittenArgs=*/false);
if (Decl.isInvalid())
return ExprError();
@ -6197,8 +6192,7 @@ bool Sema::CheckTemplateArgumentList(
if (UpdateArgsWithConversions)
TemplateArgs = std::move(NewArgs);
// Template template parameters can never have their constraints checked.
if (!PartialTemplateArgs && !isa<TemplateTemplateParmDecl>(Template)) {
if (!PartialTemplateArgs) {
// Setup the context/ThisScope for the case where we are needing to
// re-instantiate constraints outside of normal instantiation.
DeclContext *NewContext = Template->getDeclContext();
@ -6217,8 +6211,11 @@ bool Sema::CheckTemplateArgumentList(
ContextRAII Context(*this, NewContext);
CXXThisScopeRAII Scope(*this, RD, ThisQuals, RD != nullptr);
MultiLevelTemplateArgumentList MLTAL =
getTemplateInstantiationArgs(Template, CTAI.SugaredConverted);
MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
Template, NewContext, /*Final=*/true, CTAI.SugaredConverted,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConceptInstantiation=*/true);
if (!isa<ConceptDecl>(Template) &&
EnsureTemplateArgumentListConstraints(
Template, MLTAL,
@ -8209,8 +8206,9 @@ Sema::BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
/// Match two template parameters within template parameter lists.
static bool MatchTemplateParameterKind(
Sema &S, NamedDecl *New, const Decl *NewInstFrom, NamedDecl *Old,
const Decl *OldInstFrom, bool Complain,
Sema &S, NamedDecl *New,
const Sema::TemplateCompareNewDeclInfo &NewInstFrom, NamedDecl *Old,
const NamedDecl *OldInstFrom, bool Complain,
Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
// Check the actual kind (type, non-type, template).
if (Old->getKind() != New->getKind()) {
@ -8298,7 +8296,7 @@ static bool MatchTemplateParameterKind(
if (OldTTP->templateParameterKind() != NewTTP->templateParameterKind())
return false;
if (!S.TemplateParameterListsAreEqual(
NewTTP, NewTTP->getTemplateParameters(), OldTTP,
NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
OldTTP->getTemplateParameters(), Complain,
(Kind == Sema::TPL_TemplateMatch
? Sema::TPL_TemplateTemplateParmMatch
@ -8376,8 +8374,8 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
}
bool Sema::TemplateParameterListsAreEqual(
const Decl *NewInstFrom, TemplateParameterList *New,
const Decl *OldInstFrom, TemplateParameterList *Old, bool Complain,
const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
if (Old->size() != New->size()) {
if (Complain)
@ -8759,7 +8757,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;
@ -8957,13 +8955,15 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
Specialization = ClassTemplateSpecializationDecl::Create(
Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
ClassTemplate, CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl);
Specialization->setTemplateArgsAsWritten(TemplateArgs);
SetNestedNameSpecifier(*this, Specialization, SS);
if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
TemplateParameterLists);
}
if (!PrevDecl)
ClassTemplate->AddSpecialization(Specialization, InsertPos);
Specialization->setExplicitSpecializationInfo(
TemplateParams,
ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
} else {
CanQualType CanonType = CanQualType::CreateUnsafe(
Context.getCanonicalTemplateSpecializationType(
@ -8999,8 +8999,13 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplatePartialSpecializationDecl *Partial =
ClassTemplatePartialSpecializationDecl::Create(
Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
ASTTemplateArgumentListInfo::Create(Context, TemplateArgs),
ClassTemplate, CTAI.CanonicalConverted, CanonType, PrevPartial);
Partial->setTemplateArgsAsWritten(TemplateArgs);
SetNestedNameSpecifier(*this, Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Partial->setTemplateParameterListsInfo(
Context, TemplateParameterLists.drop_back(1));
}
if (!PrevPartial)
ClassTemplate->AddPartialSpecialization(Partial, InsertPos);
@ -9010,18 +9015,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// template specialization, make a note of that.
if (isMemberSpecialization)
Partial->setMemberSpecialization();
}
SetNestedNameSpecifier(*this, Specialization, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Specialization->setTemplateParameterListsInfo(
Context, TemplateParameterLists.drop_back(1));
CheckTemplatePartialSpecialization(Partial);
}
if (isPartialSpecialization)
CheckTemplatePartialSpecialization(
cast<ClassTemplatePartialSpecializationDecl>(Specialization));
// C++ [temp.expl.spec]p6:
// If a template, a member template or the member of a class template is
// explicitly specialized then that specialization shall be declared
@ -9381,7 +9378,6 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
switch (NewTSK) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
case TSK_FriendDeclaration:
assert(
(PrevTSK == TSK_Undeclared || PrevTSK == TSK_ImplicitInstantiation) &&
"previous declaration must be implicit!");
@ -9396,7 +9392,6 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// instantiation.
return false;
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
if (PrevPointOfInstantiation.isInvalid()) {
// The declaration itself has not actually been instantiated, so it is
@ -9443,7 +9438,6 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
return false;
case TSK_Undeclared:
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
// We're explicitly instantiating something that may have already been
// implicitly instantiated; that's fine.
@ -9479,7 +9473,6 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
case TSK_ExplicitInstantiationDefinition:
switch (PrevTSK) {
case TSK_Undeclared:
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
// We're explicitly instantiating something that may have already been
// implicitly instantiated; that's fine.
@ -9539,8 +9532,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
}
bool Sema::CheckDependentFunctionTemplateSpecialization(
FunctionDecl *FD, const TemplateParameterList *TemplateParams,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous) {
// Remove anything from Previous that isn't a function template in
// the correct context.
@ -9577,14 +9569,13 @@ bool Sema::CheckDependentFunctionTemplateSpecialization(
}
FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(),
TemplateParams, ExplicitTemplateArgs);
ExplicitTemplateArgs);
return false;
}
bool Sema::CheckFunctionTemplateSpecialization(
FunctionDecl *FD, const TemplateParameterList *TemplateParams,
TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous,
bool QualifiedFriend) {
FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous, bool QualifiedFriend) {
// The set of function template specializations that could match this
// explicit function template specialization.
UnresolvedSet<8> Candidates;
@ -9834,11 +9825,9 @@ bool Sema::CheckFunctionTemplateSpecialization(
TemplateArgumentList *TemplArgs = TemplateArgumentList::CreateCopy(
Context, Specialization->getTemplateSpecializationArgs()->asArray());
FD->setFunctionTemplateSpecialization(
Context, Specialization->getPrimaryTemplate(), TemplArgs,
/*InsertPos=*/nullptr, SpecInfo->getTemplateSpecializationKind(),
TemplateParams,
ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr,
/*PointOfInstantiation=*/SourceLocation(), /*AddSpecialization=*/true);
Specialization->getPrimaryTemplate(), TemplArgs, /*InsertPos=*/nullptr,
SpecInfo->getTemplateSpecializationKind(),
ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr);
// A function template specialization inherits the target attributes
// of its template. (We require the attributes explicitly in the
@ -9988,13 +9977,14 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
// FIXME: Is this really valid? Other compilers reject.
if (Member->getFriendObjectKind() != Decl::FOK_None) {
// Preserve instantiation information.
if (InstantiatedFrom) {
if (auto *MD = dyn_cast<CXXMethodDecl>(Member))
MD->setInstantiationOfMemberFunction(
cast<CXXMethodDecl>(InstantiatedFrom), TSK_FriendDeclaration);
else if (auto *RD = dyn_cast<CXXRecordDecl>(Member))
RD->setInstantiationOfMemberClass(cast<CXXRecordDecl>(InstantiatedFrom),
TSK_FriendDeclaration);
if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) {
cast<CXXMethodDecl>(Member)->setInstantiationOfMemberFunction(
cast<CXXMethodDecl>(InstantiatedFrom),
cast<CXXMethodDecl>(Instantiation)->getTemplateSpecializationKind());
} else if (InstantiatedFrom && isa<CXXRecordDecl>(Member)) {
cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
cast<CXXRecordDecl>(InstantiatedFrom),
cast<CXXRecordDecl>(Instantiation)->getTemplateSpecializationKind());
}
Previous.clear();
@ -10081,8 +10071,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
template<typename DeclT>
static void completeMemberSpecializationImpl(Sema &S, DeclT *OrigD,
SourceLocation Loc) {
if (auto Kind = OrigD->getTemplateSpecializationKind();
Kind != TSK_ImplicitInstantiation && Kind != TSK_FriendDeclaration)
if (OrigD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
return;
// FIXME: Inform AST mutation listeners of this AST mutation.
@ -10412,6 +10401,7 @@ DeclResult Sema::ActOnExplicitInstantiation(
Specialization = ClassTemplateSpecializationDecl::Create(
Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
ClassTemplate, CTAI.CanonicalConverted, CTAI.StrictPackMatch, PrevDecl);
SetNestedNameSpecifier(*this, Specialization, SS);
// A MSInheritanceAttr attached to the previous declaration must be
// propagated to the new node prior to instantiation.
@ -10430,19 +10420,22 @@ DeclResult Sema::ActOnExplicitInstantiation(
}
}
Specialization->setExplicitInstantiationInfo(
ExternLoc, TemplateLoc,
ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
Specialization->setTemplateArgsAsWritten(TemplateArgs);
// Set source locations for keywords.
Specialization->setExternKeywordLoc(ExternLoc);
Specialization->setTemplateKeywordLoc(TemplateLoc);
Specialization->setBraceRange(SourceRange());
bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>();
ProcessDeclAttributeList(S, Specialization, Attr);
ProcessAPINotes(Specialization);
// Add the explicit instantiation into its lexical context.
auto *LexicalDC = ClassTemplate->getLexicalDeclContext();
Specialization->setLexicalDeclContext(LexicalDC);
LexicalDC->addDecl(Specialization);
// Add the explicit instantiation into its lexical context. However,
// since explicit instantiations are never found by name lookup, we
// just put it into the declaration context directly.
Specialization->setLexicalDeclContext(CurContext);
CurContext->addDecl(Specialization);
// Syntax is now OK, so return if it has no other effect on semantics.
if (HasNoEffect) {
@ -10771,15 +10764,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
LookupParsedName(Previous, S, &D.getCXXScopeSpec(),
/*ObjectType=*/QualType());
// If the declarator is a template-id, translate the parser's template
// argument list into our AST format.
bool HasExplicitTemplateArgs = false;
TemplateArgumentListInfo TemplateArgs;
if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) {
TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
HasExplicitTemplateArgs = true;
}
if (!R->isFunctionType()) {
// C++ [temp.explicit]p1:
// A [...] static data member of a class template can be explicitly
@ -10829,7 +10813,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}
if (!HasExplicitTemplateArgs) {
if (D.getName().getKind() != UnqualifiedIdKind::IK_TemplateId) {
// C++1y [temp.explicit]p3:
// If the explicit instantiation is for a variable, the unqualified-id
// in the declaration shall be a template-id.
@ -10841,8 +10825,13 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}
DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
D.getIdentifierLoc(), TemplateArgs);
// Translate the parser's template argument list into our AST format.
TemplateArgumentListInfo TemplateArgs =
makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
DeclResult Res =
CheckVarTemplateId(PrevTemplate, TemplateLoc, D.getIdentifierLoc(),
TemplateArgs, /*SetWrittenArgs=*/true);
if (Res.isInvalid())
return true;
@ -10890,10 +10879,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// Instantiate static data member or variable template.
Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Prev)) {
assert(HasExplicitTemplateArgs);
VTSD->setExplicitInstantiationInfo(
ExternLoc, TemplateLoc,
ASTTemplateArgumentListInfo::Create(Context, TemplateArgs));
VTSD->setExternKeywordLoc(ExternLoc);
VTSD->setTemplateKeywordLoc(TemplateLoc);
}
// Merge attributes.
@ -10922,6 +10909,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return (Decl *)nullptr;
}
// If the declarator is a template-id, translate the parser's template
// argument list into our AST format.
bool HasExplicitTemplateArgs = false;
TemplateArgumentListInfo TemplateArgs;
if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) {
TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
HasExplicitTemplateArgs = true;
}
// C++ [temp.explicit]p1:
// A [...] function [...] can be explicitly instantiated from its template.
// A member function [...] of a class template can be explicitly

View file

@ -3182,16 +3182,36 @@ CheckDeducedArgumentConstraints(Sema &S, NamedDecl *Template,
ArrayRef<TemplateArgument> CanonicalDeducedArgs,
TemplateDeductionInfo &Info) {
llvm::SmallVector<AssociatedConstraint, 3> AssociatedConstraints;
if (auto *TD = dyn_cast<ClassTemplatePartialSpecializationDecl>(Template))
bool DeducedArgsNeedReplacement = false;
if (auto *TD = dyn_cast<ClassTemplatePartialSpecializationDecl>(Template)) {
TD->getAssociatedConstraints(AssociatedConstraints);
else if (auto *TD = dyn_cast<VarTemplatePartialSpecializationDecl>(Template))
DeducedArgsNeedReplacement = !TD->isClassScopeExplicitSpecialization();
} else if (auto *TD =
dyn_cast<VarTemplatePartialSpecializationDecl>(Template)) {
TD->getAssociatedConstraints(AssociatedConstraints);
else
DeducedArgsNeedReplacement = !TD->isClassScopeExplicitSpecialization();
} else {
cast<TemplateDecl>(Template)->getAssociatedConstraints(
AssociatedConstraints);
}
MultiLevelTemplateArgumentList MLTAL =
S.getTemplateInstantiationArgs(Template, SugaredDeducedArgs);
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);
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
Info.getLocation(),
@ -3954,8 +3974,9 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
bool IsLambda = isLambdaCallOperator(FD) || isLambdaConversionOperator(FD);
if (!IsLambda && !IsIncomplete) {
if (CheckFunctionTemplateConstraints(
Info.getLocation(), FunctionTemplate, CTAI.CanonicalConverted,
Info.AssociatedConstraintsSatisfaction))
Info.getLocation(),
FunctionTemplate->getCanonicalDecl()->getTemplatedDecl(),
CTAI.CanonicalConverted, Info.AssociatedConstraintsSatisfaction))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
Info.reset(Info.takeSugared(), TemplateArgumentList::CreateCopy(
@ -4001,8 +4022,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// ([temp.constr.constr]). If the constraints are not satisfied, type
// deduction fails.
if (IsLambda && !IsIncomplete) {
if (CheckFunctionSpecializationConstraints(
Info.getLocation(), Specialization,
if (CheckFunctionTemplateConstraints(
Info.getLocation(), Specialization, CTAI.CanonicalConverted,
Info.AssociatedConstraintsSatisfaction))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
@ -6028,7 +6049,7 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
// function parameters that positionally correspond between the two
// templates are not of the same type, neither template is more specialized
// than the other.
if (!TemplateParameterListsAreEqual(FT1, TPL1, FT2, TPL2, false,
if (!TemplateParameterListsAreEqual(TPL1, TPL2, false,
Sema::TPL_TemplateParamsEquivalent))
return nullptr;
@ -6383,7 +6404,7 @@ getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1,
// function parameters that positionally correspond between the two
// templates are not of the same type, neither template is more specialized
// than the other.
if (!S.TemplateParameterListsAreEqual(P1, TPL1, P2, TPL2, false,
if (!S.TemplateParameterListsAreEqual(TPL1, TPL2, false,
Sema::TPL_TemplateParamsEquivalent))
return nullptr;

View file

@ -65,9 +65,10 @@ static bool HaveSameAssociatedConstraints(
return true;
// General case: pairwise compare each associated constraint expression.
Sema::TemplateCompareNewDeclInfo NewInfo(New);
for (size_t I = 0, E = OldACs.size(); I != E; ++I)
if (!SemaRef.AreConstraintExpressionsEqual(Old, OldACs[I].ConstraintExpr,
New, NewACs[I].ConstraintExpr))
if (!SemaRef.AreConstraintExpressionsEqual(
Old, OldACs[I].ConstraintExpr, NewInfo, NewACs[I].ConstraintExpr))
return false;
return true;
@ -502,7 +503,6 @@ struct ConvertConstructorToDeductionGuideTransform {
: SemaRef(S), Template(Template) {
// If the template is nested, then we need to use the original
// pattern to iterate over the constructors.
// FIXME: Should this just use getTemplateInstantiationPattern?
ClassTemplateDecl *Pattern = Template;
while (Pattern->getInstantiatedFromMemberTemplate()) {
if (Pattern->isMemberSpecialization())
@ -510,9 +510,9 @@ struct ConvertConstructorToDeductionGuideTransform {
Pattern = Pattern->getInstantiatedFromMemberTemplate();
NestedPattern = Pattern;
}
if (NestedPattern)
OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(
Decl::castFromDeclContext(Template->getDeclContext()));
OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template);
}
Sema &SemaRef;
@ -1053,9 +1053,52 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
}
}
MultiLevelTemplateArgumentList ArgsForBuildingRC =
SemaRef.getTemplateInstantiationArgs(F, TemplateArgsForBuildingRC);
// A list of template arguments for transforming the require-clause of F.
// It must contain the entire set of template argument lists.
MultiLevelTemplateArgumentList ArgsForBuildingRC;
ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
// For 2), if the underlying deduction guide F is nested in a class template,
// we need the entire template argument list, as the constraint AST in the
// require-clause of F remains completely uninstantiated.
//
// For example:
// template <typename T> // depth 0
// struct Outer {
// template <typename U>
// struct Foo { Foo(U); };
//
// template <typename U> // depth 1
// requires C<U>
// Foo(U) -> Foo<int>;
// };
// template <typename U>
// using AFoo = Outer<int>::Foo<U>;
//
// In this scenario, the deduction guide for `Foo` inside `Outer<int>`:
// - The occurrence of U in the require-expression is [depth:1, index:0]
// - The occurrence of U in the function parameter is [depth:0, index:0]
// - The template parameter of U is [depth:0, index:0]
//
// We add the outer template arguments which is [int] to the multi-level arg
// list to ensure that the occurrence U in `C<U>` will be replaced with int
// during the substitution.
//
// NOTE: The underlying deduction guide F is instantiated -- either from an
// explicitly-written deduction guide member, or from a constructor.
// getInstantiatedFromMemberTemplate() can only handle the former case, so we
// check the DeclContext kind.
if (F->getLexicalDeclContext()->getDeclKind() ==
clang::Decl::ClassTemplateSpecialization) {
auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
F, F->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
for (auto It : OuterLevelArgs)
ArgsForBuildingRC.addOuterTemplateArguments(It.Args);
}
ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
if (E.isInvalid())

View file

@ -49,6 +49,38 @@ using namespace sema;
//===----------------------------------------------------------------------===/
namespace {
namespace TemplateInstArgsHelpers {
struct Response {
const Decl *NextDecl = nullptr;
bool IsDone = false;
bool ClearRelativeToPrimary = true;
static Response Done() {
Response R;
R.IsDone = true;
return R;
}
static Response ChangeDecl(const Decl *ND) {
Response R;
R.NextDecl = ND;
return R;
}
static Response ChangeDecl(const DeclContext *Ctx) {
Response R;
R.NextDecl = Decl::castFromDeclContext(Ctx);
return R;
}
static Response UseNextDecl(const Decl *CurDecl) {
return ChangeDecl(CurDecl->getDeclContext());
}
static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) {
Response R = Response::UseNextDecl(CurDecl);
R.ClearRelativeToPrimary = false;
return R;
}
};
// Retrieve the primary template for a lambda call operator. It's
// unfortunate that we only have the mappings of call operators rather
// than lambda classes.
@ -136,197 +168,397 @@ bool isLambdaEnclosedByTypeAliasDecl(
.TraverseType(Underlying);
}
// 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);
}
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;
}
}
}
}
// 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();
}
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());
}
}
}
return Response::UseNextDecl(Rec);
}
Response HandleImplicitConceptSpecializationDecl(
const ImplicitConceptSpecializationDecl *CSD,
MultiLevelTemplateArgumentList &Result) {
Result.addOuterTemplateArguments(
const_cast<ImplicitConceptSpecializationDecl *>(CSD),
CSD->getTemplateArguments(),
/*Final=*/false);
return Response::UseNextDecl(CSD);
}
Response HandleGenericDeclContext(const Decl *CurDecl) {
return Response::UseNextDecl(CurDecl);
}
} // namespace TemplateInstArgsHelpers
} // namespace
MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
const Decl *D, std::optional<ArrayRef<TemplateArgument>> Innermost,
UnsignedOrNone NumLevels, bool SkipInnerNonInstantiated) {
MultiLevelTemplateArgumentList TemplateArgs;
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;
// The scope being followed for an out-of-line-definition.
NestedNameSpecifier Qualifier = std::nullopt;
ArrayRef<TemplateParameterList *> TPLs;
using namespace TemplateInstArgsHelpers;
const Decl *CurDecl = ND;
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;
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);
}
} 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;
}
R = HandleGenericDeclContext(CurDecl);
}
const Decl *CurDecl = D;
// There is either a current qualifier for an out-of-line definition being
// followed, in which case it should be advanced, or the next qualifier
// and template parameter listss should be retrieved from the current
// declaration, if any.
bool InOutOfLineDefinition = Qualifier != std::nullopt;
switch (Qualifier.getKind()) {
case NestedNameSpecifier::Kind::Null: {
// Get the current qualifier and template parameter lists.
assert(TPLs.empty());
if (auto *TD = dyn_cast<TemplateDecl>(D)) {
D = TD->getTemplatedDecl();
// One of the template entities which doesn't have a templated decl.
if (!D)
break;
}
if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
TPLs = DD->getTemplateParameterLists();
Qualifier = DD->getQualifier();
} else if (const auto *TD = dyn_cast<TagDecl>(D)) {
TPLs = TD->getTemplateParameterLists();
Qualifier = TD->getQualifier();
}
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;
}
// 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;
}
if (!Innermost)
continue;
auto DeclArgs = *std::exchange(Innermost, std::nullopt);
assert(!DeclArgs.empty());
if (InOutOfLineDefinition) {
// There either may or may not be a template parameter list corresponding
// to the current qualifier chunk.
// A template level only exists where there is a non-empty template
// parameter list. Explicit specializations, ie `template <>` are never a
// template level.
TemplateParameterList *TPL =
!TPLs.empty() ? TPLs.consume_back() : nullptr;
if (!TPL || TPL->empty())
continue;
}
if (!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;
}
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 TemplateArgs;
return Result;
}
bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
@ -1509,8 +1741,10 @@ namespace {
CXXRecordDecl::LambdaDependencyKind
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
if (auto TypeAlias = ::getEnclosingTypeAliasTemplateDecl(getSema());
TypeAlias && ::isLambdaEnclosedByTypeAliasDecl(
if (auto TypeAlias =
TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
getSema());
TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
@ -3866,9 +4100,6 @@ bool Sema::InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec,
TemplateSpecializationKind TSK, bool Complain,
bool PrimaryStrictPackMatch) {
assert(ClassTemplateSpec->getTemplateDepth() == 0 &&
"non-instantiated declaration");
// Perform the actual instantiation on the canonical declaration.
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
ClassTemplateSpec->getCanonicalDecl());
@ -3892,12 +4123,9 @@ bool Sema::InstantiateClassTemplateSpecialization(
if (!Pattern.isUsable())
return Pattern.isInvalid();
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
ClassTemplateSpec, /*Innermost=*/std::nullopt,
/*NumLevels=*/Pattern.get()->getTemplateDepth());
bool Err = InstantiateClassImpl(PointOfInstantiation, ClassTemplateSpec,
Pattern.get(), TemplateArgs, TSK, Complain);
bool Err = InstantiateClassImpl(
PointOfInstantiation, ClassTemplateSpec, Pattern.get(),
getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain);
// If we haven't already warn on avaibility, consider the avaibility
// attributes of the partial specialization.
@ -4259,7 +4487,14 @@ ExprResult Sema::SubstConceptTemplateArguments(
[](const TemplateArgumentLoc &Loc) { return Loc.getArgument(); });
MultiLevelTemplateArgumentList MLTALForConstraint =
getTemplateInstantiationArgs(CSE->getNamedConcept(), NewArgList);
getTemplateInstantiationArgs(
CSE->getNamedConcept(),
CSE->getNamedConcept()->getLexicalDeclContext(),
/*Final=*/false,
/*Innermost=*/NewArgList,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
// Rebuild a constraint, only substituting non-dependent concept names
// and nothing else.

View file

@ -49,63 +49,40 @@ static bool isDeclWithinFunction(const Decl *D) {
return false;
}
template <typename DeclT>
template<typename DeclT>
static bool SubstQualifier(Sema &SemaRef, const DeclT *OldDecl, DeclT *NewDecl,
const MultiLevelTemplateArgumentList &TemplateArgs,
DeclContext *Owner) {
if (auto TPLs = OldDecl->getTemplateParameterLists(); !TPLs.empty()) {
SmallVector<TemplateParameterList *, 4> TempParamLists(TPLs.size());
MultiLevelTemplateArgumentList MLTAL;
const MultiLevelTemplateArgumentList &TemplateArgs) {
if (!OldDecl->getQualifierLoc())
return false;
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();
}
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()));
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()));
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, Owner);
return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
}
bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl) {
return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs, Owner);
return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
}
// Include attribute instantiation code.
@ -1759,10 +1736,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(),
@ -2405,8 +2382,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// Make sure the parameter lists match.
if (!SemaRef.TemplateParameterListsAreEqual(
RecordInst, InstParams, MostRecentPrevCT, PrevParams, true,
Sema::TPL_TemplateMatch))
RecordInst, InstParams, MostRecentPrevCT->getTemplatedDecl(),
PrevParams, true, Sema::TPL_TemplateMatch))
return nullptr;
// Do some additional validation, then merge default arguments
@ -2734,23 +2711,6 @@ 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
@ -2781,21 +2741,16 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
}
}
FunctionDecl *PrevDecl = nullptr;
if (FunctionTemplate && !TemplateParams) {
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
void *InsertPos = nullptr;
PrevDecl = FunctionTemplate->findSpecialization(Innermost, InsertPos);
if (PrevDecl) {
if (PrevDecl->getTemplateSpecializationInfo()->isExplicitSpecialization())
return PrevDecl;
for (FunctionDecl *F : PrevDecl->redecls())
// If we already have a function template specialization for this
// function template, return it.
if (F->getPrimaryTemplate() == FunctionTemplate)
return F;
}
FunctionDecl *SpecFunc
= FunctionTemplate->findSpecialization(Innermost, InsertPos);
// If we already have a function template specialization, return it.
if (SpecFunc)
return SpecFunc;
}
bool MergeWithParentScope = (TemplateParams != nullptr) ||
@ -2888,9 +2843,6 @@ 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();
@ -2947,10 +2899,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
FunctionTemplate->setLexicalDeclContext(LexicalDC);
if (PrevDecl)
FunctionTemplate->setPreviousDecl(
PrevDecl->getDescribedFunctionTemplate());
if (isFriend && D->isThisDeclarationADefinition()) {
FunctionTemplate->setInstantiatedFromMemberTemplate(
D->getDescribedFunctionTemplate());
@ -2960,14 +2908,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
Sema::CodeSynthesisContext::BuildingDeductionGuides) {
// Record this function template specialization.
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
Function->setFunctionTemplateSpecialization(
SemaRef.Context, FunctionTemplate,
TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost),
/*InsertPos=*/nullptr, /*TSK=*/TSK_ImplicitInstantiation,
/*TemplateParams=*/nullptr,
/*TemplateArgsAsWritten=*/nullptr,
/*PointOfInstantiation=*/SourceLocation(),
/*AddSpecialization=*/PrevDecl == nullptr);
Function->setFunctionTemplateSpecialization(FunctionTemplate,
TemplateArgumentList::CreateCopy(SemaRef.Context,
Innermost),
/*InsertPos=*/nullptr);
} else if (FunctionRewriteKind == RewriteKind::None) {
if (isFriend && D->isThisDeclarationADefinition()) {
// Do not connect the friend to the template unless it's actually a
@ -3025,7 +2969,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
}
if (SemaRef.CheckFunctionTemplateSpecialization(
Function, DFTSI->TemplateParameters ? TemplateParams : nullptr,
Function,
DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Previous))
Function->setInvalidDecl();
@ -3043,8 +2987,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
ExplicitArgs))
return nullptr;
if (SemaRef.CheckFunctionTemplateSpecialization(Function, TemplateParams,
&ExplicitArgs, Previous))
if (SemaRef.CheckFunctionTemplateSpecialization(Function,
&ExplicitArgs,
Previous))
Function->setInvalidDecl();
IsExplicitSpecialization = true;
@ -3161,8 +3106,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
CXXMethodDecl *D, TemplateParameterList *TemplateParams,
RewriteKind FunctionRewriteKind) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
FunctionDecl *PrevDecl = nullptr;
if (FunctionTemplate && !TemplateParams) {
// We are creating a function template specialization from a function
// template. Check whether there is already a function template
@ -3170,16 +3113,12 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
void *InsertPos = nullptr;
PrevDecl = FunctionTemplate->findSpecialization(Innermost, InsertPos);
if (PrevDecl) {
if (PrevDecl->getTemplateSpecializationInfo()->isExplicitSpecialization())
return PrevDecl;
for (FunctionDecl *F : PrevDecl->redecls())
// If we already have a function template specialization for this
// function template, return it.
if (F->getPrimaryTemplate() == FunctionTemplate)
return F;
}
FunctionDecl *SpecFunc
= FunctionTemplate->findSpecialization(Innermost, InsertPos);
// If we already have a function template specialization, return it.
if (SpecFunc)
return SpecFunc;
}
bool isFriend;
@ -3196,6 +3135,19 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
Sema::LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
SemaRef, D, TemplateArgs, Scope);
// Instantiate enclosing template arguments for friends.
SmallVector<TemplateParameterList *, 4> TempParamLists;
ArrayRef<TemplateParameterList *> TPLs = D->getTemplateParameterLists();
if (isFriend && !TPLs.empty()) {
TempParamLists.resize(TPLs.size());
for (unsigned I = 0; I != TPLs.size(); ++I) {
TemplateParameterList *InstParams = SubstTemplateParams(TPLs[I]);
if (!InstParams)
return nullptr;
TempParamLists[I] = InstParams;
}
}
auto InstantiatedExplicitSpecifier = ExplicitSpecifier::getFromDecl(D);
// deduction guides need this
const bool CouldInstantiate =
@ -3321,9 +3273,6 @@ 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();
@ -3355,33 +3304,25 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
} else if (D->isOutOfLine())
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
if (PrevDecl)
FunctionTemplate->setPreviousDecl(
PrevDecl->getDescribedFunctionTemplate());
} else if (FunctionTemplate) {
// Record this function template specialization.
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
Method->setFunctionTemplateSpecialization(
SemaRef.Context, FunctionTemplate,
TemplateArgumentList::CreateCopy(SemaRef.Context, Innermost),
/*InsertPos=*/nullptr, /*TSK=*/TSK_ImplicitInstantiation,
/*TemplateParams=*/nullptr,
/*TemplateArgsAsWritten=*/nullptr,
/*PointOfInstantiation=*/SourceLocation(),
/*AddSpecialization=*/PrevDecl == nullptr);
Method->setFunctionTemplateSpecialization(FunctionTemplate,
TemplateArgumentList::CreateCopy(SemaRef.Context,
Innermost),
/*InsertPos=*/nullptr);
} else if (!isFriend && FunctionRewriteKind == RewriteKind::None) {
// Record that this is an instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
if (SubstQualifier(D, Method))
return nullptr;
// If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
if (isFriend) {
if (!TempParamLists.empty())
Method->setTemplateParameterListsInfo(SemaRef.Context, TempParamLists);
Method->setLexicalDeclContext(Owner);
Method->setObjectOfFriendDecl();
} else if (D->isOutOfLine())
@ -3424,8 +3365,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
}
if (SemaRef.CheckFunctionTemplateSpecialization(
Method, DFTSI->TemplateParameters,
DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Method, DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Previous))
Method->setInvalidDecl();
@ -3441,8 +3381,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
ExplicitArgs))
return nullptr;
if (SemaRef.CheckFunctionTemplateSpecialization(Method, TemplateParams,
&ExplicitArgs, Previous))
if (SemaRef.CheckFunctionTemplateSpecialization(Method,
&ExplicitArgs,
Previous))
Method->setInvalidDecl();
IsExplicitSpecialization = true;
@ -4572,22 +4513,16 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Substitute into the template arguments of the class template explicit
// specialization.
// The template parameters list for an explicit specialization is always empty
// and has no constraints, so there is nothing to substitute.
TemplateArgumentListInfo InstTemplateArgs;
const ExplicitSpecializationInfo *ExplicitSpecInfo =
D->getExplicitSpecializationInfo();
if (ExplicitSpecInfo) {
auto *Args = ExplicitSpecInfo->TemplateArgsAsWritten;
InstTemplateArgs.setLAngleLoc(Args->getLAngleLoc());
InstTemplateArgs.setRAngleLoc(Args->getRAngleLoc());
if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
D->getTemplateArgsAsWritten()) {
InstTemplateArgs.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
InstTemplateArgs.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(Args->arguments(), TemplateArgs,
InstTemplateArgs))
if (SemaRef.SubstTemplateArguments(TemplateArgsInfo->arguments(),
TemplateArgs, InstTemplateArgs))
return nullptr;
}
// Otherwise, an ExplicitInstantiation always occurs in a non-dependent
// context, so there is nothing to substitute.
// Check that the template argument list is well-formed for this
// class template.
@ -4642,14 +4577,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
D->getLocation(), InstClassTemplate, CTAI.CanonicalConverted,
CTAI.StrictPackMatch, PrevDecl);
if (ExplicitSpecInfo)
InstD->setExplicitSpecializationInfo(
ExplicitSpecInfo->TemplateParams,
ASTTemplateArgumentListInfo::Create(SemaRef.Context, InstTemplateArgs));
else if (const auto *Info = D->getExplicitInstantiationInfo())
InstD->setExplicitInstantiationInfo(Info->ExternKeywordLoc,
Info->TemplateKeywordLoc,
Info->TemplateArgsAsWritten);
InstD->setTemplateArgsAsWritten(InstTemplateArgs);
// Add this partial specialization to the set of class template partial
// specializations.
@ -4663,6 +4591,8 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
InstD->setAccess(D->getAccess());
InstD->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
InstD->setSpecializationKind(D->getSpecializationKind());
InstD->setExternKeywordLoc(D->getExternKeywordLoc());
InstD->setTemplateKeywordLoc(D->getTemplateKeywordLoc());
Owner->addDecl(InstD);
@ -4682,6 +4612,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *D) {
TemplateArgumentListInfo VarTemplateArgsInfo;
VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
assert(VarTemplate &&
"A template specialization without specialized template?");
@ -4692,15 +4623,9 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
if (!InstVarTemplate)
return nullptr;
assert(!D->getExplicitInstantiationInfo());
const auto *ExplicitSpecializationInfo = D->getExplicitSpecializationInfo();
// Substitute the current template arguments.
TemplateArgumentListInfo VarTemplateArgsInfo;
if (ExplicitSpecializationInfo) {
// The template parameters for an explicit specialization are empty and
// never need to be transformed.
const auto *TemplateArgsInfo =
ExplicitSpecializationInfo->TemplateArgsAsWritten;
if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
D->getTemplateArgsAsWritten()) {
VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
@ -4731,17 +4656,12 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
PrevDecl->getPointOfInstantiation(), Ignored))
return nullptr;
VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl);
if (!VTSD)
return nullptr;
if (ExplicitSpecializationInfo)
VTSD->setExplicitSpecializationInfo(
ExplicitSpecializationInfo->TemplateParams,
ASTTemplateArgumentListInfo::Create(
SemaRef.Context,
ExplicitSpecializationInfo->TemplateArgsAsWritten));
return VTSD;
if (VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl)) {
VTSD->setTemplateArgsAsWritten(VarTemplateArgsInfo);
return VTSD;
}
return nullptr;
}
VarTemplateSpecializationDecl *
@ -4750,8 +4670,6 @@ TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
ArrayRef<TemplateArgument> Converted,
VarTemplateSpecializationDecl *PrevDecl) {
LocalInstantiationScope Scope(SemaRef);
// Do substitution on the type of the declaration
TypeSourceInfo *TSI =
SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
@ -5007,17 +4925,16 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
InstParams, InsertPos);
// Create the class template partial specialization declaration.
// FIXME: Avoid recreating the ASTTemplateArgumentListInfo if nothing changed.
ClassTemplatePartialSpecializationDecl *InstPartialSpec =
ClassTemplatePartialSpecializationDecl::Create(
SemaRef.Context, PartialSpec->getTagKind(), Owner,
PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
ASTTemplateArgumentListInfo::Create(SemaRef.Context,
InstTemplateArgs),
ClassTemplate, CTAI.CanonicalConverted,
/*CanonInjectedTST=*/CanQualType(),
/*PrevDecl=*/nullptr);
InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return nullptr;
@ -5134,11 +5051,10 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
VarTemplatePartialSpecializationDecl *InstPartialSpec =
VarTemplatePartialSpecializationDecl::Create(
SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
PartialSpec->getLocation(), InstParams,
ASTTemplateArgumentListInfo::Create(SemaRef.Context,
InstTemplateArgs),
VarTemplate, TSI->getType(), TSI, PartialSpec->getStorageClass(),
CTAI.CanonicalConverted);
PartialSpec->getLocation(), InstParams, VarTemplate, TSI->getType(),
TSI, PartialSpec->getStorageClass(), CTAI.CanonicalConverted);
InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
@ -5373,11 +5289,8 @@ bool Sema::addInstantiatedParametersToScope(
bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param) {
assert(FD->getTemplateDepth() == 0 && "function not instantiated");
assert(Param->hasUninstantiatedDefaultArg());
const auto *PatternDecl =
FD->getTemplateInstantiationPattern(/*ForDefinition=*/false);
// FIXME: We don't track member specialization info for non-defining
// friend declarations, so we will not be able to later find the function
// pattern. As a workaround, don't instantiate the default argument in this
@ -5385,50 +5298,36 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
// purposes. [dcl.fct.default]p4:
// if a friend declaration D specifies a default argument expression,
// that declaration shall be a definition.
if (!PatternDecl)
if (FD->getFriendObjectKind() != Decl::FOK_None &&
!FD->getTemplateInstantiationPattern())
return true;
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()));
TemplateArgs =
getTemplateInstantiationArgs(FD, /*Innermost=*/std::nullopt, NumLevels);
}
// Instantiate the expression.
if (Param->hasUninstantiatedDefaultArg() &&
SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
//
// FIXME: Pass in a correct Pattern argument, otherwise
// getTemplateInstantiationArgs uses the lexical context of FD, e.g.
//
// template<typename T>
// struct A {
// static int FooImpl();
//
// template<typename Tp>
// // bug: default argument A<T>::FooImpl() is evaluated with 2-level
// // template argument list [[T], [Tp]], should be [[Tp]].
// friend A<Tp> Foo(int a);
// };
//
// template<typename T>
// A<T> Foo(int a = A<T>::FooImpl());
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
FD, FD->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
/*ForDefaultArgumentSubstitution=*/true);
if (Param != OrigParam)
OrigParam->setDefaultArg(Param->getDefaultArg());
if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
if (ASTMutationListener *L = getASTMutationListener())
L->DefaultArgumentInstantiated(Param);
@ -5467,22 +5366,16 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Decl, Decl->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary*/ true);
// FIXME: We can't use getTemplateInstantiationPattern(false) in general
// here, because for a non-defining friend declaration in a class template,
// we don't store enough information to map back to the friend declaration in
// the template.
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
unsigned NumLevels = Template->getTemplateDepth();
MultiLevelTemplateArgumentList TemplateArgs;
if (const auto *Info = Decl->getTemplateSpecializationInfo();
Info &&
Info->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
TemplateArgs = getTemplateInstantiationArgs(
Info->getTemplate(), Info->TemplateArguments->asArray(), NumLevels);
else
TemplateArgs = getTemplateInstantiationArgs(
Decl, /*Innermost=*/std::nullopt, NumLevels);
if (addInstantiatedParametersToScope(Decl, Template, Scope, TemplateArgs)) {
UpdateExceptionSpec(Decl, EST_None);
return;
@ -5647,10 +5540,7 @@ FunctionDecl *Sema::InstantiateFunctionDeclaration(
MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray(),
/*Final=*/false);
return cast_or_null<FunctionDecl>(SubstDecl(
FD,
isa<CXXMethodDecl>(FD) ? FD->getParent() : FD->getLexicalDeclContext(),
MArgs));
return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs));
}
void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
@ -6005,61 +5895,36 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
RebuildTypeSourceInfoForDefaultSpecialMembers();
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
if (const FunctionTemplateSpecializationInfo *Info =
Function->getTemplateSpecializationInfo();
Info && !Info->isExplicitSpecialization()) {
const FunctionDecl *TemplatedDecl =
Info->getTemplate()->getTemplatedDecl();
// Find the primary template redeclaration which corresponds to the
// definition.
auto Redecls = TemplatedDecl->redecls();
auto It = llvm::find_if(Redecls, [](const FunctionDecl *FD) {
return FD->isInstantiatedFromMemberTemplate() ||
FD->isThisDeclarationADefinition();
});
assert(It != Redecls.end() && "Should't get here without a definition");
if (*It != TemplatedDecl) {
// If the primary template found is not the same as this function's
// primary template, then instantiate that primary template and use it
// instead.
FunctionDecl *NewFunction = InstantiateFunctionDeclaration(
(*It)->getDescribedFunctionTemplate(), Info->TemplateArguments,
PointOfInstantiation);
// 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");
DeclContext *DC = Function->getLexicalDeclContext();
std::optional<ArrayRef<TemplateArgument>> Innermost;
if (auto *Primary = Function->getPrimaryTemplate();
Primary &&
!isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) &&
Function->getTemplateSpecializationKind() !=
TSK_ExplicitSpecialization) {
auto It = llvm::find_if(Primary->redecls(),
[](const RedeclarableTemplateDecl *RTD) {
return cast<FunctionTemplateDecl>(RTD)
->isCompatibleWithDefinition();
});
assert(It != Primary->redecls().end() &&
"Should't get here without a definition");
if (FunctionDecl *Def = cast<FunctionTemplateDecl>(*It)
->getTemplatedDecl()
->getDefinition())
DC = Def->getLexicalDeclContext();
else
DC = (*It)->getLexicalDeclContext();
Innermost.emplace(Function->getTemplateSpecializationArgs()->asArray());
}
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
Function, /*Innermost=*/std::nullopt,
/*NumLevels=*/PatternDecl->getTemplateDepth(),
/*SkipInnerNonInstantiated=*/true);
Function, DC, /*Final=*/false, Innermost, false, PatternDecl);
// Substitute into the qualifier; we can get a substitution failure here
// through evil use of alias templates.
// FIXME: Is CurContext correct for this? Should we go to the (instantiation
// of the) lexical context of the pattern?
SubstQualifier(*this, PatternDecl, Function, TemplateArgs);
ActOnStartOfFunctionDef(nullptr, Function);
@ -6426,8 +6291,6 @@ void Sema::InstantiateVariableInitializer(
void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
VarDecl *Var, bool Recursive,
bool DefinitionRequired, bool AtEndOfTU) {
assert(Var->getTemplateDepth() == 0 && "variable not already instantiated");
if (Var->isInvalidDecl())
return;
@ -6445,9 +6308,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// Find the pattern and the arguments to substitute into it.
VarDecl *PatternDecl = Var->getTemplateInstantiationPattern();
assert(PatternDecl && "no pattern for templated variable");
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
Var, /*Innermost=*/std::nullopt,
/*NumLevels=*/PatternDecl->getTemplateDepth());
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Var);
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
@ -6608,6 +6470,15 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(),
TemplateArgs);
TemplateArgumentListInfo TemplateArgInfo;
if (const ASTTemplateArgumentListInfo *ArgInfo =
VarSpec->getTemplateArgsAsWritten()) {
TemplateArgInfo.setLAngleLoc(ArgInfo->getLAngleLoc());
TemplateArgInfo.setRAngleLoc(ArgInfo->getRAngleLoc());
for (const TemplateArgumentLoc &Arg : ArgInfo->arguments())
TemplateArgInfo.addArgument(Arg);
}
VarTemplateSpecializationDecl *VTSD =
Instantiator.VisitVarTemplateSpecializationDecl(
VarSpec->getSpecializedTemplate(), Def,
@ -6615,13 +6486,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
Var = VTSD;
if (Var) {
if (const auto *Info = VarSpec->getExplicitInstantiationInfo())
VTSD->setExplicitInstantiationInfo(Info->ExternKeywordLoc,
Info->TemplateKeywordLoc,
Info->TemplateArgsAsWritten);
else if (const auto *Info = VarSpec->getExplicitSpecializationInfo())
VTSD->setExplicitSpecializationInfo(Info->TemplateParams,
Info->TemplateArgsAsWritten);
VTSD->setTemplateArgsAsWritten(TemplateArgInfo);
llvm::PointerUnion<VarTemplateDecl *,
VarTemplatePartialSpecializationDecl *> PatternPtr =
@ -7411,7 +7276,6 @@ void Sema::PerformPendingInstantiations(bool LocalOnly, bool AtEndOfTU) {
if (Var != Var->getMostRecentDecl())
continue;
break;
case TSK_FriendDeclaration:
case TSK_ImplicitInstantiation:
break;
}

View file

@ -905,10 +905,9 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
if (Record.readInt()) { // hasExtInfo
auto *Info = new (Reader.getContext()) DeclaratorDecl::ExtInfo();
Record.readQualifierInfo(*Info);
Expr *ConstraintExpr = Record.readExpr();
UnsignedOrNone ArgPackSubstIndex = Record.readUnsignedOrNone();
Info->TrailingRequiresClause =
AssociatedConstraint(ConstraintExpr, ArgPackSubstIndex);
Info->TrailingRequiresClause = AssociatedConstraint(
Record.readExpr(),
UnsignedOrNone::fromInternalRepresentation(Record.readUInt32()));
DD->DeclInfo = Info;
}
QualType TSIType = Record.readType();
@ -950,9 +949,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
SmallVector<TemplateArgument, 8> TemplArgs;
Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
const TemplateParameterList *TemplateParams =
Record.readBool() ? Record.readTemplateParameterList() : nullptr;
// Template args as written.
TemplateArgumentListInfo TemplArgsWritten;
bool HasTemplateArgumentsAsWritten = Record.readBool();
@ -977,7 +973,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FunctionTemplateSpecializationInfo *FTInfo =
FunctionTemplateSpecializationInfo::Create(
C, FD, Template, TSK, TemplArgList, TemplateParams,
C, FD, Template, TSK, TemplArgList,
HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr, POI,
MSInfo);
FD->TemplateOrSpecialization = FTInfo;
@ -1012,9 +1008,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
while (NumCandidates--)
Candidates.addDecl(readDeclAs<NamedDecl>());
const TemplateParameterList *TemplateParams =
Record.readBool() ? Record.readTemplateParameterList() : nullptr;
// Templates args.
TemplateArgumentListInfo TemplArgsWritten;
bool HasTemplateArgumentsAsWritten = Record.readBool();
@ -1022,7 +1015,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
Record.readTemplateArgumentListInfo(TemplArgsWritten);
FD->setDependentTemplateSpecialization(
Reader.getContext(), Candidates, TemplateParams,
Reader.getContext(), Candidates,
HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr);
// These are not merged; we don't need to merge redeclarations of dependent
// template friends.
@ -2563,20 +2556,6 @@ RedeclarableResult ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
D->StrictPackMatch = Record.readBool();
// extern/template keyword locations for explicit instantiations
if (auto K = D->SpecializationKind;
K == TSK_ExplicitInstantiationDeclaration ||
K == TSK_ExplicitInstantiationDefinition) {
SourceLocation ExternKeywordLoc = readSourceLocation();
SourceLocation TemplateKeywordLoc = readSourceLocation();
D->setExplicitInstantiationInfo(ExternKeywordLoc, TemplateKeywordLoc,
Record.readASTTemplateArgumentListInfo());
} else if (K == TSK_ExplicitSpecialization) {
auto *TemplateParams = Record.readTemplateParameterList();
D->setExplicitSpecializationInfo(TemplateParams,
Record.readASTTemplateArgumentListInfo());
}
bool writtenAsCanonicalDecl = Record.readInt();
if (writtenAsCanonicalDecl) {
auto *CanonPattern = readDeclAs<ClassTemplateDecl>();
@ -2607,11 +2586,27 @@ RedeclarableResult ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
}
}
// extern/template keyword locations for explicit instantiations
if (Record.readBool()) {
auto *ExplicitInfo = new (C) ExplicitInstantiationInfo;
ExplicitInfo->ExternKeywordLoc = readSourceLocation();
ExplicitInfo->TemplateKeywordLoc = readSourceLocation();
D->ExplicitInfo = ExplicitInfo;
}
if (Record.readBool())
D->setTemplateArgsAsWritten(Record.readASTTemplateArgumentListInfo());
return Redecl;
}
void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
ClassTemplatePartialSpecializationDecl *D) {
// We need to read the template params first because redeclarable is going to
// need them for profiling
TemplateParameterList *Params = Record.readTemplateParameterList();
D->TemplateParams = Params;
RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
// These are read/set from/to the first declaration.
@ -2657,6 +2652,17 @@ RedeclarableResult ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
}
}
// extern/template keyword locations for explicit instantiations
if (Record.readBool()) {
auto *ExplicitInfo = new (C) ExplicitInstantiationInfo;
ExplicitInfo->ExternKeywordLoc = readSourceLocation();
ExplicitInfo->TemplateKeywordLoc = readSourceLocation();
D->ExplicitInfo = ExplicitInfo;
}
if (Record.readBool())
D->setTemplateArgsAsWritten(Record.readASTTemplateArgumentListInfo());
SmallVector<TemplateArgument, 8> TemplArgs;
Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
@ -2664,20 +2670,6 @@ RedeclarableResult ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
D->IsCompleteDefinition = Record.readInt();
// extern/template keyword locations for explicit instantiations
if (auto K = D->SpecializationKind;
K == TSK_ExplicitInstantiationDeclaration ||
K == TSK_ExplicitInstantiationDefinition) {
SourceLocation ExternKeywordLoc = readSourceLocation();
SourceLocation TemplateKeywordLoc = readSourceLocation();
D->setExplicitInstantiationInfo(ExternKeywordLoc, TemplateKeywordLoc,
Record.readASTTemplateArgumentListInfo());
} else if (K == TSK_ExplicitSpecialization) {
auto *TemplateParams = Record.readTemplateParameterList();
D->setExplicitSpecializationInfo(TemplateParams,
Record.readASTTemplateArgumentListInfo());
}
RedeclarableResult Redecl = VisitVarDeclImpl(D);
bool writtenAsCanonicalDecl = Record.readInt();
@ -2708,6 +2700,9 @@ RedeclarableResult ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
/// using Template(Partial)SpecializationDecl as input type.
void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
TemplateParameterList *Params = Record.readTemplateParameterList();
D->TemplateParams = Params;
RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
// These are read/set from/to the first declaration.

View file

@ -805,10 +805,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// Template arguments.
Record.AddTemplateArgumentList(FTSInfo->TemplateArguments);
Record.push_back(FTSInfo->TemplateParameters != nullptr);
if (FTSInfo->TemplateParameters)
Record.AddTemplateParameterList(FTSInfo->TemplateParameters);
// Template args as written.
Record.push_back(FTSInfo->TemplateArgumentsAsWritten != nullptr);
if (FTSInfo->TemplateArgumentsAsWritten)
@ -843,10 +839,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
for (FunctionTemplateDecl *FTD : DFTSInfo->getCandidates())
Record.AddDeclRef(FTD);
Record.push_back(DFTSInfo->TemplateParameters != nullptr);
if (DFTSInfo->TemplateParameters)
Record.AddTemplateParameterList(DFTSInfo->TemplateParameters);
// Templates args.
Record.push_back(DFTSInfo->TemplateArgumentsAsWritten != nullptr);
if (DFTSInfo->TemplateArgumentsAsWritten)
@ -1754,7 +1746,6 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
if (FTSInfo->TemplateArguments->size() == 1) {
const TemplateArgument &TA = FTSInfo->TemplateArguments->get(0);
if (TA.getKind() == TemplateArgument::Type &&
!FTSInfo->TemplateParameters &&
!FTSInfo->TemplateArgumentsAsWritten &&
!FTSInfo->getMemberSpecializationInfo())
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
@ -1763,8 +1754,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
FunctionDecl::TK_DependentFunctionTemplateSpecialization) {
DependentFunctionTemplateSpecializationInfo *DFTSInfo =
D->getDependentSpecializationInfo();
if (!DFTSInfo->TemplateArgumentsAsWritten &&
!DFTSInfo->TemplateParameters)
if (!DFTSInfo->TemplateArgumentsAsWritten)
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
}
}
@ -1951,36 +1941,29 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
Record.AddSourceLocation(D->getPointOfInstantiation());
Record.push_back(D->getSpecializationKind());
Record.push_back(D->hasStrictPackMatch());
switch (D->getSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
case TSK_FriendDeclaration:
assert(!D->getExplicitSpecializationInfo());
assert(!D->getExplicitInstantiationInfo());
break;
case TSK_ExplicitSpecialization: {
const auto *Info = D->getExplicitSpecializationInfo();
Record.AddTemplateParameterList(Info->TemplateParams);
Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
break;
}
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition: {
const auto *Info = D->getExplicitInstantiationInfo();
Record.AddSourceLocation(Info->ExternKeywordLoc);
Record.AddSourceLocation(Info->TemplateKeywordLoc);
Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
break;
}
}
Record.push_back(D->isCanonicalDecl());
if (D->isCanonicalDecl()) {
// When reading, we'll add it to the folding set of the following template.
Record.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl());
}
bool ExplicitInstantiation =
D->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDeclaration ||
D->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition;
Record.push_back(ExplicitInstantiation);
if (ExplicitInstantiation) {
Record.AddSourceLocation(D->getExternKeywordLoc());
Record.AddSourceLocation(D->getTemplateKeywordLoc());
}
const ASTTemplateArgumentListInfo *ArgsWritten =
D->getTemplateArgsAsWritten();
Record.push_back(!!ArgsWritten);
if (ArgsWritten)
Record.AddASTTemplateArgumentListInfo(ArgsWritten);
// Mention the implicitly generated C++ deduction guide to make sure the
// deduction guide will be rewritten as expected.
//
@ -2002,7 +1985,9 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
}
void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
ClassTemplatePartialSpecializationDecl *D) {
Record.AddTemplateParameterList(D->getTemplateParameters());
VisitClassTemplateSpecializationDecl(D);
// These are read/set from/to the first declaration.
@ -2035,34 +2020,27 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
Record.AddTemplateArgumentList(&D->getTemplateInstantiationArgs());
}
bool ExplicitInstantiation =
D->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDeclaration ||
D->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition;
Record.push_back(ExplicitInstantiation);
if (ExplicitInstantiation) {
Record.AddSourceLocation(D->getExternKeywordLoc());
Record.AddSourceLocation(D->getTemplateKeywordLoc());
}
const ASTTemplateArgumentListInfo *ArgsWritten =
D->getTemplateArgsAsWritten();
Record.push_back(!!ArgsWritten);
if (ArgsWritten)
Record.AddASTTemplateArgumentListInfo(ArgsWritten);
Record.AddTemplateArgumentList(&D->getTemplateArgs());
Record.AddSourceLocation(D->getPointOfInstantiation());
Record.push_back(D->getSpecializationKind());
Record.push_back(D->IsCompleteDefinition);
switch (D->getSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
case TSK_FriendDeclaration:
assert(!D->getExplicitSpecializationInfo());
assert(!D->getExplicitInstantiationInfo());
break;
case TSK_ExplicitSpecialization: {
const auto *Info = D->getExplicitSpecializationInfo();
Record.AddTemplateParameterList(Info->TemplateParams);
Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
break;
}
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition: {
const auto *Info = D->getExplicitInstantiationInfo();
Record.AddSourceLocation(Info->ExternKeywordLoc);
Record.AddSourceLocation(Info->TemplateKeywordLoc);
Record.AddASTTemplateArgumentListInfo(Info->TemplateArgsAsWritten);
break;
}
}
VisitVarDecl(D);
Record.push_back(D->isCanonicalDecl());
@ -2081,6 +2059,8 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
Record.AddTemplateParameterList(D->getTemplateParameters());
VisitVarTemplateSpecializationDecl(D);
// These are read/set from/to the first declaration.
@ -2457,7 +2437,6 @@ getFunctionDeclAbbrev(serialization::DeclCode Code) {
Abv->Add(
BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Template Argument Type
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Is Defaulted
Abv->Add(BitCodeAbbrevOp(0)); // TemplateParams
Abv->Add(BitCodeAbbrevOp(0)); // TemplateArgumentsAsWritten
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
Abv->Add(BitCodeAbbrevOp(0));
@ -2467,7 +2446,6 @@ getFunctionDeclAbbrev(serialization::DeclCode Code) {
TK_DependentFunctionTemplateSpecialization) {
// Candidates of specialization
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abv->Add(BitCodeAbbrevOp(0)); // TemplateParams
Abv->Add(BitCodeAbbrevOp(0)); // TemplateArgumentsAsWritten
} else {
llvm_unreachable("Unknown templated kind?");

View file

@ -166,6 +166,55 @@ bool BugSuppression::isSuppressed(const BugReport &R) {
isSuppressed(UniqueingLocation, DeclWithIssue, {});
}
static const ClassTemplateDecl *
walkInstantiatedFromChain(const ClassTemplateDecl *Tmpl) {
// For nested member templates (e.g., S2 inside S1<T>), getInstantiatedFrom
// may return the member template as instantiated within an outer
// specialization (e.g., S2 as it appears in S1<int>). That instantiated
// member template has no definition redeclaration itself; we need to walk
// up the member template chain to reach the primary template definition.
// \code
// template <class> struct S1 {
// template <class> struct S2 {
// int i;
// template <class T> int m(const S2<T>& s2) {
// return s2.i;
// }
// };
// }
// /code
const ClassTemplateDecl *MemberTmpl;
while ((MemberTmpl = Tmpl->getInstantiatedFromMemberTemplate())) {
if (Tmpl->isMemberSpecialization())
break;
Tmpl = MemberTmpl;
}
return Tmpl;
}
static const ClassTemplatePartialSpecializationDecl *walkInstantiatedFromChain(
const ClassTemplatePartialSpecializationDecl *PartialSpec) {
const ClassTemplatePartialSpecializationDecl *MemberPS;
while ((MemberPS = PartialSpec->getInstantiatedFromMember())) {
if (PartialSpec->isMemberSpecialization())
break;
PartialSpec = MemberPS;
}
return PartialSpec;
}
template <class T> static const T *chooseDefinitionRedecl(const T *Tmpl) {
static_assert(llvm::is_one_of<T, ClassTemplateDecl,
ClassTemplatePartialSpecializationDecl>::value);
for (const auto *Redecl : Tmpl->redecls()) {
if (const T *D = cast<T>(Redecl); D->isThisDeclarationADefinition()) {
return D;
}
}
assert(false && "This template must have a redecl that is a definition");
return Tmpl;
}
// For template specializations, returns the primary template definition or
// partial specialization that was used to instantiate the specialization.
// This ensures suppression attributes on templates apply to their
@ -180,19 +229,41 @@ bool BugSuppression::isSuppressed(const BugReport &R) {
// attribute.
//
// The function handles specializations (and partial specializations) of
// class templates.
// For any other decl, it returns the input unchanged.
// class and function templates.
// For any other decl, it returns the input unchagned.
static const Decl *
preferTemplateDefinitionForTemplateSpecializations(const Decl *D) {
const auto *RD = dyn_cast<CXXRecordDecl>(D);
if (!RD)
// For function template specializations (including instantiated friend
// function templates), map back to the primary template's FunctionDecl so
// that the lexical parent chain walk reaches the class where the template
// was defined inline.
//
// This handles the case where a friend function template is defined inline
// inside a [[clang::suppress]]-annotated class but was pre-declared at
// namespace scope. In that case the instantiation's lexical DC is the
// namespace (from the pre-declaration), not the class. Walking back to the
// primary template FunctionDecl — whose lexical DC IS the class — lets the
// existing parent-chain walk find the suppression attribute.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
return Pattern->getDefinition();
}
const auto *SpecializationDecl = dyn_cast<ClassTemplateSpecializationDecl>(D);
if (!SpecializationDecl)
return D;
if (const CXXRecordDecl *Pattern = RD->getTemplateInstantiationPattern())
RD = Pattern;
RD = RD->getDefinitionOrSelf();
if (const auto *CTD = RD->getDescribedClassTemplate())
return CTD;
return RD;
auto InstantiatedFrom = SpecializationDecl->getInstantiatedFrom();
if (!InstantiatedFrom)
return D;
if (const auto *Tmpl = InstantiatedFrom.dyn_cast<ClassTemplateDecl *>()) {
// Interestingly, the source template might be a forward declaration, so we
// need to find the definition redeclaration.
return chooseDefinitionRedecl(walkInstantiatedFromChain(Tmpl));
}
return chooseDefinitionRedecl(walkInstantiatedFromChain(
cast<ClassTemplatePartialSpecializationDecl *>(InstantiatedFrom)));
}
bool BugSuppression::isSuppressed(const PathDiagnosticLocation &Location,

View file

@ -726,14 +726,14 @@ public:
TraverseClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *C) {
if (!RecursiveASTVisitor::TraverseClassTemplateSpecializationDecl(C))
return false;
const auto *Info = C->getExplicitInstantiationInfo();
if (!Info)
if (C->isExplicitSpecialization())
return true; // we are only interested in explicit instantiations.
auto *Declaration =
cast<syntax::SimpleDeclaration>(handleFreeStandingTagDecl(C));
foldExplicitTemplateInstantiation(
Builder.getTemplateRange(C), Builder.findToken(Info->ExternKeywordLoc),
Builder.findToken(Info->TemplateKeywordLoc), Declaration, C);
Builder.getTemplateRange(C),
Builder.findToken(C->getExternKeywordLoc()),
Builder.findToken(C->getTemplateKeywordLoc()), Declaration, C);
return true;
}
@ -778,9 +778,8 @@ public:
foldTemplateDeclaration(R, TemplateKW, DeclarationRange, nullptr);
DeclarationRange = R;
};
if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(C))
if (const auto *Info = S->getExplicitSpecializationInfo())
ConsumeTemplateParameters(*Info->TemplateParams);
if (auto *S = dyn_cast<ClassTemplatePartialSpecializationDecl>(C))
ConsumeTemplateParameters(*S->getTemplateParameters());
for (TemplateParameterList *TPL : C->getTemplateParameterLists())
ConsumeTemplateParameters(*TPL);
return Result;

View file

@ -32,12 +32,11 @@ namespace TestFunctionRedecl {
// CHECK-LABEL: Dumping TestFunctionRedecl:
// CHECK: |-FunctionTemplateDecl 0x[[TestFunctionRedecl_T1:[^ ]+]] <line:[[@LINE-4]]:{{.+}} f external-linkage
// CHECK: | |-FunctionDecl 0x[[TestFunctionRedecl_D1:[^ ]+]] {{.+}} f 'void ()'
// CHECK: | |-FunctionDecl {{.+}} prev 0x[[TestFunctionRedecl_S1:[^ ]+]] <col:22, col:32> col:27 f 'void ()' 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_S1:[^ ]+]] {{.+}} f 'void ()' explicit_instantiation_definition instantiated_from 0x[[TestFunctionRedecl_D2:[^ ]+]] external-linkage
// CHECK: |-FunctionTemplateDecl 0x[[TestFunctionRedecl_T2:[^ ]+]] prev 0x[[TestFunctionRedecl_T1]] <line:[[@LINE-6]]:{{.+}} f external-linkage
// CHECK: | |-FunctionDecl 0x[[TestFunctionRedecl_D2]] prev 0x[[TestFunctionRedecl_D1]] {{.+}} f 'void ()'
// CHECK: | `-Function 0x[[TestFunctionRedecl_S1]] 'f' 'void ()'
// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-9]]:{{.+}} 'f'
// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-8]]:{{.+}} 'f'
// CHECK: |-Function 0x[[TestFunctionRedecl_S1]] 'f' 'void ()'
// CHECK: |-FunctionProtoTypeLoc {{.+}} 'void ()' cdecl
// CHECK: | `-BuiltinTypeLoc {{.+}} 'void'
@ -77,15 +76,15 @@ namespace TestNestedClassRedecl {
// CHECK: | | `-ClassTemplateDecl 0x[[TestNestedClassRedecl_B_T1:[^ ]+]] <line:[[@LINE-8]]:{{.+}} B external-linkage
// CHECK: | | `-CXXRecordDecl 0x[[TestNestedClassRedecl_B_D1:[^ ]+]] {{.+}} struct B
// CHECK: | `-ClassTemplateSpecializationDecl 0x[[TestNestedClassRedecl_A_S1:[^ ]+]] <line:[[@LINE-8]]:{{.+}} line:[[@LINE-11]]:{{.+}} struct A definition external-linkage instantiated_from 0x[[TestNestedClassRedecl_A_D2:[^ ]+]] implicit_instantiation
// CHECK: | |-ClassTemplateDecl 0x{{.+}} <line:[[@LINE-11]]:{{.+}} B external-linkage
// CHECK: | | |-CXXRecordDecl 0x{{.+}} struct B
// CHECK: | | `-ClassTemplateSpecialization 0x[[TestNestedClassRedecl_B_S1:[^ ]+]] 'B'
// CHECK: | `-ClassTemplateSpecializationDecl 0x[[TestNestedClassRedecl_B_S1]] <line:[[@LINE-10]]:{{.+}} struct B definition external-linkage instantiated_from 0x[[TestNestedClassRedecl_B_D1]] explicit_instantiation_definition
// CHECK: |-ClassTemplateDecl 0x{{.+}} prev 0x[[TestNestedClassRedecl_A_T1]] <line:[[@LINE-13]]:{{.+}} A external-linkage
// CHECK: | `-ClassTemplateDecl 0x{{.+}} <line:[[@LINE-11]]:{{.+}} B external-linkage
// CHECK: | |-CXXRecordDecl 0x{{.+}} struct B
// CHECK: | `-ClassTemplateSpecialization 0x[[TestNestedClassRedecl_B_S1:[^ ]+]] 'B'
// CHECK: |-ClassTemplateDecl 0x{{.+}} prev 0x[[TestNestedClassRedecl_A_T1]] <line:[[@LINE-12]]:{{.+}} A external-linkage
// CHECK: | |-CXXRecordDecl 0x[[TestNestedClassRedecl_A_D2]] prev 0x[[TestNestedClassRedecl_A_D1]] {{.+}} struct A
// CHECK: | `-ClassTemplateSpecialization 0x[[TestNestedClassRedecl_A_S1]] 'A'
// CHECK: |-ClassTemplateDecl 0x{{.+}} parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_T1]] <line:[[@LINE-15]]:{{.+}} B external-linkage
// CHECK: |-ClassTemplateDecl 0x{{.+}} parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_T1]] <line:[[@LINE-14]]:{{.+}} B external-linkage
// CHECK: | `-CXXRecordDecl 0x[[TestNestedClassRedecl_B_D2:[^ ]+]] parent 0x[[TestNestedClassRedecl_A_D1]] prev 0x[[TestNestedClassRedecl_B_D1]] {{.+}} struct B definition
// CHECK: |-ClassTemplateSpecializationDecl 0x[[TestNestedClassRedecl_B_S1]] parent 0x[[TestNestedClassRedecl_A_S1]] <line:[[@LINE-15]]:{{.+}} struct B definition external-linkage instantiated_from 0x[[TestNestedClassRedecl_B_D1]] explicit_instantiation_definition
// CHECK: `-ExplicitInstantiationDecl {{.+}} <line:[[@LINE-16]]:{{.+}} 'B'
// CHECK: |-NestedNameSpecifier TypeSpec {{.+}}
// CHECK: |-ClassTemplateSpecialization 0x[[TestNestedClassRedecl_B_S1]] 'B'

View file

@ -5,6 +5,7 @@ namespace MemberSpecialization {
struct A {
template<bool B>
void f() noexcept(B);
// FIXME expected-note@-1 {{previous declaration is here}}
template<bool B>
void g() noexcept(B); // expected-note {{previous declaration is here}}
@ -13,6 +14,7 @@ namespace MemberSpecialization {
template<>
template<bool B>
void A<int>::f() noexcept(B);
// FIXME expected-error@-1 {{exception specification in declaration does not match previous declaration}}
template<>
template<bool B>

View file

@ -283,20 +283,16 @@ auto e = [] {
namespace cwg1821 { // cwg1821: 2.9
struct A {
template <typename> struct B {
void f(); // #cwg1821-B-f
void f();
};
template <typename T> void B<T>::f(){};
// expected-error@-1 {{non-friend class member 'f' cannot have a qualified name}}
// expected-error@-2 {{class member cannot be redeclared}}
// expected-note@#cwg1821-B-f {{previous declaration is here}}
struct C {
void f(); // #cwg1821-C-f
void f();
};
void C::f() {}
// expected-error@-1 {{non-friend class member 'f' cannot have a qualified name}}
// expected-error@-2 {{class member cannot be redeclared}}
// expected-note@#cwg1821-C-f {{previous declaration is here}}
};
} // namespace cwg1821

View file

@ -138,8 +138,7 @@ namespace cwg727 { // cwg727: partial
// expected-note@#cwg727-C {{explicitly specialized declaration is here}}
template<> void A::f<double>();
// expected-error@-1 {{non-friend class member 'f' cannot have a qualified name}}
// expected-error@-2 {{function template specialization of 'f' not in class 'A' or an enclosing namespace}}
// expected-note@#cwg727-f {{explicitly specialized declaration is here}}
// expected-error@-2 {{no function template matches function template specialization 'f'}}
template<> int A::N<double>;
// expected-error@-1 {{non-friend class member 'N' cannot have a qualified name}}
// expected-error@-2 {{variable template specialization of 'N' not in class 'A' or an enclosing namespace}}

View file

@ -73,15 +73,18 @@ template <class> struct S {};
template<template<True T> typename Wrapper>
using Test = Wrapper<int>;
template<template<False T> typename Wrapper>
using Test = Wrapper<int>;
template<template<False T> typename Wrapper> // #TTP-Wrapper
using Test = Wrapper<int>; // expected-error {{constraints not satisfied for template template parameter 'Wrapper' [with T = int]}}
// expected-note@#TTP-Wrapper {{'int' does not satisfy 'False'}}
// expected-note@#False {{evaluated to false}}
template <typename U, template<False> typename T>
void foo(T<U>); // #foo
void bar() {
// FIXME: CWG2980: There is no way to check the constraints on the template template parameter.
foo<int>(S<int>{});
foo<int>(S<int>{}); // expected-error {{no matching function for call to 'foo'}}
// expected-note@#foo {{substitution failure [with U = int]: constraints not satisfied for template template parameter 'T' [with $0 = int]}}
}
}

View file

@ -1,11 +1,10 @@
// RUN: %clang_cc1 -std=c++20 -verify %s
// expected-no-diagnostics
template<typename T>
concept D = true;
template<typename T>
struct A {
struct A { // expected-note {{defined here}}
template<typename U, bool V>
void f() requires V;
@ -17,6 +16,7 @@ struct A {
template<typename U, bool V> requires V
struct B;
// expected-note@-2 {{previous template declaration is here}}
template<typename U, bool V> requires V
struct B<U*, V>;
@ -26,12 +26,14 @@ struct A {
template<D U>
struct C;
// expected-note@-2 {{previous template declaration is here}}
template<D U>
struct C<U*>;
template<typename U, bool V> requires V
static int x;
// expected-note@-2 {{previous template declaration is here}}
template<typename U, bool V> requires V
static int x<U*, V>;
@ -41,6 +43,7 @@ struct A {
template<D U>
static int y;
// expected-note@-2 {{previous template declaration is here}}
template<D U>
static int y<U*>;
@ -94,9 +97,11 @@ template<typename T>
template<D U>
int A<T>::y<U*> = 0;
// FIXME: This should be accepted.
template<>
template<typename U, bool V>
void A<short>::f() requires V;
// expected-error@-1 {{out-of-line declaration of 'f' does not match any declaration in 'A<short>'}}
template<>
template<>
@ -110,9 +115,11 @@ template<>
template<D U>
void A<short>::g();
// FIXME: This should be accepted.
template<>
template<typename U, bool V> requires V
struct A<int>::B;
// expected-error@-2 {{requires clause differs in template redeclaration}}
template<>
template<>
@ -130,9 +137,11 @@ template<>
template<typename U, bool V> requires V
struct A<int>::B<U&, V>;
// FIXME: This should be accepted.
template<>
template<D U>
struct A<int>::C;
// expected-error@-2 {{type constraint differs in template redeclaration}}
template<>
template<D U>
@ -142,9 +151,11 @@ template<>
template<D U>
struct A<int>::C<U&>;
// FIXME: This should be accepted.
template<>
template<typename U, bool V> requires V
int A<long>::x;
// expected-error@-2 {{requires clause differs in template redeclaration}}
template<>
template<>
@ -162,9 +173,11 @@ template<>
template<typename U, bool V> requires V
int A<long>::x<U&, V>;
// FIXME: This should be accepted.
template<>
template<D U>
int A<long>::y;
// expected-error@-2 {{type constraint differs in template redeclaration}}
template<>
template<D U>

View file

@ -1,5 +1,4 @@
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
// expected-no-diagnostics
// expected-no-diagnostics

View file

@ -180,20 +180,28 @@ namespace Defined {
namespace Constrained {
template<typename T>
struct A {
// FIXME expected-note@-1 2{{defined here}}
template<typename U, bool V> requires V
static constexpr int f(); // expected-note {{declared here}}
// FIXME expected-note@-1 {{declared here}}
template<typename U, bool V> requires V
static const int x; // expected-note {{declared here}}
// FIXME expected-note@-2 2{{previous template declaration is here}}
// FIXME expected-note@-2 {{declared here}}
template<typename U, bool V> requires V
static const int x<U*, V>; // expected-note {{declared here}}
// FIXME expected-note@-1 {{partial specialization matches}}
template<typename U, bool V> requires V
struct B; // expected-note {{template is declared here}}
// FIXME expected-note@-2 2{{previous template declaration is here}}
// FIXME expected-note@-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@-1 {{partial specialization matches}}
};
template<>
@ -201,36 +209,43 @@ namespace Constrained {
constexpr int A<short>::f() {
return A<long>::f<U, V>();
}
// FIXME expected-error@-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@-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@-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@-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@-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@-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@-2 {{requires clause differs in template redeclaration}}
template<>
template<typename U, bool V> requires V
@ -241,6 +256,7 @@ namespace Constrained {
struct A<long>::B {
static constexpr int y = 1;
};
// FIXME expected-error@-4 {{requires clause differs in template redeclaration}}
template<>
template<typename U, bool V> requires V
@ -258,10 +274,17 @@ namespace Constrained {
static_assert(A<int>::B<int*, true>::y == 0); // expected-error {{implicit instantiation of undefined template 'Constrained::A<int>::B<int *, true>'}}
static_assert(A<short>::f<int, true>() == 1);
// FIXME expected-error@-1 {{static assertion expression is not an integral constant expression}}
// FIXME expected-note@-2 {{undefined function 'f<int, true>' cannot be used in a constant expression}}
static_assert(A<short>::x<int, true> == 1);
// FIXME expected-error@-1 {{static assertion expression is not an integral constant expression}}
// FIXME expected-note@-2 {{initializer of 'x<int, true>' is unknown}}
static_assert(A<short>::x<int*, true> == 2);
// FIXME expected-error@-1 {{ambiguous partial specializations of 'x'}}
static_assert(A<short>::B<int, true>::y == 1);
// FIXME expected-error@-1 {{implicit instantiation of undefined template 'Constrained::A<short>::B<int, true>'}}
static_assert(A<short>::B<int*, true>::y == 2);
// FIXME expected-error@-1 {{ambiguous partial specializations of 'B<int *, true>'}}
} // namespace Constrained
namespace Dependent {

View file

@ -85,15 +85,3 @@ 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

View file

@ -171,13 +171,6 @@ 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 {

View file

@ -1,28 +0,0 @@
// 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>();

View file

@ -6,6 +6,5 @@ constexpr void gh195416() {
static constexpr S S::bar;
// expected-error@-1 {{non-friend class member 'bar' cannot have a qualified name}}
// expected-error@-2 {{static data member 'bar' not allowed in local struct 'S'}}
// expected-error@-3 {{no member named 'bar' in 'gh195416()::U::S'}}
};
}

View file

@ -1466,10 +1466,3 @@ 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@-1 {{no return statement in constexpr function}}
} // namespace GH202106

View file

@ -792,29 +792,3 @@ 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

View file

@ -3,10 +3,9 @@
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
struct rdar9677163 {
struct Y { ~Y(); }; // expected-note {{previous declaration is here}}
struct Y { ~Y(); };
struct Z { ~Z(); };
Y::~Y() { } // expected-error{{non-friend class member '~Y' cannot have a qualified name}}
// expected-error@-1 {{destructor cannot be redeclared}}
~Z(); // expected-error{{expected the class name after '~' to name the enclosing class}}
};
@ -80,20 +79,3 @@ 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@-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@-1 {{non-friend class member 'f' cannot have a qualified name}}
// expected-error@-2 {{class member cannot be redeclared}}
};
} // namespace GH202109

View file

@ -1,12 +0,0 @@
// RUN: %clang_cc1 -verify %s
template <class> void foo(int = 0;
// expected-error@-1 {{expected ')'}}
// expected-note@-2 {{to match this '('}}
void bar();
#include "dadfoksbdsdldfafszcf.h"
// expected-error@-1 {{file not found}}
void baz() { foo<int>(); }

View file

@ -840,7 +840,7 @@ namespace PackIndexExpr1 {
template <int... T>
concept C = true;
template <typename...> struct TplClass {
template <typename...> struct TplClass { // #PackIndexExpr1-TplClassDef
template <int... Ts>
requires C<Ts...[0]>
static auto buggy() -> void;
@ -850,6 +850,9 @@ template <>
template <int... Ts>
requires C<Ts...[0]>
auto TplClass<int>::buggy() -> void {}
// FIXME: These shouldn't diagnose, but are a result of a revert: #193558
// expected-error@-2{{does not match any declaration in}}
// expected-note@#PackIndexExpr1-TplClassDef{{TplClass defined here}}
} // namespace PackIndexExpr1
namespace PackIndexExpr2 {
@ -900,16 +903,18 @@ namespace FuncTemplateInClass {
template <int T> concept C = true;
namespace t1 {
template <int> struct TplClass {
template <int> struct TplClass { // expected-note {{defined here}}
template <int Ts>
requires C<Ts>
static auto buggy() -> void;
};
// FIXME: This should be accepted.
template <>
template <int Ts>
requires C<Ts>
auto TplClass<0>::buggy() -> void {}
// expected-error@-1 {{out-of-line definition of 'buggy' does not match any declaration}}
} //namespace t1
namespace t2 {
template <int> struct TplClass { // expected-note {{defined here}}

View file

@ -338,11 +338,3 @@ class Foo {
bool aux;
};
}
namespace GH101330 {
template <class T> struct A {
template <int N> friend void f() noexcept(N == 0);
};
template <int N> void f() noexcept(N == 0) {}
template struct A<int>;
} // namespace GH101330

View file

@ -8,9 +8,10 @@ template<typename ...T> struct X {
template<typename T, typename U> using A = T;
// FIXME: These definitions are not OK, X<A<T, decltype(...)>...> is not equivalent to X<T...>.
// These definitions are OK, X<A<T, decltype(...)>...> is equivalent to X<T...>
// so this defines the member of the primary template.
template<typename ...T>
void X<A<T, decltype(f(T()))>...>::f(int) {}
void X<A<T, decltype(f(T()))>...>::f(int) {} // expected-error {{undeclared}}
template<typename ...T>
int X<A<T, decltype(f(T()))>...>::n = 0; // expected-error {{undeclared}}
@ -22,7 +23,8 @@ void g() {
X<Y>().f(0);
X<Y>::n = 1;
// FIXME: There should be no substitutiton failure since the out-of-line definitions were not valid.
X<void>().f(0);
// Error, substitution fails; this should not be treated as a SFINAE-able
// condition, so we don't select X<void>::f(...).
X<void>().f(0); // expected-note {{instantiation of}}
X<void>::n = 1; // expected-note {{instantiation of}}
}

View file

@ -10,77 +10,64 @@ int main()
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+foo$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
//
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+foo$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+foo$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
//
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'foo<int>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'foo<int>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
//
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+foo$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+foo$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
//
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+b$}}
// CHECK: {{^kind:[ ]+DefaultFunctionArgumentInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:12'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+b$}}
// CHECK: {{^kind:[ ]+DefaultFunctionArgumentInstantiation$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:12'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
//
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'foo<int>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'foo<int>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-default-func-arg.cpp:3:6'}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:85:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-default-func-arg.cpp:72:3'$}}
foo<int>();
}

View file

@ -207,18 +207,6 @@ template <bool = true> void d(int = 0) { d(); }
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:171:42'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:171:42'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:171:42'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'unnamed function parameter 0 of d<true>'$}}
// CHECK: {{^kind:[ ]+DefaultFunctionArgumentInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
@ -237,41 +225,41 @@ void e() {
}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:236:5'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:235:3\)'$}}
// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}}
// CHECK: {{^kind:[ ]+Memoization$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:235:3'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}}
template <template<typename> class>
@ -287,71 +275,71 @@ void foo() {
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
// CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
// CHECK: {{^poi:[ ]+''$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
// CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
// CHECK: {{^poi:[ ]+''$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
// CHECK: {{^kind:[ ]+PartialOrderingTTP$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:5'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}}
// CHECK: {{^kind:[ ]+PartialOrderingTTP$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:277:35'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:5'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'d<C>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+'d<C>'$}}
// CHECK: {{^kind:[ ]+TemplateInstantiation$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:278:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+Begin$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}
// CHECK-LABEL: {{^---$}}
// CHECK: {{^name:[ ]+d$}}
// CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}}
// CHECK: {{^event:[ ]+End$}}
// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:283:3'$}}
// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}}

View file

@ -732,7 +732,6 @@ bool CursorVisitor::VisitClassTemplateSpecializationDecl(
switch (D->getSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
case TSK_FriendDeclaration:
// Nothing to visit
return false;

View file

@ -5299,13 +5299,11 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportTemplateParameterLists) {
Decl *FromTU = getTuDecl(Code, Lang_CXX03);
auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU,
functionDecl(hasName("f"), isExplicitTemplateSpecialization()));
ASSERT_EQ(FromD->getTemplateSpecializationInfo()->TemplateParameters->size(),
0u);
ASSERT_EQ(FromD->getTemplateParameterLists().size(), 1u);
auto *ToD = Import(FromD, Lang_CXX03);
// The template parameter list should exist.
ASSERT_EQ(ToD->getTemplateSpecializationInfo()->TemplateParameters->size(),
0u);
EXPECT_EQ(ToD->getTemplateParameterLists().size(), 1u);
}
const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateDecl>

View file

@ -6071,14 +6071,14 @@ public:
FunDecl);
ExpectCorrectResult("ForCallable first",
callExpr(forCallable(declaresSameEntityAsNode(FunDecl)),
callExpr(forCallable(equalsNode(FunDecl)),
callee(cxxMethodDecl().bind("callee")))
.bind("call"),
FunDecl);
ExpectCorrectResult("ForCallable second",
callExpr(callee(cxxMethodDecl().bind("callee")),
forCallable(declaresSameEntityAsNode(FunDecl)))
forCallable(equalsNode(FunDecl)))
.bind("call"),
FunDecl);

View file

@ -1154,7 +1154,9 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::chrono::sys_seconds summary provider",
"^std::__[[:alnum:]]+::chrono::time_point<"
"std::__[[:alnum:]]+::chrono::system_clock, "
"std::__[[:alnum:]]+::chrono::duration<[^,]*> >$",
"std::__[[:alnum:]]+::chrono::duration<.*, "
"std::__[[:alnum:]]+::ratio<1, 1> "
"> >$",
eTypeOptionHideChildren | eTypeOptionHideValue |
eTypeOptionCascade,
true);
@ -1164,7 +1166,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"^std::__[[:alnum:]]+::chrono::time_point<"
"std::__[[:alnum:]]+::chrono::system_clock, "
"std::__[[:alnum:]]+::chrono::duration<int, "
"std::__[[:alnum:]]+::ratio<86400> "
"std::__[[:alnum:]]+::ratio<86400, 1> "
"> >$",
eTypeOptionHideChildren | eTypeOptionHideValue |
eTypeOptionCascade,
@ -1176,7 +1178,9 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"libc++ std::chrono::local_seconds summary provider",
"^std::__[[:alnum:]]+::chrono::time_point<"
"std::__[[:alnum:]]+::chrono::local_t, "
"std::__[[:alnum:]]+::chrono::duration<[^,]*> >$",
"std::__[[:alnum:]]+::chrono::duration<.*, "
"std::__[[:alnum:]]+::ratio<1, 1> "
"> >$",
eTypeOptionHideChildren | eTypeOptionHideValue | eTypeOptionCascade,
true);
AddCXXSummary(cpp_category_sp,
@ -1185,7 +1189,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"^std::__[[:alnum:]]+::chrono::time_point<"
"std::__[[:alnum:]]+::chrono::local_t, "
"std::__[[:alnum:]]+::chrono::duration<int, "
"std::__[[:alnum:]]+::ratio<86400> "
"std::__[[:alnum:]]+::ratio<86400, 1> "
"> >$",
eTypeOptionHideChildren | eTypeOptionHideValue |
eTypeOptionCascade,

View file

@ -1449,11 +1449,8 @@ void TypeSystemClang::CreateFunctionTemplateSpecializationInfo(
TemplateArgumentList *template_args_ptr = TemplateArgumentList::CreateCopy(
func_decl->getASTContext(), infos.GetArgs());
func_decl->setFunctionTemplateSpecialization(
func_decl->getASTContext(), func_tmpl_decl, template_args_ptr,
/*InsertPos=*/nullptr, TSK_ImplicitInstantiation,
/*TemplateParams=*/nullptr, /*TemplateArgsAsWritten=*/nullptr,
/*PointOfInstantiation=*/SourceLocation(), /*AddSpecialization=*/true);
func_decl->setFunctionTemplateSpecialization(func_tmpl_decl,
template_args_ptr, nullptr);
}
/// Returns true if the given template parameter can represent the given value.
@ -1652,40 +1649,6 @@ TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) {
template_param_list);
}
static const ASTTemplateArgumentListInfo *getTrivialTemplateArgumentListInfo(
ASTContext &ast, ArrayRef<TemplateArgument> args, SourceLocation Loc) {
TemplateArgumentListInfo Args(/*LAngleLoc=*/Loc, /*RAngleLoc=*/Loc);
for (const auto &arg : args) {
if (arg.getIsDefaulted())
break;
switch (arg.getKind()) {
case TemplateArgument::Type:
Args.addArgument(TemplateArgumentLoc(
arg.getAsType(), ast.getTrivialTypeSourceInfo(arg.getAsType(), Loc)));
break;
case TemplateArgument::Expression:
Args.addArgument(TemplateArgumentLoc(arg, arg.getAsExpr()));
break;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
Args.addArgument(
TemplateArgumentLoc(ast, arg, Loc, NestedNameSpecifierLoc(), Loc));
break;
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
case TemplateArgument::Pack:
case TemplateArgument::StructuralValue:
Args.addArgument(
TemplateArgumentLoc(arg, TemplateArgumentLocInfo(ast, Loc)));
break;
case TemplateArgument::Null:
llvm_unreachable("unexpected null template argument");
}
}
return ASTTemplateArgumentListInfo::Create(ast, Args);
}
ClassTemplateSpecializationDecl *
TypeSystemClang::CreateClassTemplateSpecializationDecl(
DeclContext *decl_ctx, OptionalClangModuleID owning_module,
@ -1728,13 +1691,6 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl(
class_template_specialization_decl->setSpecializationKind(
TSK_ExplicitSpecialization);
SourceLocation FakeLoc = class_template_specialization_decl->getLocation();
auto *TemplateParams = TemplateParameterList::Create(
ast, /*TemplateLoc=*/FakeLoc, /*LAngleLoc=*/FakeLoc,
/*Params=*/ArrayRef<NamedDecl *>(), /*RAngleLoc=*/FakeLoc,
/*RequiresClause=*/nullptr);
class_template_specialization_decl->setExplicitSpecializationInfo(
TemplateParams, ::getTrivialTemplateArgumentListInfo(ast, args, FakeLoc));
return class_template_specialization_decl;
}