diff options
Diffstat (limited to 'clang/lib/Sema')
24 files changed, 981 insertions, 408 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 35ad0b5..fdb6302 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -581,7 +581,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { // mark them as live. for (const auto *B : *cfg) { if (!live[B->getBlockID()]) { - if (B->pred_begin() == B->pred_end()) { + if (B->preds().empty()) { const Stmt *Term = B->getTerminatorStmt(); if (isa_and_nonnull<CXXTryStmt>(Term)) // When not adding EH edges from calls, catch clauses diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index fbfb242..1f040c8 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -20,26 +20,19 @@ char MultiplexExternalSemaSource::ID; /// given element to it. /// MultiplexExternalSemaSource::MultiplexExternalSemaSource( - ExternalSemaSource *S1, ExternalSemaSource *S2) { - S1->Retain(); - S2->Retain(); - Sources.push_back(S1); - Sources.push_back(S2); -} - -// pin the vtable here. -MultiplexExternalSemaSource::~MultiplexExternalSemaSource() { - for (auto *S : Sources) - S->Release(); + llvm::IntrusiveRefCntPtr<ExternalSemaSource> S1, + llvm::IntrusiveRefCntPtr<ExternalSemaSource> S2) { + Sources.push_back(std::move(S1)); + Sources.push_back(std::move(S2)); } /// Appends new source to the source list. /// ///\param[in] source - An ExternalSemaSource. /// -void MultiplexExternalSemaSource::AddSource(ExternalSemaSource *Source) { - Source->Retain(); - Sources.push_back(Source); +void MultiplexExternalSemaSource::AddSource( + llvm::IntrusiveRefCntPtr<ExternalSemaSource> Source) { + Sources.push_back(std::move(Source)); } //===----------------------------------------------------------------------===// @@ -92,7 +85,7 @@ CXXBaseSpecifier *MultiplexExternalSemaSource::GetExternalCXXBaseSpecifiers( CXXCtorInitializer ** MultiplexExternalSemaSource::GetExternalCXXCtorInitializers(uint64_t Offset) { - for (auto *S : Sources) + for (auto &S : Sources) if (auto *R = S->GetExternalCXXCtorInitializers(Offset)) return R; return nullptr; @@ -371,6 +364,6 @@ bool MultiplexExternalSemaSource::MaybeDiagnoseMissingCompleteType( void MultiplexExternalSemaSource::AssignedLambdaNumbering( CXXRecordDecl *Lambda) { - for (auto *Source : Sources) + for (auto &Source : Sources) Source->AssignedLambdaNumbering(Lambda); } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 43a7f9e..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()); } @@ -656,18 +654,19 @@ ASTMutationListener *Sema::getASTMutationListener() const { return getASTConsumer().GetASTMutationListener(); } -void Sema::addExternalSource(ExternalSemaSource *E) { +void Sema::addExternalSource(IntrusiveRefCntPtr<ExternalSemaSource> E) { assert(E && "Cannot use with NULL ptr"); if (!ExternalSource) { - ExternalSource = E; + ExternalSource = std::move(E); return; } - if (auto *Ex = dyn_cast<MultiplexExternalSemaSource>(ExternalSource)) - Ex->AddSource(E); + if (auto *Ex = dyn_cast<MultiplexExternalSemaSource>(ExternalSource.get())) + Ex->AddSource(std::move(E)); else - ExternalSource = new MultiplexExternalSemaSource(ExternalSource.get(), E); + ExternalSource = llvm::makeIntrusiveRefCnt<MultiplexExternalSemaSource>( + ExternalSource, std::move(E)); } void Sema::PrintStats() const { diff --git a/clang/lib/Sema/SemaAMDGPU.cpp b/clang/lib/Sema/SemaAMDGPU.cpp index 8580de2..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: @@ -93,8 +93,13 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f32_fp8: case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f32_bf8: case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f32_fp4: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f16_fp6: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_bf16_fp6: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f16_bf6: + case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_bf16_bf6: + 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 20fdf2d..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)) @@ -5255,8 +5254,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, if (getLangOpts().CPlusPlus && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) if (EnumDecl *Enum = dyn_cast_or_null<EnumDecl>(Tag)) - if (Enum->enumerator_begin() == Enum->enumerator_end() && - !Enum->getIdentifier() && !Enum->isInvalidDecl()) + if (Enum->enumerators().empty() && !Enum->getIdentifier() && + !Enum->isInvalidDecl()) DeclaresAnything = false; if (!DS.isMissingDeclaratorOk()) { @@ -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()); @@ -14724,7 +14720,6 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { type->isIntegralOrEnumerationType()) { // In C++98, in-class initialization for a static data member must // be an integer constant expression. - // SourceLocation Loc; if (!Init->isIntegerConstantExpr(Context)) { Diag(Init->getExprLoc(), diag::ext_in_class_initializer_non_constant) @@ -20599,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/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 16b18bc..f5f18b0 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7441,6 +7441,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_HLSLVkConstantId: S.HLSL().handleVkConstantIdAttr(D, AL); break; + case ParsedAttr::AT_HLSLVkBinding: + S.HLSL().handleVkBindingAttr(D, AL); + break; case ParsedAttr::AT_HLSLSV_GroupThreadID: S.HLSL().handleSV_GroupThreadIDAttr(D, AL); break; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 45c7178..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."); } @@ -6523,8 +6524,7 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, // Diagnose uses of the C++20 "ADL-only template-id call" feature in earlier // language modes. if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(Fn); - ULE && ULE->hasExplicitTemplateArgs() && - ULE->decls_begin() == ULE->decls_end()) { + ULE && ULE->hasExplicitTemplateArgs() && ULE->decls().empty()) { DiagCompat(Fn->getExprLoc(), diag_compat::adl_only_template_id) << ULE->getName(); } diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 9276554..8536e04 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Frontend/HLSL/HLSLBinding.h" #include "llvm/Frontend/HLSL/RootSignatureValidations.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DXILABI.h" @@ -596,8 +597,9 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) { // create buffer layout struct createHostLayoutStructForBuffer(SemaRef, BufDecl); + HLSLVkBindingAttr *VkBinding = Dcl->getAttr<HLSLVkBindingAttr>(); HLSLResourceBindingAttr *RBA = Dcl->getAttr<HLSLResourceBindingAttr>(); - if (!RBA || !RBA->hasRegisterSlot()) { + if (!VkBinding && (!RBA || !RBA->hasRegisterSlot())) { SemaRef.Diag(Dcl->getLocation(), diag::warn_hlsl_implicit_binding); // Use HLSLResourceBindingAttr to transfer implicit binding order_ID // to codegen. If it does not exist, create an implicit attribute. @@ -1083,6 +1085,102 @@ void SemaHLSL::ActOnFinishRootSignatureDecl( SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope()); } +namespace { + +struct PerVisibilityBindingChecker { + SemaHLSL *S; + // We need one builder per `llvm::dxbc::ShaderVisibility` value. + std::array<llvm::hlsl::BindingInfoBuilder, 8> Builders; + + struct ElemInfo { + const hlsl::RootSignatureElement *Elem; + llvm::dxbc::ShaderVisibility Vis; + bool Diagnosed; + }; + llvm::SmallVector<ElemInfo> ElemInfoMap; + + PerVisibilityBindingChecker(SemaHLSL *S) : S(S) {} + + void trackBinding(llvm::dxbc::ShaderVisibility Visibility, + llvm::dxil::ResourceClass RC, uint32_t Space, + uint32_t LowerBound, uint32_t UpperBound, + const hlsl::RootSignatureElement *Elem) { + uint32_t BuilderIndex = llvm::to_underlying(Visibility); + assert(BuilderIndex < Builders.size() && + "Not enough builders for visibility type"); + Builders[BuilderIndex].trackBinding(RC, Space, LowerBound, UpperBound, + static_cast<const void *>(Elem)); + + static_assert(llvm::to_underlying(llvm::dxbc::ShaderVisibility::All) == 0, + "'All' visibility must come first"); + if (Visibility == llvm::dxbc::ShaderVisibility::All) + for (size_t I = 1, E = Builders.size(); I < E; ++I) + Builders[I].trackBinding(RC, Space, LowerBound, UpperBound, + static_cast<const void *>(Elem)); + + ElemInfoMap.push_back({Elem, Visibility, false}); + } + + ElemInfo &getInfo(const hlsl::RootSignatureElement *Elem) { + auto It = llvm::lower_bound( + ElemInfoMap, Elem, + [](const auto &LHS, const auto &RHS) { return LHS.Elem < RHS; }); + assert(It->Elem == Elem && "Element not in map"); + return *It; + } + + bool checkOverlap() { + llvm::sort(ElemInfoMap, [](const auto &LHS, const auto &RHS) { + return LHS.Elem < RHS.Elem; + }); + + bool HadOverlap = false; + + using llvm::hlsl::BindingInfoBuilder; + auto ReportOverlap = [this, &HadOverlap]( + const BindingInfoBuilder &Builder, + const BindingInfoBuilder::Binding &Reported) { + HadOverlap = true; + + const auto *Elem = + static_cast<const hlsl::RootSignatureElement *>(Reported.Cookie); + const BindingInfoBuilder::Binding &Previous = + Builder.findOverlapping(Reported); + const auto *PrevElem = + static_cast<const hlsl::RootSignatureElement *>(Previous.Cookie); + + ElemInfo &Info = getInfo(Elem); + // We will have already diagnosed this binding if there's overlap in the + // "All" visibility as well as any particular visibility. + if (Info.Diagnosed) + return; + Info.Diagnosed = true; + + ElemInfo &PrevInfo = getInfo(PrevElem); + llvm::dxbc::ShaderVisibility CommonVis = + Info.Vis == llvm::dxbc::ShaderVisibility::All ? PrevInfo.Vis + : Info.Vis; + + this->S->Diag(Elem->getLocation(), diag::err_hlsl_resource_range_overlap) + << llvm::to_underlying(Reported.RC) << Reported.LowerBound + << Reported.isUnbounded() << Reported.UpperBound + << llvm::to_underlying(Previous.RC) << Previous.LowerBound + << Previous.isUnbounded() << Previous.UpperBound << Reported.Space + << CommonVis; + + this->S->Diag(PrevElem->getLocation(), + diag::note_hlsl_resource_range_here); + }; + + for (BindingInfoBuilder &Builder : Builders) + Builder.calculateBindingInfo(ReportOverlap); + + return HadOverlap; + } +}; + +} // end anonymous namespace + bool SemaHLSL::handleRootSignatureElements( ArrayRef<hlsl::RootSignatureElement> Elements) { // Define some common error handling functions @@ -1171,147 +1269,67 @@ bool SemaHLSL::handleRootSignatureElements( } } - using RangeInfo = llvm::hlsl::rootsig::RangeInfo; - using OverlappingRanges = llvm::hlsl::rootsig::OverlappingRanges; - using InfoPairT = std::pair<RangeInfo, const hlsl::RootSignatureElement *>; + PerVisibilityBindingChecker BindingChecker(this); + SmallVector<std::pair<const llvm::hlsl::rootsig::DescriptorTableClause *, + const hlsl::RootSignatureElement *>> + UnboundClauses; - // 1. Collect RangeInfos - llvm::SmallVector<InfoPairT> InfoPairs; for (const hlsl::RootSignatureElement &RootSigElem : Elements) { const llvm::hlsl::rootsig::RootElement &Elem = RootSigElem.getElement(); if (const auto *Descriptor = std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) { - RangeInfo Info; - Info.LowerBound = Descriptor->Reg.Number; - Info.UpperBound = Info.LowerBound; // use inclusive ranges [] + uint32_t LowerBound(Descriptor->Reg.Number); + uint32_t UpperBound(LowerBound); // inclusive range - Info.Class = - llvm::dxil::ResourceClass(llvm::to_underlying(Descriptor->Type)); - Info.Space = Descriptor->Space; - Info.Visibility = Descriptor->Visibility; - - InfoPairs.push_back({Info, &RootSigElem}); + BindingChecker.trackBinding( + Descriptor->Visibility, + static_cast<llvm::dxil::ResourceClass>(Descriptor->Type), + Descriptor->Space, LowerBound, UpperBound, &RootSigElem); } else if (const auto *Constants = std::get_if<llvm::hlsl::rootsig::RootConstants>(&Elem)) { - RangeInfo Info; - Info.LowerBound = Constants->Reg.Number; - Info.UpperBound = Info.LowerBound; // use inclusive ranges [] - - Info.Class = llvm::dxil::ResourceClass::CBuffer; - Info.Space = Constants->Space; - Info.Visibility = Constants->Visibility; + uint32_t LowerBound(Constants->Reg.Number); + uint32_t UpperBound(LowerBound); // inclusive range - InfoPairs.push_back({Info, &RootSigElem}); + BindingChecker.trackBinding( + Constants->Visibility, llvm::dxil::ResourceClass::CBuffer, + Constants->Space, LowerBound, UpperBound, &RootSigElem); } else if (const auto *Sampler = std::get_if<llvm::hlsl::rootsig::StaticSampler>(&Elem)) { - RangeInfo Info; - Info.LowerBound = Sampler->Reg.Number; - Info.UpperBound = Info.LowerBound; // use inclusive ranges [] + uint32_t LowerBound(Sampler->Reg.Number); + uint32_t UpperBound(LowerBound); // inclusive range - Info.Class = llvm::dxil::ResourceClass::Sampler; - Info.Space = Sampler->Space; - Info.Visibility = Sampler->Visibility; - - InfoPairs.push_back({Info, &RootSigElem}); + BindingChecker.trackBinding( + Sampler->Visibility, llvm::dxil::ResourceClass::Sampler, + Sampler->Space, LowerBound, UpperBound, &RootSigElem); } else if (const auto *Clause = std::get_if<llvm::hlsl::rootsig::DescriptorTableClause>( &Elem)) { - RangeInfo Info; - Info.LowerBound = Clause->Reg.Number; - // Relevant error will have already been reported above and needs to be - // fixed before we can conduct range analysis, so shortcut error return - if (Clause->NumDescriptors == 0) - return true; - Info.UpperBound = Clause->NumDescriptors == RangeInfo::Unbounded - ? RangeInfo::Unbounded - : Info.LowerBound + Clause->NumDescriptors - - 1; // use inclusive ranges [] - - Info.Class = Clause->Type; - Info.Space = Clause->Space; - - // Note: Clause does not hold the visibility this will need to - InfoPairs.push_back({Info, &RootSigElem}); + // We'll process these once we see the table element. + UnboundClauses.emplace_back(Clause, &RootSigElem); } else if (const auto *Table = std::get_if<llvm::hlsl::rootsig::DescriptorTable>(&Elem)) { - // Table holds the Visibility of all owned Clauses in Table, so iterate - // owned Clauses and update their corresponding RangeInfo - assert(Table->NumClauses <= InfoPairs.size() && "RootElement"); - // The last Table->NumClauses elements of Infos are the owned Clauses - // generated RangeInfo - auto TableInfos = - MutableArrayRef<InfoPairT>(InfoPairs).take_back(Table->NumClauses); - for (InfoPairT &Pair : TableInfos) - Pair.first.Visibility = Table->Visibility; - } - } - - // 2. Sort with the RangeInfo <operator to prepare it for findOverlapping - llvm::sort(InfoPairs, - [](InfoPairT A, InfoPairT B) { return A.first < B.first; }); - - llvm::SmallVector<RangeInfo> Infos; - for (const InfoPairT &Pair : InfoPairs) - Infos.push_back(Pair.first); - - // Helpers to report diagnostics - uint32_t DuplicateCounter = 0; - using ElemPair = std::pair<const hlsl::RootSignatureElement *, - const hlsl::RootSignatureElement *>; - auto GetElemPair = [&Infos, &InfoPairs, &DuplicateCounter]( - OverlappingRanges Overlap) -> ElemPair { - // Given we sorted the InfoPairs (and by implication) Infos, and, - // that Overlap.B is the item retrieved from the ResourceRange. Then it is - // guarenteed that Overlap.B <= Overlap.A. - // - // So we will find Overlap.B first and then continue to find Overlap.A - // after - auto InfoB = std::lower_bound(Infos.begin(), Infos.end(), *Overlap.B); - auto DistB = std::distance(Infos.begin(), InfoB); - auto PairB = InfoPairs.begin(); - std::advance(PairB, DistB); - - auto InfoA = std::lower_bound(InfoB, Infos.end(), *Overlap.A); - // Similarily, from the property that we have sorted the RangeInfos, - // all duplicates will be processed one after the other. So - // DuplicateCounter can be re-used for each set of duplicates we - // encounter as we handle incoming errors - DuplicateCounter = InfoA == InfoB ? DuplicateCounter + 1 : 0; - auto DistA = std::distance(InfoB, InfoA) + DuplicateCounter; - auto PairA = PairB; - std::advance(PairA, DistA); - - return {PairA->second, PairB->second}; - }; - - auto ReportOverlap = [this, &GetElemPair](OverlappingRanges Overlap) { - auto Pair = GetElemPair(Overlap); - const RangeInfo *Info = Overlap.A; - const hlsl::RootSignatureElement *Elem = Pair.first; - const RangeInfo *OInfo = Overlap.B; - - auto CommonVis = Info->Visibility == llvm::dxbc::ShaderVisibility::All - ? OInfo->Visibility - : Info->Visibility; - this->Diag(Elem->getLocation(), diag::err_hlsl_resource_range_overlap) - << llvm::to_underlying(Info->Class) << Info->LowerBound - << /*unbounded=*/(Info->UpperBound == RangeInfo::Unbounded) - << Info->UpperBound << llvm::to_underlying(OInfo->Class) - << OInfo->LowerBound - << /*unbounded=*/(OInfo->UpperBound == RangeInfo::Unbounded) - << OInfo->UpperBound << Info->Space << CommonVis; - - const hlsl::RootSignatureElement *OElem = Pair.second; - this->Diag(OElem->getLocation(), diag::note_hlsl_resource_range_here); - }; - - // 3. Invoke find overlapping ranges - llvm::SmallVector<OverlappingRanges> Overlaps = - llvm::hlsl::rootsig::findOverlappingRanges(Infos); - for (OverlappingRanges Overlap : Overlaps) - ReportOverlap(Overlap); + assert(UnboundClauses.size() == Table->NumClauses && + "Number of unbound elements must match the number of clauses"); + for (const auto &[Clause, ClauseElem] : UnboundClauses) { + uint32_t LowerBound(Clause->Reg.Number); + // Relevant error will have already been reported above and needs to be + // fixed before we can conduct range analysis, so shortcut error return + if (Clause->NumDescriptors == 0) + return true; + uint32_t UpperBound = Clause->NumDescriptors == ~0u + ? ~0u + : LowerBound + Clause->NumDescriptors - 1; + + BindingChecker.trackBinding( + Table->Visibility, + static_cast<llvm::dxil::ResourceClass>(Clause->Type), Clause->Space, + LowerBound, UpperBound, ClauseElem); + } + UnboundClauses.clear(); + } + } - return Overlaps.size() != 0; + return BindingChecker.checkOverlap(); } void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) { @@ -1479,6 +1497,23 @@ void SemaHLSL::handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL) { D->addAttr(NewAttr); } +void SemaHLSL::handleVkBindingAttr(Decl *D, const ParsedAttr &AL) { + // The vk::binding attribute only applies to SPIR-V. + if (!getASTContext().getTargetInfo().getTriple().isSPIRV()) + return; + + uint32_t Binding = 0; + if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Binding)) + return; + uint32_t Set = 0; + if (AL.getNumArgs() > 1 && + !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Set)) + return; + + D->addAttr(::new (getASTContext()) + HLSLVkBindingAttr(getASTContext(), AL, Binding, Set)); +} + bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) { const auto *VT = T->getAs<VectorType>(); @@ -3643,8 +3678,12 @@ static bool initVarDeclWithCtor(Sema &S, VarDecl *VD, bool SemaHLSL::initGlobalResourceDecl(VarDecl *VD) { std::optional<uint32_t> RegisterSlot; uint32_t SpaceNo = 0; + HLSLVkBindingAttr *VkBinding = VD->getAttr<HLSLVkBindingAttr>(); HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>(); - if (RBA) { + if (VkBinding) { + RegisterSlot = VkBinding->getBinding(); + SpaceNo = VkBinding->getSet(); + } else if (RBA) { if (RBA->hasRegisterSlot()) RegisterSlot = RBA->getSlotNumber(); SpaceNo = RBA->getSpaceNumber(); @@ -3747,6 +3786,9 @@ void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) { bool HasBinding = false; for (Attr *A : VD->attrs()) { + if (isa<HLSLVkBindingAttr>(A)) + HasBinding = true; + HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A); if (!RBA || !RBA->hasRegisterSlot()) continue; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 1c6f292..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: @@ -4836,7 +4836,7 @@ static void TryReferenceListInitialization(Sema &S, } // Update the initializer if we've resolved an overloaded function. - if (Sequence.step_begin() != Sequence.step_end()) + if (!Sequence.steps().empty()) Sequence.RewrapReferenceInitList(cv1T1, InitList); } // Perform address space compatibility check. diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 8bde18f..dc73ded 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3130,7 +3130,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, CollectEnclosingNamespace(Result.Namespaces, BaseCtx); // Make sure we visit the bases of this base class. - if (BaseDecl->bases_begin() != BaseDecl->bases_end()) + if (!BaseDecl->bases().empty()) Bases.push_back(BaseDecl); } } diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index b137549..ff9f85f 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -1222,7 +1222,8 @@ bool ExposureChecker::isTULocal(const NamedDecl *D) { // [basic.link]p15.5 // - a specialization of a template whose (possibly instantiated) declaration // is an exposure. - if (checkExposure(PrimaryTemplate, /*Diag=*/false)) + if (ExposureSet.count(PrimaryTemplate) || + checkExposure(PrimaryTemplate, /*Diag=*/false)) return true; // Avoid calling checkExposure again since it is expensive. diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 8bfea62..62fe3d1 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" @@ -629,7 +630,7 @@ namespace { // private, firstprivate, and reduction, which require certain operators to be // available. ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind CK, Expr *VarExpr, - Expr *InnerExpr) { + SourceLocation InnerLoc, QualType InnerTy) { // There is nothing to do here, only these three have these sorts of // restrictions. if (CK != OpenACCClauseKind::Private && @@ -638,50 +639,71 @@ ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind CK, Expr *VarExpr, return VarExpr; // We can't test this if it isn't here, or if the type isn't clear yet. - if (!InnerExpr || InnerExpr->isTypeDependent()) + if (InnerTy.isNull() || InnerTy->isDependentType()) return VarExpr; - const auto *RD = InnerExpr->getType()->getAsCXXRecordDecl(); + InnerTy = InnerTy.getUnqualifiedType(); + if (auto *RefTy = InnerTy->getAs<ReferenceType>()) + InnerTy = RefTy->getPointeeType(); + + if (auto *ArrTy = InnerTy->getAsArrayTypeUnsafe()) + return CheckVarType(S, CK, VarExpr, InnerLoc, ArrTy->getElementType()); + + auto *RD = InnerTy->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) { return CD->isDefaultConstructor() && !CD->isDeleted(); }) != RD->ctors().end(); if (!HasNonDeletedDefaultCtor && !RD->needsImplicitDefaultConstructor()) { - S.Diag(InnerExpr->getBeginLoc(), - clang::diag::warn_acc_var_referenced_lacks_op) - << InnerExpr->getType() << CK - << clang::diag::AccVarReferencedReason::DefCtor; + S.Diag(InnerLoc, clang::diag::warn_acc_var_referenced_lacks_op) + << InnerTy << CK << 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(InnerLoc, clang::diag::warn_acc_var_referenced_lacks_op) + << InnerTy << CK << clang::diag::AccVarReferencedReason::CopyCtor; + return ExprError(); + } + } + } else if (CK == OpenACCClauseKind::Reduction) { + // TODO: OpenACC: + // Reduction must have copyctor + dtor + operation in InnerTy I think? + // Need to confirm when implementing this part. } // All 3 things need to make sure they have a dtor. bool DestructorDeleted = RD->getDestructor() && RD->getDestructor()->isDeleted(); if (DestructorDeleted && !RD->needsImplicitDestructor()) { - S.Diag(InnerExpr->getBeginLoc(), - clang::diag::warn_acc_var_referenced_lacks_op) - << InnerExpr->getType() << CK - << clang::diag::AccVarReferencedReason::Dtor; + S.Diag(InnerLoc, clang::diag::warn_acc_var_referenced_lacks_op) + << InnerTy << CK << clang::diag::AccVarReferencedReason::Dtor; return ExprError(); } return VarExpr; } + +ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind CK, Expr *VarExpr, + Expr *InnerExpr) { + if (!InnerExpr) + return VarExpr; + return CheckVarType(S, CK, VarExpr, InnerExpr->getBeginLoc(), + InnerExpr->getType()); +} } // namespace ExprResult SemaOpenACC::ActOnVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK, @@ -2552,3 +2574,57 @@ ExprResult SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) { return BuildOpenACCAsteriskSizeExpr(AsteriskLoc); } + +VarDecl *SemaOpenACC::CreateInitRecipe(OpenACCClauseKind CK, + 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; + + if (CK == OpenACCClauseKind::Private) { + // 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, {}); + } else if (CK == OpenACCClauseKind::FirstPrivate) { + // TODO: OpenACC: Implement this to do a 'copy' operation. + } else if (CK == OpenACCClauseKind::Reduction) { + // TODO: OpenACC: Implement this for whatever reduction needs. + } else { + llvm_unreachable("Unknown clause kind in CreateInitRecipe"); + } + + 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..88d217f 100644 --- a/clang/lib/Sema/SemaOpenACCClause.cpp +++ b/clang/lib/Sema/SemaOpenACCClause.cpp @@ -795,9 +795,16 @@ 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(OpenACCClauseKind::Private, VarExpr)); + + return OpenACCPrivateClause::Create( + Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), + InitRecipes, Clause.getEndLoc()); } OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause( @@ -806,9 +813,16 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause( // really isn't anything to do here. GCC does some duplicate-finding, though // it isn't apparent in the standard where this is justified. + llvm::SmallVector<VarDecl *> InitRecipes; + + // Assemble the recipes list. + for (const Expr *VarExpr : Clause.getVarList()) + InitRecipes.push_back( + SemaRef.CreateInitRecipe(OpenACCClauseKind::FirstPrivate, VarExpr)); + return OpenACCFirstPrivateClause::Create( Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), - Clause.getEndLoc()); + InitRecipes, Clause.getEndLoc()); } OpenACCClause *SemaOpenACCClauseVisitor::VisitNoCreateClause( 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 572dbf2..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; @@ -1387,7 +1397,8 @@ static void CheckFoldOperand(Sema &S, Expr *E) { S.Diag(E->getExprLoc(), diag::err_fold_expression_bad_operand) << E->getSourceRange() << FixItHint::CreateInsertion(E->getBeginLoc(), "(") - << FixItHint::CreateInsertion(E->getEndLoc(), ")"); + << FixItHint::CreateInsertion(S.getLocForEndOfToken(E->getEndLoc()), + ")"); } } 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/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index c2f0600..1d8687e 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -11,7 +11,9 @@ //===----------------------------------------------------------------------===// #include "clang/AST/DeclCXX.h" +#include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" +#include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/DiagnosticParse.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/TypeTraits.h" @@ -1963,6 +1965,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) { .Case("is_assignable", TypeTrait::BTT_IsAssignable) .Case("is_empty", TypeTrait::UTT_IsEmpty) .Case("is_standard_layout", TypeTrait::UTT_IsStandardLayout) + .Case("is_constructible", TypeTrait::TT_IsConstructible) .Default(std::nullopt); } @@ -1999,8 +2002,16 @@ static ExtractedTypeTraitInfo ExtractTypeTraitFromExpression(const Expr *E) { Trait = StdNameToTypeTrait(Name); if (!Trait) return std::nullopt; - for (const auto &Arg : VD->getTemplateArgs().asArray()) - Args.push_back(Arg.getAsType()); + for (const auto &Arg : VD->getTemplateArgs().asArray()) { + if (Arg.getKind() == TemplateArgument::ArgKind::Pack) { + for (const auto &InnerArg : Arg.pack_elements()) + Args.push_back(InnerArg.getAsType()); + } else if (Arg.getKind() == TemplateArgument::ArgKind::Type) { + Args.push_back(Arg.getAsType()); + } else { + llvm_unreachable("Unexpected kind"); + } + } return {{Trait.value(), std::move(Args)}}; } @@ -2273,6 +2284,60 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef, } } +static void DiagnoseNonConstructibleReason( + Sema &SemaRef, SourceLocation Loc, + const llvm::SmallVector<clang::QualType, 1> &Ts) { + if (Ts.empty()) { + return; + } + + bool ContainsVoid = false; + for (const QualType &ArgTy : Ts) { + ContainsVoid |= ArgTy->isVoidType(); + } + + if (ContainsVoid) + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::CVVoidType; + + QualType T = Ts[0]; + if (T->isFunctionType()) + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::FunctionType; + + if (T->isIncompleteArrayType()) + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::IncompleteArrayType; + + const CXXRecordDecl *D = T->getAsCXXRecordDecl(); + if (!D || D->isInvalidDecl() || !D->hasDefinition()) + return; + + llvm::BumpPtrAllocator OpaqueExprAllocator; + SmallVector<Expr *, 2> ArgExprs; + ArgExprs.reserve(Ts.size() - 1); + for (unsigned I = 1, N = Ts.size(); I != N; ++I) { + QualType ArgTy = Ts[I]; + if (ArgTy->isObjectType() || ArgTy->isFunctionType()) + ArgTy = SemaRef.Context.getRValueReferenceType(ArgTy); + ArgExprs.push_back( + new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>()) + OpaqueValueExpr(Loc, ArgTy.getNonLValueExprType(SemaRef.Context), + Expr::getValueKindForType(ArgTy))); + } + + EnterExpressionEvaluationContext Unevaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::ContextRAII TUContext(SemaRef, + SemaRef.Context.getTranslationUnitDecl()); + InitializedEntity To(InitializedEntity::InitializeTemporary(T)); + InitializationKind InitKind(InitializationKind::CreateDirect(Loc, Loc, Loc)); + InitializationSequence Init(SemaRef, To, InitKind, ArgExprs); + + Init.Diagnose(SemaRef, To, InitKind, ArgExprs); + SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D; +} + static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef, SourceLocation Loc, QualType T) { SemaRef.Diag(Loc, diag::note_unsatisfied_trait) @@ -2559,6 +2624,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) { case UTT_IsStandardLayout: DiagnoseNonStandardLayoutReason(*this, E->getBeginLoc(), Args[0]); break; + case TT_IsConstructible: + DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args); + break; default: break; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index c7428d1..6ce5535 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( + OpenACCClauseKind::Private, 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()); } @@ -11906,12 +11941,31 @@ void OpenACCClauseTransform<Derived>::VisitDeviceClause( template <typename Derived> void OpenACCClauseTransform<Derived>::VisitFirstPrivateClause( const OpenACCFirstPrivateClause &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( + OpenACCClauseKind::FirstPrivate, VarRef.get())); + } + } + ParsedClause.setVarListDetails(InstantiatedVarList, OpenACCModifierKind::Invalid); NewClause = OpenACCFirstPrivateClause::Create( Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), - ParsedClause.getLParenLoc(), ParsedClause.getVarList(), + ParsedClause.getLParenLoc(), ParsedClause.getVarList(), InitRecipes, ParsedClause.getEndLoc()); } |