aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaTemplate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaTemplate.cpp')
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp1261
1 files changed, 763 insertions, 498 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1542a07713fb..4b144c239fa4 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -39,6 +39,7 @@
#include "llvm/ADT/StringExtras.h"
#include <iterator>
+#include <optional>
using namespace clang;
using namespace sema;
@@ -109,7 +110,7 @@ NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D,
return D;
}
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+ if (const auto *Record = dyn_cast<CXXRecordDecl>(D)) {
// C++ [temp.local]p1:
// Like normal (non-template) classes, class templates have an
// injected-class-name (Clause 9). The injected-class-name
@@ -126,8 +127,7 @@ NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D,
if (Record->getDescribedClassTemplate())
return Record->getDescribedClassTemplate();
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+ if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Record))
return Spec->getSpecializedTemplate();
}
@@ -399,6 +399,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
LookupCtx = computeDeclContext(ObjectType);
IsDependent = !LookupCtx && ObjectType->isDependentType();
assert((IsDependent || !ObjectType->isIncompleteType() ||
+ !ObjectType->getAs<TagType>() ||
ObjectType->castAs<TagType>()->isBeingDefined()) &&
"Caller should have completed object type");
@@ -816,7 +817,7 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
if (!Complain || (PatternDef && PatternDef->isInvalidDecl()))
return true;
- llvm::Optional<unsigned> Note;
+ std::optional<unsigned> Note;
QualType InstantiationTy;
if (TagDecl *TD = dyn_cast<TagDecl>(Instantiation))
InstantiationTy = Context.getTypeDeclType(TD);
@@ -941,7 +942,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
TemplateName Template = Arg.getAsTemplate().get();
TemplateArgument TArg;
if (Arg.getEllipsisLoc().isValid())
- TArg = TemplateArgument(Template, Optional<unsigned int>());
+ TArg = TemplateArgument(Template, std::optional<unsigned int>());
else
TArg = Template;
return TemplateArgumentLoc(
@@ -1207,7 +1208,7 @@ static ExprResult formImmediatelyDeclaredConstraint(
ImmediatelyDeclaredConstraint.get(), BO_LAnd,
EllipsisLoc, /*RHS=*/nullptr,
/*RParenLoc=*/SourceLocation(),
- /*NumExpansions=*/None);
+ /*NumExpansions=*/std::nullopt);
}
/// Attach a type-constraint to a template parameter.
@@ -1530,11 +1531,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
CheckValidDeclSpecifiers();
- if (TInfo->getType()->isUndeducedType()) {
- Diag(D.getIdentifierLoc(),
- diag::warn_cxx14_compat_template_nontype_parm_auto_type)
- << QualType(TInfo->getType()->getContainedAutoType(), 0);
- }
+ if (const auto *T = TInfo->getType()->getContainedDeducedType())
+ if (isa<AutoType>(T))
+ Diag(D.getIdentifierLoc(),
+ diag::warn_cxx14_compat_template_nontype_parm_auto_type)
+ << QualType(TInfo->getType()->getContainedAutoType(), 0);
assert(S->isTemplateParamScope() &&
"Non-type template parameter not in template parameter scope!");
@@ -1591,9 +1592,10 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument))
return Param;
- TemplateArgument Converted;
- ExprResult DefaultRes =
- CheckTemplateArgument(Param, Param->getType(), Default, Converted);
+ TemplateArgument SugaredConverted, CanonicalConverted;
+ ExprResult DefaultRes = CheckTemplateArgument(
+ Param, Param->getType(), Default, SugaredConverted, CanonicalConverted,
+ CTAK_Specified);
if (DefaultRes.isInvalid()) {
Param->setInvalidDecl();
return Param;
@@ -1686,6 +1688,99 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S,
return Param;
}
+namespace {
+class ConstraintRefersToContainingTemplateChecker
+ : public TreeTransform<ConstraintRefersToContainingTemplateChecker> {
+ bool Result = false;
+ const FunctionDecl *Friend = nullptr;
+ unsigned TemplateDepth = 0;
+
+ // Check a record-decl that we've seen to see if it is a lexical parent of the
+ // Friend, likely because it was referred to without its template arguments.
+ void CheckIfContainingRecord(const CXXRecordDecl *CheckingRD) {
+ CheckingRD = CheckingRD->getMostRecentDecl();
+
+ for (const DeclContext *DC = Friend->getLexicalDeclContext();
+ DC && !DC->isFileContext(); DC = DC->getParent())
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
+ if (CheckingRD == RD->getMostRecentDecl())
+ Result = true;
+ }
+
+ void CheckNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ assert(D->getDepth() <= TemplateDepth &&
+ "Nothing should reference a value below the actual template depth, "
+ "depth is likely wrong");
+ if (D->getDepth() != TemplateDepth)
+ Result = true;
+
+ // Necessary because the type of the NTTP might be what refers to the parent
+ // constriant.
+ TransformType(D->getType());
+ }
+
+public:
+ using inherited = TreeTransform<ConstraintRefersToContainingTemplateChecker>;
+
+ ConstraintRefersToContainingTemplateChecker(Sema &SemaRef,
+ const FunctionDecl *Friend,
+ unsigned TemplateDepth)
+ : inherited(SemaRef), Friend(Friend), TemplateDepth(TemplateDepth) {}
+ bool getResult() const { return Result; }
+
+ // This should be the only template parm type that we have to deal with.
+ // SubstTempalteTypeParmPack, SubstNonTypeTemplateParmPack, and
+ // FunctionParmPackExpr are all partially substituted, which cannot happen
+ // with concepts at this point in translation.
+ using inherited::TransformTemplateTypeParmType;
+ QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+ TemplateTypeParmTypeLoc TL, bool) {
+ assert(TL.getDecl()->getDepth() <= TemplateDepth &&
+ "Nothing should reference a value below the actual template depth, "
+ "depth is likely wrong");
+ if (TL.getDecl()->getDepth() != TemplateDepth)
+ Result = true;
+ return inherited::TransformTemplateTypeParmType(
+ TLB, TL,
+ /*SuppressObjCLifetime=*/false);
+ }
+
+ Decl *TransformDecl(SourceLocation Loc, Decl *D) {
+ if (!D)
+ return D;
+ // FIXME : This is possibly an incomplete list, but it is unclear what other
+ // Decl kinds could be used to refer to the template parameters. This is a
+ // best guess so far based on examples currently available, but the
+ // unreachable should catch future instances/cases.
+ if (auto *TD = dyn_cast<TypedefNameDecl>(D))
+ TransformType(TD->getUnderlyingType());
+ else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(D))
+ CheckNonTypeTemplateParmDecl(NTTPD);
+ else if (auto *VD = dyn_cast<ValueDecl>(D))
+ TransformType(VD->getType());
+ else if (auto *TD = dyn_cast<TemplateDecl>(D))
+ TransformTemplateParameterList(TD->getTemplateParameters());
+ else if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ CheckIfContainingRecord(RD);
+ else if (isa<NamedDecl>(D)) {
+ // No direct types to visit here I believe.
+ } else
+ llvm_unreachable("Don't know how to handle this declaration type yet");
+ return D;
+ }
+};
+} // namespace
+
+bool Sema::ConstraintExpressionDependsOnEnclosingTemplate(
+ const FunctionDecl *Friend, unsigned TemplateDepth,
+ const Expr *Constraint) {
+ assert(Friend->getFriendObjectKind() && "Only works on a friend");
+ ConstraintRefersToContainingTemplateChecker Checker(*this, Friend,
+ TemplateDepth);
+ Checker.TransformExpr(const_cast<Expr *>(Constraint));
+ return Checker.getResult();
+}
+
/// ActOnTemplateParameterList - Builds a TemplateParameterList, optionally
/// constrained by RequiresClause, that contains the template parameters in
/// Params.
@@ -1705,8 +1800,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
return TemplateParameterList::Create(
Context, TemplateLoc, LAngleLoc,
- llvm::makeArrayRef(Params.data(), Params.size()),
- RAngleLoc, RequiresClause);
+ llvm::ArrayRef(Params.data(), Params.size()), RAngleLoc, RequiresClause);
}
static void SetNestedNameSpecifier(Sema &S, TagDecl *T,
@@ -1985,8 +2079,8 @@ DeclResult Sema::CheckClassTemplate(
SetNestedNameSpecifier(*this, NewClass, SS);
if (NumOuterTemplateParamLists > 0)
NewClass->setTemplateParameterListsInfo(
- Context, llvm::makeArrayRef(OuterTemplateParamLists,
- NumOuterTemplateParamLists));
+ Context,
+ llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
@@ -2284,10 +2378,12 @@ private:
/*Depth*/ 0, Depth1IndexAdjustment + TTP->getIndex(),
TTP->getIdentifier(), TTP->wasDeclaredWithTypename(),
TTP->isParameterPack(), TTP->hasTypeConstraint(),
- TTP->isExpandedParameterPack() ?
- llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
+ TTP->isExpandedParameterPack()
+ ? std::optional<unsigned>(TTP->getNumExpansionParameters())
+ : std::nullopt);
if (const auto *TC = TTP->getTypeConstraint())
- SemaRef.SubstTypeConstraint(NewTTP, TC, Args);
+ SemaRef.SubstTypeConstraint(NewTTP, TC, Args,
+ /*EvaluateConstraint*/ true);
if (TTP->hasDefaultArgument()) {
TypeSourceInfo *InstantiatedDefaultArg =
SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
@@ -2444,6 +2540,8 @@ private:
TInfo->getType(), TInfo, LocEnd, Ctor);
Guide->setImplicit();
Guide->setParams(Params);
+ if (Ctor && Ctor->getTrailingRequiresClause())
+ Guide->setTrailingRequiresClause(Ctor->getTrailingRequiresClause());
for (auto *Param : Params)
Param->setDeclContext(Guide);
@@ -2535,7 +2633,7 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
// additional function template derived as above from a hypothetical
// constructor C().
if (!AddedAny)
- Transform.buildSimpleDeductionGuide(None);
+ Transform.buildSimpleDeductionGuide(std::nullopt);
// -- An additional function template derived as above from a hypothetical
// constructor C(C), called the copy deduction candidate.
@@ -3411,7 +3509,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// Fabricate an empty template parameter list for the invented header.
return TemplateParameterList::Create(Context, SourceLocation(),
- SourceLocation(), None,
+ SourceLocation(), std::nullopt,
SourceLocation(), nullptr);
}
@@ -3496,45 +3594,54 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
static QualType
checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
- const SmallVectorImpl<TemplateArgument> &Converted,
+ ArrayRef<TemplateArgument> Converted,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
ASTContext &Context = SemaRef.getASTContext();
+
switch (BTD->getBuiltinTemplateKind()) {
case BTK__make_integer_seq: {
// Specializations of __make_integer_seq<S, T, N> are treated like
// S<T, 0, ..., N-1>.
+ QualType OrigType = Converted[1].getAsType();
// C++14 [inteseq.intseq]p1:
// T shall be an integer type.
- if (!Converted[1].getAsType()->isIntegralType(Context)) {
+ if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) {
SemaRef.Diag(TemplateArgs[1].getLocation(),
diag::err_integer_sequence_integral_element_type);
return QualType();
}
- // C++14 [inteseq.make]p1:
- // If N is negative the program is ill-formed.
TemplateArgument NumArgsArg = Converted[2];
- llvm::APSInt NumArgs = NumArgsArg.getAsIntegral();
- if (NumArgs < 0) {
+ if (NumArgsArg.isDependent())
+ return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
+ Converted);
+
+ TemplateArgumentListInfo SyntheticTemplateArgs;
+ // The type argument, wrapped in substitution sugar, gets reused as the
+ // first template argument in the synthetic template argument list.
+ SyntheticTemplateArgs.addArgument(
+ TemplateArgumentLoc(TemplateArgument(OrigType),
+ SemaRef.Context.getTrivialTypeSourceInfo(
+ OrigType, TemplateArgs[1].getLocation())));
+
+ if (llvm::APSInt NumArgs = NumArgsArg.getAsIntegral(); NumArgs >= 0) {
+ // Expand N into 0 ... N-1.
+ for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
+ I < NumArgs; ++I) {
+ TemplateArgument TA(Context, I, OrigType);
+ SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
+ TA, OrigType, TemplateArgs[2].getLocation()));
+ }
+ } else {
+ // C++14 [inteseq.make]p1:
+ // If N is negative the program is ill-formed.
SemaRef.Diag(TemplateArgs[2].getLocation(),
diag::err_integer_sequence_negative_length);
return QualType();
}
- QualType ArgTy = NumArgsArg.getIntegralType();
- TemplateArgumentListInfo SyntheticTemplateArgs;
- // The type argument gets reused as the first template argument in the
- // synthetic template argument list.
- SyntheticTemplateArgs.addArgument(TemplateArgs[1]);
- // Expand N into 0 ... N-1.
- for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
- I < NumArgs; ++I) {
- TemplateArgument TA(Context, I, ArgTy);
- SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
- TA, ArgTy, TemplateArgs[2].getLocation()));
- }
// The first template argument will be reused as the template decl that
// our synthetic template arguments will be applied to.
return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(),
@@ -3548,11 +3655,15 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
assert(Converted.size() == 2 &&
"__type_pack_element should be given an index and a parameter pack");
- // If the Index is out of bounds, the program is ill-formed.
TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
+ if (IndexArg.isDependent() || Ts.isDependent())
+ return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
+ Converted);
+
llvm::APSInt Index = IndexArg.getAsIntegral();
assert(Index >= 0 && "the index used with __type_pack_element should be of "
"type std::size_t, and hence be non-negative");
+ // If the Index is out of bounds, the program is ill-formed.
if (Index >= Ts.pack_size()) {
SemaRef.Diag(TemplateArgs[0].getLocation(),
diag::err_type_pack_element_out_of_bounds);
@@ -3560,8 +3671,8 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
}
// We simply return the type at index `Index`.
- auto Nth = std::next(Ts.pack_begin(), Index.getExtValue());
- return Nth->getAsType();
+ int64_t N = Index.getExtValue();
+ return Ts.getPackAsArray()[N].getAsType();
}
llvm_unreachable("unexpected BuiltinTemplateDecl!");
}
@@ -3585,9 +3696,8 @@ static void collectConjunctionTerms(Expr *Clause,
if (BinOp->getOpcode() == BO_LAnd) {
collectConjunctionTerms(BinOp->getLHS(), Terms);
collectConjunctionTerms(BinOp->getRHS(), Terms);
+ return;
}
-
- return;
}
Terms.push_back(Clause);
@@ -3715,10 +3825,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// assume the template is a type template. Either our assumption is
// correct, or the code is ill-formed and will be diagnosed when the
// dependent name is substituted.
- return Context.getDependentTemplateSpecializationType(ETK_None,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ return Context.getDependentTemplateSpecializationType(
+ ETK_None, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
if (Name.getAsAssumedTemplateName() &&
resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc))
@@ -3730,7 +3839,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
- return Context.getTemplateSpecializationType(Name, TemplateArgs);
+ return Context.getTemplateSpecializationType(Name,
+ TemplateArgs.arguments());
Diag(TemplateLoc, diag::err_template_id_not_a_type)
<< Name;
@@ -3740,9 +3850,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
- false, Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false,
+ SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return QualType();
@@ -3756,12 +3866,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
if (Pattern->isInvalidDecl())
return QualType();
- TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
- Converted);
-
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs);
+ TemplateArgLists.addOuterTemplateArguments(Template, CanonicalConverted,
+ /*Final=*/false);
TemplateArgLists.addOuterRetainedLevels(
AliasTemplate->getTemplateParameters()->getDepth());
@@ -3808,9 +3916,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
return QualType();
}
+ } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
+ CanonType = checkBuiltinTemplateIdType(*this, BTD, SugaredConverted,
+ TemplateLoc, TemplateArgs);
} else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs, Converted)) {
+ TemplateArgs, CanonicalConverted)) {
// This class template specialization is a dependent
// type. Therefore, its canonical type is another class template
// specialization type that contains all of the converted
@@ -3818,7 +3929,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// A<T, T> have identical types when A is declared as:
//
// template<typename T, typename U = T> struct A;
- CanonType = Context.getCanonicalTemplateSpecializationType(Name, Converted);
+ CanonType = Context.getCanonicalTemplateSpecializationType(
+ Name, CanonicalConverted);
// This might work out to be a current instantiation, in which
// case the canonical type needs to be the InjectedClassNameType.
@@ -3857,13 +3969,13 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
break;
}
}
- } else if (ClassTemplateDecl *ClassTemplate
- = dyn_cast<ClassTemplateDecl>(Template)) {
+ } else if (ClassTemplateDecl *ClassTemplate =
+ dyn_cast<ClassTemplateDecl>(Template)) {
// Find the class template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *Decl
- = ClassTemplate->findSpecialization(Converted, InsertPos);
+ ClassTemplateSpecializationDecl *Decl =
+ ClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
if (!Decl) {
// This is the first time we have referenced this class template
// specialization. Create the canonical declaration and add it to
@@ -3872,7 +3984,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
Context, ClassTemplate->getTemplatedDecl()->getTagKind(),
ClassTemplate->getDeclContext(),
ClassTemplate->getTemplatedDecl()->getBeginLoc(),
- ClassTemplate->getLocation(), ClassTemplate, Converted, nullptr);
+ ClassTemplate->getLocation(), ClassTemplate, CanonicalConverted,
+ nullptr);
ClassTemplate->AddSpecialization(Decl, InsertPos);
if (ClassTemplate->isOutOfLine())
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
@@ -3882,8 +3995,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
ClassTemplate->getTemplatedDecl()->hasAttrs()) {
InstantiatingTemplate Inst(*this, TemplateLoc, Decl);
if (!Inst.isInvalid()) {
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(Converted);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template,
+ CanonicalConverted,
+ /*Final=*/false);
InstantiateAttrsForDecl(TemplateArgLists,
ClassTemplate->getTemplatedDecl(), Decl);
}
@@ -3895,15 +4009,15 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
CanonType = Context.getTypeDeclType(Decl);
assert(isa<RecordType>(CanonType) &&
"type of non-dependent specialization is not a RecordType");
- } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
- CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc,
- TemplateArgs);
+ } else {
+ llvm_unreachable("Unhandled template kind");
}
// Build the fully-sugared type for this class template
// specialization, which refers back to the class template
// specialization we created or found.
- return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
+ return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(),
+ CanonType);
}
void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName,
@@ -3964,7 +4078,8 @@ TypeResult Sema::ActOnTemplateIdType(
TemplateTy TemplateD, IdentifierInfo *TemplateII,
SourceLocation TemplateIILoc, SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc,
- bool IsCtorOrDtorName, bool IsClassName) {
+ bool IsCtorOrDtorName, bool IsClassName,
+ ImplicitTypenameContext AllowImplicitTypename) {
if (SS.isInvalid())
return true;
@@ -3978,9 +4093,18 @@ TypeResult Sema::ActOnTemplateIdType(
// qualified-id denotes a type, forming an
// elaborated-type-specifier (7.1.5.3).
if (!LookupCtx && isDependentScopeSpecifier(SS)) {
- Diag(SS.getBeginLoc(), diag::err_typename_missing_template)
- << SS.getScopeRep() << TemplateII->getName();
- // Recover as if 'typename' were specified.
+ // C++2a relaxes some of those restrictions in [temp.res]p5.
+ if (AllowImplicitTypename == ImplicitTypenameContext::Yes) {
+ if (getLangOpts().CPlusPlus20)
+ Diag(SS.getBeginLoc(), diag::warn_cxx17_compat_implicit_typename);
+ else
+ Diag(SS.getBeginLoc(), diag::ext_implicit_typename)
+ << SS.getScopeRep() << TemplateII->getName()
+ << FixItHint::CreateInsertion(SS.getBeginLoc(), "typename ");
+ } else
+ Diag(SS.getBeginLoc(), diag::err_typename_missing_template)
+ << SS.getScopeRep() << TemplateII->getName();
+
// FIXME: This is not quite correct recovery as we don't transform SS
// into the corresponding dependent form (and we don't diagnose missing
// 'template' keywords within SS as a result).
@@ -4014,11 +4138,10 @@ TypeResult Sema::ActOnTemplateIdType(
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
- QualType T
- = Context.getDependentTemplateSpecializationType(ETK_None,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ assert(SS.getScopeRep() == DTN->getQualifier());
+ QualType T = Context.getDependentTemplateSpecializationType(
+ ETK_None, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Build type-source information.
TypeLocBuilder TLB;
DependentTemplateSpecializationTypeLoc SpecTL
@@ -4034,14 +4157,14 @@ TypeResult Sema::ActOnTemplateIdType(
return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
}
- QualType Result = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
- if (Result.isNull())
+ QualType SpecTy = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
+ if (SpecTy.isNull())
return true;
// Build type-source information.
TypeLocBuilder TLB;
- TemplateSpecializationTypeLoc SpecTL
- = TLB.push<TemplateSpecializationTypeLoc>(Result);
+ TemplateSpecializationTypeLoc SpecTL =
+ TLB.push<TemplateSpecializationTypeLoc>(SpecTy);
SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
SpecTL.setTemplateNameLoc(TemplateIILoc);
SpecTL.setLAngleLoc(LAngleLoc);
@@ -4049,18 +4172,14 @@ TypeResult Sema::ActOnTemplateIdType(
for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i)
SpecTL.setArgLocInfo(i, TemplateArgs[i].getLocInfo());
- // NOTE: avoid constructing an ElaboratedTypeLoc if this is a
- // constructor or destructor name (in such a case, the scope specifier
- // will be attached to the enclosing Decl or Expr node).
- if (SS.isNotEmpty() && !IsCtorOrDtorName) {
- // Create an elaborated-type-specifier containing the nested-name-specifier.
- Result = Context.getElaboratedType(ETK_None, SS.getScopeRep(), Result);
- ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(Result);
- ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ // Create an elaborated-type-specifier containing the nested-name-specifier.
+ QualType ElTy = getElaboratedType(
+ ETK_None, !IsCtorOrDtorName ? SS : CXXScopeSpec(), SpecTy);
+ ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(ElTy);
+ ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ if (!ElabTL.isEmpty())
ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
- }
-
- return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
+ return CreateParsedType(ElTy, TLB.getTypeSourceInfo(Context, ElTy));
}
TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
@@ -4088,10 +4207,10 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
= TypeWithKeyword::getKeywordForTagTypeKind(TagKind);
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
- QualType T = Context.getDependentTemplateSpecializationType(Keyword,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ assert(SS.getScopeRep() == DTN->getQualifier());
+ QualType T = Context.getDependentTemplateSpecializationType(
+ Keyword, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Build type-source information.
TypeLocBuilder TLB;
@@ -4386,9 +4505,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs,
- false, Converted,
+ false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
@@ -4396,21 +4515,22 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// corresponds to these arguments.
if (IsPartialSpecialization) {
if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, VarTemplate,
- TemplateArgs.size(), Converted))
+ TemplateArgs.size(),
+ CanonicalConverted))
return true;
// FIXME: Move these checks to CheckTemplatePartialSpecializationArgs so we
// also do them during instantiation.
if (!Name.isDependent() &&
- !TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
- Converted)) {
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, CanonicalConverted)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< VarTemplate->getDeclName();
IsPartialSpecialization = false;
}
if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
- Converted) &&
+ CanonicalConverted) &&
(!Context.getLangOpts().CPlusPlus20 ||
!TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
@@ -4431,10 +4551,10 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplateSpecializationDecl *PrevDecl = nullptr;
if (IsPartialSpecialization)
- PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams,
- InsertPos);
+ PrevDecl = VarTemplate->findPartialSpecialization(
+ CanonicalConverted, TemplateParams, InsertPos);
else
- PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos);
+ PrevDecl = VarTemplate->findSpecialization(CanonicalConverted, InsertPos);
VarTemplateSpecializationDecl *Specialization = nullptr;
@@ -4461,7 +4581,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplatePartialSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
- Converted, TemplateArgs);
+ CanonicalConverted, TemplateArgs);
if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
@@ -4478,7 +4598,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// this explicit specialization or friend declaration.
Specialization = VarTemplateSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
- VarTemplate, DI->getType(), DI, SC, Converted);
+ VarTemplate, DI->getType(), DI, SC, CanonicalConverted);
Specialization->setTemplateArgsInfo(TemplateArgs);
if (!PrevDecl)
@@ -4556,24 +4676,25 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
assert(Template && "A variable template id without template?");
// Check that the template argument list is well-formed for this template.
- SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(
Template, TemplateNameLoc,
const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
- Converted, /*UpdateArgsWithConversions=*/true))
+ SugaredConverted, CanonicalConverted,
+ /*UpdateArgsWithConversions=*/true))
return true;
// Produce a placeholder value if the specialization is dependent.
if (Template->getDeclContext()->isDependentContext() ||
- TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
- Converted))
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, CanonicalConverted))
return DeclResult();
// Find the variable template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
- if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization(
- Converted, InsertPos)) {
+ if (VarTemplateSpecializationDecl *Spec =
+ Template->findSpecialization(CanonicalConverted, InsertPos)) {
checkSpecializationReachability(TemplateNameLoc, Spec);
// If we already have a variable template specialization, return it.
return Spec;
@@ -4585,7 +4706,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// that it represents. That is,
VarDecl *InstantiationPattern = Template->getTemplatedDecl();
TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
- Converted);
+ CanonicalConverted);
TemplateArgumentList *InstantiationArgs = &TemplateArgList;
bool AmbiguousPartialSpec = false;
typedef PartialSpecMatchResult MatchResult;
@@ -4617,7 +4738,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
} else {
Matched.push_back(PartialSpecMatchResult());
Matched.back().Partial = Partial;
- Matched.back().Args = Info.take();
+ Matched.back().Args = Info.takeCanonical();
}
}
@@ -4673,7 +4794,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// FIXME: LateAttrs et al.?
VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
Template, InstantiationPattern, *InstantiationArgs, TemplateArgs,
- Converted, TemplateNameLoc /*, LateAttrs, StartingScope*/);
+ CanonicalConverted, TemplateNameLoc /*, LateAttrs, StartingScope*/);
if (!Decl)
return true;
@@ -4744,29 +4865,41 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
const TemplateArgumentListInfo *TemplateArgs) {
assert(NamedConcept && "A concept template id without a template?");
- llvm::SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(),
- const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
- /*PartialTemplateArgs=*/false, Converted,
- /*UpdateArgsWithConversions=*/false))
+ llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(
+ NamedConcept, ConceptNameInfo.getLoc(),
+ const_cast<TemplateArgumentListInfo &>(*TemplateArgs),
+ /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted,
+ /*UpdateArgsWithConversions=*/false))
return ExprError();
+ auto *CSD = ImplicitConceptSpecializationDecl::Create(
+ Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(),
+ CanonicalConverted);
ConstraintSatisfaction Satisfaction;
bool AreArgsDependent =
- TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs,
- Converted);
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ *TemplateArgs, CanonicalConverted);
+ MultiLevelTemplateArgumentList MLTAL(NamedConcept, CanonicalConverted,
+ /*Final=*/false);
+ LocalInstantiationScope Scope(*this);
+
+ EnterExpressionEvaluationContext EECtx{
+ *this, ExpressionEvaluationContext::ConstantEvaluated, CSD};
+
if (!AreArgsDependent &&
CheckConstraintSatisfaction(
- NamedConcept, {NamedConcept->getConstraintExpr()}, Converted,
+ NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL,
SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
TemplateArgs->getRAngleLoc()),
Satisfaction))
return ExprError();
- return ConceptSpecializationExpr::Create(Context,
+ return ConceptSpecializationExpr::Create(
+ Context,
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
- ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted,
+ ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), CSD,
AreArgsDependent ? nullptr : &Satisfaction);
}
@@ -5008,9 +5141,10 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
return TNK_Non_template;
}
-bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
- TemplateArgumentLoc &AL,
- SmallVectorImpl<TemplateArgument> &Converted) {
+bool Sema::CheckTemplateTypeArgument(
+ TemplateTypeParmDecl *Param, TemplateArgumentLoc &AL,
+ SmallVectorImpl<TemplateArgument> &SugaredConverted,
+ SmallVectorImpl<TemplateArgument> &CanonicalConverted) {
const TemplateArgument &Arg = AL.getArgument();
QualType ArgType;
TypeSourceInfo *TSI = nullptr;
@@ -5087,7 +5221,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
}
}
// fallthrough
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
default: {
// We have a template type parameter but the template argument
@@ -5103,9 +5237,6 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
if (CheckTemplateArgument(TSI))
return true;
- // Add the converted template type argument.
- ArgType = Context.getCanonicalType(ArgType);
-
// Objective-C ARC:
// If an explicitly-specified template argument type is a lifetime type
// with no lifetime qualifier, the __strong lifetime qualifier is inferred.
@@ -5117,7 +5248,9 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
ArgType = Context.getQualifiedType(ArgType, Qs);
}
- Converted.push_back(TemplateArgument(ArgType));
+ SugaredConverted.push_back(TemplateArgument(ArgType));
+ CanonicalConverted.push_back(
+ TemplateArgument(Context.getCanonicalType(ArgType)));
return false;
}
@@ -5142,31 +5275,27 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
/// \param Converted the list of template arguments provided for template
/// parameters that precede \p Param in the template parameter list.
/// \returns the substituted template argument, or NULL if an error occurred.
-static TypeSourceInfo *
-SubstDefaultTemplateArgument(Sema &SemaRef,
- TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- TemplateTypeParmDecl *Param,
- SmallVectorImpl<TemplateArgument> &Converted) {
+static TypeSourceInfo *SubstDefaultTemplateArgument(
+ Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, TemplateTypeParmDecl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted) {
TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo();
// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
if (ArgType->getType()->isInstantiationDependentType()) {
- Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Param, Template, Converted,
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return nullptr;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
-
// Only substitute for the innermost template argument list.
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
+ /*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
- TemplateArgLists.addOuterTemplateArguments(None);
+ TemplateArgLists.addOuterTemplateArguments(std::nullopt);
bool ForLambdaCallOperator = false;
if (const auto *Rec = dyn_cast<CXXRecordDecl>(Template->getDeclContext()))
@@ -5203,26 +5332,22 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// parameters that precede \p Param in the template parameter list.
///
/// \returns the substituted template argument, or NULL if an error occurred.
-static ExprResult
-SubstDefaultTemplateArgument(Sema &SemaRef,
- TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- NonTypeTemplateParmDecl *Param,
- SmallVectorImpl<TemplateArgument> &Converted) {
- Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Param, Template, Converted,
+static ExprResult SubstDefaultTemplateArgument(
+ Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted) {
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return ExprError();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
-
// Only substitute for the innermost template argument list.
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
+ /*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
- TemplateArgLists.addOuterTemplateArguments(None);
+ TemplateArgLists.addOuterTemplateArguments(std::nullopt);
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
EnterExpressionEvaluationContext ConstantEvaluated(
@@ -5255,27 +5380,23 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// source-location information) that precedes the template name.
///
/// \returns the substituted template argument, or NULL if an error occurred.
-static TemplateName
-SubstDefaultTemplateArgument(Sema &SemaRef,
- TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- TemplateTemplateParmDecl *Param,
- SmallVectorImpl<TemplateArgument> &Converted,
- NestedNameSpecifierLoc &QualifierLoc) {
+static TemplateName SubstDefaultTemplateArgument(
+ Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted,
+ NestedNameSpecifierLoc &QualifierLoc) {
Sema::InstantiatingTemplate Inst(
- SemaRef, TemplateLoc, TemplateParameter(Param), Template, Converted,
- SourceRange(TemplateLoc, RAngleLoc));
+ SemaRef, TemplateLoc, TemplateParameter(Param), Template,
+ SugaredConverted, SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return TemplateName();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
-
// Only substitute for the innermost template argument list.
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
+ /*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
- TemplateArgLists.addOuterTemplateArguments(None);
+ TemplateArgLists.addOuterTemplateArguments(std::nullopt);
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
// Substitute into the nested-name-specifier first,
@@ -5297,14 +5418,11 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// If the given template parameter has a default template
/// argument, substitute into that default template argument and
/// return the corresponding template argument.
-TemplateArgumentLoc
-Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- Decl *Param,
- SmallVectorImpl<TemplateArgument>
- &Converted,
- bool &HasDefaultArg) {
+TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable(
+ TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, Decl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg) {
HasDefaultArg = false;
if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
@@ -5312,11 +5430,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
return TemplateArgumentLoc();
HasDefaultArg = true;
- TypeSourceInfo *DI = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- TypeParm,
- Converted);
+ TypeSourceInfo *DI = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TypeParm, SugaredConverted,
+ CanonicalConverted);
if (DI)
return TemplateArgumentLoc(TemplateArgument(DI->getType()), DI);
@@ -5329,11 +5445,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
return TemplateArgumentLoc();
HasDefaultArg = true;
- ExprResult Arg = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- NonTypeParm,
- Converted);
+ ExprResult Arg = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, NonTypeParm, SugaredConverted,
+ CanonicalConverted);
if (Arg.isInvalid())
return TemplateArgumentLoc();
@@ -5348,12 +5462,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
HasDefaultArg = true;
NestedNameSpecifierLoc QualifierLoc;
- TemplateName TName = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- TempTempParm,
- Converted,
- QualifierLoc);
+ TemplateName TName = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TempTempParm, SugaredConverted,
+ CanonicalConverted, QualifierLoc);
if (TName.isNull())
return TemplateArgumentLoc();
@@ -5423,17 +5534,17 @@ convertTypeTemplateArgumentToTemplate(ASTContext &Context, TypeLoc TLoc) {
/// explicitly written, deduced, etc.
///
/// \returns true on error, false otherwise.
-bool Sema::CheckTemplateArgument(NamedDecl *Param,
- TemplateArgumentLoc &Arg,
- NamedDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- unsigned ArgumentPackIndex,
- SmallVectorImpl<TemplateArgument> &Converted,
- CheckTemplateArgumentKind CTAK) {
+bool Sema::CheckTemplateArgument(
+ NamedDecl *Param, TemplateArgumentLoc &Arg, NamedDecl *Template,
+ SourceLocation TemplateLoc, SourceLocation RAngleLoc,
+ unsigned ArgumentPackIndex,
+ SmallVectorImpl<TemplateArgument> &SugaredConverted,
+ SmallVectorImpl<TemplateArgument> &CanonicalConverted,
+ CheckTemplateArgumentKind CTAK) {
// Check template type parameters.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
- return CheckTemplateTypeArgument(TTP, Arg, Converted);
+ return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
+ CanonicalConverted);
// Check non-type template parameters.
if (NonTypeTemplateParmDecl *NTTP =dyn_cast<NonTypeTemplateParmDecl>(Param)) {
@@ -5448,27 +5559,22 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
!isa<TemplateTemplateParmDecl>(Template) &&
!Template->getDeclContext()->isDependentContext()) {
// Do substitution on the type of the non-type template parameter.
- InstantiatingTemplate Inst(*this, TemplateLoc, Template,
- NTTP, Converted,
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template, NTTP,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted);
-
+ MultiLevelTemplateArgumentList MLTAL(Template, SugaredConverted,
+ /*Final=*/true);
// If the parameter is a pack expansion, expand this slice of the pack.
if (auto *PET = NTTPType->getAs<PackExpansionType>()) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this,
ArgumentPackIndex);
- NTTPType = SubstType(PET->getPattern(),
- MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(),
+ NTTPType = SubstType(PET->getPattern(), MLTAL, NTTP->getLocation(),
NTTP->getDeclName());
} else {
- NTTPType = SubstType(NTTPType,
- MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(),
+ NTTPType = SubstType(NTTPType, MLTAL, NTTP->getLocation(),
NTTP->getDeclName());
}
@@ -5486,11 +5592,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
llvm_unreachable("Should never see a NULL template argument here");
case TemplateArgument::Expression: {
- TemplateArgument Result;
+ Expr *E = Arg.getArgument().getAsExpr();
+ TemplateArgument SugaredResult, CanonicalResult;
unsigned CurSFINAEErrors = NumSFINAEErrors;
- ExprResult Res =
- CheckTemplateArgument(NTTP, NTTPType, Arg.getArgument().getAsExpr(),
- Result, CTAK);
+ ExprResult Res = CheckTemplateArgument(NTTP, NTTPType, E, SugaredResult,
+ CanonicalResult, CTAK);
if (Res.isInvalid())
return true;
// If the current template argument causes an error, give up now.
@@ -5499,12 +5605,13 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
// If the resulting expression is new, then use it in place of the
// old expression in the template argument.
- if (Res.get() != Arg.getArgument().getAsExpr()) {
+ if (Res.get() != E) {
TemplateArgument TA(Res.get());
Arg = TemplateArgumentLoc(TA, Res.get());
}
- Converted.push_back(Result);
+ SugaredConverted.push_back(SugaredResult);
+ CanonicalConverted.push_back(CanonicalResult);
break;
}
@@ -5513,7 +5620,9 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::NullPtr:
// We've already checked this template argument, so just copy
// it to the list of converted arguments.
- Converted.push_back(Arg.getArgument());
+ SugaredConverted.push_back(Arg.getArgument());
+ CanonicalConverted.push_back(
+ Context.getCanonicalTemplateArgument(Arg.getArgument()));
break;
case TemplateArgument::Template:
@@ -5549,12 +5658,14 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
return true;
}
- TemplateArgument Result;
- E = CheckTemplateArgument(NTTP, NTTPType, E.get(), Result);
+ TemplateArgument SugaredResult, CanonicalResult;
+ E = CheckTemplateArgument(NTTP, NTTPType, E.get(), SugaredResult,
+ CanonicalResult, CTAK_Specified);
if (E.isInvalid())
return true;
- Converted.push_back(Result);
+ SugaredConverted.push_back(SugaredResult);
+ CanonicalConverted.push_back(CanonicalResult);
break;
}
@@ -5611,15 +5722,17 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
{
// Set up a template instantiation context.
LocalInstantiationScope Scope(*this);
- InstantiatingTemplate Inst(*this, TemplateLoc, Template,
- TempParm, Converted,
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template, TempParm,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
- Params = SubstTemplateParams(Params, CurContext,
- MultiLevelTemplateArgumentList(TemplateArgs));
+ Params =
+ SubstTemplateParams(Params, CurContext,
+ MultiLevelTemplateArgumentList(
+ Template, SugaredConverted, /*Final=*/true),
+ /*EvaluateConstraints=*/false);
if (!Params)
return true;
}
@@ -5644,7 +5757,9 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
if (CheckTemplateTemplateArgument(TempParm, Params, Arg))
return true;
- Converted.push_back(Arg.getArgument());
+ SugaredConverted.push_back(Arg.getArgument());
+ CanonicalConverted.push_back(
+ Context.getCanonicalTemplateArgument(Arg.getArgument()));
break;
case TemplateArgument::Expression:
@@ -5711,7 +5826,8 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
bool Sema::CheckTemplateArgumentList(
TemplateDecl *Template, SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
- SmallVectorImpl<TemplateArgument> &Converted,
+ SmallVectorImpl<TemplateArgument> &SugaredConverted,
+ SmallVectorImpl<TemplateArgument> &CanonicalConverted,
bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) {
if (ConstraintsNotSatisfied)
@@ -5737,7 +5853,8 @@ bool Sema::CheckTemplateArgumentList(
// corresponding parameter declared by the template in its
// template-parameter-list.
bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
- SmallVector<TemplateArgument, 2> ArgumentPack;
+ SmallVector<TemplateArgument, 2> SugaredArgumentPack;
+ SmallVector<TemplateArgument, 2> CanonicalArgumentPack;
unsigned ArgIdx = 0, NumArgs = NewArgs.size();
LocalInstantiationScope InstScope(*this, true);
for (TemplateParameterList::iterator Param = Params->begin(),
@@ -5745,13 +5862,17 @@ bool Sema::CheckTemplateArgumentList(
Param != ParamEnd; /* increment in loop */) {
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
- if (Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
- if (*Expansions == ArgumentPack.size()) {
+ if (std::optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
+ if (*Expansions == SugaredArgumentPack.size()) {
// We're done with this parameter pack. Pack up its arguments and add
// them to the list.
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context, ArgumentPack));
- ArgumentPack.clear();
+ SugaredConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
+ SugaredArgumentPack.clear();
+
+ CanonicalConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack));
+ CanonicalArgumentPack.clear();
// This argument is assigned to the next parameter.
++Param;
@@ -5770,9 +5891,10 @@ bool Sema::CheckTemplateArgumentList(
if (ArgIdx < NumArgs) {
// Check the template argument we were given.
- if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template,
- TemplateLoc, RAngleLoc,
- ArgumentPack.size(), Converted))
+ if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
+ RAngleLoc, SugaredArgumentPack.size(),
+ SugaredConverted, CanonicalConverted,
+ CTAK_Specified))
return true;
bool PackExpansionIntoNonPack =
@@ -5801,7 +5923,8 @@ bool Sema::CheckTemplateArgumentList(
// deduced argument and place it on the argument pack. Note that we
// stay on the same template parameter so that we can deduce more
// arguments.
- ArgumentPack.push_back(Converted.pop_back_val());
+ SugaredArgumentPack.push_back(SugaredConverted.pop_back_val());
+ CanonicalArgumentPack.push_back(CanonicalConverted.pop_back_val());
} else {
// Move to the next template parameter.
++Param;
@@ -5811,16 +5934,25 @@ bool Sema::CheckTemplateArgumentList(
// the remaining arguments, because we don't know what parameters they'll
// match up with.
if (PackExpansionIntoNonPack) {
- if (!ArgumentPack.empty()) {
+ if (!SugaredArgumentPack.empty()) {
// If we were part way through filling in an expanded parameter pack,
// fall back to just producing individual arguments.
- Converted.insert(Converted.end(),
- ArgumentPack.begin(), ArgumentPack.end());
- ArgumentPack.clear();
+ SugaredConverted.insert(SugaredConverted.end(),
+ SugaredArgumentPack.begin(),
+ SugaredArgumentPack.end());
+ SugaredArgumentPack.clear();
+
+ CanonicalConverted.insert(CanonicalConverted.end(),
+ CanonicalArgumentPack.begin(),
+ CanonicalArgumentPack.end());
+ CanonicalArgumentPack.clear();
}
while (ArgIdx < NumArgs) {
- Converted.push_back(NewArgs[ArgIdx].getArgument());
+ const TemplateArgument &Arg = NewArgs[ArgIdx].getArgument();
+ SugaredConverted.push_back(Arg);
+ CanonicalConverted.push_back(
+ Context.getCanonicalTemplateArgument(Arg));
++ArgIdx;
}
@@ -5832,9 +5964,12 @@ bool Sema::CheckTemplateArgumentList(
// If we're checking a partial template argument list, we're done.
if (PartialTemplateArgs) {
- if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty())
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context, ArgumentPack));
+ if ((*Param)->isTemplateParameterPack() && !SugaredArgumentPack.empty()) {
+ SugaredConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
+ CanonicalConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack));
+ }
return false;
}
@@ -5847,12 +5982,20 @@ bool Sema::CheckTemplateArgumentList(
// A non-expanded parameter pack before the end of the parameter list
// only occurs for an ill-formed template parameter list, unless we've
// got a partial argument list for a function template, so just bail out.
- if (Param + 1 != ParamEnd)
+ if (Param + 1 != ParamEnd) {
+ assert(
+ (Template->getMostRecentDecl()->getKind() != Decl::Kind::Concept) &&
+ "Concept templates must have parameter packs at the end.");
return true;
+ }
+
+ SugaredConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
+ SugaredArgumentPack.clear();
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context, ArgumentPack));
- ArgumentPack.clear();
+ CanonicalConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack));
+ CanonicalArgumentPack.clear();
++Param;
continue;
@@ -5871,12 +6014,9 @@ bool Sema::CheckTemplateArgumentList(
return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
NewArgs);
- TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this,
- Template,
- TemplateLoc,
- RAngleLoc,
- TTP,
- Converted);
+ TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TTP, SugaredConverted,
+ CanonicalConverted);
if (!ArgType)
return true;
@@ -5888,11 +6028,9 @@ bool Sema::CheckTemplateArgumentList(
return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
NewArgs);
- ExprResult E = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- NTTP,
- Converted);
+ ExprResult E = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, NTTP, SugaredConverted,
+ CanonicalConverted);
if (E.isInvalid())
return true;
@@ -5907,12 +6045,9 @@ bool Sema::CheckTemplateArgumentList(
NewArgs);
NestedNameSpecifierLoc QualifierLoc;
- TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- TempParm,
- Converted,
- QualifierLoc);
+ TemplateName Name = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TempParm, SugaredConverted,
+ CanonicalConverted, QualifierLoc);
if (Name.isNull())
return true;
@@ -5925,14 +6060,16 @@ bool Sema::CheckTemplateArgumentList(
// the default template argument. We're not actually instantiating a
// template here, we just create this object to put a note into the
// context stack.
- InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param, Converted,
+ InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;
// Check the default template argument.
- if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc,
- RAngleLoc, 0, Converted))
+ if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
+ SugaredConverted, CanonicalConverted,
+ CTAK_Specified))
return true;
// Core issue 150 (assumed resolution): if this is a template template
@@ -5952,8 +6089,12 @@ bool Sema::CheckTemplateArgumentList(
// still dependent).
if (ArgIdx < NumArgs && CurrentInstantiationScope &&
CurrentInstantiationScope->getPartiallySubstitutedPack()) {
- while (ArgIdx < NumArgs && NewArgs[ArgIdx].getArgument().isPackExpansion())
- Converted.push_back(NewArgs[ArgIdx++].getArgument());
+ while (ArgIdx < NumArgs &&
+ NewArgs[ArgIdx].getArgument().isPackExpansion()) {
+ const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument();
+ SugaredConverted.push_back(Arg);
+ CanonicalConverted.push_back(Context.getCanonicalTemplateArgument(Arg));
+ }
}
// If we have any leftover arguments, then there were too many arguments.
@@ -5974,13 +6115,39 @@ bool Sema::CheckTemplateArgumentList(
if (UpdateArgsWithConversions)
TemplateArgs = std::move(NewArgs);
- if (!PartialTemplateArgs &&
- EnsureTemplateArgumentListConstraints(
- Template, Converted, SourceRange(TemplateLoc,
- TemplateArgs.getRAngleLoc()))) {
- if (ConstraintsNotSatisfied)
- *ConstraintsNotSatisfied = true;
- return true;
+ if (!PartialTemplateArgs) {
+ TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
+ CanonicalConverted);
+ // Setup the context/ThisScope for the case where we are needing to
+ // re-instantiate constraints outside of normal instantiation.
+ DeclContext *NewContext = Template->getDeclContext();
+
+ // If this template is in a template, make sure we extract the templated
+ // decl.
+ if (auto *TD = dyn_cast<TemplateDecl>(NewContext))
+ NewContext = Decl::castToDeclContext(TD->getTemplatedDecl());
+ auto *RD = dyn_cast<CXXRecordDecl>(NewContext);
+
+ Qualifiers ThisQuals;
+ if (const auto *Method =
+ dyn_cast_or_null<CXXMethodDecl>(Template->getTemplatedDecl()))
+ ThisQuals = Method->getMethodQualifiers();
+
+ ContextRAII Context(*this, NewContext);
+ CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr);
+
+ MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
+ Template, /*Final=*/false, &StackTemplateArgs,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConceptInstantiation=*/true);
+ if (EnsureTemplateArgumentListConstraints(
+ Template, MLTAL,
+ SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
+ if (ConstraintsNotSatisfied)
+ *ConstraintsNotSatisfied = true;
+ return true;
+ }
}
return false;
@@ -6125,7 +6292,7 @@ bool UnnamedLocalNoLinkageFinder::VisitTypeOfExprType(const TypeOfExprType*) {
}
bool UnnamedLocalNoLinkageFinder::VisitTypeOfType(const TypeOfType* T) {
- return Visit(T->getUnderlyingType());
+ return Visit(T->getUnmodifiedType());
}
bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) {
@@ -6274,8 +6441,9 @@ bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) {
assert(ArgInfo && "invalid TypeSourceInfo");
QualType Arg = ArgInfo->getType();
SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
+ QualType CanonArg = Context.getCanonicalType(Arg);
- if (Arg->isVariablyModifiedType()) {
+ if (CanonArg->isVariablyModifiedType()) {
return Diag(SR.getBegin(), diag::err_variably_modified_template_arg) << Arg;
} else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) {
return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR;
@@ -6288,9 +6456,9 @@ bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) {
//
// C++11 allows these, and even in C++03 we allow them as an extension with
// a warning.
- if (LangOpts.CPlusPlus11 || Arg->hasUnnamedOrLocalType()) {
+ if (LangOpts.CPlusPlus11 || CanonArg->hasUnnamedOrLocalType()) {
UnnamedLocalNoLinkageFinder Finder(*this, SR);
- (void)Finder.Visit(Context.getCanonicalType(Arg));
+ (void)Finder.Visit(CanonArg);
}
return false;
@@ -6362,7 +6530,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
// - a constant expression that evaluates to a null pointer value (4.10); or
// - a constant expression that evaluates to a null member pointer value
// (4.11); or
- if ((EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) ||
+ if ((EvalResult.Val.isLValue() && EvalResult.Val.isNullPointer()) ||
(EvalResult.Val.isMemberPointer() &&
!EvalResult.Val.getMemberPointerDecl())) {
// If our expression has an appropriate type, we've succeeded.
@@ -6380,6 +6548,16 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
return NPV_NullPointer;
}
+ if (EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) {
+ // We found a pointer that isn't null, but doesn't refer to an object.
+ // We could just return NPV_NotNullPointer, but we can print a better
+ // message with the information we have here.
+ S.Diag(Arg->getExprLoc(), diag::err_template_arg_invalid)
+ << EvalResult.Val.getAsString(S.Context, ParamType);
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return NPV_Error;
+ }
+
// If we don't have a null pointer value, but we do have a NULL pointer
// constant, suggest a cast to the appropriate type.
if (Arg->isNullPointerConstant(S.Context, Expr::NPC_NeverValueDependent)) {
@@ -6457,12 +6635,9 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter(
/// Checks whether the given template argument is the address
/// of an object or function according to C++ [temp.arg.nontype]p1.
-static bool
-CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
- NonTypeTemplateParmDecl *Param,
- QualType ParamType,
- Expr *ArgIn,
- TemplateArgument &Converted) {
+static bool CheckTemplateArgumentAddressOfObjectOrFunction(
+ Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn,
+ TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) {
bool Invalid = false;
Expr *Arg = ArgIn;
QualType ArgType = Arg->getType();
@@ -6566,8 +6741,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Entity)) {
case NPV_NullPointer:
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
- /*isNullPtr=*/true);
+ SugaredConverted = TemplateArgument(ParamType,
+ /*isNullPtr=*/true);
+ CanonicalConverted =
+ TemplateArgument(S.Context.getCanonicalType(ParamType),
+ /*isNullPtr=*/true);
return false;
case NPV_Error:
@@ -6581,7 +6759,9 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Stop checking the precise nature of the argument if it is value dependent,
// it should be checked when instantiated.
if (Arg->isValueDependent()) {
- Converted = TemplateArgument(ArgIn);
+ SugaredConverted = TemplateArgument(ArgIn);
+ CanonicalConverted =
+ S.Context.getCanonicalTemplateArgument(SugaredConverted);
return false;
}
@@ -6711,19 +6891,21 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
// Create the template argument.
- Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
- S.Context.getCanonicalType(ParamType));
+ SugaredConverted = TemplateArgument(Entity, ParamType);
+ CanonicalConverted =
+ TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
+ S.Context.getCanonicalType(ParamType));
S.MarkAnyDeclReferenced(Arg->getBeginLoc(), Entity, false);
return false;
}
/// Checks whether the given template argument is a pointer to
/// member constant according to C++ [temp.arg.nontype]p1.
-static bool CheckTemplateArgumentPointerToMember(Sema &S,
- NonTypeTemplateParmDecl *Param,
- QualType ParamType,
- Expr *&ResultArg,
- TemplateArgument &Converted) {
+static bool
+CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
+ QualType ParamType, Expr *&ResultArg,
+ TemplateArgument &SugaredConverted,
+ TemplateArgument &CanonicalConverted) {
bool Invalid = false;
Expr *Arg = ResultArg;
@@ -6771,10 +6953,14 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
if (VD->getType()->isMemberPointerType()) {
if (isa<NonTypeTemplateParmDecl>(VD)) {
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ S.Context.getCanonicalTemplateArgument(SugaredConverted);
} else {
- VD = cast<ValueDecl>(VD->getCanonicalDecl());
- Converted = TemplateArgument(VD, ParamType);
+ SugaredConverted = TemplateArgument(VD, ParamType);
+ CanonicalConverted =
+ TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()),
+ S.Context.getCanonicalType(ParamType));
}
return Invalid;
}
@@ -6792,8 +6978,10 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
return true;
case NPV_NullPointer:
S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
- /*isNullPtr*/true);
+ SugaredConverted = TemplateArgument(ParamType,
+ /*isNullPtr*/ true);
+ CanonicalConverted = TemplateArgument(S.Context.getCanonicalType(ParamType),
+ /*isNullPtr*/ true);
return false;
case NPV_NotNullPointer:
break;
@@ -6830,10 +7018,15 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
// Okay: this is the address of a non-static member, and therefore
// a member pointer constant.
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ S.Context.getCanonicalTemplateArgument(SugaredConverted);
} else {
- ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
- Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType));
+ ValueDecl *D = DRE->getDecl();
+ SugaredConverted = TemplateArgument(D, ParamType);
+ CanonicalConverted =
+ TemplateArgument(cast<ValueDecl>(D->getCanonicalDecl()),
+ S.Context.getCanonicalType(ParamType));
}
return Invalid;
}
@@ -6854,7 +7047,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
/// type of the non-type template parameter after it has been instantiated.
ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType ParamType, Expr *Arg,
- TemplateArgument &Converted,
+ TemplateArgument &SugaredConverted,
+ TemplateArgument &CanonicalConverted,
CheckTemplateArgumentKind CTAK) {
SourceLocation StartLoc = Arg->getBeginLoc();
@@ -6869,7 +7063,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CTAK == CTAK_Deduced && Arg->isTypeDependent()) {
auto *AT = dyn_cast<AutoType>(DeducedT);
if (AT && AT->isDecltypeAuto()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted = TemplateArgument(
+ Context.getCanonicalTemplateArgument(SugaredConverted));
return Arg;
}
}
@@ -6877,7 +7073,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// When checking a deduced template argument, deduce from its type even if
// the type is dependent, in order to check the types of non-type template
// arguments line up properly in partial ordering.
- Optional<unsigned> Depth = Param->getDepth() + 1;
Expr *DeductionArg = Arg;
if (auto *PE = dyn_cast<PackExpansionExpr>(DeductionArg))
DeductionArg = PE->getPattern();
@@ -6893,20 +7088,30 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, Inits);
if (ParamType.isNull())
return ExprError();
- } else if (DeduceAutoType(
- TSI, DeductionArg, ParamType, Depth,
- // We do not check constraints right now because the
- // immediately-declared constraint of the auto type is also
- // an associated constraint, and will be checked along with
- // the other associated constraints after checking the
- // template argument list.
- /*IgnoreConstraints=*/true) == DAR_Failed) {
- Diag(Arg->getExprLoc(),
- diag::err_non_type_template_parm_type_deduction_failure)
- << Param->getDeclName() << Param->getType() << Arg->getType()
- << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return ExprError();
+ } else {
+ TemplateDeductionInfo Info(DeductionArg->getExprLoc(),
+ Param->getDepth() + 1);
+ ParamType = QualType();
+ TemplateDeductionResult Result =
+ DeduceAutoType(TSI->getTypeLoc(), DeductionArg, ParamType, Info,
+ /*DependentDeduction=*/true,
+ // We do not check constraints right now because the
+ // immediately-declared constraint of the auto type is
+ // also an associated constraint, and will be checked
+ // along with the other associated constraints after
+ // checking the template argument list.
+ /*IgnoreConstraints=*/true);
+ if (Result == TDK_AlreadyDiagnosed) {
+ if (ParamType.isNull())
+ return ExprError();
+ } else if (Result != TDK_Success) {
+ Diag(Arg->getExprLoc(),
+ diag::err_non_type_template_parm_type_deduction_failure)
+ << Param->getDeclName() << Param->getType() << Arg->getType()
+ << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return ExprError();
+ }
}
// CheckNonTypeTemplateParameterType will produce a diagnostic if there's
// an error. The error message normally references the parameter
@@ -6938,7 +7143,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// work. Similarly for CTAD, when comparing 'A<x>' against 'A'.
if ((ParamType->isDependentType() || Arg->isTypeDependent()) &&
!Arg->getType()->getContainedDeducedType()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted = TemplateArgument(
+ Context.getCanonicalTemplateArgument(SugaredConverted));
return Arg;
}
// FIXME: This attempts to implement C++ [temp.deduct.type]p17. Per DR1770,
@@ -6953,11 +7160,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
// If either the parameter has a dependent type or the argument is
- // type-dependent, there's nothing we can check now. The argument only
- // contains an unexpanded pack during partial ordering, and there's
- // nothing more we can check in that case.
- if (ParamType->isDependentType() || Arg->isTypeDependent() ||
- Arg->containsUnexpandedParameterPack()) {
+ // type-dependent, there's nothing we can check now.
+ if (ParamType->isDependentType() || Arg->isTypeDependent()) {
// Force the argument to the type of the parameter to maintain invariants.
auto *PE = dyn_cast<PackExpansionExpr>(Arg);
if (PE)
@@ -6975,7 +7179,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(),
PE->getNumExpansions());
}
- Converted = TemplateArgument(E.get());
+ SugaredConverted = TemplateArgument(E.get());
+ CanonicalConverted = TemplateArgument(
+ Context.getCanonicalTemplateArgument(SugaredConverted));
return E;
}
@@ -7000,11 +7206,16 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Context.hasSameUnqualifiedType(ParamType, InnerArg->getType())) {
NamedDecl *ND = cast<DeclRefExpr>(InnerArg)->getDecl();
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
- Converted = TemplateArgument(TPO, CanonParamType);
+
+ SugaredConverted = TemplateArgument(TPO, ParamType);
+ CanonicalConverted =
+ TemplateArgument(TPO->getCanonicalDecl(), CanonParamType);
return Arg;
}
if (isa<NonTypeTemplateParmDecl>(ND)) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg;
}
}
@@ -7021,7 +7232,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// For a value-dependent argument, CheckConvertedConstantExpression is
// permitted (and expected) to be unable to determine a value.
if (ArgResult.get()->isValueDependent()) {
- Converted = TemplateArgument(ArgResult.get());
+ SugaredConverted = TemplateArgument(ArgResult.get());
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return ArgResult;
}
@@ -7029,14 +7242,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
switch (Value.getKind()) {
case APValue::None:
assert(ParamType->isNullPtrType());
- Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true);
+ SugaredConverted = TemplateArgument(ParamType, /*isNullPtr=*/true);
+ CanonicalConverted = TemplateArgument(CanonParamType, /*isNullPtr=*/true);
break;
case APValue::Indeterminate:
llvm_unreachable("result of constant evaluation should be initialized");
break;
case APValue::Int:
assert(ParamType->isIntegralOrEnumerationType());
- Converted = TemplateArgument(Context, Value.getInt(), CanonParamType);
+ SugaredConverted = TemplateArgument(Context, Value.getInt(), ParamType);
+ CanonicalConverted =
+ TemplateArgument(Context, Value.getInt(), CanonParamType);
break;
case APValue::MemberPointer: {
assert(ParamType->isMemberPointerType());
@@ -7051,8 +7267,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
auto *VD = const_cast<ValueDecl*>(Value.getMemberPointerDecl());
- Converted = VD ? TemplateArgument(VD, CanonParamType)
- : TemplateArgument(CanonParamType, /*isNullPtr*/true);
+ SugaredConverted = VD ? TemplateArgument(VD, ParamType)
+ : TemplateArgument(ParamType, /*isNullPtr=*/true);
+ CanonicalConverted =
+ VD ? TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()),
+ CanonParamType)
+ : TemplateArgument(CanonParamType, /*isNullPtr=*/true);
break;
}
case APValue::LValue: {
@@ -7092,17 +7312,25 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
"null reference should not be a constant expression");
assert((!VD || !ParamType->isNullPtrType()) &&
"non-null value of type nullptr_t?");
- Converted = VD ? TemplateArgument(VD, CanonParamType)
- : TemplateArgument(CanonParamType, /*isNullPtr*/true);
+
+ SugaredConverted = VD ? TemplateArgument(VD, ParamType)
+ : TemplateArgument(ParamType, /*isNullPtr=*/true);
+ CanonicalConverted =
+ VD ? TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()),
+ CanonParamType)
+ : TemplateArgument(CanonParamType, /*isNullPtr=*/true);
break;
}
case APValue::Struct:
- case APValue::Union:
+ case APValue::Union: {
// Get or create the corresponding template parameter object.
- Converted = TemplateArgument(
- Context.getTemplateParamObjectDecl(CanonParamType, Value),
- CanonParamType);
+ TemplateParamObjectDecl *D =
+ Context.getTemplateParamObjectDecl(ParamType, Value);
+ SugaredConverted = TemplateArgument(D, ParamType);
+ CanonicalConverted =
+ TemplateArgument(D->getCanonicalDecl(), CanonParamType);
break;
+ }
case APValue::AddrLabelDiff:
return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff);
case APValue::FixedPoint:
@@ -7152,7 +7380,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// We can't check arbitrary value-dependent arguments.
if (ArgResult.get()->isValueDependent()) {
- Converted = TemplateArgument(ArgResult.get());
+ SugaredConverted = TemplateArgument(ArgResult.get());
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return ArgResult;
}
@@ -7166,8 +7396,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
? Context.getIntWidth(IntegerType)
: Context.getTypeSize(IntegerType));
- Converted = TemplateArgument(Context, Value,
- Context.getCanonicalType(ParamType));
+ SugaredConverted = TemplateArgument(Context, Value, ParamType);
+ CanonicalConverted =
+ TemplateArgument(Context, Value, Context.getCanonicalType(ParamType));
return ArgResult;
}
@@ -7237,13 +7468,16 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (Arg->isValueDependent()) {
// The argument is value-dependent. Create a new
// TemplateArgument with the converted expression.
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg;
}
- QualType IntegerType = Context.getCanonicalType(ParamType);
- if (const EnumType *Enum = IntegerType->getAs<EnumType>())
- IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType());
+ QualType IntegerType = ParamType;
+ if (const EnumType *Enum = IntegerType->getAs<EnumType>()) {
+ IntegerType = Enum->getDecl()->getIntegerType();
+ }
if (ParamType->isBooleanType()) {
// Value must be zero or one.
@@ -7289,10 +7523,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
}
- Converted = TemplateArgument(Context, Value,
- ParamType->isEnumeralType()
- ? Context.getCanonicalType(ParamType)
- : IntegerType);
+ QualType T = ParamType->isEnumeralType() ? ParamType : IntegerType;
+ SugaredConverted = TemplateArgument(Context, Value, T);
+ CanonicalConverted =
+ TemplateArgument(Context, Value, Context.getCanonicalType(T));
return Arg;
}
@@ -7337,15 +7571,15 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
if (!ParamType->isMemberPointerType()) {
- if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted))
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(
+ *this, Param, ParamType, Arg, SugaredConverted,
+ CanonicalConverted))
return ExprError();
return Arg;
}
- if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg,
- Converted))
+ if (CheckTemplateArgumentPointerToMember(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7358,9 +7592,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamType->getPointeeType()->isIncompleteOrObjectType() &&
"Only object pointers allowed here");
- if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted))
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7389,9 +7622,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
}
- if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted))
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7399,7 +7631,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Deal with parameters of type std::nullptr_t.
if (ParamType->isNullPtrType()) {
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg;
}
@@ -7415,8 +7649,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
case NPV_NullPointer:
Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(Context.getCanonicalType(ParamType),
- /*isNullPtr*/true);
+ SugaredConverted = TemplateArgument(ParamType,
+ /*isNullPtr=*/true);
+ CanonicalConverted = TemplateArgument(Context.getCanonicalType(ParamType),
+ /*isNullPtr=*/true);
return Arg;
}
}
@@ -7425,8 +7661,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// member, qualification conversions (4.4) are applied.
assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
- if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg,
- Converted))
+ if (CheckTemplateArgumentPointerToMember(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7499,10 +7735,10 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template,
Arg.getLocation())) {
- // C++2a[temp.func.order]p2
+ // P2113
+ // C++20[temp.func.order]p2
// [...] If both deductions succeed, the partial ordering selects the
- // more constrained template as described by the rules in
- // [temp.constr.order].
+ // more constrained template (if one exists) as determined below.
SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
Params->getAssociatedConstraints(ParamsAC);
// C++2a[temp.arg.template]p3
@@ -7510,7 +7746,9 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
// are not considered.
if (ParamsAC.empty())
return false;
+
Template->getAssociatedConstraints(TemplateAC);
+
bool IsParamAtLeastAsConstrained;
if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
IsParamAtLeastAsConstrained))
@@ -7685,8 +7923,8 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
E = new (Context) CharacterLiteral(Arg.getAsIntegral().getZExtValue(),
Kind, T, Loc);
} else if (T->isBooleanType()) {
- E = new (Context) CXXBoolLiteralExpr(Arg.getAsIntegral().getBoolValue(),
- T, Loc);
+ E = CXXBoolLiteralExpr::Create(Context, Arg.getAsIntegral().getBoolValue(),
+ T, Loc);
} else if (T->isNullPtrType()) {
E = new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc);
} else {
@@ -7706,10 +7944,11 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
}
/// Match two template parameters within template parameter lists.
-static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
- bool Complain,
- Sema::TemplateParameterListEqualKind Kind,
- SourceLocation TemplateArgLoc) {
+static bool MatchTemplateParameterKind(
+ Sema &S, NamedDecl *New, const NamedDecl *NewInstFrom, NamedDecl *Old,
+ const NamedDecl *OldInstFrom, bool Complain,
+ Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc,
+ bool PartialOrdering) {
// Check the actual kind (type, non-type, template).
if (Old->getKind() != New->getKind()) {
if (Complain) {
@@ -7791,20 +8030,34 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
else if (TemplateTemplateParmDecl *OldTTP
= dyn_cast<TemplateTemplateParmDecl>(Old)) {
TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
- if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
- OldTTP->getTemplateParameters(),
- Complain,
- (Kind == Sema::TPL_TemplateMatch
- ? Sema::TPL_TemplateTemplateParmMatch
- : Kind),
- TemplateArgLoc))
+ if (!S.TemplateParameterListsAreEqual(
+ NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
+ OldTTP->getTemplateParameters(), Complain,
+ (Kind == Sema::TPL_TemplateMatch
+ ? Sema::TPL_TemplateTemplateParmMatch
+ : Kind),
+ TemplateArgLoc, PartialOrdering))
return false;
- } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) {
+ }
+
+ if (!PartialOrdering && Kind != Sema::TPL_TemplateTemplateArgumentMatch &&
+ !isa<TemplateTemplateParmDecl>(Old)) {
const Expr *NewC = nullptr, *OldC = nullptr;
- if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint())
- NewC = TC->getImmediatelyDeclaredConstraint();
- if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint())
- OldC = TC->getImmediatelyDeclaredConstraint();
+
+ if (isa<TemplateTypeParmDecl>(New)) {
+ if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint())
+ NewC = TC->getImmediatelyDeclaredConstraint();
+ if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint())
+ OldC = TC->getImmediatelyDeclaredConstraint();
+ } else if (isa<NonTypeTemplateParmDecl>(New)) {
+ if (const Expr *E = cast<NonTypeTemplateParmDecl>(New)
+ ->getPlaceholderTypeConstraint())
+ NewC = E;
+ if (const Expr *E = cast<NonTypeTemplateParmDecl>(Old)
+ ->getPlaceholderTypeConstraint())
+ OldC = E;
+ } else
+ llvm_unreachable("unexpected template parameter type");
auto Diagnose = [&] {
S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(),
@@ -7820,10 +8073,8 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
}
if (NewC) {
- llvm::FoldingSetNodeID OldCID, NewCID;
- OldC->Profile(OldCID, S.Context, /*Canonical=*/true);
- NewC->Profile(NewCID, S.Context, /*Canonical=*/true);
- if (OldCID != NewCID) {
+ if (!S.AreConstraintExpressionsEqual(OldInstFrom, OldC, NewInstFrom,
+ NewC)) {
if (Complain)
Diagnose();
return false;
@@ -7879,12 +8130,11 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
///
/// \returns True if the template parameter lists are equal, false
/// otherwise.
-bool
-Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
- TemplateParameterList *Old,
- bool Complain,
- TemplateParameterListEqualKind Kind,
- SourceLocation TemplateArgLoc) {
+bool Sema::TemplateParameterListsAreEqual(
+ const NamedDecl *NewInstFrom, TemplateParameterList *New,
+ const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+ TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc,
+ bool PartialOrdering) {
if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) {
if (Complain)
DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
@@ -7914,8 +8164,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
return false;
}
- if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
- Kind, TemplateArgLoc))
+ if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
+ OldInstFrom, Complain, Kind,
+ TemplateArgLoc, PartialOrdering))
return false;
++NewParm;
@@ -7930,8 +8181,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
// template parameter pack in P (ignoring whether those template
// parameters are template parameter packs).
for (; NewParm != NewParmEnd; ++NewParm) {
- if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
- Kind, TemplateArgLoc))
+ if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
+ OldInstFrom, Complain, Kind,
+ TemplateArgLoc, PartialOrdering))
return false;
}
}
@@ -7945,7 +8197,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
return false;
}
- if (Kind != TPL_TemplateTemplateArgumentMatch) {
+ if (!PartialOrdering && Kind != TPL_TemplateTemplateArgumentMatch) {
const Expr *NewRC = New->getRequiresClause();
const Expr *OldRC = Old->getRequiresClause();
@@ -7963,10 +8215,8 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
}
if (NewRC) {
- llvm::FoldingSetNodeID OldRCID, NewRCID;
- OldRC->Profile(OldRCID, Context, /*Canonical=*/true);
- NewRC->Profile(NewRCID, Context, /*Canonical=*/true);
- if (OldRCID != NewRCID) {
+ if (!AreConstraintExpressionsEqual(OldInstFrom, OldRC, NewInstFrom,
+ NewRC)) {
if (Complain)
Diagnose();
return false;
@@ -8413,9 +8663,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
+ false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
@@ -8423,14 +8673,15 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// corresponds to these arguments.
if (isPartialSpecialization) {
if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, ClassTemplate,
- TemplateArgs.size(), Converted))
+ TemplateArgs.size(),
+ CanonicalConverted))
return true;
// FIXME: Move this to CheckTemplatePartialSpecializationArgs so we
// also do it during instantiation.
if (!Name.isDependent() &&
- !TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
- Converted)) {
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, CanonicalConverted)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< ClassTemplate->getDeclName();
isPartialSpecialization = false;
@@ -8441,11 +8692,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplateSpecializationDecl *PrevDecl = nullptr;
if (isPartialSpecialization)
- PrevDecl = ClassTemplate->findPartialSpecialization(Converted,
- TemplateParams,
- InsertPos);
+ PrevDecl = ClassTemplate->findPartialSpecialization(
+ CanonicalConverted, TemplateParams, InsertPos);
else
- PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos);
+ PrevDecl = ClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
ClassTemplateSpecializationDecl *Specialization = nullptr;
@@ -8464,7 +8714,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// arguments of the class template partial specialization.
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
CanonType = Context.getTemplateSpecializationType(CanonTemplate,
- Converted);
+ CanonicalConverted);
if (Context.hasSameType(CanonType,
ClassTemplate->getInjectedClassNameSpecialization()) &&
@@ -8494,16 +8744,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// Create a new class template partial specialization declaration node.
ClassTemplatePartialSpecializationDecl *PrevPartial
= cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
- ClassTemplatePartialSpecializationDecl *Partial
- = ClassTemplatePartialSpecializationDecl::Create(Context, Kind,
- ClassTemplate->getDeclContext(),
- KWLoc, TemplateNameLoc,
- TemplateParams,
- ClassTemplate,
- Converted,
- TemplateArgs,
- CanonType,
- PrevPartial);
+ ClassTemplatePartialSpecializationDecl *Partial =
+ ClassTemplatePartialSpecializationDecl::Create(
+ Context, Kind, ClassTemplate->getDeclContext(), KWLoc,
+ TemplateNameLoc, TemplateParams, ClassTemplate, CanonicalConverted,
+ TemplateArgs, CanonType, PrevPartial);
SetNestedNameSpecifier(*this, Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Partial->setTemplateParameterListsInfo(
@@ -8523,13 +8768,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
} else {
// Create a new class template specialization declaration node for
// this explicit specialization or friend declaration.
- Specialization
- = ClassTemplateSpecializationDecl::Create(Context, Kind,
- ClassTemplate->getDeclContext(),
- KWLoc, TemplateNameLoc,
- ClassTemplate,
- Converted,
- PrevDecl);
+ Specialization = ClassTemplateSpecializationDecl::Create(
+ Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
+ ClassTemplate, CanonicalConverted, PrevDecl);
SetNestedNameSpecifier(*this, Specialization, SS);
if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
@@ -8541,8 +8782,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
if (CurContext->isDependentContext()) {
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
- CanonType = Context.getTemplateSpecializationType(
- CanonTemplate, Converted);
+ CanonType = Context.getTemplateSpecializationType(CanonTemplate,
+ CanonicalConverted);
} else {
CanonType = Context.getTypeDeclType(Specialization);
}
@@ -8686,17 +8927,33 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
return nullptr;
}
- if (TemplateParameterLists.front()->size() == 0) {
+ TemplateParameterList *Params = TemplateParameterLists.front();
+
+ if (Params->size() == 0) {
Diag(NameLoc, diag::err_concept_no_parameters);
return nullptr;
}
+ // Ensure that the parameter pack, if present, is the last parameter in the
+ // template.
+ for (TemplateParameterList::const_iterator ParamIt = Params->begin(),
+ ParamEnd = Params->end();
+ ParamIt != ParamEnd; ++ParamIt) {
+ Decl const *Param = *ParamIt;
+ if (Param->isParameterPack()) {
+ if (++ParamIt == ParamEnd)
+ break;
+ Diag(Param->getLocation(),
+ diag::err_template_param_pack_must_be_last_template_parameter);
+ return nullptr;
+ }
+ }
+
if (DiagnoseUnexpandedParameterPack(ConstraintExpr))
return nullptr;
- ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
- TemplateParameterLists.front(),
- ConstraintExpr);
+ ConceptDecl *NewDecl =
+ ConceptDecl::Create(Context, DC, NameLoc, Name, Params, ConstraintExpr);
if (NewDecl->hasAssociatedConstraints()) {
// C++2a [temp.concept]p4:
@@ -8728,7 +8985,7 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
if (Previous.empty())
return;
- auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl());
+ auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl()->getUnderlyingDecl());
if (!OldConcept) {
auto *Old = Previous.getRepresentativeDecl();
Diag(NewDecl->getLocation(), diag::err_redefinition_different_kind)
@@ -8746,7 +9003,8 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
AddToScope = false;
return;
}
- if (hasReachableDefinition(OldConcept)) {
+ if (hasReachableDefinition(OldConcept) &&
+ IsRedefinitionInModule(NewDecl, OldConcept)) {
Diag(NewDecl->getLocation(), diag::err_redefinition)
<< NewDecl->getDeclName();
notePreviousDefinition(OldConcept, NewDecl->getLocation());
@@ -8758,14 +9016,18 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
// Other decls (e.g. namespaces) also have this shortcoming.
return;
}
- Context.setPrimaryMergedDecl(NewDecl, OldConcept);
+ // We unwrap canonical decl late to check for module visibility.
+ Context.setPrimaryMergedDecl(NewDecl, OldConcept->getCanonicalDecl());
}
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
-static void StripImplicitInstantiation(NamedDecl *D) {
- D->dropAttr<DLLImportAttr>();
- D->dropAttr<DLLExportAttr>();
+static void StripImplicitInstantiation(NamedDecl *D, bool MinGW) {
+ if (MinGW || (isa<FunctionDecl>(D) &&
+ cast<FunctionDecl>(D)->isFunctionTemplateSpecialization())) {
+ D->dropAttr<DLLImportAttr>();
+ D->dropAttr<DLLExportAttr>();
+ }
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
FD->setInlineSpecified(false);
@@ -8840,11 +9102,13 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
if (PrevPointOfInstantiation.isInvalid()) {
// The declaration itself has not actually been instantiated, so it is
// still okay to specialize it.
- StripImplicitInstantiation(PrevDecl);
+ StripImplicitInstantiation(
+ PrevDecl,
+ Context.getTargetInfo().getTriple().isWindowsGNUEnvironment());
return false;
}
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
@@ -9701,17 +9965,17 @@ DeclResult Sema::ActOnExplicitInstantiation(
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
+ false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
// Find the class template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *PrevDecl
- = ClassTemplate->findSpecialization(Converted, InsertPos);
+ ClassTemplateSpecializationDecl *PrevDecl =
+ ClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
TemplateSpecializationKind PrevDecl_TSK
= PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared;
@@ -9768,13 +10032,9 @@ DeclResult Sema::ActOnExplicitInstantiation(
if (!Specialization) {
// Create a new class template specialization declaration node for
// this explicit specialization.
- Specialization
- = ClassTemplateSpecializationDecl::Create(Context, Kind,
- ClassTemplate->getDeclContext(),
- KWLoc, TemplateNameLoc,
- ClassTemplate,
- Converted,
- PrevDecl);
+ Specialization = ClassTemplateSpecializationDecl::Create(
+ Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
+ ClassTemplate, CanonicalConverted, PrevDecl);
SetNestedNameSpecifier(*this, Specialization, SS);
if (!HasNoEffect && !PrevDecl) {
@@ -9921,13 +10181,14 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc,
bool Owned = false;
bool IsDependent = false;
- Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference,
- KWLoc, SS, Name, NameLoc, Attr, AS_none,
- /*ModulePrivateLoc=*/SourceLocation(),
- MultiTemplateParamsArg(), Owned, IsDependent,
- SourceLocation(), false, TypeResult(),
- /*IsTypeSpecifier*/false,
- /*IsTemplateParamOrArg*/false);
+ UsingShadowDecl* FoundUsing = nullptr;
+ Decl *TagD =
+ ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr,
+ AS_none, /*ModulePrivateLoc=*/SourceLocation(),
+ MultiTemplateParamsArg(), Owned, IsDependent, SourceLocation(),
+ false, TypeResult(), /*IsTypeSpecifier*/ false,
+ /*IsTemplateParamOrArg*/ false, /*OOK=*/OOK_Outside, FoundUsing)
+ .get();
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
if (!TagD)
@@ -10469,10 +10730,11 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
}
-TypeResult
-Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
- const CXXScopeSpec &SS, const IdentifierInfo &II,
- SourceLocation IdLoc) {
+TypeResult Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
+ const CXXScopeSpec &SS,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ ImplicitTypenameContext IsImplicitTypename) {
if (SS.isInvalid())
return true;
@@ -10485,9 +10747,13 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
TypeSourceInfo *TSI = nullptr;
- QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None,
- TypenameLoc, QualifierLoc, II, IdLoc, &TSI,
- /*DeducedTSTContext=*/true);
+ QualType T =
+ CheckTypenameType((TypenameLoc.isValid() ||
+ IsImplicitTypename == ImplicitTypenameContext::Yes)
+ ? ETK_Typename
+ : ETK_None,
+ TypenameLoc, QualifierLoc, II, IdLoc, &TSI,
+ /*DeducedTSTContext=*/true);
if (T.isNull())
return true;
return CreateParsedType(T, TSI);
@@ -10533,10 +10799,9 @@ Sema::ActOnTypenameType(Scope *S,
// Construct a dependent template specialization type.
assert(DTN && "dependent template has non-dependent name?");
assert(DTN->getQualifier() == SS.getScopeRep());
- QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ QualType T = Context.getDependentTemplateSpecializationType(
+ ETK_Typename, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Create source-location information for this type.
TypeLocBuilder Builder;
@@ -10745,7 +11010,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
}
// Fall through to create a dependent typename type, from which we can recover
// better.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.