diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaAMDGPU.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenACC.cpp | 78 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenACCClause.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaRISCV.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 391 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 210 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 32 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateVariadic.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 85 |
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()); } |