diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaTemplate.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaTemplate.cpp | 1012 |
1 files changed, 675 insertions, 337 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm-project/clang/lib/Sema/SemaTemplate.cpp index 135ca2b25cbe..ad4ea2d2593d 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaTemplate.cpp @@ -20,9 +20,11 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.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" @@ -44,27 +46,7 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps, return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); } -namespace clang { -/// [temp.constr.decl]p2: A template's associated constraints are -/// defined as a single constraint-expression derived from the introduced -/// constraint-expressions [ ... ]. -/// -/// \param Params The template parameter list and optional requires-clause. -/// -/// \param FD The underlying templated function declaration for a function -/// template. -static Expr *formAssociatedConstraints(TemplateParameterList *Params, - FunctionDecl *FD); -} - -static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params, - FunctionDecl *FD) { - // FIXME: Concepts: collect additional introduced constraint-expressions - assert(!FD && "Cannot collect constraints from function declaration yet."); - return Params->getRequiresClause(); -} - -/// Determine whether the declaration found is acceptable as the name +/// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. /// @@ -644,7 +626,7 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<TemplateCandidateFilter>(*this); + return std::make_unique<TemplateCandidateFilter>(*this); } }; @@ -734,9 +716,13 @@ 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, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo, - TemplateArgs); + Context, QualifierLoc, TemplateKWLoc, NameInfo, TemplateArgs); } @@ -844,15 +830,14 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { assert(PrevDecl->isTemplateParameter() && "Not a template parameter"); - // Microsoft Visual C++ permits template parameters to be shadowed. - if (getLangOpts().MicrosoftExt) - return; - // C++ [temp.local]p4: // A template-parameter shall not be redeclared within its // scope (including nested scopes). - Diag(Loc, diag::err_template_param_shadow) - << cast<NamedDecl>(PrevDecl)->getDeclName(); + // + // Make this a warning when MSVC compatibility is requested. + unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow + : diag::err_template_param_shadow; + Diag(Loc, DiagId) << cast<NamedDecl>(PrevDecl)->getDeclName(); Diag(PrevDecl->getLocation(), diag::note_template_param_here); } @@ -991,27 +976,29 @@ ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) { /// 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) { + 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!"); - SourceLocation Loc = ParamNameLoc; - if (!ParamName) - Loc = KeyLoc; - bool IsParameterPack = EllipsisLoc.isValid(); TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), - KeyLoc, Loc, Depth, Position, ParamName, - Typename, IsParameterPack); + 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); @@ -1036,7 +1023,7 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, assert(DefaultTInfo && "expected source information for type"); // Check for unexpanded parameter packs. - if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo, + if (DiagnoseUnexpandedParameterPack(ParamNameLoc, DefaultTInfo, UPPC_DefaultArgument)) return Param; @@ -1052,6 +1039,171 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, 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::ActOnTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstr, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc) { + ConceptDecl *CD = + cast<ConceptDecl>(TypeConstr->Template.get().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; + } + + TemplateArgumentListInfo TemplateArgs; + if (TypeConstr->LAngleLoc.isValid()) { + TemplateArgs = + makeTemplateArgumentListInfo(*this, *TypeConstr); + } + return AttachTypeConstraint( + SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), + DeclarationNameInfo(DeclarationName(TypeConstr->Name), + TypeConstr->TemplateNameLoc), CD, + TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, + ConstrainedParameter, EllipsisLoc); +} + +template<typename ArgumentLocAppender> +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<typename T> concept C1 = true; + // template<C1... T> struct s1; + // + // The constraint: (C1<T> && ...) + return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), + ImmediatelyDeclaredConstraint.get(), BO_LAnd, + EllipsisLoc, /*RHS=*/nullptr, + /*RParenLoc=*/SourceLocation(), + /*NumExpansions=*/None); +} + +/// Attach a type-constraint to a template parameter. +/// \returns true if an error occured. 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<A1, ..., An>, then let E' be + // C<T, A1, ..., An>. Otherwise, let E' be C<T>. [...] + 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; + + ConstrainedParameter->setTypeConstraint(NS, NameInfo, + /*FoundDecl=*/NamedConcept, + NamedConcept, ArgsAsWritten, + ImmediatelyDeclaredConstraint.get()); + return false; +} + +bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, + SourceLocation EllipsisLoc) { + if (NTTP->getType() != TL.getType() || + TL.getAutoKeyword() != AutoTypeKeyword::Auto) { + Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), + diag::err_unsupported_placeholder_constraint) + << NTTP->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(NTTP, NTTP->getType(), VK_RValue, + NTTP->getLocation()); + if (!Ref) + return true; + ExprResult ImmediatelyDeclaredConstraint = + formImmediatelyDeclaredConstraint( + *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), + TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), + BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->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; + + NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get()); + return false; +} + /// Check that the type of a non-type template parameter is /// well-formed. /// @@ -1096,9 +1248,6 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T, T->isMemberPointerType() || // -- std::nullptr_t. T->isNullPtrType() || - // If T is a dependent type, we can't do the check now, so we - // assume that it is well-formed. - T->isDependentType() || // Allow use of auto in template parameter declarations. T->isUndeducedType()) { // C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter @@ -1111,9 +1260,18 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T, // 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. - else if (T->isArrayType() || T->isFunctionType()) + 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(); + Diag(Loc, diag::err_template_nontype_parm_bad_type) << T; @@ -1130,11 +1288,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, // Check that we have valid decl-specifiers specified. auto CheckValidDeclSpecifiers = [this, &D] { // C++ [temp.param] - // p1 + // p1 // template-parameter: // ... // parameter-declaration - // p2 + // p2 // ... A storage class shall not be specified in a template-parameter // declaration. // [dcl.typedef]p1: @@ -1207,9 +1365,18 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, TInfo); Param->setAccess(AS_public); + if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) + if (TL.isConstrained()) + if (AttachTypeConstraint(TL, 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); @@ -1273,6 +1440,10 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S, Name, Params); Param->setAccess(AS_public); + if (Param->isParameterPack()) + if (auto *LSI = getEnclosingLambda()) + LSI->LocalPacks.push_back(Param); + // If the template template parameter has a name, then link the identifier // into the scope and lookup mechanisms. if (Name) { @@ -1516,9 +1687,6 @@ DeclResult Sema::CheckClassTemplate( } } - // TODO Memory management; associated constraints are not always stored. - Expr *const CurAC = formAssociatedConstraints(TemplateParams, nullptr); - if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. Skip this check // for a friend in a dependent context: the template parameter list itself @@ -1530,30 +1698,6 @@ DeclResult Sema::CheckClassTemplate( TPL_TemplateMatch)) return true; - // Check for matching associated constraints on redeclarations. - const Expr *const PrevAC = PrevClassTemplate->getAssociatedConstraints(); - const bool RedeclACMismatch = [&] { - if (!(CurAC || PrevAC)) - return false; // Nothing to check; no mismatch. - if (CurAC && PrevAC) { - llvm::FoldingSetNodeID CurACInfo, PrevACInfo; - CurAC->Profile(CurACInfo, Context, /*Canonical=*/true); - PrevAC->Profile(PrevACInfo, Context, /*Canonical=*/true); - if (CurACInfo == PrevACInfo) - return false; // All good; no mismatch. - } - return true; - }(); - - if (RedeclACMismatch) { - Diag(CurAC ? CurAC->getBeginLoc() : NameLoc, - diag::err_template_different_associated_constraints); - Diag(PrevAC ? PrevAC->getBeginLoc() : PrevClassTemplate->getLocation(), - diag::note_template_prev_declaration) - << /*declaration*/ 0; - return true; - } - // C++ [temp.class]p4: // In a redeclaration, partial specialization, explicit // specialization or explicit instantiation of a class template, @@ -1657,15 +1801,10 @@ DeclResult Sema::CheckClassTemplate( AddMsStructLayoutForRecord(NewClass); } - // Attach the associated constraints when the declaration will not be part of - // a decl chain. - Expr *const ACtoAttach = - PrevClassTemplate && ShouldAddRedecl ? nullptr : CurAC; - ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, - NewClass, ACtoAttach); + NewClass); if (ShouldAddRedecl) NewTemplate->setPreviousDecl(PrevClassTemplate); @@ -1704,6 +1843,7 @@ DeclResult Sema::CheckClassTemplate( mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl()); AddPushedVisibilityAttribute(NewClass); + inferGslOwnerPointerAttribute(NewClass); if (TUK != TUK_Friend) { // Per C++ [basic.scope.temp]p2, skip the template parameter scopes. @@ -1901,7 +2041,25 @@ private: SemaRef.Context, DC, TTP->getBeginLoc(), TTP->getLocation(), /*Depth*/ 0, Depth1IndexAdjustment + TTP->getIndex(), TTP->getIdentifier(), TTP->wasDeclaredWithTypename(), - TTP->isParameterPack()); + TTP->isParameterPack(), TTP->hasTypeConstraint(), + TTP->isExpandedParameterPack() ? + llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None); + if (const auto *TC = TTP->getTypeConstraint()) { + TemplateArgumentListInfo TransformedArgs; + const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten(); + if (!ArgsAsWritten || + SemaRef.Subst(ArgsAsWritten->getTemplateArgs(), + ArgsAsWritten->NumTemplateArgs, TransformedArgs, + Args)) + SemaRef.AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), ArgsAsWritten ? &TransformedArgs : nullptr, + NewTTP, + NewTTP->isParameterPack() + ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation()); + } if (TTP->hasDefaultArgument()) { TypeSourceInfo *InstantiatedDefaultArg = SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args, @@ -1927,7 +2085,7 @@ private: // Ask the template instantiator to do the heavy lifting for us, then adjust // the index of the parameter once it's done. auto *NewParam = - cast_or_null<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args)); + cast<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args)); assert(NewParam->getDepth() == 0 && "unexpected template param depth"); NewParam->setPosition(NewParam->getPosition() + Depth1IndexAdjustment); return NewParam; @@ -2210,6 +2368,17 @@ static bool DiagnoseUnexpandedParameterPacks(Sema &S, TemplateParameterList *Params = TTP->getTemplateParameters(); for (unsigned I = 0, N = Params->size(); I != N; ++I) { NamedDecl *P = Params->getParam(I); + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(P)) { + if (!TTP->isParameterPack()) + if (const TypeConstraint *TC = TTP->getTypeConstraint()) + if (TC->hasExplicitTemplateArgs()) + for (auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments()) + if (S.DiagnoseUnexpandedParameterPack(ArgLoc, + Sema::UPPC_TypeConstraint)) + return true; + continue; + } + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) { if (!NTTP->isParameterPack() && S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(), @@ -2582,6 +2751,9 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { /// list. static bool DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) { + if (!Params->size()) + return false; + DependencyChecker Checker(Params, /*IgnoreNonTypeDependent*/false); Checker.TraverseType(T); return Checker.Match; @@ -2643,7 +2815,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend, - bool &IsMemberSpecialization, bool &Invalid) { + bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) { IsMemberSpecialization = false; Invalid = false; @@ -2751,8 +2923,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) { if (SawNonEmptyTemplateParameterList) { - Diag(DeclLoc, diag::err_specialize_member_of_template) - << !Recovery << Range; + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_specialize_member_of_template) + << !Recovery << Range; Invalid = true; IsMemberSpecialization = false; return true; @@ -2773,9 +2946,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( else ExpectedTemplateLoc = DeclStartLoc; - Diag(DeclLoc, diag::err_template_spec_needs_header) - << Range - << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_template_spec_needs_header) + << Range + << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); return false; }; @@ -2865,12 +3039,13 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (ParamIdx < ParamLists.size()) { if (ParamLists[ParamIdx]->size() > 0) { // The header has template parameters when it shouldn't. Complain. - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - diag::err_template_param_list_matches_nontemplate) - << T - << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), - ParamLists[ParamIdx]->getRAngleLoc()) - << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + if (!SuppressDiagnostic) + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + diag::err_template_param_list_matches_nontemplate) + << T + << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), + ParamLists[ParamIdx]->getRAngleLoc()) + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); Invalid = true; return nullptr; } @@ -2906,7 +3081,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (ExpectedTemplateParams && !TemplateParameterListsAreEqual(ParamLists[ParamIdx], ExpectedTemplateParams, - true, TPL_TemplateMatch)) + !SuppressDiagnostic, TPL_TemplateMatch)) Invalid = true; if (!Invalid && @@ -2918,9 +3093,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( continue; } - Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) - << T - << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) + << T + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); Invalid = true; continue; } @@ -2956,16 +3132,18 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( AllExplicitSpecHeaders = false; } - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers - : diag::err_template_spec_extra_headers) - << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), - ParamLists[ParamLists.size() - 2]->getRAngleLoc()); + if (!SuppressDiagnostic) + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers + : diag::err_template_spec_extra_headers) + << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), + ParamLists[ParamLists.size() - 2]->getRAngleLoc()); // If there was a specialization somewhere, such that 'template<>' is // not required, and there were any 'template<>' headers, note where the // specialization occurred. - if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader) + if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader && + !SuppressDiagnostic) Diag(ExplicitSpecLoc, diag::note_explicit_template_spec_does_not_need_header) << NestedTypes.back(); @@ -3243,8 +3421,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template || isa<FunctionTemplateDecl>(Template) || - isa<VarTemplateDecl>(Template) || - isa<ConceptDecl>(Template)) { + isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) { // We might have a substituted template template parameter pack. If so, // build a template specialization type for it. if (Name.getAsSubstTemplateTemplateParmPack()) @@ -3260,7 +3437,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, - false, Converted)) + false, Converted, + /*UpdateArgsWithConversion=*/true)) return QualType(); QualType CanonType; @@ -3268,6 +3446,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, bool InstantiationDependent = false; if (TypeAliasTemplateDecl *AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Template)) { + // Find the canonical type for this type alias template specialization. TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl(); if (Pattern->isInvalidDecl()) @@ -3454,7 +3633,7 @@ bool Sema::resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name, getAsTypeTemplateDecl(TC.getCorrectionDecl()); } std::unique_ptr<CorrectionCandidateCallback> clone() override { - return llvm::make_unique<CandidateCallback>(*this); + return std::make_unique<CandidateCallback>(*this); } } FilterCCC; @@ -3740,17 +3919,6 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params, return true; } -/// 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; -} - template<typename PartialSpecDecl> static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { if (Partial->getDeclContext()->isDependentContext()) @@ -3779,6 +3947,11 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { } S.Diag(Template->getLocation(), diag::note_template_decl_here); + SmallVector<const Expr *, 3> PartialAC, TemplateAC; + Template->getAssociatedConstraints(TemplateAC); + Partial->getAssociatedConstraints(PartialAC); + S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Partial, PartialAC, Template, + TemplateAC); } static void @@ -3905,7 +4078,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, - false, Converted)) + false, Converted, + /*UpdateArgsWithConversion=*/true)) return true; // Find the variable template (partial) specialization declaration that @@ -3928,7 +4102,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization( } if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(), - Converted)) { + Converted) && + (!Context.getLangOpts().CPlusPlus2a || + !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: // // -- The argument list of the specialization shall not be identical @@ -3947,8 +4123,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( VarTemplateSpecializationDecl *PrevDecl = nullptr; if (IsPartialSpecialization) - // FIXME: Template parameter list matters too - PrevDecl = VarTemplate->findPartialSpecialization(Converted, InsertPos); + PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams, + InsertPos); else PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos); @@ -4076,7 +4252,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, if (CheckTemplateArgumentList( Template, TemplateNameLoc, const_cast<TemplateArgumentListInfo &>(TemplateArgs), false, - Converted)) + Converted, /*UpdateArgsWithConversion=*/true)) return true; // Find the variable template specialization declaration that @@ -4253,14 +4429,43 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name, ExprResult Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, - const DeclarationNameInfo &NameInfo, - ConceptDecl *Template, - SourceLocation TemplateLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &ConceptNameInfo, + NamedDecl *FoundDecl, + ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs) { - // TODO: Do concept specialization here. - Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) << - "concept specialization"; - return ExprError(); + assert(NamedConcept && "A concept template id without a template?"); + + llvm::SmallVector<TemplateArgument, 4> Converted; + if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(), + const_cast<TemplateArgumentListInfo&>(*TemplateArgs), + /*PartialTemplateArgs=*/false, Converted, + /*UpdateArgsWithConversion=*/false)) + return ExprError(); + + ConstraintSatisfaction Satisfaction; + bool AreArgsDependent = false; + for (TemplateArgument &Arg : Converted) { + if (Arg.isDependent()) { + AreArgsDependent = true; + break; + } + } + if (!AreArgsDependent && + CheckConstraintSatisfaction(NamedConcept, + {NamedConcept->getConstraintExpr()}, + Converted, + SourceRange(SS.isSet() ? SS.getBeginLoc() : + ConceptNameInfo.getLoc(), + TemplateArgs->getRAngleLoc()), + Satisfaction)) + return ExprError(); + + return ConceptSpecializationExpr::Create(Context, + SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, + TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, + ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted, + AreArgsDependent ? nullptr : &Satisfaction); } ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, @@ -4303,10 +4508,10 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, TemplateKWLoc, TemplateArgs); } - if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) { - return CheckConceptTemplateId(SS, R.getLookupNameInfo(), - R.getAsSingle<ConceptDecl>(), - TemplateKWLoc, TemplateArgs); + if (R.getAsSingle<ConceptDecl>()) { + return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(), + R.getFoundDecl(), + R.getAsSingle<ConceptDecl>(), TemplateArgs); } // We don't want lookup warnings at this point. @@ -4910,9 +5115,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack()) NTTPType = NTTP->getExpansionType(ArgumentPackIndex); - // FIXME: Do we need to substitute into parameters here if they're - // instantiation-dependent but not dependent? - if (NTTPType->isDependentType() && + if (NTTPType->isInstantiationDependentType() && !isa<TemplateTemplateParmDecl>(Template) && !Template->getDeclContext()->isDependentContext()) { // Do substitution on the type of the non-type template parameter. @@ -5109,7 +5312,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - if (CheckTemplateTemplateArgument(Params, Arg)) + if (CheckTemplateTemplateArgument(TempParm, Params, Arg)) return true; Converted.push_back(Arg.getArgument()); @@ -5149,6 +5352,12 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, /// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us /// is not a pack expansion, so returns an empty Optional. static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) { + if (TemplateTypeParmDecl *TTP + = dyn_cast<TemplateTypeParmDecl>(Param)) { + if (TTP->isExpandedParameterPack()) + return TTP->getNumExpansionParameters(); + } + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { if (NTTP->isExpandedParameterPack()) @@ -5207,7 +5416,11 @@ bool Sema::CheckTemplateArgumentList( TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl<TemplateArgument> &Converted, - bool UpdateArgsWithConversions) { + bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) { + + if (ConstraintsNotSatisfied) + *ConstraintsNotSatisfied = false; + // Make a copy of the template arguments for processing. Only make the // changes at the end when successful in matching the arguments to the // template. @@ -5269,12 +5482,16 @@ bool Sema::CheckTemplateArgumentList( bool PackExpansionIntoNonPack = NewArgs[ArgIdx].getArgument().isPackExpansion() && (!(*Param)->isTemplateParameterPack() || getExpandedPackSize(*Param)); - if (PackExpansionIntoNonPack && isa<TypeAliasTemplateDecl>(Template)) { + if (PackExpansionIntoNonPack && (isa<TypeAliasTemplateDecl>(Template) || + isa<ConceptDecl>(Template))) { // Core issue 1430: we have a pack expansion as an argument to an // alias template, and it's not part of a parameter pack. This // can't be canonicalized, so reject it now. + // As for concepts - we cannot normalize constraints where this + // situation exists. Diag(NewArgs[ArgIdx].getLocation(), - diag::err_alias_template_expansion_into_fixed_list) + diag::err_template_expansion_into_fixed_list) + << (isa<ConceptDecl>(Template) ? 1 : 0) << NewArgs[ArgIdx].getSourceRange(); Diag((*Param)->getLocation(), diag::note_template_param_here); return true; @@ -5322,7 +5539,6 @@ bool Sema::CheckTemplateArgumentList( if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty()) Converted.push_back( TemplateArgument::CreatePackCopy(Context, ArgumentPack)); - return false; } @@ -5461,6 +5677,15 @@ bool Sema::CheckTemplateArgumentList( if (UpdateArgsWithConversions) TemplateArgs = std::move(NewArgs); + if (!PartialTemplateArgs && + EnsureTemplateArgumentListConstraints( + Template, Converted, SourceRange(TemplateLoc, + TemplateArgs.getRAngleLoc()))) { + if (ConstraintsNotSatisfied) + *ConstraintsNotSatisfied = true; + return true; + } + return false; } @@ -5486,7 +5711,7 @@ namespace { bool Visit##Class##Type(const Class##Type *) { return false; } #define NON_CANONICAL_TYPE(Class, Parent) \ bool Visit##Class##Type(const Class##Type *) { return false; } -#include "clang/AST/TypeNodes.def" +#include "clang/AST/TypeNodes.inc" bool VisitTagDecl(const TagDecl *Tag); bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS); @@ -5862,7 +6087,7 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter( Expr *Arg, QualType ArgType) { bool ObjCLifetimeConversion; if (ParamType->isPointerType() && - !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() && + !ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType() && S.IsQualificationConversion(ArgType, ParamType, false, ObjCLifetimeConversion)) { // For pointer-to-object types, qualification conversions are @@ -6364,7 +6589,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, DeductionArg = PE->getPattern(); if (DeduceAutoType( Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), - DeductionArg, ParamType, Depth) == DAR_Failed) { + DeductionArg, ParamType, Depth, + // We do not check constraints right now because the + // immediately-declared constraint of the auto type is also an + // associated constraint, and will be checked along with the other + // associated constraints after checking the template argument list. + /*IgnoreConstraints=*/true) == DAR_Failed) { Diag(Arg->getExprLoc(), diag::err_non_type_template_parm_type_deduction_failure) << Param->getDeclName() << Param->getType() << Arg->getType() @@ -6414,8 +6644,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } // If either the parameter has a dependent type or the argument is - // type-dependent, there's nothing we can check now. - if (ParamType->isDependentType() || Arg->isTypeDependent()) { + // type-dependent, there's nothing we can check now. The argument only + // contains an unexpanded pack during partial ordering, and there's + // nothing more we can check in that case. + if (ParamType->isDependentType() || Arg->isTypeDependent() || + Arg->containsUnexpandedParameterPack()) { // Force the argument to the type of the parameter to maintain invariants. auto *PE = dyn_cast<PackExpansionExpr>(Arg); if (PE) @@ -6735,20 +6968,20 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // overloaded functions (or a pointer to such), the matching // function is selected from the set (13.4). (ParamType->isPointerType() && - ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) || + ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType()) || // -- For a non-type template-parameter of type reference to // function, no conversions apply. If the template-argument // represents a set of overloaded functions, the matching // function is selected from the set (13.4). (ParamType->isReferenceType() && - ParamType->getAs<ReferenceType>()->getPointeeType()->isFunctionType()) || + ParamType->castAs<ReferenceType>()->getPointeeType()->isFunctionType()) || // -- For a non-type template-parameter of type pointer to // member function, no conversions apply. If the // template-argument represents a set of overloaded member // functions, the matching member function is selected from // the set (13.4). (ParamType->isMemberPointerType() && - ParamType->getAs<MemberPointerType>()->getPointeeType() + ParamType->castAs<MemberPointerType>()->getPointeeType() ->isFunctionType())) { if (Arg->getType() == Context.OverloadTy) { @@ -6868,7 +7101,8 @@ static void DiagnoseTemplateParameterListArityMismatch( /// /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. -bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params, +bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, + TemplateParameterList *Params, TemplateArgumentLoc &Arg) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); TemplateDecl *Template = Name.getAsTemplateDecl(); @@ -6907,6 +7141,9 @@ bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params, // C++1z [temp.arg.template]p3: (DR 150) // A template-argument matches a template template-parameter P when P // is at least as specialized as the template-argument A. + // FIXME: We should enable RelaxedTemplateTemplateArgs by default as it is a + // defect report resolution from C++17 and shouldn't be introduced by + // concepts. if (getLangOpts().RelaxedTemplateTemplateArgs) { // Quick check for the common case: // If P contains a parameter pack, then A [...] matches P if each of A's @@ -6914,12 +7151,44 @@ bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params, // the template-parameter-list of P. if (TemplateParameterListsAreEqual( Template->getTemplateParameters(), Params, false, - TPL_TemplateTemplateArgumentMatch, Arg.getLocation())) + TPL_TemplateTemplateArgumentMatch, Arg.getLocation()) && + // If the argument has no associated constraints, then the parameter is + // definitely at least as specialized as the argument. + // Otherwise - we need a more thorough check. + !Template->hasAssociatedConstraints()) return false; if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template, - Arg.getLocation())) + Arg.getLocation())) { + // C++2a[temp.func.order]p2 + // [...] If both deductions succeed, the partial ordering selects the + // more constrained template as described by the rules in + // [temp.constr.order]. + SmallVector<const Expr *, 3> ParamsAC, TemplateAC; + Params->getAssociatedConstraints(ParamsAC); + // C++2a[temp.arg.template]p3 + // [...] In this comparison, if P is unconstrained, the constraints on A + // are not considered. + if (ParamsAC.empty()) + return false; + Template->getAssociatedConstraints(TemplateAC); + bool IsParamAtLeastAsConstrained; + if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, + IsParamAtLeastAsConstrained)) + return true; + if (!IsParamAtLeastAsConstrained) { + Diag(Arg.getLocation(), + diag::err_template_template_parameter_not_at_least_as_constrained) + << Template << Param << Arg.getSourceRange(); + Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; + Diag(Template->getLocation(), diag::note_entity_declared_at) + << Template; + MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template, + TemplateAC); + return true; + } return false; + } // FIXME: Produce better diagnostics for deduction failures. } @@ -6963,94 +7232,73 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, ValueDecl *VD = Arg.getAsDecl(); - if (VD->getDeclContext()->isRecord() && - (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) || - isa<IndirectFieldDecl>(VD))) { - // If the value is a class member, we might have a pointer-to-member. - // Determine whether the non-type template template parameter is of - // pointer-to-member type. If so, we need to build an appropriate - // expression for a pointer-to-member, since a "normal" DeclRefExpr - // would refer to the member itself. - if (ParamType->isMemberPointerType()) { - QualType ClassType - = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext())); - NestedNameSpecifier *Qualifier - = NestedNameSpecifier::Create(Context, nullptr, false, - ClassType.getTypePtr()); - CXXScopeSpec SS; - SS.MakeTrivial(Context, Qualifier, Loc); - - // The actual value-ness of this is unimportant, but for - // internal consistency's sake, references to instance methods - // are r-values. - ExprValueKind VK = VK_LValue; - if (isa<CXXMethodDecl>(VD) && cast<CXXMethodDecl>(VD)->isInstance()) - VK = VK_RValue; - - ExprResult RefExpr = BuildDeclRefExpr(VD, - VD->getType().getNonReferenceType(), - VK, - Loc, - &SS); - if (RefExpr.isInvalid()) - return ExprError(); - - RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); - - // We might need to perform a trailing qualification conversion, since - // the element type on the parameter could be more qualified than the - // element type in the expression we constructed. - bool ObjCLifetimeConversion; - if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(), - ParamType.getUnqualifiedType(), false, - ObjCLifetimeConversion)) - RefExpr = ImpCastExprToType(RefExpr.get(), ParamType.getUnqualifiedType(), CK_NoOp); - - assert(!RefExpr.isInvalid() && - Context.hasSameType(((Expr*) RefExpr.get())->getType(), - ParamType.getUnqualifiedType())); - return RefExpr; - } - } - - QualType T = VD->getType().getNonReferenceType(); + CXXScopeSpec SS; + if (ParamType->isMemberPointerType()) { + // If this is a pointer to member, we need to use a qualified name to + // form a suitable pointer-to-member constant. + assert(VD->getDeclContext()->isRecord() && + (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) || + isa<IndirectFieldDecl>(VD))); + QualType ClassType + = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext())); + NestedNameSpecifier *Qualifier + = NestedNameSpecifier::Create(Context, nullptr, false, + ClassType.getTypePtr()); + SS.MakeTrivial(Context, Qualifier, Loc); + } + + ExprResult RefExpr = BuildDeclarationNameExpr( + SS, DeclarationNameInfo(VD->getDeclName(), Loc), VD); + if (RefExpr.isInvalid()) + return ExprError(); - if (ParamType->isPointerType()) { - // When the non-type template parameter is a pointer, take the - // address of the declaration. - ExprResult RefExpr = BuildDeclRefExpr(VD, T, VK_LValue, Loc); + // For a pointer, the argument declaration is the pointee. Take its address. + QualType ElemT(RefExpr.get()->getType()->getArrayElementTypeNoTypeQual(), 0); + if (ParamType->isPointerType() && !ElemT.isNull() && + Context.hasSimilarType(ElemT, ParamType->getPointeeType())) { + // Decay an array argument if we want a pointer to its first element. + RefExpr = DefaultFunctionArrayConversion(RefExpr.get()); if (RefExpr.isInvalid()) return ExprError(); - - if (!Context.hasSameUnqualifiedType(ParamType->getPointeeType(), T) && - (T->isFunctionType() || T->isArrayType())) { - // Decay functions and arrays unless we're forming a pointer to array. - RefExpr = DefaultFunctionArrayConversion(RefExpr.get()); - if (RefExpr.isInvalid()) - return ExprError(); - - return RefExpr; + } else if (ParamType->isPointerType() || ParamType->isMemberPointerType()) { + // For any other pointer, take the address (or form a pointer-to-member). + RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); + if (RefExpr.isInvalid()) + return ExprError(); + } else { + assert(ParamType->isReferenceType() && + "unexpected type for decl template argument"); + } + + // At this point we should have the right value category. + assert(ParamType->isReferenceType() == RefExpr.get()->isLValue() && + "value kind mismatch for non-type template argument"); + + // The type of the template parameter can differ from the type of the + // argument in various ways; convert it now if necessary. + QualType DestExprType = ParamType.getNonLValueExprType(Context); + if (!Context.hasSameType(RefExpr.get()->getType(), DestExprType)) { + CastKind CK; + QualType Ignored; + if (Context.hasSimilarType(RefExpr.get()->getType(), DestExprType) || + IsFunctionConversion(RefExpr.get()->getType(), DestExprType, Ignored)) { + CK = CK_NoOp; + } else if (ParamType->isVoidPointerType() && + RefExpr.get()->getType()->isPointerType()) { + CK = CK_BitCast; + } else { + // FIXME: Pointers to members can need conversion derived-to-base or + // base-to-derived conversions. We currently don't retain enough + // information to convert properly (we need to track a cast path or + // subobject number in the template argument). + llvm_unreachable( + "unexpected conversion required for non-type template argument"); } - - // Take the address of everything else - return CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); - } - - ExprValueKind VK = VK_RValue; - - // If the non-type template parameter has reference type, qualify the - // resulting declaration reference with the extra qualifiers on the - // type that the reference refers to. - if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>()) { - VK = VK_LValue; - T = Context.getQualifiedType(T, - TargetRef->getPointeeType().getQualifiers()); - } else if (isa<FunctionDecl>(VD)) { - // References to functions are always lvalues. - VK = VK_LValue; + RefExpr = ImpCastExprToType(RefExpr.get(), DestExprType, CK, + RefExpr.get()->getValueKind()); } - return BuildDeclRefExpr(VD, T, VK, Loc); + return RefExpr; } /// Construct a new expression that refers to the given @@ -7171,46 +7419,72 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, // 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_TemplateTemplateArgumentMatch && - (OldNTTP->getType()->isDependentType() || - NewNTTP->getType()->isDependentType())) - return true; - - if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { - 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 (Kind != Sema::TPL_TemplateTemplateArgumentMatch || + (!OldNTTP->getType()->isDependentType() && + !NewNTTP->getType()->isDependentType())) + if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { + 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 true; + return false; + } } - // For template template parameters, check the template parameter types. // The template parameter lists of template template // parameters must agree. - if (TemplateTemplateParmDecl *OldTTP + else if (TemplateTemplateParmDecl *OldTTP = dyn_cast<TemplateTemplateParmDecl>(Old)) { TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New); - return S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), - OldTTP->getTemplateParameters(), - Complain, + if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), + OldTTP->getTemplateParameters(), + Complain, (Kind == Sema::TPL_TemplateMatch ? Sema::TPL_TemplateTemplateParmMatch : Kind), - TemplateArgLoc); + TemplateArgLoc)) + return false; + } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) { + const Expr *NewC = nullptr, *OldC = nullptr; + if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint()) + NewC = TC->getImmediatelyDeclaredConstraint(); + if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint()) + OldC = TC->getImmediatelyDeclaredConstraint(); + + auto Diagnose = [&] { + S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(), + diag::err_template_different_type_constraint); + S.Diag(OldC ? OldC->getBeginLoc() : Old->getBeginLoc(), + diag::note_template_prev_declaration) << /*declaration*/0; + }; + + if (!NewC != !OldC) { + if (Complain) + Diagnose(); + return false; + } + + if (NewC) { + llvm::FoldingSetNodeID OldCID, NewCID; + OldC->Profile(OldCID, S.Context, /*Canonical=*/true); + NewC->Profile(NewCID, S.Context, /*Canonical=*/true); + if (OldCID != NewCID) { + if (Complain) + Diagnose(); + return false; + } + } } return true; @@ -7327,6 +7601,35 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, return false; } + if (Kind != TPL_TemplateTemplateArgumentMatch) { + const Expr *NewRC = New->getRequiresClause(); + const Expr *OldRC = Old->getRequiresClause(); + + auto Diagnose = [&] { + Diag(NewRC ? NewRC->getBeginLoc() : New->getTemplateLoc(), + diag::err_template_different_requires_clause); + Diag(OldRC ? OldRC->getBeginLoc() : Old->getTemplateLoc(), + diag::note_template_prev_declaration) << /*declaration*/0; + }; + + if (!NewRC != !OldRC) { + if (Complain) + Diagnose(); + return false; + } + + if (NewRC) { + llvm::FoldingSetNodeID OldRCID, NewRCID; + OldRC->Profile(OldRCID, Context, /*Canonical=*/true); + NewRC->Profile(NewRCID, Context, /*Canonical=*/true); + if (OldRCID != NewRCID) { + if (Complain) + Diagnose(); + return false; + } + } + } + return true; } @@ -7347,7 +7650,8 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) { // C++ [temp]p4: // A template [...] shall not have C linkage. DeclContext *Ctx = S->getEntity(); - if (Ctx && Ctx->isExternCContext()) { + assert(Ctx && "Unknown context"); + if (Ctx->isExternCContext()) { Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage) << TemplateParams->getSourceRange(); if (const LinkageSpecDecl *LSD = Ctx->getExternCContext()) @@ -7637,13 +7941,11 @@ bool Sema::CheckTemplatePartialSpecializationArgs( DeclResult Sema::ActOnClassTemplateSpecialization( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, - const ParsedAttributesView &Attr, + SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, + TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) { assert(TUK != TUK_Reference && "References are not specializations"); - CXXScopeSpec &SS = TemplateId.SS; - // NOTE: KWLoc is the location of the tag keyword. This will instead // store the location of the outermost template keyword in the declaration. SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0 @@ -7759,7 +8061,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, - TemplateArgs, false, Converted)) + TemplateArgs, false, Converted, + /*UpdateArgsWithConversion=*/true)) return true; // Find the class template (partial) specialization declaration that @@ -7785,8 +8088,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization( ClassTemplateSpecializationDecl *PrevDecl = nullptr; if (isPartialSpecialization) - // FIXME: Template parameter list matters, too - PrevDecl = ClassTemplate->findPartialSpecialization(Converted, InsertPos); + PrevDecl = ClassTemplate->findPartialSpecialization(Converted, + TemplateParams, + InsertPos); else PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos); @@ -7810,7 +8114,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization( Converted); if (Context.hasSameType(CanonType, - ClassTemplate->getInjectedClassNameSpecialization())) { + ClassTemplate->getInjectedClassNameSpecialization()) && + (!Context.getLangOpts().CPlusPlus2a || + !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: // // -- The argument list of the specialization shall not be identical @@ -8035,24 +8341,10 @@ Decl *Sema::ActOnConceptDefinition(Scope *S, ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name, TemplateParameterLists.front(), ConstraintExpr); - - if (!ConstraintExpr->isTypeDependent() && - ConstraintExpr->getType() != Context.BoolTy) { - // C++2a [temp.constr.atomic]p3: - // E shall be a constant expression of type bool. - // TODO: Do this check for individual atomic constraints - // and not the constraint expression. Probably should do it in - // ParseConstraintExpression. - Diag(ConstraintExpr->getSourceRange().getBegin(), - diag::err_concept_initialized_with_non_bool_type) - << ConstraintExpr->getType(); - NewDecl->setInvalidDecl(); - } - - if (NewDecl->getAssociatedConstraints()) { + + if (NewDecl->hasAssociatedConstraints()) { // C++2a [temp.concept]p4: // A concept shall not have associated constraints. - // TODO: Make a test once we have actual associated constraints. Diag(NameLoc, diag::err_concept_no_associated_constraints); NewDecl->setInvalidDecl(); } @@ -8468,7 +8760,7 @@ bool Sema::CheckFunctionTemplateSpecialization( // candidates at once, to get proper sorting and limiting. for (auto *OldND : Previous) { if (auto *OldFD = dyn_cast<FunctionDecl>(OldND->getUnderlyingDecl())) - NoteOverloadCandidate(OldND, OldFD, FD->getType(), false); + NoteOverloadCandidate(OldND, OldFD, CRK_None, FD->getType(), false); } FailedCandidates.NoteCandidates(*this, FD->getLocation()); return true; @@ -9019,7 +9311,8 @@ DeclResult Sema::ActOnExplicitInstantiation( // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, - TemplateArgs, false, Converted)) + TemplateArgs, false, Converted, + /*UpdateArgsWithConversion=*/true)) return true; // Find the class template specialization declaration that @@ -9786,24 +10079,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, << FixItHint::CreateRemoval(TypenameLoc); NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); + TypeSourceInfo *TSI = nullptr; QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None, - TypenameLoc, QualifierLoc, II, IdLoc); + TypenameLoc, QualifierLoc, II, IdLoc, &TSI, + /*DeducedTSTContext=*/true); if (T.isNull()) return true; - - TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); - if (isa<DependentNameType>(T)) { - DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>(); - TL.setElaboratedKeywordLoc(TypenameLoc); - TL.setQualifierLoc(QualifierLoc); - TL.setNameLoc(IdLoc); - } else { - ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs<ElaboratedTypeLoc>(); - TL.setElaboratedKeywordLoc(TypenameLoc); - TL.setQualifierLoc(QualifierLoc); - TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc); - } - return CreateParsedType(T, TSI); } @@ -9940,6 +10221,35 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, return true; } +QualType +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, + SourceLocation IILoc, + TypeSourceInfo **TSI, + bool DeducedTSTContext) { + QualType T = CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, II, IILoc, + DeducedTSTContext); + if (T.isNull()) + return QualType(); + + *TSI = Context.CreateTypeSourceInfo(T); + if (isa<DependentNameType>(T)) { + DependentNameTypeLoc TL = + (*TSI)->getTypeLoc().castAs<DependentNameTypeLoc>(); + TL.setElaboratedKeywordLoc(KeywordLoc); + TL.setQualifierLoc(QualifierLoc); + TL.setNameLoc(IILoc); + } else { + ElaboratedTypeLoc TL = (*TSI)->getTypeLoc().castAs<ElaboratedTypeLoc>(); + TL.setElaboratedKeywordLoc(KeywordLoc); + TL.setQualifierLoc(QualifierLoc); + TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IILoc); + } + return T; +} + /// Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType @@ -9947,32 +10257,38 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, - SourceLocation IILoc) { + SourceLocation IILoc, bool DeducedTSTContext) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); - DeclContext *Ctx = computeDeclContext(SS); - if (!Ctx) { - // If the nested-name-specifier is dependent and couldn't be - // resolved to a type, build a typename type. - assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); - return Context.getDependentNameType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - &II); + DeclContext *Ctx = nullptr; + if (QualifierLoc) { + Ctx = computeDeclContext(SS); + if (!Ctx) { + // If the nested-name-specifier is dependent and couldn't be + // resolved to a type, build a typename type. + assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); + return Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + &II); + } + + // If the nested-name-specifier refers to the current instantiation, + // the "typename" keyword itself is superfluous. In C++03, the + // program is actually ill-formed. However, DR 382 (in C++0x CD1) + // allows such extraneous "typename" keywords, and we retroactively + // apply this DR to C++03 code with only a warning. In any case we continue. + + if (RequireCompleteDeclContext(SS, Ctx)) + return QualType(); } - // If the nested-name-specifier refers to the current instantiation, - // the "typename" keyword itself is superfluous. In C++03, the - // program is actually ill-formed. However, DR 382 (in C++0x CD1) - // allows such extraneous "typename" keywords, and we retroactively - // apply this DR to C++03 code with only a warning. In any case we continue. - - if (RequireCompleteDeclContext(SS, Ctx)) - return QualType(); - DeclarationName Name(&II); LookupResult Result(*this, Name, IILoc, LookupOrdinaryName); - LookupQualifiedName(Result, Ctx, SS); + if (Ctx) + LookupQualifiedName(Result, Ctx, SS); + else + LookupName(Result, CurScope); unsigned DiagID = 0; Decl *Referenced = nullptr; switch (Result.getResultKind()) { @@ -9981,7 +10297,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // a more specific diagnostic. SourceRange CondRange; Expr *Cond = nullptr; - if (isEnableIf(QualifierLoc, II, CondRange, Cond)) { + if (Ctx && isEnableIf(QualifierLoc, II, CondRange, Cond)) { // If we have a condition, narrow it down to the specific failed // condition. if (Cond) { @@ -9997,12 +10313,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, return QualType(); } - Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if) + Diag(CondRange.getBegin(), + diag::err_typename_nested_not_found_enable_if) << Ctx << CondRange; return QualType(); } - DiagID = diag::err_typename_nested_not_found; + DiagID = Ctx ? diag::err_typename_nested_not_found + : diag::err_unknown_typename; break; } @@ -10068,6 +10386,19 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // is a placeholder for a deduced class type [...]. if (getLangOpts().CPlusPlus17) { if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) { + if (!DeducedTSTContext) { + QualType T(QualifierLoc + ? QualifierLoc.getNestedNameSpecifier()->getAsType() + : nullptr, 0); + if (!T.isNull()) + Diag(IILoc, diag::err_dependent_deduced_tst) + << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << T; + else + Diag(IILoc, diag::err_deduced_tst) + << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)); + Diag(TD->getLocation(), diag::note_template_decl_here); + return QualType(); + } return Context.getElaboratedType( Keyword, QualifierLoc.getNestedNameSpecifier(), Context.getDeducedTemplateSpecializationType(TemplateName(TD), @@ -10075,12 +10406,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, } } - DiagID = diag::err_typename_nested_not_type; + DiagID = Ctx ? diag::err_typename_nested_not_type + : diag::err_typename_not_type; Referenced = Result.getFoundDecl(); break; case LookupResult::FoundOverloaded: - DiagID = diag::err_typename_nested_not_type; + DiagID = Ctx ? diag::err_typename_nested_not_type + : diag::err_typename_not_type; Referenced = *Result.begin(); break; @@ -10092,9 +10425,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // type. Emit an appropriate diagnostic and return an error. SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(), IILoc); - Diag(IILoc, DiagID) << FullRange << Name << Ctx; + if (Ctx) + Diag(IILoc, DiagID) << FullRange << Name << Ctx; + else + Diag(IILoc, DiagID) << FullRange << Name; if (Referenced) - Diag(Referenced->getLocation(), diag::note_typename_refers_here) + Diag(Referenced->getLocation(), + Ctx ? diag::note_typename_member_refers_here + : diag::note_typename_refers_here) << Name; return QualType(); } @@ -10297,7 +10635,7 @@ void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, if (!FD) return; - auto LPT = llvm::make_unique<LateParsedTemplate>(); + auto LPT = std::make_unique<LateParsedTemplate>(); // Take tokens to avoid allocations LPT->Toks.swap(Toks); |
