aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/Sema.cpp4
-rw-r--r--clang/lib/Sema/SemaAMDGPU.cpp3
-rw-r--r--clang/lib/Sema/SemaChecking.cpp3
-rw-r--r--clang/lib/Sema/SemaDecl.cpp22
-rw-r--r--clang/lib/Sema/SemaExpr.cpp5
-rw-r--r--clang/lib/Sema/SemaInit.cpp2
-rw-r--r--clang/lib/Sema/SemaOpenACC.cpp78
-rw-r--r--clang/lib/Sema/SemaOpenACCClause.cpp12
-rw-r--r--clang/lib/Sema/SemaRISCV.cpp12
-rw-r--r--clang/lib/Sema/SemaStmt.cpp6
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp391
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp210
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp32
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp6
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp10
-rw-r--r--clang/lib/Sema/SemaType.cpp10
-rw-r--r--clang/lib/Sema/TreeTransform.h85
17 files changed, 654 insertions, 237 deletions
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 924becf..cfb2f60 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -443,9 +443,7 @@ void Sema::Initialize() {
if (getLangOpts().MSVCCompat) {
if (getLangOpts().CPlusPlus &&
IdResolver.begin(&Context.Idents.get("type_info")) == IdResolver.end())
- PushOnScopeChains(
- Context.buildImplicitRecord("type_info", TagTypeKind::Class),
- TUScope);
+ PushOnScopeChains(Context.getMSTypeInfoTagDecl(), TUScope);
addImplicitTypedef("size_t", Context.getSizeType());
}
diff --git a/clang/lib/Sema/SemaAMDGPU.cpp b/clang/lib/Sema/SemaAMDGPU.cpp
index a5fbd70..1913bb8 100644
--- a/clang/lib/Sema/SemaAMDGPU.cpp
+++ b/clang/lib/Sema/SemaAMDGPU.cpp
@@ -82,7 +82,7 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
return checkMovDPPFunctionCall(TheCall, 5, 1);
case AMDGPU::BI__builtin_amdgcn_mov_dpp8:
return checkMovDPPFunctionCall(TheCall, 2, 1);
- case AMDGPU::BI__builtin_amdgcn_update_dpp: {
+ case AMDGPU::BI__builtin_amdgcn_update_dpp:
return checkMovDPPFunctionCall(TheCall, 6, 2);
case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f16_fp8:
case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_bf16_fp8:
@@ -100,7 +100,6 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f32_fp6:
case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f32_bf6:
return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7);
- }
default:
return false;
}
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index bc87611..3c4511b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -35,6 +35,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
+#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/UnresolvedSet.h"
@@ -3716,7 +3717,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
}
void Sema::CheckConstrainedAuto(const AutoType *AutoT, SourceLocation Loc) {
- if (ConceptDecl *Decl = AutoT->getTypeConstraintConcept()) {
+ if (TemplateDecl *Decl = AutoT->getTypeConstraintConcept()) {
DiagnoseUseOfDecl(Decl, Loc);
}
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 3eaf2eb..b5eb825 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -3269,11 +3269,10 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
continue;
if (isa<InferredNoReturnAttr>(I)) {
- if (auto *FD = dyn_cast<FunctionDecl>(New)) {
- if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
- continue; // Don't propagate inferred noreturn attributes to explicit
- // specializations.
- }
+ if (auto *FD = dyn_cast<FunctionDecl>(New);
+ FD &&
+ FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ continue; // Don't propagate inferred noreturn attributes to explicit
}
if (mergeDeclAttribute(*this, New, I, LocalAMK))
@@ -8113,9 +8112,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
- NewVD->addAttr(AsmLabelAttr::Create(Context, Label,
- /*IsLiteralLabel=*/true,
- SE->getStrTokenLoc(0)));
+ NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0)));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
@@ -10345,9 +10342,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (Expr *E = D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewFD->addAttr(AsmLabelAttr::Create(Context, SE->getString(),
- /*IsLiteralLabel=*/true,
- SE->getStrTokenLoc(0)));
+ NewFD->addAttr(
+ AsmLabelAttr::Create(Context, SE->getString(), SE->getStrTokenLoc(0)));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier());
@@ -20598,8 +20594,8 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
LookupOrdinaryName);
AttributeCommonInfo Info(AliasName, SourceRange(AliasNameLoc),
AttributeCommonInfo::Form::Pragma());
- AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit(
- Context, AliasName->getName(), /*IsLiteralLabel=*/true, Info);
+ AsmLabelAttr *Attr =
+ AsmLabelAttr::CreateImplicit(Context, AliasName->getName(), Info);
// If a declaration that:
// 1) declares a function or a variable
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e4c2543..6793d6d 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2903,8 +2903,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// in BuildTemplateIdExpr().
// The single lookup result must be a variable template declaration.
if (Id.getKind() == UnqualifiedIdKind::IK_TemplateId && Id.TemplateId &&
- Id.TemplateId->Kind == TNK_Var_template) {
- assert(R.getAsSingle<VarTemplateDecl>() &&
+ (Id.TemplateId->Kind == TNK_Var_template ||
+ Id.TemplateId->Kind == TNK_Concept_template)) {
+ assert(R.getAsSingle<TemplateDecl>() &&
"There should only be one declaration found.");
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 7b9c638..1dd38c0 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -3713,7 +3713,7 @@ ValueDecl *InitializedEntity::getDecl() const {
case EK_ParenAggInitMember:
case EK_Binding:
case EK_TemplateParameter:
- return Variable.VariableOrMember;
+ return cast<ValueDecl>(Variable.VariableOrMember);
case EK_Parameter:
case EK_Parameter_CF_Audited:
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 8bfea62..8212646 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -17,6 +17,7 @@
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/OpenACCKinds.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Sema.h"
#include "llvm/ADT/StringExtras.h"
@@ -641,21 +642,13 @@ ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind CK, Expr *VarExpr,
if (!InnerExpr || InnerExpr->isTypeDependent())
return VarExpr;
- const auto *RD = InnerExpr->getType()->getAsCXXRecordDecl();
+ auto *RD = InnerExpr->getType()->getAsCXXRecordDecl();
// if this isn't a C++ record decl, we can create/copy/destroy this thing at
// will without problem, so this is a success.
if (!RD)
return VarExpr;
- // TODO: OpenACC:
- // Private must have default ctor + dtor in InnerExpr
- // FirstPrivate must have copyctor + dtor in InnerExpr
- // Reduction must have copyctor + dtor + operation in InnerExpr
-
- // TODO OpenACC: It isn't clear what the requirements are for default
- // constructor/copy constructor are for First private and reduction, but
- // private requires a default constructor.
if (CK == OpenACCClauseKind::Private) {
bool HasNonDeletedDefaultCtor =
llvm::find_if(RD->ctors(), [](const CXXConstructorDecl *CD) {
@@ -668,6 +661,26 @@ ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind CK, Expr *VarExpr,
<< clang::diag::AccVarReferencedReason::DefCtor;
return ExprError();
}
+ } else if (CK == OpenACCClauseKind::FirstPrivate) {
+ if (!RD->hasSimpleCopyConstructor()) {
+ Sema::SpecialMemberOverloadResult SMOR = S.SemaRef.LookupSpecialMember(
+ RD, CXXSpecialMemberKind::CopyConstructor, /*ConstArg=*/true,
+ /*VolatileArg=*/false, /*RValueThis=*/false, /*ConstThis=*/false,
+ /*VolatileThis=*/false);
+
+ if (SMOR.getKind() != Sema::SpecialMemberOverloadResult::Success ||
+ SMOR.getMethod()->isDeleted()) {
+ S.Diag(InnerExpr->getBeginLoc(),
+ clang::diag::warn_acc_var_referenced_lacks_op)
+ << InnerExpr->getType() << CK
+ << clang::diag::AccVarReferencedReason::CopyCtor;
+ return ExprError();
+ }
+ }
+ } else if (CK == OpenACCClauseKind::Reduction) {
+ // TODO: OpenACC:
+ // Reduction must have copyctor + dtor + operation in InnerExpr I think?
+ // Need to confirm when implementing this part.
}
// All 3 things need to make sure they have a dtor.
@@ -2552,3 +2565,50 @@ ExprResult
SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) {
return BuildOpenACCAsteriskSizeExpr(AsteriskLoc);
}
+
+VarDecl *SemaOpenACC::CreateInitRecipe(const Expr *VarExpr) {
+ // Strip off any array subscripts/array section exprs to get to the type of
+ // the variable.
+ while (isa_and_present<ArraySectionExpr, ArraySubscriptExpr>(VarExpr)) {
+ if (const auto *AS = dyn_cast<ArraySectionExpr>(VarExpr))
+ VarExpr = AS->getBase()->IgnoreParenImpCasts();
+ else if (const auto *Sub = dyn_cast<ArraySubscriptExpr>(VarExpr))
+ VarExpr = Sub->getBase()->IgnoreParenImpCasts();
+ }
+
+ // If for some reason the expression is invalid, or this is dependent, just
+ // fill in with nullptr. We'll count on TreeTransform to make this if
+ // necessary.
+ if (!VarExpr || VarExpr->getType()->isDependentType())
+ return nullptr;
+
+ QualType VarTy =
+ VarExpr->getType().getNonReferenceType().getUnqualifiedType();
+
+ VarDecl *Recipe = VarDecl::Create(
+ getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(),
+ VarExpr->getBeginLoc(),
+ &getASTContext().Idents.get("openacc.private.init"), VarTy,
+ getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto);
+
+ ExprResult Init;
+
+ {
+ // Trap errors so we don't get weird ones here. If we can't init, we'll just
+ // swallow the errors.
+ Sema::TentativeAnalysisScope Trap{SemaRef};
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(Recipe);
+ InitializationKind Kind =
+ InitializationKind::CreateDefault(Recipe->getLocation());
+
+ InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {});
+ Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {});
+ }
+
+ if (Init.get()) {
+ Recipe->setInit(Init.get());
+ Recipe->setInitStyle(VarDecl::CallInit);
+ }
+
+ return Recipe;
+}
diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp
index b54a012..9f1a617 100644
--- a/clang/lib/Sema/SemaOpenACCClause.cpp
+++ b/clang/lib/Sema/SemaOpenACCClause.cpp
@@ -795,9 +795,15 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitPrivateClause(
// really isn't anything to do here. GCC does some duplicate-finding, though
// it isn't apparent in the standard where this is justified.
- return OpenACCPrivateClause::Create(Ctx, Clause.getBeginLoc(),
- Clause.getLParenLoc(),
- Clause.getVarList(), Clause.getEndLoc());
+ llvm::SmallVector<VarDecl *> InitRecipes;
+
+ // Assemble the recipes list.
+ for (const Expr *VarExpr : Clause.getVarList())
+ InitRecipes.push_back(SemaRef.CreateInitRecipe(VarExpr));
+
+ return OpenACCPrivateClause::Create(
+ Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(),
+ InitRecipes, Clause.getEndLoc());
}
OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause(
diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp
index 994cd07..7b16d08 100644
--- a/clang/lib/Sema/SemaRISCV.cpp
+++ b/clang/lib/Sema/SemaRISCV.cpp
@@ -1552,9 +1552,11 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
HasSiFiveCLICType = true;
break;
case RISCVInterruptAttr::supervisor:
+ case RISCVInterruptAttr::rnmi:
case RISCVInterruptAttr::qcinest:
case RISCVInterruptAttr::qcinonest:
- // "supervisor" and "qci-(no)nest" cannot be combined with any other types
+ // "supervisor", "rnmi" and "qci-(no)nest" cannot be combined with any
+ // other types
HasUnaryType = true;
break;
}
@@ -1608,6 +1610,14 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
return;
}
} break;
+ case RISCVInterruptAttr::rnmi: {
+ if (!HasFeature("smrnmi")) {
+ Diag(AL.getLoc(),
+ diag::err_riscv_attribute_interrupt_requires_extension)
+ << RISCVInterruptAttr::ConvertInterruptTypeToStr(Type) << "Smrnmi";
+ return;
+ }
+ } break;
default:
break;
}
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 3f89843..a5f9202 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2284,7 +2284,11 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
// we can diagnose if we don't see any variable declarations. This
// covers a case like declaring a typedef, function, or structure
// type rather than a variable.
- NonVarSeen = DI;
+ //
+ // Note, _Static_assert is acceptable because it does not declare an
+ // identifier at all, so "for object having" does not apply.
+ if (!isa<StaticAssertDecl>(DI))
+ NonVarSeen = DI;
}
}
// Diagnose if we saw a non-variable declaration but no variable
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 21fed2e..b6b8932 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TemplateName.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticSema.h"
@@ -38,6 +39,7 @@
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/SaveAndRestore.h"
#include <optional>
@@ -306,9 +308,11 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) ||
isa<BuiltinTemplateDecl>(TD) || isa<ConceptDecl>(TD));
TemplateKind =
- isa<VarTemplateDecl>(TD) ? TNK_Var_template :
- isa<ConceptDecl>(TD) ? TNK_Concept_template :
- TNK_Type_template;
+ isa<TemplateTemplateParmDecl>(TD)
+ ? dyn_cast<TemplateTemplateParmDecl>(TD)->templateParameterKind()
+ : isa<VarTemplateDecl>(TD) ? TNK_Var_template
+ : isa<ConceptDecl>(TD) ? TNK_Concept_template
+ : TNK_Type_template;
}
}
@@ -1071,12 +1075,26 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
bool Sema::CheckTypeConstraint(TemplateIdAnnotation *TypeConstr) {
TemplateName TN = TypeConstr->Template.get();
- ConceptDecl *CD = cast<ConceptDecl>(TN.getAsTemplateDecl());
+ NamedDecl *CD = nullptr;
+ bool IsTypeConcept = false;
+ bool RequiresArguments = false;
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TN.getAsTemplateDecl())) {
+ IsTypeConcept = TTP->isTypeConceptTemplateParam();
+ RequiresArguments =
+ TTP->getTemplateParameters()->getMinRequiredArguments() > 1;
+ CD = TTP;
+ } else {
+ CD = TN.getAsTemplateDecl();
+ IsTypeConcept = cast<ConceptDecl>(CD)->isTypeConcept();
+ RequiresArguments = cast<ConceptDecl>(CD)
+ ->getTemplateParameters()
+ ->getMinRequiredArguments() > 1;
+ }
// C++2a [temp.param]p4:
// [...] The concept designated by a type-constraint shall be a type
// concept ([temp.concept]).
- if (!CD->isTypeConcept()) {
+ if (!IsTypeConcept) {
Diag(TypeConstr->TemplateNameLoc,
diag::err_type_constraint_non_type_concept);
return true;
@@ -1087,8 +1105,7 @@ bool Sema::CheckTypeConstraint(TemplateIdAnnotation *TypeConstr) {
bool WereArgsSpecified = TypeConstr->LAngleLoc.isValid();
- if (!WereArgsSpecified &&
- CD->getTemplateParameters()->getMinRequiredArguments() > 1) {
+ if (!WereArgsSpecified && RequiresArguments) {
Diag(TypeConstr->TemplateNameLoc,
diag::err_type_constraint_missing_arguments)
<< CD;
@@ -1115,7 +1132,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS,
return true;
TemplateName TN = TypeConstr->Template.get();
- ConceptDecl *CD = cast<ConceptDecl>(TN.getAsTemplateDecl());
+ TemplateDecl *CD = cast<TemplateDecl>(TN.getAsTemplateDecl());
UsingShadowDecl *USD = TN.getAsUsingShadowDecl();
DeclarationNameInfo ConceptName(DeclarationName(TypeConstr->Name),
@@ -1143,7 +1160,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS,
template <typename ArgumentLocAppender>
static ExprResult formImmediatelyDeclaredConstraint(
Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo,
- ConceptDecl *NamedConcept, NamedDecl *FoundDecl, SourceLocation LAngleLoc,
+ NamedDecl *NamedConcept, NamedDecl *FoundDecl, SourceLocation LAngleLoc,
SourceLocation RAngleLoc, QualType ConstrainedType,
SourceLocation ParamNameLoc, ArgumentLocAppender Appender,
SourceLocation EllipsisLoc) {
@@ -1162,10 +1179,19 @@ static ExprResult formImmediatelyDeclaredConstraint(
// constraint of T. [...]
CXXScopeSpec SS;
SS.Adopt(NS);
- ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
- SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
- /*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, NamedConcept,
- &ConstraintArgs);
+ ExprResult ImmediatelyDeclaredConstraint;
+ if (auto *CD = dyn_cast<ConceptDecl>(NamedConcept)) {
+ ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
+ SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
+ /*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, CD,
+ &ConstraintArgs);
+ }
+ // We have a template template parameter
+ else {
+ auto *CDT = dyn_cast<TemplateTemplateParmDecl>(NamedConcept);
+ ImmediatelyDeclaredConstraint = S.CheckVarOrConceptTemplateTemplateId(
+ SS, NameInfo, CDT, SourceLocation(), &ConstraintArgs);
+ }
if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
return ImmediatelyDeclaredConstraint;
@@ -1191,7 +1217,8 @@ static ExprResult formImmediatelyDeclaredConstraint(
bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
DeclarationNameInfo NameInfo,
- ConceptDecl *NamedConcept, NamedDecl *FoundDecl,
+ TemplateDecl *NamedConcept,
+ NamedDecl *FoundDecl,
const TemplateArgumentListInfo *TemplateArgs,
TemplateTypeParmDecl *ConstrainedParameter,
SourceLocation EllipsisLoc) {
@@ -1588,11 +1615,15 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
return Param;
}
+/// ActOnTemplateTemplateParameter - Called when a C++ template template
+/// parameter (e.g. T in template <template \<typename> class T> class array)
+/// has been parsed. S is the current scope.
NamedDecl *Sema::ActOnTemplateTemplateParameter(
- Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params,
- bool Typename, SourceLocation EllipsisLoc, IdentifierInfo *Name,
- SourceLocation NameLoc, unsigned Depth, unsigned Position,
- SourceLocation EqualLoc, ParsedTemplateArgument Default) {
+ Scope *S, SourceLocation TmpLoc, TemplateNameKind Kind, bool Typename,
+ TemplateParameterList *Params, SourceLocation EllipsisLoc,
+ IdentifierInfo *Name, SourceLocation NameLoc, unsigned Depth,
+ unsigned Position, SourceLocation EqualLoc,
+ ParsedTemplateArgument Default) {
assert(S->isTemplateParamScope() &&
"Template template parameter not in template parameter scope!");
@@ -1609,7 +1640,7 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(
TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(
Context, Context.getTranslationUnitDecl(),
NameLoc.isInvalid() ? TmpLoc : NameLoc, Depth, Position, IsParameterPack,
- Name, Typename, Params);
+ Name, Kind, Typename, Params);
Param->setAccess(AS_public);
if (Param->isParameterPack())
@@ -1658,6 +1689,14 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(
return Param;
}
+ TemplateName Name =
+ DefaultArg.getArgument().getAsTemplateOrTemplatePattern();
+ TemplateDecl *Template = Name.getAsTemplateDecl();
+ if (Template &&
+ !CheckDeclCompatibleWithTemplateTemplate(Template, Param, DefaultArg)) {
+ return Param;
+ }
+
// Check for unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(DefaultArg.getLocation(),
DefaultArg.getArgument().getAsTemplate(),
@@ -2667,6 +2706,18 @@ struct DependencyChecker : DynamicRecursiveASTVisitor {
return DynamicRecursiveASTVisitor::VisitDeclRefExpr(E);
}
+ bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) override {
+ if (ULE->isConceptReference() || ULE->isVarDeclReference()) {
+ if (auto *TTP = ULE->getTemplateTemplateDecl()) {
+ if (Matches(TTP->getDepth(), ULE->getExprLoc()))
+ return false;
+ }
+ for (auto &TLoc : ULE->template_arguments())
+ DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(TLoc);
+ }
+ return DynamicRecursiveASTVisitor::VisitUnresolvedLookupExpr(ULE);
+ }
+
bool VisitSubstTemplateTypeParmType(SubstTemplateTypeParmType *T) override {
return TraverseType(T->getReplacementType());
}
@@ -4047,8 +4098,10 @@ static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized,
static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D);
-static bool isTemplateArgumentTemplateParameter(
- const TemplateArgument &Arg, unsigned Depth, unsigned Index) {
+static bool isTemplateArgumentTemplateParameter(const TemplateArgument &Arg,
+ NamedDecl *Param,
+ unsigned Depth,
+ unsigned Index) {
switch (Arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::NullPtr:
@@ -4104,7 +4157,8 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params,
Arg = Arg.pack_begin()->getPackExpansionPattern();
}
- if (!isTemplateArgumentTemplateParameter(Arg, Depth, I))
+ if (!isTemplateArgumentTemplateParameter(Arg, Params->getParam(I), Depth,
+ I))
return false;
}
@@ -4694,6 +4748,43 @@ ExprResult Sema::CheckVarTemplateId(
return BuildDeclarationNameExpr(SS, NameInfo, Var, FoundD, TemplateArgs);
}
+ExprResult Sema::CheckVarOrConceptTemplateTemplateId(
+ const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
+ TemplateTemplateParmDecl *Template, SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ assert(Template && "A variable template id without template?");
+
+ if (Template->templateParameterKind() != TemplateNameKind::TNK_Var_template &&
+ Template->templateParameterKind() !=
+ TemplateNameKind::TNK_Concept_template)
+ return ExprResult();
+
+ // Check that the template argument list is well-formed for this template.
+ CheckTemplateArgumentInfo CTAI;
+ if (CheckTemplateArgumentList(
+ Template, TemplateLoc,
+ // FIXME: TemplateArgs will not be modified because
+ // UpdateArgsWithConversions is false, however, we should
+ // CheckTemplateArgumentList to be const-correct.
+ const_cast<TemplateArgumentListInfo &>(*TemplateArgs),
+ /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, CTAI,
+ /*UpdateArgsWithConversions=*/false))
+ return true;
+
+ UnresolvedSet<1> R;
+ R.addDecl(Template);
+
+ // FIXME: We model references to variable template and concept parameters
+ // as an UnresolvedLookupExpr. This is because they encapsulate the same
+ // data, can generally be used in the same places and work the same way.
+ // However, it might be cleaner to use a dedicated AST node in the long run.
+ return UnresolvedLookupExpr::Create(
+ getASTContext(), nullptr, SS.getWithLocInContext(getASTContext()),
+ SourceLocation(), NameInfo, false, TemplateArgs, R.begin(), R.end(),
+ /*KnownDependent=*/false,
+ /*KnownInstantiationDependent=*/false);
+}
+
void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
SourceLocation Loc) {
Diag(Loc, diag::err_template_missing_args)
@@ -4804,21 +4895,29 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
KnownDependent = true;
}
+ // We don't want lookup warnings at this point.
+ R.suppressDiagnostics();
+
if (R.getAsSingle<ConceptDecl>()) {
return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(),
R.getRepresentativeDecl(),
R.getAsSingle<ConceptDecl>(), TemplateArgs);
}
- // We don't want lookup warnings at this point.
- R.suppressDiagnostics();
+ // Check variable template ids (C++17) and concept template parameters
+ // (C++26).
+ UnresolvedLookupExpr *ULE;
+ if (R.getAsSingle<TemplateTemplateParmDecl>())
+ return CheckVarOrConceptTemplateTemplateId(
+ SS, R.getLookupNameInfo(), R.getAsSingle<TemplateTemplateParmDecl>(),
+ TemplateKWLoc, TemplateArgs);
- UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(
+ // Function templates
+ ULE = UnresolvedLookupExpr::Create(
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
TemplateKWLoc, R.getLookupNameInfo(), RequiresADL, TemplateArgs,
R.begin(), R.end(), KnownDependent,
/*KnownInstantiationDependent=*/false);
-
// Model the templates with UnresolvedTemplateTy. The expression should then
// either be transformed in an instantiation or be diagnosed in
// CheckPlaceholderExpr.
@@ -5609,12 +5708,25 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
break;
case TemplateArgument::Expression:
- case TemplateArgument::Type:
+ case TemplateArgument::Type: {
+ auto Kind = 0;
+ switch (TempParm->templateParameterKind()) {
+ case TemplateNameKind::TNK_Var_template:
+ Kind = 1;
+ break;
+ case TemplateNameKind::TNK_Concept_template:
+ Kind = 2;
+ break;
+ default:
+ break;
+ }
+
// We have a template template parameter but the template
// argument does not refer to a template.
Diag(ArgLoc.getLocation(), diag::err_template_arg_must_be_template)
- << getLangOpts().CPlusPlus11;
+ << Kind << getLangOpts().CPlusPlus11;
return true;
+ }
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
@@ -6359,7 +6471,7 @@ enum NullPointerValueKind {
/// Determine whether the given template argument is a null pointer
/// value of the appropriate type.
static NullPointerValueKind
-isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
+isNullPointerValueTemplateArgument(Sema &S, NamedDecl *Param,
QualType ParamType, Expr *Arg,
Decl *Entity = nullptr) {
if (Arg->isValueDependent() || Arg->isTypeDependent())
@@ -6464,9 +6576,10 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
/// Checks whether the given template argument is compatible with its
/// template parameter.
-static bool CheckTemplateArgumentIsCompatibleWithParameter(
- Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn,
- Expr *Arg, QualType ArgType) {
+static bool
+CheckTemplateArgumentIsCompatibleWithParameter(Sema &S, NamedDecl *Param,
+ QualType ParamType, Expr *ArgIn,
+ Expr *Arg, QualType ArgType) {
bool ObjCLifetimeConversion;
if (ParamType->isPointerType() &&
!ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType() &&
@@ -6522,7 +6635,7 @@ 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,
+ Sema &S, NamedDecl *Param, QualType ParamType, Expr *ArgIn,
TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) {
bool Invalid = false;
Expr *Arg = ArgIn;
@@ -6784,11 +6897,9 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction(
/// 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 &SugaredConverted,
- TemplateArgument &CanonicalConverted) {
+static bool CheckTemplateArgumentPointerToMember(
+ Sema &S, NamedDecl *Param, QualType ParamType, Expr *&ResultArg,
+ TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) {
bool Invalid = false;
Expr *Arg = ResultArg;
@@ -6919,8 +7030,15 @@ CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
return true;
}
-ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
- QualType ParamType, Expr *Arg,
+/// Check a template argument against its corresponding
+/// non-type template parameter.
+///
+/// This routine implements the semantics of C++ [temp.arg.nontype].
+/// If an error occurred, it returns ExprError(); otherwise, it
+/// returns the converted template argument. \p ParamType is the
+/// type of the non-type template parameter after it has been instantiated.
+ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
+ Expr *Arg,
TemplateArgument &SugaredConverted,
TemplateArgument &CanonicalConverted,
bool StrictCheck,
@@ -6974,7 +7092,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
} else {
TemplateDeductionInfo Info(DeductionArg->getExprLoc(),
- Param->getDepth() + 1);
+ Param->getTemplateDepth() + 1);
ParamType = QualType();
TemplateDeductionResult Result =
DeduceAutoType(TSI->getTypeLoc(), DeductionArg, ParamType, Info,
@@ -6986,13 +7104,14 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// checking the template argument list.
/*IgnoreConstraints=*/true);
if (Result == TemplateDeductionResult::AlreadyDiagnosed) {
- if (ParamType.isNull())
- return ExprError();
+ return ExprError();
} else if (Result != TemplateDeductionResult::Success) {
- Diag(Arg->getExprLoc(),
- diag::err_non_type_template_parm_type_deduction_failure)
- << Param->getDeclName() << Param->getType() << Arg->getType()
- << Arg->getSourceRange();
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ Diag(Arg->getExprLoc(),
+ diag::err_non_type_template_parm_type_deduction_failure)
+ << Param->getDeclName() << NTTP->getType() << Arg->getType()
+ << Arg->getSourceRange();
+ }
NoteTemplateParameterLocation(*Param);
return ExprError();
}
@@ -7387,7 +7506,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (IntegerType->isUnsignedIntegerOrEnumerationType() &&
(OldValue.isSigned() && OldValue.isNegative())) {
Diag(Arg->getBeginLoc(), diag::warn_template_arg_negative)
- << toString(OldValue, 10) << toString(Value, 10) << Param->getType()
+ << toString(OldValue, 10) << toString(Value, 10) << ParamType
<< Arg->getSourceRange();
NoteTemplateParameterLocation(*Param);
}
@@ -7402,7 +7521,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
RequiredBits = OldValue.getSignificantBits();
if (RequiredBits > AllowedBits) {
Diag(Arg->getBeginLoc(), diag::warn_template_arg_too_large)
- << toString(OldValue, 10) << toString(Value, 10) << Param->getType()
+ << toString(OldValue, 10) << toString(Value, 10) << ParamType
<< Arg->getSourceRange();
NoteTemplateParameterLocation(*Param);
}
@@ -7581,6 +7700,81 @@ static void DiagnoseTemplateParameterListArityMismatch(
Sema &S, TemplateParameterList *New, TemplateParameterList *Old,
Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc);
+bool Sema::CheckDeclCompatibleWithTemplateTemplate(
+ TemplateDecl *Template, TemplateTemplateParmDecl *Param,
+ const TemplateArgumentLoc &Arg) {
+ // C++0x [temp.arg.template]p1:
+ // A template-argument for a template template-parameter shall be
+ // the name of a class template or an alias template, expressed as an
+ // id-expression. When the template-argument names a class template, only
+ // primary class templates are considered when matching the
+ // template template argument with the corresponding parameter;
+ // partial specializations are not considered even if their
+ // parameter lists match that of the template template parameter.
+ //
+
+ TemplateNameKind Kind = TNK_Non_template;
+ unsigned DiagFoundKind = 0;
+
+ if (auto *TTP = llvm::dyn_cast<TemplateTemplateParmDecl>(Template)) {
+ switch (TTP->templateParameterKind()) {
+ case TemplateNameKind::TNK_Concept_template:
+ DiagFoundKind = 3;
+ break;
+ case TemplateNameKind::TNK_Var_template:
+ DiagFoundKind = 2;
+ break;
+ default:
+ DiagFoundKind = 1;
+ break;
+ }
+ Kind = TTP->templateParameterKind();
+ } else if (isa<ConceptDecl>(Template)) {
+ Kind = TemplateNameKind::TNK_Concept_template;
+ DiagFoundKind = 3;
+ } else if (isa<FunctionTemplateDecl>(Template)) {
+ Kind = TemplateNameKind::TNK_Function_template;
+ DiagFoundKind = 0;
+ } else if (isa<VarTemplateDecl>(Template)) {
+ Kind = TemplateNameKind::TNK_Var_template;
+ DiagFoundKind = 2;
+ } else if (isa<ClassTemplateDecl>(Template) ||
+ isa<TypeAliasTemplateDecl>(Template) ||
+ isa<BuiltinTemplateDecl>(Template)) {
+ Kind = TemplateNameKind::TNK_Type_template;
+ DiagFoundKind = 1;
+ } else {
+ assert(false && "Unexpected Decl");
+ }
+
+ if (Kind == Param->templateParameterKind()) {
+ return true;
+ }
+
+ unsigned DiagKind = 0;
+ switch (Param->templateParameterKind()) {
+ case TemplateNameKind::TNK_Concept_template:
+ DiagKind = 2;
+ break;
+ case TemplateNameKind::TNK_Var_template:
+ DiagKind = 1;
+ break;
+ default:
+ DiagKind = 0;
+ break;
+ }
+ Diag(Arg.getLocation(), diag::err_template_arg_not_valid_template)
+ << DiagKind;
+ Diag(Template->getLocation(), diag::note_template_arg_refers_to_template_here)
+ << DiagFoundKind << Template;
+ return false;
+}
+
+/// Check a template argument against its corresponding
+/// template template parameter.
+///
+/// This routine implements the semantics of C++ [temp.arg.template].
+/// It returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
TemplateParameterList *Params,
TemplateArgumentLoc &Arg,
@@ -7597,27 +7791,8 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
if (Template->isInvalidDecl())
return true;
- // C++0x [temp.arg.template]p1:
- // A template-argument for a template template-parameter shall be
- // the name of a class template or an alias template, expressed as an
- // id-expression. When the template-argument names a class template, only
- // primary class templates are considered when matching the
- // template template argument with the corresponding parameter;
- // partial specializations are not considered even if their
- // parameter lists match that of the template template parameter.
- //
- // Note that we also allow template template parameters here, which
- // will happen when we are dealing with, e.g., class template
- // partial specializations.
- if (!isa<ClassTemplateDecl>(Template) &&
- !isa<TemplateTemplateParmDecl>(Template) &&
- !isa<TypeAliasTemplateDecl>(Template) &&
- !isa<BuiltinTemplateDecl>(Template)) {
- assert(isa<FunctionTemplateDecl>(Template) &&
- "Only function templates are possible here");
- Diag(Arg.getLocation(), diag::err_template_arg_not_valid_template);
- Diag(Template->getLocation(), diag::note_template_arg_refers_here_func)
- << Template;
+ if (!CheckDeclCompatibleWithTemplateTemplate(Template, Param, Arg)) {
+ return true;
}
// C++1z [temp.arg.template]p3: (DR 150)
@@ -7689,6 +7864,10 @@ void Sema::NoteTemplateParameterLocation(const NamedDecl &Decl) {
diag::note_template_param_external);
}
+/// Given a non-type template argument that refers to a
+/// declaration and the type of its corresponding non-type template
+/// parameter, produce an expression that properly refers to that
+/// declaration.
ExprResult Sema::BuildExpressionFromDeclTemplateArgument(
const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc,
NamedDecl *TemplateParam) {
@@ -8009,34 +8188,40 @@ static bool MatchTemplateParameterKind(
return false;
}
-
// For non-type template parameters, check the type of the parameter.
- if (NonTypeTemplateParmDecl *OldNTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Old)) {
+ if (NonTypeTemplateParmDecl *OldNTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(Old)) {
NonTypeTemplateParmDecl *NewNTTP = cast<NonTypeTemplateParmDecl>(New);
- // C++20 [temp.over.link]p6:
- // Two [non-type] template-parameters are equivalent [if] they have
- // equivalent types ignoring the use of type-constraints for
- // placeholder types
- QualType OldType = S.Context.getUnconstrainedType(OldNTTP->getType());
- QualType NewType = S.Context.getUnconstrainedType(NewNTTP->getType());
- if (!S.Context.hasSameType(OldType, NewType)) {
- if (Complain) {
- unsigned NextDiag = diag::err_template_nontype_parm_different_type;
- if (TemplateArgLoc.isValid()) {
- S.Diag(TemplateArgLoc,
- diag::err_template_arg_template_params_mismatch);
- NextDiag = diag::note_template_nontype_parm_different_type;
+ // If we are matching a template template argument to a template
+ // template parameter and one of the non-type template parameter types
+ // is dependent, then we must wait until template instantiation time
+ // to actually compare the arguments.
+ if (Kind != Sema::TPL_TemplateTemplateParmMatch ||
+ (!OldNTTP->getType()->isDependentType() &&
+ !NewNTTP->getType()->isDependentType())) {
+ // C++20 [temp.over.link]p6:
+ // Two [non-type] template-parameters are equivalent [if] they have
+ // equivalent types ignoring the use of type-constraints for
+ // placeholder types
+ QualType OldType = S.Context.getUnconstrainedType(OldNTTP->getType());
+ QualType NewType = S.Context.getUnconstrainedType(NewNTTP->getType());
+ if (!S.Context.hasSameType(OldType, NewType)) {
+ if (Complain) {
+ unsigned NextDiag = diag::err_template_nontype_parm_different_type;
+ if (TemplateArgLoc.isValid()) {
+ S.Diag(TemplateArgLoc,
+ diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_nontype_parm_different_type;
+ }
+ S.Diag(NewNTTP->getLocation(), NextDiag)
+ << NewNTTP->getType() << (Kind != Sema::TPL_TemplateMatch);
+ S.Diag(OldNTTP->getLocation(),
+ diag::note_template_nontype_parm_prev_declaration)
+ << OldNTTP->getType();
}
- S.Diag(NewNTTP->getLocation(), NextDiag)
- << NewNTTP->getType() << (Kind != Sema::TPL_TemplateMatch);
- S.Diag(OldNTTP->getLocation(),
- diag::note_template_nontype_parm_prev_declaration)
- << OldNTTP->getType();
+ return false;
}
-
- return false;
}
}
// For template template parameters, check the template parameter types.
@@ -8045,6 +8230,8 @@ static bool MatchTemplateParameterKind(
else if (TemplateTemplateParmDecl *OldTTP =
dyn_cast<TemplateTemplateParmDecl>(Old)) {
TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
+ if (OldTTP->templateParameterKind() != NewTTP->templateParameterKind())
+ return false;
if (!S.TemplateParameterListsAreEqual(
NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
OldTTP->getTemplateParameters(), Complain,
@@ -8056,6 +8243,7 @@ static bool MatchTemplateParameterKind(
}
if (Kind != Sema::TPL_TemplateParamsEquivalent &&
+ Kind != Sema::TPL_TemplateTemplateParmMatch &&
!isa<TemplateTemplateParmDecl>(Old)) {
const Expr *NewC = nullptr, *OldC = nullptr;
@@ -8421,6 +8609,11 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
if (isa<NonTypeTemplateParmDecl>(DRE->getDecl()))
continue;
+ if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(ArgExpr);
+ ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) {
+ continue;
+ }
+
// C++ [temp.class.spec]p9:
// Within the argument list of a class template partial
// specialization, the following restrictions apply:
@@ -9032,13 +9225,15 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
Context.setPrimaryMergedDecl(NewDecl, OldConcept->getCanonicalDecl());
}
-bool Sema::CheckConceptUseInDefinition(ConceptDecl *Concept,
- SourceLocation Loc) {
- if (!Concept->isInvalidDecl() && !Concept->hasDefinition()) {
- Diag(Loc, diag::err_recursive_concept) << Concept;
- Diag(Concept->getLocation(), diag::note_declared_at);
+bool Sema::CheckConceptUseInDefinition(NamedDecl *Concept, SourceLocation Loc) {
+ if (auto *CE = llvm::dyn_cast<ConceptDecl>(Concept);
+ CE && !CE->isInvalidDecl() && !CE->hasDefinition()) {
+ Diag(Loc, diag::err_recursive_concept) << CE;
+ Diag(CE->getLocation(), diag::note_declared_at);
return true;
}
+ // Concept template parameters don't have a definition and can't
+ // be defined recursively.
return false;
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 9e56e697..0d70321 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -37,6 +37,7 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TemplateKinds.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/Sema.h"
@@ -146,11 +147,7 @@ static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
bool OnlyDeduced, unsigned Level,
llvm::SmallBitVector &Deduced);
-/// If the given expression is of a form that permits the deduction
-/// of a non-type template parameter, return the declaration of that
-/// non-type template parameter.
-static const NonTypeTemplateParmDecl *
-getDeducedParameterFromExpr(const Expr *E, unsigned Depth) {
+static const Expr *unwrapExpressionForDeduction(const Expr *E) {
// If we are within an alias template, the expression may have undergone
// any number of parameter substitutions already.
while (true) {
@@ -170,18 +167,100 @@ getDeducedParameterFromExpr(const Expr *E, unsigned Depth) {
} else
break;
}
+ return E;
+}
+
+class NonTypeOrVarTemplateParmDecl {
+public:
+ NonTypeOrVarTemplateParmDecl(const NamedDecl *Template) : Template(Template) {
+ assert(
+ !Template || isa<NonTypeTemplateParmDecl>(Template) ||
+ (isa<TemplateTemplateParmDecl>(Template) &&
+ (cast<TemplateTemplateParmDecl>(Template)->templateParameterKind() ==
+ TNK_Var_template ||
+ cast<TemplateTemplateParmDecl>(Template)->templateParameterKind() ==
+ TNK_Concept_template)));
+ }
+
+ QualType getType() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->getType();
+ return getTemplate()->templateParameterKind() == TNK_Concept_template
+ ? getTemplate()->getASTContext().BoolTy
+ : getTemplate()->getASTContext().DependentTy;
+ }
+
+ unsigned getDepth() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->getDepth();
+ return getTemplate()->getDepth();
+ }
+
+ unsigned getIndex() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->getIndex();
+ return getTemplate()->getIndex();
+ }
+
+ const TemplateTemplateParmDecl *getTemplate() const {
+ return cast<TemplateTemplateParmDecl>(Template);
+ }
+
+ const NonTypeTemplateParmDecl *getNTTP() const {
+ return cast<NonTypeTemplateParmDecl>(Template);
+ }
+
+ TemplateParameter asTemplateParam() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return const_cast<NonTypeTemplateParmDecl *>(NTTP);
+ return const_cast<TemplateTemplateParmDecl *>(getTemplate());
+ }
+
+ bool isExpandedParameterPack() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->isExpandedParameterPack();
+ return getTemplate()->isExpandedParameterPack();
+ }
+
+ SourceLocation getLocation() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->getLocation();
+ return getTemplate()->getLocation();
+ }
+
+ operator bool() const { return Template; }
+private:
+ const NamedDecl *Template;
+};
+
+/// If the given expression is of a form that permits the deduction
+/// of a non-type template parameter, return the declaration of that
+/// non-type template parameter.
+static NonTypeOrVarTemplateParmDecl
+getDeducedNTTParameterFromExpr(const Expr *E, unsigned Depth) {
+ // If we are within an alias template, the expression may have undergone
+ // any number of parameter substitutions already.
+ E = unwrapExpressionForDeduction(E);
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()))
if (NTTP->getDepth() == Depth)
return NTTP;
+ if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E);
+ ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) {
+ if (auto *TTP = ULE->getTemplateTemplateDecl()) {
+
+ if (TTP->getDepth() == Depth)
+ return TTP;
+ }
+ }
return nullptr;
}
-static const NonTypeTemplateParmDecl *
-getDeducedParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) {
- return getDeducedParameterFromExpr(E, Info.getDeducedDepth());
+static const NonTypeOrVarTemplateParmDecl
+getDeducedNTTParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) {
+ return getDeducedNTTParameterFromExpr(E, Info.getDeducedDepth());
}
/// Determine whether two declaration pointers refer to the same
@@ -386,29 +465,28 @@ checkDeducedTemplateArguments(ASTContext &Context,
/// deduction is funneled through here.
static TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP,
+ const NonTypeOrVarTemplateParmDecl NTTP,
const DeducedTemplateArgument &NewDeduced,
QualType ValueType, TemplateDeductionInfo &Info,
bool PartialOrdering,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool *HasDeducedAnyParam) {
- assert(NTTP->getDepth() == Info.getDeducedDepth() &&
+ assert(NTTP.getDepth() == Info.getDeducedDepth() &&
"deducing non-type template argument with wrong depth");
DeducedTemplateArgument Result = checkDeducedTemplateArguments(
- S.Context, Deduced[NTTP->getIndex()], NewDeduced);
+ S.Context, Deduced[NTTP.getIndex()], NewDeduced);
if (Result.isNull()) {
- Info.Param = const_cast<NonTypeTemplateParmDecl*>(NTTP);
- Info.FirstArg = Deduced[NTTP->getIndex()];
+ Info.Param = NTTP.asTemplateParam();
+ Info.FirstArg = Deduced[NTTP.getIndex()];
Info.SecondArg = NewDeduced;
return TemplateDeductionResult::Inconsistent;
}
-
- Deduced[NTTP->getIndex()] = Result;
+ Deduced[NTTP.getIndex()] = Result;
if (!S.getLangOpts().CPlusPlus17)
return TemplateDeductionResult::Success;
- if (NTTP->isExpandedParameterPack())
+ if (NTTP.isExpandedParameterPack())
// FIXME: We may still need to deduce parts of the type here! But we
// don't have any way to find which slice of the type to use, and the
// type stored on the NTTP itself is nonsense. Perhaps the type of an
@@ -417,7 +495,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
// Get the type of the parameter for deduction. If it's a (dependent) array
// or function type, we will not have decayed it yet, so do that now.
- QualType ParamType = S.Context.getAdjustedParameterType(NTTP->getType());
+ QualType ParamType = S.Context.getAdjustedParameterType(NTTP.getType());
if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType))
ParamType = Expansion->getPattern();
@@ -444,7 +522,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
/// from the given integral constant.
static TemplateDeductionResult DeduceNonTypeTemplateArgument(
Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value,
+ NonTypeOrVarTemplateParmDecl NTTP, const llvm::APSInt &Value,
QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info,
bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool *HasDeducedAnyParam) {
@@ -459,14 +537,14 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument(
/// from the given null pointer template argument type.
static TemplateDeductionResult
DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP,
+ NonTypeOrVarTemplateParmDecl NTTP,
QualType NullPtrType, TemplateDeductionInfo &Info,
bool PartialOrdering,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool *HasDeducedAnyParam) {
Expr *Value = S.ImpCastExprToType(
new (S.Context) CXXNullPtrLiteralExpr(S.Context.NullPtrTy,
- NTTP->getLocation()),
+ NTTP.getLocation()),
NullPtrType,
NullPtrType->isMemberPointerType() ? CK_NullToMemberPointer
: CK_NullToPointer)
@@ -482,7 +560,7 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
/// \returns true if deduction succeeded, false otherwise.
static TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP, Expr *Value,
+ NonTypeOrVarTemplateParmDecl NTTP, Expr *Value,
TemplateDeductionInfo &Info, bool PartialOrdering,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool *HasDeducedAnyParam) {
@@ -497,7 +575,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
/// \returns true if deduction succeeded, false otherwise.
static TemplateDeductionResult
DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams,
- const NonTypeTemplateParmDecl *NTTP, ValueDecl *D,
+ NonTypeOrVarTemplateParmDecl NTTP, ValueDecl *D,
QualType T, TemplateDeductionInfo &Info,
bool PartialOrdering,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
@@ -1930,14 +2008,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Determine the array bound is something we can deduce.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, DAP->getSizeExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, DAP->getSizeExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
// We can perform template argument deduction for the given non-type
// template parameter.
- assert(NTTP->getDepth() == Info.getDeducedDepth() &&
+ assert(NTTP.getDepth() == Info.getDeducedDepth() &&
"saw non-type template parameter with wrong depth");
if (const auto *CAA = dyn_cast<ConstantArrayType>(AA)) {
llvm::APSInt Size(CAA->getSize());
@@ -1994,10 +2072,10 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// deducing through the noexcept-specifier if it's part of the canonical
// type. libstdc++ relies on this.
Expr *NoexceptExpr = FPP->getNoexceptExpr();
- if (const NonTypeTemplateParmDecl *NTTP =
- NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr)
+ if (NonTypeOrVarTemplateParmDecl NTTP =
+ NoexceptExpr ? getDeducedNTTParameterFromExpr(Info, NoexceptExpr)
: nullptr) {
- assert(NTTP->getDepth() == Info.getDeducedDepth() &&
+ assert(NTTP.getDepth() == Info.getDeducedDepth() &&
"saw non-type template parameter with wrong depth");
llvm::APSInt Noexcept(1);
@@ -2191,8 +2269,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the vector size, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2217,8 +2295,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the vector size, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2246,8 +2324,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the vector size, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2271,8 +2349,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the vector size, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, VP->getSizeExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2348,8 +2426,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return TemplateDeductionResult::NonDeducedMismatch;
}
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, ParamExpr);
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, ParamExpr);
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2395,8 +2473,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the address space, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2420,8 +2498,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
return Result;
// Perform deduction on the address space, if we can.
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2440,8 +2518,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
if (IP->isUnsigned() != IA->isUnsigned())
return TemplateDeductionResult::NonDeducedMismatch;
- const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, IP->getNumBitsExpr());
+ NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, IP->getNumBitsExpr());
if (!NTTP)
return TemplateDeductionResult::Success;
@@ -2573,8 +2651,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
return TemplateDeductionResult::NonDeducedMismatch;
case TemplateArgument::Expression:
- if (const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, P.getAsExpr())) {
+ if (NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(Info, P.getAsExpr())) {
switch (A.getKind()) {
case TemplateArgument::Expression: {
const Expr *E = A.getAsExpr();
@@ -2628,7 +2706,6 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
}
llvm_unreachable("Unknown template argument kind");
}
-
// Can't deduce anything, but that's okay.
return TemplateDeductionResult::Success;
case TemplateArgument::Pack:
@@ -4392,8 +4469,8 @@ static TemplateDeductionResult DeduceFromInitializerList(
// from the length of the initializer list.
if (auto *DependentArrTy = dyn_cast_or_null<DependentSizedArrayType>(ArrTy)) {
// Determine the array bound is something we can deduce.
- if (const NonTypeTemplateParmDecl *NTTP =
- getDeducedParameterFromExpr(Info, DependentArrTy->getSizeExpr())) {
+ if (NonTypeOrVarTemplateParmDecl NTTP = getDeducedNTTParameterFromExpr(
+ Info, DependentArrTy->getSizeExpr())) {
// We can perform template argument deduction for the given non-type
// template parameter.
// C++ [temp.deduct.type]p13:
@@ -5098,7 +5175,7 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
AutoTypeLoc TypeLoc,
QualType Deduced) {
ConstraintSatisfaction Satisfaction;
- ConceptDecl *Concept = Type.getTypeConstraintConcept();
+ ConceptDecl *Concept = cast<ConceptDecl>(Type.getTypeConstraintConcept());
TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
TypeLoc.getRAngleLoc());
TemplateArgs.addArgument(
@@ -6654,6 +6731,18 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor {
Used[NTTP->getIndex()] = true;
return true;
}
+
+ bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) override {
+ if (ULE->isConceptReference() || ULE->isVarDeclReference()) {
+ if (auto *TTP = ULE->getTemplateTemplateDecl()) {
+ if (TTP->getDepth() == Depth)
+ Used[TTP->getIndex()] = true;
+ }
+ for (auto &TLoc : ULE->template_arguments())
+ DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(TLoc);
+ }
+ return true;
+ }
};
}
@@ -6675,17 +6764,28 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E))
E = Expansion->getPattern();
- const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(E, Depth);
- if (!NTTP)
+ E = unwrapExpressionForDeduction(E);
+ if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E);
+ ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) {
+ if (const auto *TTP = ULE->getTemplateTemplateDecl())
+ Used[TTP->getIndex()] = true;
+ for (auto &TLoc : ULE->template_arguments())
+ MarkUsedTemplateParameters(Ctx, TLoc.getArgument(), OnlyDeduced, Depth,
+ Used);
return;
+ }
- if (NTTP->getDepth() == Depth)
- Used[NTTP->getIndex()] = true;
+ const NonTypeOrVarTemplateParmDecl NTTP =
+ getDeducedNTTParameterFromExpr(E, Depth);
+ if (!NTTP)
+ return;
+ if (NTTP.getDepth() == Depth)
+ Used[NTTP.getIndex()] = true;
// In C++17 mode, additional arguments may be deduced from the type of a
// non-type argument.
if (Ctx.getLangOpts().CPlusPlus17)
- MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used);
+ MarkUsedTemplateParameters(Ctx, NTTP.getType(), OnlyDeduced, Depth, Used);
}
/// Mark the template parameters that are used by the given
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index d84d0ca1..0d96d18 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1899,8 +1899,7 @@ namespace {
private:
ExprResult
- transformNonTypeTemplateParmRef(Decl *AssociatedDecl,
- const NonTypeTemplateParmDecl *parm,
+ transformNonTypeTemplateParmRef(Decl *AssociatedDecl, const NamedDecl *parm,
SourceLocation loc, TemplateArgument arg,
UnsignedOrNone PackIndex, bool Final);
};
@@ -2338,22 +2337,25 @@ TemplateInstantiator::TransformOpenACCRoutineDeclAttr(
}
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
- Decl *AssociatedDecl, const NonTypeTemplateParmDecl *parm,
- SourceLocation loc, TemplateArgument arg, UnsignedOrNone PackIndex,
- bool Final) {
+ Decl *AssociatedDecl, const NamedDecl *parm, SourceLocation loc,
+ TemplateArgument arg, UnsignedOrNone PackIndex, bool Final) {
ExprResult result;
// Determine the substituted parameter type. We can usually infer this from
// the template argument, but not always.
auto SubstParamType = [&] {
- QualType T;
- if (parm->isExpandedParameterPack())
- T = parm->getExpansionType(*SemaRef.ArgPackSubstIndex);
- else
- T = parm->getType();
- if (parm->isParameterPack() && isa<PackExpansionType>(T))
- T = cast<PackExpansionType>(T)->getPattern();
- return SemaRef.SubstType(T, TemplateArgs, loc, parm->getDeclName());
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(parm)) {
+ QualType T;
+ if (NTTP->isExpandedParameterPack())
+ T = NTTP->getExpansionType(*SemaRef.ArgPackSubstIndex);
+ else
+ T = NTTP->getType();
+ if (parm->isParameterPack() && isa<PackExpansionType>(T))
+ T = cast<PackExpansionType>(T)->getPattern();
+ return SemaRef.SubstType(T, TemplateArgs, loc, parm->getDeclName());
+ }
+ return SemaRef.SubstType(arg.getAsExpr()->getType(), TemplateArgs, loc,
+ parm->getDeclName());
};
bool refParam = false;
@@ -2408,7 +2410,9 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
Expr *resultExpr = result.get();
return new (SemaRef.Context) SubstNonTypeTemplateParmExpr(
resultExpr->getType(), resultExpr->getValueKind(), loc, resultExpr,
- AssociatedDecl, parm->getIndex(), PackIndex, refParam, Final);
+ AssociatedDecl,
+ clang::getDepthAndIndex(const_cast<NamedDecl *>(parm)).second, PackIndex,
+ refParam, Final);
}
ExprResult
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 233bb65..87ec4f7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3784,14 +3784,14 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
Param = TemplateTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
- D->getPosition(), D->getIdentifier(), D->wasDeclaredWithTypename(),
- InstParams, ExpandedParams);
+ D->getPosition(), D->getIdentifier(), D->templateParameterKind(),
+ D->wasDeclaredWithTypename(), InstParams, ExpandedParams);
else
Param = TemplateTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->isParameterPack(), D->getIdentifier(),
- D->wasDeclaredWithTypename(), InstParams);
+ D->templateParameterKind(), D->wasDeclaredWithTypename(), InstParams);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
NestedNameSpecifierLoc QualifierLoc =
D->getDefaultArgument().getTemplateQualifierLoc();
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index b0a673d..d2baa2e 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -310,6 +310,16 @@ class CollectUnexpandedParameterPacksVisitor
return DynamicRecursiveASTVisitor::TraverseLambdaCapture(Lambda, C, Init);
}
+ bool TraverseUnresolvedLookupExpr(UnresolvedLookupExpr *E) override {
+ if (E->getNumDecls() == 1) {
+ NamedDecl *ND = *E->decls_begin();
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND);
+ TTP && TTP->isParameterPack())
+ addUnexpanded(ND, E->getBeginLoc());
+ }
+ return DynamicRecursiveASTVisitor::TraverseUnresolvedLookupExpr(E);
+ }
+
#ifndef NDEBUG
bool TraverseFunctionParmPackExpr(FunctionParmPackExpr *) override {
ContainsIntermediatePacks = true;
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 7dbd4bb..1289bed 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1306,12 +1306,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
? AutoTypeKeyword::DecltypeAuto
: AutoTypeKeyword::Auto;
- ConceptDecl *TypeConstraintConcept = nullptr;
+ TemplateDecl *TypeConstraintConcept = nullptr;
llvm::SmallVector<TemplateArgument, 8> TemplateArgs;
if (DS.isConstrainedAuto()) {
if (TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId()) {
TypeConstraintConcept =
- cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl());
+ cast<TemplateDecl>(TemplateId->Template.get().getAsTemplateDecl());
TemplateArgumentListInfo TemplateArgsInfo;
TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc);
TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc);
@@ -3090,15 +3090,13 @@ InventTemplateParameter(TypeProcessingState &state, QualType T,
if (!Invalid) {
UsingShadowDecl *USD =
TemplateId->Template.get().getAsUsingShadowDecl();
- auto *CD =
- cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl());
+ TemplateDecl *CD = TemplateId->Template.get().getAsTemplateDecl();
S.AttachTypeConstraint(
D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context),
DeclarationNameInfo(DeclarationName(TemplateId->Name),
TemplateId->TemplateNameLoc),
CD,
- /*FoundDecl=*/
- USD ? cast<NamedDecl>(USD) : CD,
+ /*FoundDecl=*/USD ? cast<NamedDecl>(USD) : CD,
TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr,
InventedTemplateParam, D.getEllipsisLoc());
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c7428d1..5ff5fbf5 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -610,6 +610,10 @@ public:
TemplateArgumentLoc &Output,
bool Uneval = false);
+ TemplateArgument
+ TransformNamedTemplateTemplateArgument(CXXScopeSpec &SS, TemplateName Name,
+ SourceLocation NameLoc);
+
/// Transform the given set of template arguments.
///
/// By default, this operation transforms all of the template arguments
@@ -4843,6 +4847,15 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
llvm_unreachable("overloaded function decl survived to here");
}
+template <typename Derived>
+TemplateArgument TreeTransform<Derived>::TransformNamedTemplateTemplateArgument(
+ CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc) {
+ TemplateName TN = getDerived().TransformTemplateName(SS, Name, NameLoc);
+ if (TN.isNull())
+ return TemplateArgument();
+ return TemplateArgument(TN);
+}
+
template<typename Derived>
void TreeTransform<Derived>::InventTemplateArgumentLoc(
const TemplateArgument &Arg,
@@ -4927,13 +4940,13 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- TemplateName Template = getDerived().TransformTemplateName(
+
+ TemplateArgument Out = getDerived().TransformNamedTemplateTemplateArgument(
SS, Arg.getAsTemplate(), Input.getTemplateNameLoc());
- if (Template.isNull())
+ if (Out.isNull())
return true;
-
- Output = TemplateArgumentLoc(SemaRef.Context, TemplateArgument(Template),
- QualifierLoc, Input.getTemplateNameLoc());
+ Output = TemplateArgumentLoc(SemaRef.Context, Out, QualifierLoc,
+ Input.getTemplateNameLoc());
return false;
}
@@ -5029,10 +5042,8 @@ template<typename InputIterator>
bool TreeTransform<Derived>::TransformTemplateArguments(
InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs,
bool Uneval) {
- for (; First != Last; ++First) {
+ for (TemplateArgumentLoc In : llvm::make_range(First, Last)) {
TemplateArgumentLoc Out;
- TemplateArgumentLoc In = *First;
-
if (In.getArgument().getKind() == TemplateArgument::Pack) {
// Unpack argument packs, which we translate them into separate
// arguments.
@@ -5042,11 +5053,10 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
typedef TemplateArgumentLocInventIterator<Derived,
TemplateArgument::pack_iterator>
PackLocIterator;
- if (TransformTemplateArguments(PackLocIterator(*this,
- In.getArgument().pack_begin()),
- PackLocIterator(*this,
- In.getArgument().pack_end()),
- Outputs, Uneval))
+ if (TransformTemplateArguments(
+ PackLocIterator(*this, In.getArgument().pack_begin()),
+ PackLocIterator(*this, In.getArgument().pack_end()), Outputs,
+ Uneval))
return true;
continue;
@@ -11730,20 +11740,26 @@ class OpenACCClauseTransform final
SemaOpenACC::OpenACCParsedClause &ParsedClause;
OpenACCClause *NewClause = nullptr;
+ ExprResult VisitVar(Expr *VarRef) {
+ ExprResult Res = Self.TransformExpr(VarRef);
+
+ if (!Res.isUsable())
+ return Res;
+
+ Res = Self.getSema().OpenACC().ActOnVar(ParsedClause.getDirectiveKind(),
+ ParsedClause.getClauseKind(),
+ Res.get());
+
+ return Res;
+ }
+
llvm::SmallVector<Expr *> VisitVarList(ArrayRef<Expr *> VarList) {
llvm::SmallVector<Expr *> InstantiatedVarList;
for (Expr *CurVar : VarList) {
- ExprResult Res = Self.TransformExpr(CurVar);
+ ExprResult VarRef = VisitVar(CurVar);
- if (!Res.isUsable())
- continue;
-
- Res = Self.getSema().OpenACC().ActOnVar(ParsedClause.getDirectiveKind(),
- ParsedClause.getClauseKind(),
- Res.get());
-
- if (Res.isUsable())
- InstantiatedVarList.push_back(Res.get());
+ if (VarRef.isUsable())
+ InstantiatedVarList.push_back(VarRef.get());
}
return InstantiatedVarList;
@@ -11870,12 +11886,31 @@ void OpenACCClauseTransform<Derived>::VisitNumGangsClause(
template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitPrivateClause(
const OpenACCPrivateClause &C) {
- ParsedClause.setVarListDetails(VisitVarList(C.getVarList()),
+ llvm::SmallVector<Expr *> InstantiatedVarList;
+ llvm::SmallVector<VarDecl *> InitRecipes;
+
+ for (const auto [RefExpr, InitRecipe] :
+ llvm::zip(C.getVarList(), C.getInitRecipes())) {
+ ExprResult VarRef = VisitVar(RefExpr);
+
+ if (VarRef.isUsable()) {
+ InstantiatedVarList.push_back(VarRef.get());
+
+ // We only have to create a new one if it is dependent, and Sema won't
+ // make one of these unless the type is non-dependent.
+ if (InitRecipe)
+ InitRecipes.push_back(InitRecipe);
+ else
+ InitRecipes.push_back(
+ Self.getSema().OpenACC().CreateInitRecipe(VarRef.get()));
+ }
+ }
+ ParsedClause.setVarListDetails(InstantiatedVarList,
OpenACCModifierKind::Invalid);
NewClause = OpenACCPrivateClause::Create(
Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
- ParsedClause.getLParenLoc(), ParsedClause.getVarList(),
+ ParsedClause.getLParenLoc(), ParsedClause.getVarList(), InitRecipes,
ParsedClause.getEndLoc());
}