//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// // // This file implements semantic analysis for C++ templates. //===----------------------------------------------------------------------===// #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TemplateName.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include #include using namespace clang; using namespace sema; // Exported for use by Parser. SourceRange clang::getTemplateParamsRange(TemplateParameterList const * const *Ps, unsigned N) { if (!N) return SourceRange(); return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); } unsigned Sema::getTemplateDepth(Scope *S) const { unsigned Depth = 0; // Each template parameter scope represents one level of template parameter // depth. for (Scope *TempParamScope = S->getTemplateParamParent(); TempParamScope; TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) { ++Depth; } // Note that there are template parameters with the given depth. auto ParamsAtDepth = [&](unsigned D) { Depth = std::max(Depth, D + 1); }; // Look for parameters of an enclosing generic lambda. We don't create a // template parameter scope for these. for (FunctionScopeInfo *FSI : getFunctionScopes()) { if (auto *LSI = dyn_cast(FSI)) { if (!LSI->TemplateParams.empty()) { ParamsAtDepth(LSI->AutoTemplateParameterDepth); break; } if (LSI->GLTemplateParameterList) { ParamsAtDepth(LSI->GLTemplateParameterList->getDepth()); break; } } } // Look for parameters of an enclosing terse function template. We don't // create a template parameter scope for these either. for (const InventedTemplateParameterInfo &Info : getInventedParameterInfos()) { if (!Info.TemplateParams.empty()) { ParamsAtDepth(Info.AutoTemplateParameterDepth); break; } } return Depth; } /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. /// /// Note that this may return an UnresolvedUsingValueDecl if AllowDependent /// is true. In all other cases it will return a TemplateDecl (or null). NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D, bool AllowFunctionTemplates, bool AllowDependent) { D = D->getUnderlyingDecl(); if (isa(D)) { if (!AllowFunctionTemplates && isa(D)) return nullptr; return D; } if (const auto *Record = dyn_cast(D)) { // C++ [temp.local]p1: // Like normal (non-template) classes, class templates have an // injected-class-name (Clause 9). The injected-class-name // can be used with or without a template-argument-list. When // it is used without a template-argument-list, it is // equivalent to the injected-class-name followed by the // template-parameters of the class template enclosed in // <>. When it is used with a template-argument-list, it // refers to the specified class template specialization, // which could be the current specialization or another // specialization. if (Record->isInjectedClassName()) { Record = cast(Record->getDeclContext()); if (Record->getDescribedClassTemplate()) return Record->getDescribedClassTemplate(); if (const auto *Spec = dyn_cast(Record)) return Spec->getSpecializedTemplate(); } return nullptr; } // 'using Dependent::foo;' can resolve to a template name. // 'using typename Dependent::foo;' cannot (not even if 'foo' is an // injected-class-name). if (AllowDependent && isa(D)) return D; return nullptr; } void Sema::FilterAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates, bool AllowDependent) { LookupResult::Filter filter = R.makeFilter(); while (filter.hasNext()) { NamedDecl *Orig = filter.next(); if (!getAsTemplateNameDecl(Orig, AllowFunctionTemplates, AllowDependent)) filter.erase(); } filter.done(); } bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates, bool AllowDependent, bool AllowNonTemplateFunctions) { for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) { if (getAsTemplateNameDecl(*I, AllowFunctionTemplates, AllowDependent)) return true; if (AllowNonTemplateFunctions && isa((*I)->getUnderlyingDecl())) return true; } return false; } TemplateNameKind Sema::isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, const UnqualifiedId &Name, ParsedType ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult, bool &MemberOfUnknownSpecialization, bool Disambiguation) { assert(getLangOpts().CPlusPlus && "No template names in C!"); DeclarationName TName; MemberOfUnknownSpecialization = false; switch (Name.getKind()) { case UnqualifiedIdKind::IK_Identifier: TName = DeclarationName(Name.Identifier); break; case UnqualifiedIdKind::IK_OperatorFunctionId: TName = Context.DeclarationNames.getCXXOperatorName( Name.OperatorFunctionId.Operator); break; case UnqualifiedIdKind::IK_LiteralOperatorId: TName = Context.DeclarationNames.getCXXLiteralOperatorName(Name.Identifier); break; default: return TNK_Non_template; } QualType ObjectType = ObjectTypePtr.get(); AssumedTemplateKind AssumedTemplate; LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName); if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, MemberOfUnknownSpecialization, SourceLocation(), &AssumedTemplate, /*AllowTypoCorrection=*/!Disambiguation)) return TNK_Non_template; if (AssumedTemplate != AssumedTemplateKind::None) { TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName)); // Let the parser know whether we found nothing or found functions; if we // found nothing, we want to more carefully check whether this is actually // a function template name versus some other kind of undeclared identifier. return AssumedTemplate == AssumedTemplateKind::FoundNothing ? TNK_Undeclared_template : TNK_Function_template; } if (R.empty()) return TNK_Non_template; NamedDecl *D = nullptr; UsingShadowDecl *FoundUsingShadow = dyn_cast(*R.begin()); if (R.isAmbiguous()) { // If we got an ambiguity involving a non-function template, treat this // as a template name, and pick an arbitrary template for error recovery. bool AnyFunctionTemplates = false; for (NamedDecl *FoundD : R) { if (NamedDecl *FoundTemplate = getAsTemplateNameDecl(FoundD)) { if (isa(FoundTemplate)) AnyFunctionTemplates = true; else { D = FoundTemplate; FoundUsingShadow = dyn_cast(FoundD); break; } } } // If we didn't find any templates at all, this isn't a template name. // Leave the ambiguity for a later lookup to diagnose. if (!D && !AnyFunctionTemplates) { R.suppressDiagnostics(); return TNK_Non_template; } // If the only templates were function templates, filter out the rest. // We'll diagnose the ambiguity later. if (!D) FilterAcceptableTemplateNames(R); } // At this point, we have either picked a single template name declaration D // or we have a non-empty set of results R containing either one template name // declaration or a set of function templates. TemplateName Template; TemplateNameKind TemplateKind; unsigned ResultCount = R.end() - R.begin(); if (!D && ResultCount > 1) { // We assume that we'll preserve the qualifier from a function // template name in other ways. Template = Context.getOverloadedTemplateName(R.begin(), R.end()); TemplateKind = TNK_Function_template; // We'll do this lookup again later. R.suppressDiagnostics(); } else { if (!D) { D = getAsTemplateNameDecl(*R.begin()); assert(D && "unambiguous result is not a template name"); } if (isa(D)) { // We don't yet know whether this is a template-name or not. MemberOfUnknownSpecialization = true; return TNK_Non_template; } TemplateDecl *TD = cast(D); Template = FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD); assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD); if (SS.isSet() && !SS.isInvalid()) { NestedNameSpecifier *Qualifier = SS.getScopeRep(); Template = Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword, Template); } if (isa(TD)) { TemplateKind = TNK_Function_template; // We'll do this lookup again later. R.suppressDiagnostics(); } else { assert(isa(TD) || isa(TD) || isa(TD) || isa(TD) || isa(TD) || isa(TD)); TemplateKind = isa(TD) ? TNK_Var_template : isa(TD) ? TNK_Concept_template : TNK_Type_template; } } TemplateResult = TemplateTy::make(Template); return TemplateKind; } bool Sema::isDeductionGuideName(Scope *S, const IdentifierInfo &Name, SourceLocation NameLoc, CXXScopeSpec &SS, ParsedTemplateTy *Template /*=nullptr*/) { bool MemberOfUnknownSpecialization = false; // We could use redeclaration lookup here, but we don't need to: the // syntactic form of a deduction guide is enough to identify it even // if we can't look up the template name at all. LookupResult R(*this, DeclarationName(&Name), NameLoc, LookupOrdinaryName); if (LookupTemplateName(R, S, SS, /*ObjectType*/ QualType(), /*EnteringContext*/ false, MemberOfUnknownSpecialization)) return false; if (R.empty()) return false; if (R.isAmbiguous()) { // FIXME: Diagnose an ambiguity if we find at least one template. R.suppressDiagnostics(); return false; } // We only treat template-names that name type templates as valid deduction // guide names. TemplateDecl *TD = R.getAsSingle(); if (!TD || !getAsTypeTemplateDecl(TD)) return false; if (Template) *Template = TemplateTy::make(TemplateName(TD)); return true; } bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, TemplateTy &SuggestedTemplate, TemplateNameKind &SuggestedKind) { // We can't recover unless there's a dependent scope specifier preceding the // template name. // FIXME: Typo correction? if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) || computeDeclContext(*SS)) return false; // The code is missing a 'template' keyword prior to the dependent template // name. NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep(); Diag(IILoc, diag::err_template_kw_missing) << Qualifier << II.getName() << FixItHint::CreateInsertion(IILoc, "template "); SuggestedTemplate = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II)); SuggestedKind = TNK_Dependent_template_name; return true; } bool Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization, RequiredTemplateKind RequiredTemplate, AssumedTemplateKind *ATK, bool AllowTypoCorrection) { if (ATK) *ATK = AssumedTemplateKind::None; if (SS.isInvalid()) return true; Found.setTemplateNameLookup(true); // Determine where to perform name lookup MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = nullptr; bool IsDependent = false; if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. assert(SS.isEmpty() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); IsDependent = !LookupCtx && ObjectType->isDependentType(); assert((IsDependent || !ObjectType->isIncompleteType() || !ObjectType->getAs() || ObjectType->castAs()->isBeingDefined()) && "Caller should have completed object type"); // Template names cannot appear inside an Objective-C class or object type // or a vector type. // // FIXME: This is wrong. For example: // // template using Vec = T __attribute__((ext_vector_type(4))); // Vec vi; // vi.Vec::~Vec(); // // ... should be accepted but we will not treat 'Vec' as a template name // here. The right thing to do would be to check if the name is a valid // vector component name, and look up a template name if not. And similarly // for lookups into Objective-C class and object types, where the same // problem can arise. if (ObjectType->isObjCObjectOrInterfaceType() || ObjectType->isVectorType()) { Found.clear(); return false; } } else if (SS.isNotEmpty()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); IsDependent = !LookupCtx && isDependentScopeSpecifier(SS); // The declaration context must be complete. if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) return true; } bool ObjectTypeSearchedInScope = false; bool AllowFunctionTemplatesInLookup = true; if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. LookupQualifiedName(Found, LookupCtx); // FIXME: The C++ standard does not clearly specify what happens in the // case where the object type is dependent, and implementations vary. In // Clang, we treat a name after a . or -> as a template-name if lookup // finds a non-dependent member or member of the current instantiation that // is a type template, or finds no such members and lookup in the context // of the postfix-expression finds a type template. In the latter case, the // name is nonetheless dependent, and we may resolve it to a member of an // unknown specialization when we come to instantiate the template. IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } if (SS.isEmpty() && (ObjectType.isNull() || Found.empty())) { // C++ [basic.lookup.classref]p1: // In a class member access expression (5.2.5), if the . or -> token is // immediately followed by an identifier followed by a <, the // identifier must be looked up to determine whether the < is the // beginning of a template argument list (14.2) or a less-than operator. // The identifier is first looked up in the class of the object // expression. If the identifier is not found, it is then looked up in // the context of the entire postfix-expression and shall name a class // template. if (S) LookupName(Found, S); if (!ObjectType.isNull()) { // FIXME: We should filter out all non-type templates here, particularly // variable templates and concepts. But the exclusion of alias templates // and template template parameters is a wording defect. AllowFunctionTemplatesInLookup = false; ObjectTypeSearchedInScope = true; } IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } if (Found.isAmbiguous()) return false; if (ATK && SS.isEmpty() && ObjectType.isNull() && !RequiredTemplate.hasTemplateKeyword()) { // C++2a [temp.names]p2: // A name is also considered to refer to a template if it is an // unqualified-id followed by a < and name lookup finds either one or more // functions or finds nothing. // // To keep our behavior consistent, we apply the "finds nothing" part in // all language modes, and diagnose the empty lookup in ActOnCallExpr if we // successfully form a call to an undeclared template-id. bool AllFunctions = getLangOpts().CPlusPlus20 && llvm::all_of(Found, [](NamedDecl *ND) { return isa(ND->getUnderlyingDecl()); }); if (AllFunctions || (Found.empty() && !IsDependent)) { // If lookup found any functions, or if this is a name that can only be // used for a function, then strongly assume this is a function // template-id. *ATK = (Found.empty() && Found.getLookupName().isIdentifier()) ? AssumedTemplateKind::FoundNothing : AssumedTemplateKind::FoundFunctions; Found.clear(); return false; } } if (Found.empty() && !IsDependent && AllowTypoCorrection) { // If we did not find any names, and this is not a disambiguation, attempt // to correct any typos. DeclarationName Name = Found.getLookupName(); Found.clear(); // Simple filter callback that, for keywords, only accepts the C++ *_cast DefaultFilterCCC FilterCCC{}; FilterCCC.WantTypeSpecifiers = false; FilterCCC.WantExpressionKeywords = false; FilterCCC.WantRemainingKeywords = false; FilterCCC.WantCXXNamedCasts = true; if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, FilterCCC, CTK_ErrorRecovery, LookupCtx)) { if (auto *ND = Corrected.getFoundDecl()) Found.addDecl(ND); FilterAcceptableTemplateNames(Found); if (Found.isAmbiguous()) { Found.clear(); } else if (!Found.empty()) { Found.setLookupName(Corrected.getCorrection()); if (LookupCtx) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; diagnoseTypo(Corrected, PDiag(diag::err_no_member_template_suggest) << Name << LookupCtx << DroppedSpecifier << SS.getRange()); } else { diagnoseTypo(Corrected, PDiag(diag::err_no_template_suggest) << Name); } } } } NamedDecl *ExampleLookupResult = Found.empty() ? nullptr : Found.getRepresentativeDecl(); FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup); if (Found.empty()) { if (IsDependent) { MemberOfUnknownSpecialization = true; return false; } // If a 'template' keyword was used, a lookup that finds only non-template // names is an error. if (ExampleLookupResult && RequiredTemplate) { Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template) << Found.getLookupName() << SS.getRange() << RequiredTemplate.hasTemplateKeyword() << RequiredTemplate.getTemplateKeywordLoc(); Diag(ExampleLookupResult->getUnderlyingDecl()->getLocation(), diag::note_template_kw_refers_to_non_template) << Found.getLookupName(); return true; } return false; } if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope && !getLangOpts().CPlusPlus11) { // C++03 [basic.lookup.classref]p1: // [...] If the lookup in the class of the object expression finds a // template, the name is also looked up in the context of the entire // postfix-expression and [...] // // Note: C++11 does not perform this second lookup. LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(), LookupOrdinaryName); FoundOuter.setTemplateNameLookup(true); LookupName(FoundOuter, S); // FIXME: We silently accept an ambiguous lookup here, in violation of // [basic.lookup]/1. FilterAcceptableTemplateNames(FoundOuter, /*AllowFunctionTemplates=*/false); NamedDecl *OuterTemplate; if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise } else if (FoundOuter.isAmbiguous() || !FoundOuter.isSingleResult() || !(OuterTemplate = getAsTemplateNameDecl(FoundOuter.getFoundDecl()))) { // - if the name is found in the context of the entire // postfix-expression and does not name a class template, the name // found in the class of the object expression is used, otherwise FoundOuter.clear(); } else if (!Found.isSuppressingAmbiguousDiagnostics()) { // - if the name found is a class template, it must refer to the same // entity as the one found in the class of the object expression, // otherwise the program is ill-formed. if (!Found.isSingleResult() || getAsTemplateNameDecl(Found.getFoundDecl())->getCanonicalDecl() != OuterTemplate->getCanonicalDecl()) { Diag(Found.getNameLoc(), diag::ext_nested_name_member_ref_lookup_ambiguous) << Found.getLookupName() << ObjectType; Diag(Found.getRepresentativeDecl()->getLocation(), diag::note_ambig_member_ref_object_type) << ObjectType; Diag(FoundOuter.getFoundDecl()->getLocation(), diag::note_ambig_member_ref_scope); // Recover by taking the template that we found in the object // expression's type. } } } return false; } void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, SourceLocation Less, SourceLocation Greater) { if (TemplateName.isInvalid()) return; DeclarationNameInfo NameInfo; CXXScopeSpec SS; LookupNameKind LookupKind; DeclContext *LookupCtx = nullptr; NamedDecl *Found = nullptr; bool MissingTemplateKeyword = false; // Figure out what name we looked up. if (auto *DRE = dyn_cast(TemplateName.get())) { NameInfo = DRE->getNameInfo(); SS.Adopt(DRE->getQualifierLoc()); LookupKind = LookupOrdinaryName; Found = DRE->getFoundDecl(); } else if (auto *ME = dyn_cast(TemplateName.get())) { NameInfo = ME->getMemberNameInfo(); SS.Adopt(ME->getQualifierLoc()); LookupKind = LookupMemberName; LookupCtx = ME->getBase()->getType()->getAsCXXRecordDecl(); Found = ME->getMemberDecl(); } else if (auto *DSDRE = dyn_cast(TemplateName.get())) { NameInfo = DSDRE->getNameInfo(); SS.Adopt(DSDRE->getQualifierLoc()); MissingTemplateKeyword = true; } else if (auto *DSME = dyn_cast(TemplateName.get())) { NameInfo = DSME->getMemberNameInfo(); SS.Adopt(DSME->getQualifierLoc()); MissingTemplateKeyword = true; } else { llvm_unreachable("unexpected kind of potential template name"); } // If this is a dependent-scope lookup, diagnose that the 'template' keyword // was missing. if (MissingTemplateKeyword) { Diag(NameInfo.getBeginLoc(), diag::err_template_kw_missing) << "" << NameInfo.getName().getAsString() << SourceRange(Less, Greater); return; } // Try to correct the name by looking for templates and C++ named casts. struct TemplateCandidateFilter : CorrectionCandidateCallback { Sema &S; TemplateCandidateFilter(Sema &S) : S(S) { WantTypeSpecifiers = false; WantExpressionKeywords = false; WantRemainingKeywords = false; WantCXXNamedCasts = true; }; bool ValidateCandidate(const TypoCorrection &Candidate) override { if (auto *ND = Candidate.getCorrectionDecl()) return S.getAsTemplateNameDecl(ND); return Candidate.isKeyword(); } std::unique_ptr clone() override { return std::make_unique(*this); } }; DeclarationName Name = NameInfo.getName(); TemplateCandidateFilter CCC(*this); if (TypoCorrection Corrected = CorrectTypo(NameInfo, LookupKind, S, &SS, CCC, CTK_ErrorRecovery, LookupCtx)) { auto *ND = Corrected.getFoundDecl(); if (ND) ND = getAsTemplateNameDecl(ND); if (ND || Corrected.isKeyword()) { if (LookupCtx) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; diagnoseTypo(Corrected, PDiag(diag::err_non_template_in_member_template_id_suggest) << Name << LookupCtx << DroppedSpecifier << SS.getRange(), false); } else { diagnoseTypo(Corrected, PDiag(diag::err_non_template_in_template_id_suggest) << Name, false); } if (Found) Diag(Found->getLocation(), diag::note_non_template_in_template_id_found); return; } } Diag(NameInfo.getLoc(), diag::err_non_template_in_template_id) << Name << SourceRange(Less, Greater); if (Found) Diag(Found->getLocation(), diag::note_non_template_in_template_id_found); } /// ActOnDependentIdExpression - Handle a dependent id-expression that /// was just parsed. This is only possible with an explicit scope /// specifier naming a dependent type. ExprResult Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs) { DeclContext *DC = getFunctionLevelDeclContext(); // C++11 [expr.prim.general]p12: // An id-expression that denotes a non-static data member or non-static // member function of a class can only be used: // (...) // - if that id-expression denotes a non-static data member and it // appears in an unevaluated operand. // // If this might be the case, form a DependentScopeDeclRefExpr instead of a // CXXDependentScopeMemberExpr. The former can instantiate to either // DeclRefExpr or MemberExpr depending on lookup results, while the latter is // always a MemberExpr. bool MightBeCxx11UnevalField = getLangOpts().CPlusPlus11 && isUnevaluatedContext(); // Check if the nested name specifier is an enum type. bool IsEnum = false; if (NestedNameSpecifier *NNS = SS.getScopeRep()) IsEnum = isa_and_nonnull(NNS->getAsType()); if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum && isa(DC) && cast(DC)->isImplicitObjectMemberFunction()) { QualType ThisType = cast(DC)->getThisType().getNonReferenceType(); // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. NamedDecl *FirstQualifierInScope = nullptr; return CXXDependentScopeMemberExpr::Create( Context, /*This=*/nullptr, ThisType, /*IsArrow=*/!Context.getLangOpts().HLSL, /*Op=*/SourceLocation(), SS.getWithLocInContext(Context), TemplateKWLoc, FirstQualifierInScope, NameInfo, TemplateArgs); } return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs); } ExprResult Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs) { // DependentScopeDeclRefExpr::Create requires a valid QualifierLoc NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); if (!QualifierLoc) return ExprError(); return DependentScopeDeclRefExpr::Create( Context, QualifierLoc, TemplateKWLoc, NameInfo, TemplateArgs); } /// Determine whether we would be unable to instantiate this template (because /// it either has no definition, or is in the process of being instantiated). bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, NamedDecl *Instantiation, bool InstantiatedFromMember, const NamedDecl *Pattern, const NamedDecl *PatternDef, TemplateSpecializationKind TSK, bool Complain /*= true*/) { assert(isa(Instantiation) || isa(Instantiation) || isa(Instantiation)); bool IsEntityBeingDefined = false; if (const TagDecl *TD = dyn_cast_or_null(PatternDef)) IsEntityBeingDefined = TD->isBeingDefined(); if (PatternDef && !IsEntityBeingDefined) { NamedDecl *SuggestedDef = nullptr; if (!hasReachableDefinition(const_cast(PatternDef), &SuggestedDef, /*OnlyNeedComplete*/ false)) { // If we're allowed to diagnose this and recover, do so. bool Recover = Complain && !isSFINAEContext(); if (Complain) diagnoseMissingImport(PointOfInstantiation, SuggestedDef, Sema::MissingImportKind::Definition, Recover); return !Recover; } return false; } if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) return true; QualType InstantiationTy; if (TagDecl *TD = dyn_cast(Instantiation)) InstantiationTy = Context.getTypeDeclType(TD); if (PatternDef) { Diag(PointOfInstantiation, diag::err_template_instantiate_within_definition) << /*implicit|explicit*/(TSK != TSK_ImplicitInstantiation) << InstantiationTy; // Not much point in noting the template declaration here, since // we're lexically inside it. Instantiation->setInvalidDecl(); } else if (InstantiatedFromMember) { if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << /*member function*/ 1 << Instantiation->getDeclName() << Instantiation->getDeclContext(); Diag(Pattern->getLocation(), diag::note_explicit_instantiation_here); } else { assert(isa(Instantiation) && "Must be a TagDecl!"); Diag(PointOfInstantiation, diag::err_implicit_instantiate_member_undefined) << InstantiationTy; Diag(Pattern->getLocation(), diag::note_member_declared_at); } } else { if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_func_template) << Pattern; Diag(Pattern->getLocation(), diag::note_explicit_instantiation_here); } else if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) << (TSK != TSK_ImplicitInstantiation) << InstantiationTy; NoteTemplateLocation(*Pattern); } else { assert(isa(Instantiation) && "Must be a VarDecl!"); if (isa(Instantiation)) { Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_var_template) << Instantiation; Instantiation->setInvalidDecl(); } else Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << /*static data member*/ 2 << Instantiation->getDeclName() << Instantiation->getDeclContext(); Diag(Pattern->getLocation(), diag::note_explicit_instantiation_here); } } // In general, Instantiation isn't marked invalid to get more than one // error for multiple undefined instantiations. But the code that does // explicit declaration -> explicit definition conversion can't handle // invalid declarations, so mark as invalid in that case. if (TSK == TSK_ExplicitInstantiationDeclaration) Instantiation->setInvalidDecl(); return true; } /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining /// that the template parameter 'PrevDecl' is being shadowed by a new /// declaration at location Loc. Returns true to indicate that this is /// an error, and false otherwise. void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { assert(PrevDecl->isTemplateParameter() && "Not a template parameter"); // C++ [temp.local]p4: // A template-parameter shall not be redeclared within its // scope (including nested scopes). // // Make this a warning when MSVC compatibility is requested. unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow : diag::err_template_param_shadow; const auto *ND = cast(PrevDecl); Diag(Loc, DiagId) << ND->getDeclName(); NoteTemplateParameterLocation(*ND); } /// AdjustDeclIfTemplate - If the given decl happens to be a template, reset /// the parameter D to reference the templated declaration and return a pointer /// to the template declaration. Otherwise, do nothing to D and return null. TemplateDecl *Sema::AdjustDeclIfTemplate(Decl *&D) { if (TemplateDecl *Temp = dyn_cast_or_null(D)) { D = Temp->getTemplatedDecl(); return Temp; } return nullptr; } ParsedTemplateArgument ParsedTemplateArgument::getTemplatePackExpansion( SourceLocation EllipsisLoc) const { assert(Kind == Template && "Only template template arguments can be pack expansions here"); assert(getAsTemplate().get().containsUnexpandedParameterPack() && "Template template argument pack expansion without packs"); ParsedTemplateArgument Result(*this); Result.EllipsisLoc = EllipsisLoc; return Result; } static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, const ParsedTemplateArgument &Arg) { switch (Arg.getKind()) { case ParsedTemplateArgument::Type: { TypeSourceInfo *DI; QualType T = SemaRef.GetTypeFromParser(Arg.getAsType(), &DI); if (!DI) DI = SemaRef.Context.getTrivialTypeSourceInfo(T, Arg.getLocation()); return TemplateArgumentLoc(TemplateArgument(T), DI); } case ParsedTemplateArgument::NonType: { Expr *E = static_cast(Arg.getAsExpr()); return TemplateArgumentLoc(TemplateArgument(E), E); } case ParsedTemplateArgument::Template: { TemplateName Template = Arg.getAsTemplate().get(); TemplateArgument TArg; if (Arg.getEllipsisLoc().isValid()) TArg = TemplateArgument(Template, std::optional()); else TArg = Template; return TemplateArgumentLoc( SemaRef.Context, TArg, Arg.getScopeSpec().getWithLocInContext(SemaRef.Context), Arg.getLocation(), Arg.getEllipsisLoc()); } } llvm_unreachable("Unhandled parsed template argument"); } /// Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, TemplateArgumentListInfo &TemplateArgs) { for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I) TemplateArgs.addArgument(translateTemplateArgument(*this, TemplateArgsIn[I])); } static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S, SourceLocation Loc, IdentifierInfo *Name) { NamedDecl *PrevDecl = SemaRef.LookupSingleName( S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) SemaRef.DiagnoseTemplateParameterShadow(Loc, PrevDecl); } /// Convert a parsed type into a parsed template argument. This is mostly /// trivial, except that we may have parsed a C++17 deduced class template /// specialization type, in which case we should form a template template /// argument instead of a type template argument. ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) { TypeSourceInfo *TInfo; QualType T = GetTypeFromParser(ParsedType.get(), &TInfo); if (T.isNull()) return ParsedTemplateArgument(); assert(TInfo && "template argument with no location"); // If we might have formed a deduced template specialization type, convert // it to a template template argument. if (getLangOpts().CPlusPlus17) { TypeLoc TL = TInfo->getTypeLoc(); SourceLocation EllipsisLoc; if (auto PET = TL.getAs()) { EllipsisLoc = PET.getEllipsisLoc(); TL = PET.getPatternLoc(); } CXXScopeSpec SS; if (auto ET = TL.getAs()) { SS.Adopt(ET.getQualifierLoc()); TL = ET.getNamedTypeLoc(); } if (auto DTST = TL.getAs()) { TemplateName Name = DTST.getTypePtr()->getTemplateName(); if (SS.isSet()) Name = Context.getQualifiedTemplateName(SS.getScopeRep(), /*HasTemplateKeyword=*/false, Name); ParsedTemplateArgument Result(SS, TemplateTy::make(Name), DTST.getTemplateNameLoc()); if (EllipsisLoc.isValid()) Result = Result.getTemplatePackExpansion(EllipsisLoc); return Result; } } // This is a normal type template argument. Note, if the type template // argument is an injected-class-name for a template, it has a dual nature // and can be used as either a type or a template. We handle that in // convertTypeTemplateArgumentToTemplate. return ParsedTemplateArgument(ParsedTemplateArgument::Type, ParsedType.get().getAsOpaquePtr(), TInfo->getTypeLoc().getBeginLoc()); } /// ActOnTypeParameter - Called when a C++ template type parameter /// (e.g., "typename T") has been parsed. Typename specifies whether /// the keyword "typename" was used to declare the type parameter /// (otherwise, "class" was used), and KeyLoc is the location of the /// "class" or "typename" keyword. ParamName is the name of the /// parameter (NULL indicates an unnamed template parameter) and /// ParamNameLoc is the location of the parameter name (if any). /// If the type parameter has a default argument, it will be added /// later via ActOnTypeParameterDefault. NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedType DefaultArg, bool HasTypeConstraint) { assert(S->isTemplateParamScope() && "Template type parameter not in template parameter scope!"); bool IsParameterPack = EllipsisLoc.isValid(); TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), KeyLoc, ParamNameLoc, Depth, Position, ParamName, Typename, IsParameterPack, HasTypeConstraint); Param->setAccess(AS_public); if (Param->isParameterPack()) if (auto *LSI = getEnclosingLambda()) LSI->LocalPacks.push_back(Param); if (ParamName) { maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName); // Add the template parameter into the current scope. S->AddDecl(Param); IdResolver.AddDecl(Param); } // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of // template-parameter that is not a template parameter pack. if (DefaultArg && IsParameterPack) { Diag(EqualLoc, diag::err_template_param_pack_default_arg); DefaultArg = nullptr; } // Handle the default argument, if provided. if (DefaultArg) { TypeSourceInfo *DefaultTInfo; GetTypeFromParser(DefaultArg, &DefaultTInfo); assert(DefaultTInfo && "expected source information for type"); // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(ParamNameLoc, DefaultTInfo, UPPC_DefaultArgument)) return Param; // Check the template argument itself. if (CheckTemplateArgument(DefaultTInfo)) { Param->setInvalidDecl(); return Param; } Param->setDefaultArgument(DefaultTInfo); } return Param; } /// Convert the parser's template argument list representation into our form. static TemplateArgumentListInfo makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc, TemplateId.RAngleLoc); ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(), TemplateId.NumArgs); S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs); return TemplateArgs; } bool Sema::CheckTypeConstraint(TemplateIdAnnotation *TypeConstr) { TemplateName TN = TypeConstr->Template.get(); ConceptDecl *CD = cast(TN.getAsTemplateDecl()); // C++2a [temp.param]p4: // [...] The concept designated by a type-constraint shall be a type // concept ([temp.concept]). if (!CD->isTypeConcept()) { Diag(TypeConstr->TemplateNameLoc, diag::err_type_constraint_non_type_concept); return true; } bool WereArgsSpecified = TypeConstr->LAngleLoc.isValid(); if (!WereArgsSpecified && CD->getTemplateParameters()->getMinRequiredArguments() > 1) { Diag(TypeConstr->TemplateNameLoc, diag::err_type_constraint_missing_arguments) << CD; return true; } return false; } bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstr, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { return BuildTypeConstraint(SS, TypeConstr, ConstrainedParameter, EllipsisLoc, false); } bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstr, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc, bool AllowUnexpandedPack) { if (CheckTypeConstraint(TypeConstr)) return true; TemplateName TN = TypeConstr->Template.get(); ConceptDecl *CD = cast(TN.getAsTemplateDecl()); DeclarationNameInfo ConceptName(DeclarationName(TypeConstr->Name), TypeConstr->TemplateNameLoc); TemplateArgumentListInfo TemplateArgs; if (TypeConstr->LAngleLoc.isValid()) { TemplateArgs = makeTemplateArgumentListInfo(*this, *TypeConstr); if (EllipsisLoc.isInvalid() && !AllowUnexpandedPack) { for (TemplateArgumentLoc Arg : TemplateArgs.arguments()) { if (DiagnoseUnexpandedParameterPack(Arg, UPPC_TypeConstraint)) return true; } } } return AttachTypeConstraint( SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), ConceptName, CD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, ConstrainedParameter, EllipsisLoc); } template static ExprResult formImmediatelyDeclaredConstraint( Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, ConceptDecl *NamedConcept, SourceLocation LAngleLoc, SourceLocation RAngleLoc, QualType ConstrainedType, SourceLocation ParamNameLoc, ArgumentLocAppender Appender, SourceLocation EllipsisLoc) { TemplateArgumentListInfo ConstraintArgs; ConstraintArgs.addArgument( S.getTrivialTemplateArgumentLoc(TemplateArgument(ConstrainedType), /*NTTPType=*/QualType(), ParamNameLoc)); ConstraintArgs.setRAngleLoc(RAngleLoc); ConstraintArgs.setLAngleLoc(LAngleLoc); Appender(ConstraintArgs); // C++2a [temp.param]p4: // [...] This constraint-expression E is called the immediately-declared // constraint of T. [...] CXXScopeSpec SS; SS.Adopt(NS); ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId( SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs); if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid()) return ImmediatelyDeclaredConstraint; // C++2a [temp.param]p4: // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). // // We have the following case: // // template concept C1 = true; // template struct s1; // // The constraint: (C1 && ...) // // Note that the type of C1 is known to be 'bool', so we don't need to do // any unqualified lookups for 'operator&&' here. return S.BuildCXXFoldExpr(/*UnqualifiedLookup=*/nullptr, /*LParenLoc=*/SourceLocation(), ImmediatelyDeclaredConstraint.get(), BO_LAnd, EllipsisLoc, /*RHS=*/nullptr, /*RParenLoc=*/SourceLocation(), /*NumExpansions=*/std::nullopt); } /// Attach a type-constraint to a template parameter. /// \returns true if an error occurred. This can happen if the /// immediately-declared constraint could not be formed (e.g. incorrect number /// of arguments for the named concept). bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { // C++2a [temp.param]p4: // [...] If Q is of the form C, then let E' be // C. Otherwise, let E' be C. [...] const ASTTemplateArgumentListInfo *ArgsAsWritten = TemplateArgs ? ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs) : nullptr; QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( *this, NS, NameInfo, NamedConcept, TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(), TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(), ParamAsArgument, ConstrainedParameter->getLocation(), [&] (TemplateArgumentListInfo &ConstraintArgs) { if (TemplateArgs) for (const auto &ArgLoc : TemplateArgs->arguments()) ConstraintArgs.addArgument(ArgLoc); }, EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid()) return true; auto *CL = ConceptReference::Create(Context, /*NNS=*/NS, /*TemplateKWLoc=*/SourceLocation{}, /*ConceptNameInfo=*/NameInfo, /*FoundDecl=*/NamedConcept, /*NamedConcept=*/NamedConcept, /*ArgsWritten=*/ArgsAsWritten); ConstrainedParameter->setTypeConstraint(CL, ImmediatelyDeclaredConstraint.get()); return false; } bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NewConstrainedParm, NonTypeTemplateParmDecl *OrigConstrainedParm, SourceLocation EllipsisLoc) { if (NewConstrainedParm->getType() != TL.getType() || TL.getAutoKeyword() != AutoTypeKeyword::Auto) { Diag(NewConstrainedParm->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_unsupported_placeholder_constraint) << NewConstrainedParm->getTypeSourceInfo() ->getTypeLoc() .getSourceRange(); return true; } // FIXME: Concepts: This should be the type of the placeholder, but this is // unclear in the wording right now. DeclRefExpr *Ref = BuildDeclRefExpr(OrigConstrainedParm, OrigConstrainedParm->getType(), VK_PRValue, OrigConstrainedParm->getLocation()); if (!Ref) return true; ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), BuildDecltypeType(Ref), OrigConstrainedParm->getLocation(), [&](TemplateArgumentListInfo &ConstraintArgs) { for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) ConstraintArgs.addArgument(TL.getArgLoc(I)); }, EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid() || !ImmediatelyDeclaredConstraint.isUsable()) return true; NewConstrainedParm->setPlaceholderTypeConstraint( ImmediatelyDeclaredConstraint.get()); return false; } /// Check that the type of a non-type template parameter is /// well-formed. /// /// \returns the (possibly-promoted) parameter type if valid; /// otherwise, produces a diagnostic and returns a NULL type. QualType Sema::CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI, SourceLocation Loc) { if (TSI->getType()->isUndeducedType()) { // C++17 [temp.dep.expr]p3: // An id-expression is type-dependent if it contains // - an identifier associated by name lookup with a non-type // template-parameter declared with a type that contains a // placeholder type (7.1.7.4), TSI = SubstAutoTypeSourceInfoDependent(TSI); } return CheckNonTypeTemplateParameterType(TSI->getType(), Loc); } /// Require the given type to be a structural type, and diagnose if it is not. /// /// \return \c true if an error was produced. bool Sema::RequireStructuralType(QualType T, SourceLocation Loc) { if (T->isDependentType()) return false; if (RequireCompleteType(Loc, T, diag::err_template_nontype_parm_incomplete)) return true; if (T->isStructuralType()) return false; // Structural types are required to be object types or lvalue references. if (T->isRValueReferenceType()) { Diag(Loc, diag::err_template_nontype_parm_rvalue_ref) << T; return true; } // Don't mention structural types in our diagnostic prior to C++20. Also, // there's not much more we can say about non-scalar non-class types -- // because we can't see functions or arrays here, those can only be language // extensions. if (!getLangOpts().CPlusPlus20 || (!T->isScalarType() && !T->isRecordType())) { Diag(Loc, diag::err_template_nontype_parm_bad_type) << T; return true; } // Structural types are required to be literal types. if (RequireLiteralType(Loc, T, diag::err_template_nontype_parm_not_literal)) return true; Diag(Loc, diag::err_template_nontype_parm_not_structural) << T; // Drill down into the reason why the class is non-structural. while (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) { // All members are required to be public and non-mutable, and can't be of // rvalue reference type. Check these conditions first to prefer a "local" // reason over a more distant one. for (const FieldDecl *FD : RD->fields()) { if (FD->getAccess() != AS_public) { Diag(FD->getLocation(), diag::note_not_structural_non_public) << T << 0; return true; } if (FD->isMutable()) { Diag(FD->getLocation(), diag::note_not_structural_mutable_field) << T; return true; } if (FD->getType()->isRValueReferenceType()) { Diag(FD->getLocation(), diag::note_not_structural_rvalue_ref_field) << T; return true; } } // All bases are required to be public. for (const auto &BaseSpec : RD->bases()) { if (BaseSpec.getAccessSpecifier() != AS_public) { Diag(BaseSpec.getBaseTypeLoc(), diag::note_not_structural_non_public) << T << 1; return true; } } // All subobjects are required to be of structural types. SourceLocation SubLoc; QualType SubType; int Kind = -1; for (const FieldDecl *FD : RD->fields()) { QualType T = Context.getBaseElementType(FD->getType()); if (!T->isStructuralType()) { SubLoc = FD->getLocation(); SubType = T; Kind = 0; break; } } if (Kind == -1) { for (const auto &BaseSpec : RD->bases()) { QualType T = BaseSpec.getType(); if (!T->isStructuralType()) { SubLoc = BaseSpec.getBaseTypeLoc(); SubType = T; Kind = 1; break; } } } assert(Kind != -1 && "couldn't find reason why type is not structural"); Diag(SubLoc, diag::note_not_structural_subobject) << T << Kind << SubType; T = SubType; RD = T->getAsCXXRecordDecl(); } return true; } QualType Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { // We don't allow variably-modified types as the type of non-type template // parameters. if (T->isVariablyModifiedType()) { Diag(Loc, diag::err_variably_modified_nontype_template_param) << T; return QualType(); } // C++ [temp.param]p4: // // A non-type template-parameter shall have one of the following // (optionally cv-qualified) types: // // -- integral or enumeration type, if (T->isIntegralOrEnumerationType() || // -- pointer to object or pointer to function, T->isPointerType() || // -- lvalue reference to object or lvalue reference to function, T->isLValueReferenceType() || // -- pointer to member, T->isMemberPointerType() || // -- std::nullptr_t, or T->isNullPtrType() || // -- a type that contains a placeholder type. T->isUndeducedType()) { // C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter // are ignored when determining its type. return T.getUnqualifiedType(); } // C++ [temp.param]p8: // // A non-type template-parameter of type "array of T" or // "function returning T" is adjusted to be of type "pointer to // T" or "pointer to function returning T", respectively. if (T->isArrayType() || T->isFunctionType()) return Context.getDecayedType(T); // If T is a dependent type, we can't do the check now, so we // assume that it is well-formed. Note that stripping off the // qualifiers here is not really correct if T turns out to be // an array type, but we'll recompute the type everywhere it's // used during instantiation, so that should be OK. (Using the // qualified type is equally wrong.) if (T->isDependentType()) return T.getUnqualifiedType(); // C++20 [temp.param]p6: // -- a structural type if (RequireStructuralType(T, Loc)) return QualType(); if (!getLangOpts().CPlusPlus20) { // FIXME: Consider allowing structural types as an extension in C++17. (In // earlier language modes, the template argument evaluation rules are too // inflexible.) Diag(Loc, diag::err_template_nontype_parm_bad_structural_type) << T; return QualType(); } Diag(Loc, diag::warn_cxx17_compat_template_nontype_parm_type) << T; return T.getUnqualifiedType(); } NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, unsigned Depth, unsigned Position, SourceLocation EqualLoc, Expr *Default) { TypeSourceInfo *TInfo = GetTypeForDeclarator(D); // Check that we have valid decl-specifiers specified. auto CheckValidDeclSpecifiers = [this, &D] { // C++ [temp.param] // p1 // template-parameter: // ... // parameter-declaration // p2 // ... A storage class shall not be specified in a template-parameter // declaration. // [dcl.typedef]p1: // The typedef specifier [...] shall not be used in the decl-specifier-seq // of a parameter-declaration const DeclSpec &DS = D.getDeclSpec(); auto EmitDiag = [this](SourceLocation Loc) { Diag(Loc, diag::err_invalid_decl_specifier_in_nontype_parm) << FixItHint::CreateRemoval(Loc); }; if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) EmitDiag(DS.getStorageClassSpecLoc()); if (DS.getThreadStorageClassSpec() != TSCS_unspecified) EmitDiag(DS.getThreadStorageClassSpecLoc()); // [dcl.inline]p1: // The inline specifier can be applied only to the declaration or // definition of a variable or function. if (DS.isInlineSpecified()) EmitDiag(DS.getInlineSpecLoc()); // [dcl.constexpr]p1: // The constexpr specifier shall be applied only to the definition of a // variable or variable template or the declaration of a function or // function template. if (DS.hasConstexprSpecifier()) EmitDiag(DS.getConstexprSpecLoc()); // [dcl.fct.spec]p1: // Function-specifiers can be used only in function declarations. if (DS.isVirtualSpecified()) EmitDiag(DS.getVirtualSpecLoc()); if (DS.hasExplicitSpecifier()) EmitDiag(DS.getExplicitSpecLoc()); if (DS.isNoreturnSpecified()) EmitDiag(DS.getNoreturnSpecLoc()); }; CheckValidDeclSpecifiers(); if (const auto *T = TInfo->getType()->getContainedDeducedType()) if (isa(T)) Diag(D.getIdentifierLoc(), diag::warn_cxx14_compat_template_nontype_parm_auto_type) << QualType(TInfo->getType()->getContainedAutoType(), 0); assert(S->isTemplateParamScope() && "Non-type template parameter not in template parameter scope!"); bool Invalid = false; QualType T = CheckNonTypeTemplateParameterType(TInfo, D.getIdentifierLoc()); if (T.isNull()) { T = Context.IntTy; // Recover with an 'int' type. Invalid = true; } CheckFunctionOrTemplateParamDeclarator(S, D); IdentifierInfo *ParamName = D.getIdentifier(); bool IsParameterPack = D.hasEllipsis(); NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create( Context, Context.getTranslationUnitDecl(), D.getBeginLoc(), D.getIdentifierLoc(), Depth, Position, ParamName, T, IsParameterPack, TInfo); Param->setAccess(AS_public); if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) if (TL.isConstrained()) if (AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) Invalid = true; if (Invalid) Param->setInvalidDecl(); if (Param->isParameterPack()) if (auto *LSI = getEnclosingLambda()) LSI->LocalPacks.push_back(Param); if (ParamName) { maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(), ParamName); // Add the template parameter into the current scope. S->AddDecl(Param); IdResolver.AddDecl(Param); } // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of // template-parameter that is not a template parameter pack. if (Default && IsParameterPack) { Diag(EqualLoc, diag::err_template_param_pack_default_arg); Default = nullptr; } // Check the well-formedness of the default template argument, if provided. if (Default) { // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument)) return Param; Param->setDefaultArgument(Default); } return Param; } /// ActOnTemplateTemplateParameter - Called when a C++ template template /// parameter (e.g. T in template