Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -66,7 +66,8 @@ /// derived classes. class TemplateParameterList final : private llvm::TrailingObjects { + llvm::PointerUnion> { /// The location of the 'template' keyword. SourceLocation TemplateLoc; @@ -91,13 +92,15 @@ protected: TemplateParameterList(const ASTContext& C, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef Params, - SourceLocation RAngleLoc, Expr *RequiresClause); + SourceLocation RAngleLoc, Expr *RequiresClause, + TemplateParameterList *InheritedConstraints); size_t numTrailingObjects(OverloadToken) const { return NumParams; } - size_t numTrailingObjects(OverloadToken) const { + size_t numTrailingObjects( + OverloadToken>) const{ return HasRequiresClause ? 1 : 0; } @@ -107,11 +110,10 @@ friend TrailingObjects; static TemplateParameterList *Create(const ASTContext &C, - SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - ArrayRef Params, - SourceLocation RAngleLoc, - Expr *RequiresClause); + SourceLocation TemplateLoc, SourceLocation LAngleLoc, + ArrayRef Params, SourceLocation RAngleLoc, + Expr *RequiresClause, + TemplateParameterList *InheritedConstraints = nullptr); /// Iterates through the template parameters in this list. using iterator = NamedDecl **; @@ -170,14 +172,63 @@ return false; } + SourceLocation getTemplateLoc() const { return TemplateLoc; } + SourceLocation getLAngleLoc() const { return LAngleLoc; } + SourceLocation getRAngleLoc() const { return RAngleLoc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(TemplateLoc, RAngleLoc); + } + /// The constraint-expression of the associated requires-clause. Expr *getRequiresClause() { - return HasRequiresClause ? getTrailingObjects()[0] : nullptr; + if (!HasRequiresClause) + return nullptr; + const auto &P = *getTrailingObjects>(); + if (auto *I = P.dyn_cast()) + return I->getRequiresClause(); + return P.get(); } /// The constraint-expression of the associated requires-clause. const Expr *getRequiresClause() const { - return HasRequiresClause ? getTrailingObjects()[0] : nullptr; + if (!HasRequiresClause) + return nullptr; + const auto &P = *getTrailingObjects>(); + if (auto *I = P.dyn_cast()) + return I->getRequiresClause(); + return P.get(); + } + + void setRequiresClause(Expr *RC) { + assert(HasRequiresClause && + "Can only set requires clause on TPLs that were originally created " + "with one."); + *getTrailingObjects>() = RC; + } + + void setInheritedConstraints(TemplateParameterList *InheritedConstraints) { + assert(HasRequiresClause && + "Can only setInheritedConstraints when there is already a requires " + "clause"); + auto &P = *getTrailingObjects>(); + P = InheritedConstraints; + } + + TemplateParameterList *getInheritedConstraints() { + return getTrailingObjects>() + ->get(); + } + + bool inheritsConstraints() const { + return getTrailingObjects>() + ->is(); } /// \brief All associated constraints derived from this template parameter @@ -188,16 +239,10 @@ /// conjunction ("and"). llvm::SmallVector getAssociatedConstraints() const; + /// \brief Whether there are associated constraints in this template parameter + /// list or in any of its parameters. bool hasAssociatedConstraints() const; - SourceLocation getTemplateLoc() const { return TemplateLoc; } - SourceLocation getLAngleLoc() const { return LAngleLoc; } - SourceLocation getRAngleLoc() const { return RAngleLoc; } - - SourceRange getSourceRange() const LLVM_READONLY { - return SourceRange(TemplateLoc, RAngleLoc); - } - public: // FIXME: workaround for MSVC 2013; remove when no longer needed using FixedSizeStorageOwner = TrailingObjects::FixedSizeStorageOwner; @@ -210,9 +255,8 @@ class FixedSizeTemplateParameterListStorage : public TemplateParameterList::FixedSizeStorageOwner { typename TemplateParameterList::FixedSizeStorage< - NamedDecl *, Expr *>::with_counts< - N, HasRequiresClause ? 1u : 0u - >::type storage; + NamedDecl *, llvm::PointerUnion>:: + with_counts::type storage; public: FixedSizeTemplateParameterListStorage(const ASTContext &C, @@ -220,12 +264,16 @@ SourceLocation LAngleLoc, ArrayRef Params, SourceLocation RAngleLoc, - Expr *RequiresClause) + Expr *RequiresClause, + TemplateParameterList *InheritedConstraints) : FixedSizeStorageOwner( (assert(N == Params.size()), - assert(HasRequiresClause == (RequiresClause != nullptr)), + assert(HasRequiresClause == (RequiresClause != nullptr + || (InheritedConstraints != nullptr + && InheritedConstraints->HasRequiresClause))), new (static_cast(&storage)) TemplateParameterList(C, - TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause))) {} + TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause, + InheritedConstraints))) {} }; /// A template argument list. @@ -415,14 +463,6 @@ return TemplateParams; } - /// \brief Get the total constraint-expression associated with this template, - /// including constraint-expressions derived from the requires-clause, - /// trailing requires-clause (for functions and methods) and constrained - /// template parameters. - llvm::SmallVector getAssociatedConstraints() const; - - bool hasAssociatedConstraints() const; - /// Get the underlying, templated declaration. NamedDecl *getTemplatedDecl() const { return TemplatedDecl; } @@ -438,6 +478,14 @@ TemplatedDecl->getSourceRange().getEnd()); } + /// \brief Get the total constraint-expression associated with this template, + /// including constraint-expressions derived from the requires-clause, + /// trailing requires-clause (for functions and methods) and constrained + /// template parameters. + llvm::SmallVector getAssociatedConstraints() const; + + bool hasAssociatedConstraints() const; + protected: NamedDecl *TemplatedDecl; TemplateParameterList *TemplateParams; @@ -1120,8 +1168,10 @@ DefArgStorage DefaultArgument; /// \brief The constraint expression introduced by this declaration (by means - /// of a 'constrained-parameter'. - Expr *ConstraintExpression = nullptr; + /// of a 'constrained-parameter'. or a pointer to another argument from which + /// we inherit the constraint expression (in case of redeclaration or + /// instantiation) + llvm::PointerUnion ConstraintExpression; TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc, SourceLocation IdLoc, IdentifierInfo *Id, @@ -1202,7 +1252,12 @@ /// \brief Returns the constraint expression associated with this template /// parameter (if any). Expr *getConstraintExpression() const { - return ConstraintExpression; + if (ConstraintExpression.isNull()) + return nullptr; + if (auto *Inherited = + ConstraintExpression.dyn_cast()) + return Inherited->getConstraintExpression(); + return ConstraintExpression.get(); } /// \brief Sets the constraint expression associated with this template @@ -1211,6 +1266,20 @@ ConstraintExpression = E; } + /// \brief Sets the constraint expression associated with this template + /// parameter (if any). + void setInheritedConstraintExpression(TemplateTypeParmDecl *Prev) { + ConstraintExpression = Prev; + } + + TemplateTypeParmDecl *getInheritedFromConstraintExpressionDecl() const { + return ConstraintExpression.get(); + } + + bool constraintExpressionWasInherited() const { + return ConstraintExpression.is(); + } + /// \brief Get the associated-constraints of this template parameter. /// Currently, this will either be a vector of size 1 containing the /// constrained-parameter constraint or an empty vector. @@ -1218,8 +1287,8 @@ /// Use this instead of getConstraintExpression for concepts APIs that /// accept an ArrayRef of constraint expressions. llvm::SmallVector getAssociatedConstraints() const { - if (ConstraintExpression) - return{ConstraintExpression}; + if (Expr *CE = getConstraintExpression()) + return{CE}; return{}; } @@ -1263,8 +1332,10 @@ unsigned NumExpandedTypes = 0; /// \brief The constraint expression introduced by this declaration (by means - /// of a 'constrained-parameter'. - Expr *ConstraintExpression = nullptr; + /// of a 'constrained-parameter'. or a pointer to another argument from which + /// we inherit the constraint expression (in case of redeclaration or + /// instantiation) + llvm::PointerUnion ConstraintExpression; size_t numTrailingObjects( OverloadToken>) const { @@ -1415,7 +1486,12 @@ /// \brief Returns the constraint expression associated with this template /// parameter (if any). Expr *getConstraintExpression() const { - return ConstraintExpression; + if (ConstraintExpression.isNull()) + return nullptr; + if (auto *Inherited = + ConstraintExpression.dyn_cast()) + return Inherited->getConstraintExpression(); + return ConstraintExpression.get(); } /// \brief Sets the constraint expression associated with this template @@ -1424,6 +1500,20 @@ ConstraintExpression = E; } + /// \brief Sets the constraint expression associated with this template + /// parameter (if any). + void setInheritedConstraintExpression(NonTypeTemplateParmDecl *Prev) { + ConstraintExpression = Prev; + } + + NonTypeTemplateParmDecl *getInheritedFromConstraintExpressionDecl() const { + return ConstraintExpression.get(); + } + + bool constraintExpressionWasInherited() const { + return ConstraintExpression.is(); + } + /// \brief Get the associated-constraints of this template parameter. /// Currently, this will either be a vector of size 1 containing the /// constrained-parameter constraint or an empty vector. @@ -1431,8 +1521,8 @@ /// Use this instead of getConstraintExpression for concepts APIs that /// accept an ArrayRef of constraint expressions. llvm::SmallVector getAssociatedConstraints() const { - if (ConstraintExpression) - return{ConstraintExpression}; + if (Expr *CE = getConstraintExpression()) + return{CE}; return{}; } @@ -1470,8 +1560,10 @@ unsigned NumExpandedParams = 0; /// \brief The constraint expression introduced by this declaration (by means - /// of a 'constrained-parameter'. - Expr *ConstraintExpression = nullptr; + /// of a 'constrained-parameter'. or a pointer to another argument from which + /// we inherit the constraint expression (in case of redeclaration or + /// instantiation) + llvm::PointerUnion ConstraintExpression; TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, bool ParameterPack, @@ -1603,7 +1695,12 @@ /// \brief Returns the constraint expression associated with this template /// parameter (if any). Expr *getConstraintExpression() const { - return ConstraintExpression; + if (ConstraintExpression.isNull()) + return nullptr; + if (auto *Inherited = + ConstraintExpression.dyn_cast()) + return Inherited->getConstraintExpression(); + return ConstraintExpression.get(); } /// \brief Sets the constraint expression associated with this template @@ -1612,6 +1709,20 @@ ConstraintExpression = E; } + /// \brief Sets the constraint expression associated with this template + /// parameter (if any). + void setInheritedConstraintExpression(TemplateTemplateParmDecl *Prev) { + ConstraintExpression = Prev; + } + + TemplateTemplateParmDecl *getInheritedFromConstraintExpressionDecl() const { + return ConstraintExpression.get(); + } + + bool constraintExpressionWasInherited() const { + return ConstraintExpression.is(); + } + /// \brief Get the associated-constraints of this template parameter. /// Currently, this will either be a vector of size 1 containing the /// constrained-parameter constraint or an empty vector. @@ -1619,8 +1730,8 @@ /// Use this instead of getConstraintExpression for concepts APIs that /// accept an ArrayRef of constraint expressions. llvm::SmallVector getAssociatedConstraints() const { - if (ConstraintExpression) - return{ConstraintExpression}; + if (Expr *CE = getConstraintExpression()) + return{CE}; return{}; } @@ -2060,9 +2171,9 @@ /// template<> template /// struct X::Inner { /* ... */ }; /// \endcode - bool isMemberSpecialization() { + bool isMemberSpecialization() const { const auto *First = - cast(getFirstDecl()); + cast(getFirstDecl()); return First->InstantiatedFromMember.getInt(); } @@ -2906,9 +3017,9 @@ /// template<> template /// U* X::Inner = (T*)(0) + 1; /// \endcode - bool isMemberSpecialization() { + bool isMemberSpecialization() const { const auto *First = - cast(getFirstDecl()); + cast(getFirstDecl()); return First->InstantiatedFromMember.getInt(); } Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2664,11 +2664,8 @@ TRY_TO(TraverseTypeLoc(RetReq.getConstrainedParamExpectedType() ->getTypeLoc())); } - } else { - auto *NestedReq = cast(Req); - if (!NestedReq->isSubstitutionFailure()) - TRY_TO(TraverseStmt(NestedReq->getConstraintExpr())); - } + } else + TRY_TO(TraverseStmt(cast(Req)->getConstraintExpr())); }) // These literals (all of them) do not need any action. Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2470,8 +2470,8 @@ def note_atomic_constraint_evaluated_to_false_elaborated : Note< "%select{and|because}0 '%1' (%2 %3 %4) evaluated to false">; def note_could_not_normalize_argument_substitution_failed : Note< - "when substituting into %0 %1. Make sure concept arguments are " - "valid for any substitution">; + "when substituting into %0. Make sure concept arguments are valid for any " + "substitution">; def err_constrained_virtual_method : Error< "virtual function cannot have a requires clause">; def err_reference_to_function_with_unsatisfied_constraints : Error< Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -5781,15 +5781,17 @@ /// \brief Returns whether the given declaration's associated constraints are /// more constrained than another declaration's according to the partial /// ordering of constraints. - /// \param NoCache If true, the subsumption cache will not be used or updated - /// with the result of the check. Use when the given decls may have different - /// associated constraints later (e.g. when D1 is a template template - /// parameter and AC1 are the associated constraints for the current - /// instantiation). bool IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef AC1, - NamedDecl *D2, ArrayRef AC2, - bool NoCache = false); + NamedDecl *D2, ArrayRef AC2); + + /// \brief Returns whether the given declaration's associated constraints are + /// more constrained than another declaration's according to the partial + /// ordering of constraints. + bool IsAtLeastAsConstrained(ArrayRef AC1, + const MultiLevelTemplateArgumentList &MLTAL1, + ArrayRef AC2, + const MultiLevelTemplateArgumentList &MLTAL2); /// \brief If D1 was not at least as constrained as D2, but would've been if /// a pair of atomic constraints involved had been declared in a concept and @@ -5797,6 +5799,10 @@ /// \returns true if such a diagnostic was emitted, false otherwise. bool MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, ArrayRef AC1, NamedDecl *D2, ArrayRef AC2); + bool MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, + ArrayRef AC1, const MultiLevelTemplateArgumentList &MLTAL1, + NamedDecl *D2, ArrayRef AC2, + const MultiLevelTemplateArgumentList &MLTAL2); /// \brief Check whether the given list of constraint expressions are /// satisfied (as if in a 'conjunction') given template arguments. @@ -5811,23 +5817,16 @@ /// expression. /// \returns true if an error occurred and satisfaction could not be checked, /// false otherwise. - bool CheckConstraintSatisfaction(TemplateDecl *Template, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction); + bool CheckConstraintSatisfaction(NamedDecl *Template, + ArrayRef ConstraintExprs, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction); - bool CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl *TD, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction); - - bool CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl *TD, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction); + bool CheckConstraintSatisfaction(NestedRequirement *Req, + const Expr *ConstraintExpr, + const MultiLevelTemplateArgumentList &TemplateArgs, + ConstraintSatisfaction &Satisfaction, bool &IsDependent, + bool &ContainsUnexpandedParameterPack); /// \brief Check whether the given non-dependent constraint expression is /// satisfied. Returns false and updates Satisfaction with the satisfaction @@ -6693,9 +6692,11 @@ QualType InstantiatedParamType, Expr *Arg, TemplateArgument &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); - bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, - TemplateParameterList *Params, - TemplateArgumentLoc &Arg); + bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, + TemplateParameterList *Params, + TemplateArgumentLoc &Arg, + unsigned ArgumentPackIndex, + ArrayRef Converted); ExprResult BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, @@ -7439,7 +7440,7 @@ // MultiLevelTemplateArgumentList - getTemplateInstantiationArgs(NamedDecl *D, + getTemplateInstantiationArgs(Decl *D, const TemplateArgumentList *Innermost = nullptr, bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr); @@ -7817,6 +7818,8 @@ /// specialization in some surrounding active instantiation. bool isAlreadyInstantiating() const { return AlreadyInstantiating; } + InstantiatingTemplate(InstantiatingTemplate&&); + private: Sema &SemaRef; bool Invalid; @@ -8224,9 +8227,7 @@ void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, FunctionDecl *Function); - bool CheckInstantiatedFunctionTemplateConstraints( - SourceLocation PointOfInstantiation, FunctionDecl *Decl, - ArrayRef TemplateArgs, + bool CheckFunctionConstraints(FunctionDecl *Decl, ConstraintSatisfaction &Satisfaction); FunctionDecl *InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD, const TemplateArgumentList *Args, Index: include/clang/Sema/SemaConcept.h =================================================================== --- include/clang/Sema/SemaConcept.h +++ include/clang/Sema/SemaConcept.h @@ -23,6 +23,7 @@ #include namespace clang { class ConceptSpecializationExpr; +class MultiLevelTemplateArgumentList; class Sema; /// \brief The result of a constraint satisfaction check, containing the @@ -334,46 +335,29 @@ /// \brief A requires-expression requirement which is satisfied when a general /// constraint expression is satisfied ('nested' requirements). class NestedRequirement : public Requirement { - llvm::PointerUnion Value; + Expr *ConstraintExpr; ConstraintSatisfaction Satisfaction; public: friend class ASTStmtReader; friend class ASTStmtWriter; - NestedRequirement(SubstitutionDiagnostic *SubstDiag) : - Requirement(RK_Nested, /*Dependent=*/false, - /*ContainsUnexpandedParameterPack*/false, - /*Satisfied=*/false), Value(SubstDiag) {} - NestedRequirement(Expr *Constraint) : - Requirement(RK_Nested, /*Dependent=*/true, + Requirement(RK_Nested, /*IsDependent=*/true, Constraint->containsUnexpandedParameterPack()), - Value(Constraint) { - assert(Constraint->isInstantiationDependent() && - "Nested requirement with Non-dependent constraint must be " - "constructed with a Sema& or a ConstraintSatisfaction object"); + ConstraintExpr(Constraint) { + assert(Constraint->isInstantiationDependent() && "Non-dependent constraint " + "expressions must be provided along a Sema& or a precalculated " + "ConstraintSatisfaction"); } - NestedRequirement(Sema &S, Expr *Constraint); + NestedRequirement(Sema &S, Expr *Constraint, + const MultiLevelTemplateArgumentList &TemplateArgs); NestedRequirement(Expr *Constraint, ConstraintSatisfaction Satisfaction) : Requirement(RK_Nested, false, false, Satisfaction.IsSatisfied), - Value(Constraint), Satisfaction(std::move(Satisfaction)) {} - - bool isSubstitutionFailure() const { - return Value.is(); - } - SubstitutionDiagnostic *getSubstitutionDiagnostic() const { - assert(isSubstitutionFailure() && - "getSubstitutionDiagnostic() may not be called when there was no " - "substitution failure."); - return Value.get(); - } + ConstraintExpr(Constraint), Satisfaction(std::move(Satisfaction)) {} Expr *getConstraintExpr() const { - assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called " - "on nested requirements with " - "substitution failures."); - return Value.get(); + return ConstraintExpr; } void Diagnose(Sema &S, bool First) const override; Index: lib/AST/DeclTemplate.cpp =================================================================== --- lib/AST/DeclTemplate.cpp +++ lib/AST/DeclTemplate.cpp @@ -49,10 +49,12 @@ SourceLocation LAngleLoc, ArrayRef Params, SourceLocation RAngleLoc, - Expr *RequiresClause) + Expr *RequiresClause, + TemplateParameterList *InheritedConstraints) : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), NumParams(Params.size()), ContainsUnexpandedParameterPack(false), - HasRequiresClause(RequiresClause != nullptr), + HasRequiresClause(RequiresClause != nullptr || + (InheritedConstraints && InheritedConstraints->HasRequiresClause)), HasConstrainedParameters(false) { for (unsigned Idx = 0; Idx < NumParams; ++Idx) { NamedDecl *P = Params[Idx]; @@ -87,9 +89,15 @@ } if (HasRequiresClause) { - if (RequiresClause->containsUnexpandedParameterPack()) - ContainsUnexpandedParameterPack = true; - *getTrailingObjects() = RequiresClause; + auto &P = *getTrailingObjects>(); + if (InheritedConstraints) + P = InheritedConstraints; + else { + if (RequiresClause->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + P = RequiresClause; + } } } @@ -97,12 +105,19 @@ TemplateParameterList::Create(const ASTContext &C, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef Params, - SourceLocation RAngleLoc, Expr *RequiresClause) { - void *Mem = C.Allocate(totalSizeToAlloc( - Params.size(), RequiresClause ? 1u : 0u), + SourceLocation RAngleLoc, Expr *RequiresClause, + TemplateParameterList *InheritedConstraints) { + assert(!RequiresClause || !InheritedConstraints); + void *Mem = C.Allocate(totalSizeToAlloc>( + Params.size(), RequiresClause || + (InheritedConstraints && + InheritedConstraints->HasRequiresClause) ? 1u : 0u), alignof(TemplateParameterList)); return new (Mem) TemplateParameterList(C, TemplateLoc, LAngleLoc, Params, - RAngleLoc, RequiresClause); + RAngleLoc, RequiresClause, + InheritedConstraints); } unsigned TemplateParameterList::getMinRequiredArguments() const { Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -2284,10 +2284,7 @@ } else { auto *NestedReq = cast(Req); OS << "requires "; - if (NestedReq->isSubstitutionFailure()) - OS << "<>"; - else - PrintExpr(NestedReq->getConstraintExpr()); + PrintExpr(NestedReq->getConstraintExpr()); } OS << "; "; } Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -1343,9 +1343,7 @@ } else { ID.AddInteger(Requirement::RK_Nested); auto *NestedReq = cast(Req); - ID.AddBoolean(NestedReq->isSubstitutionFailure()); - if (!NestedReq->isSubstitutionFailure()) - Visit(NestedReq->getConstraintExpr()); + Visit(NestedReq->getConstraintExpr()); } } } Index: lib/Sema/SemaConcept.cpp =================================================================== --- lib/Sema/SemaConcept.cpp +++ lib/Sema/SemaConcept.cpp @@ -21,6 +21,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/SemaInternal.h" #include "clang/AST/ExprCXX.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" using namespace clang; @@ -100,7 +101,7 @@ SourceLocation New){ Diag(New, diag::err_template_different_associated_constraints); - Diag(Old, diag::note_template_prev_declaration) << /*declaration*/0; + Diag(Old, diag::note_template_decl_here); } template @@ -178,11 +179,14 @@ return false; } -template -static bool calculateConstraintSatisfaction( - Sema &S, TemplateDeclT *Template, ArrayRef TemplateArgs, - SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL, - const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { +template +static bool calculateConstraintSatisfaction(Sema &S, + SubstitutionInstantiatingTemplateCreator Creator, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation TemplateNameLoc, const Expr *ConstraintExpr, + ConstraintSatisfaction &Satisfaction, + bool *ContainsUnexpandedParameterPack = nullptr, + bool *IsDependent = nullptr) { return calculateConstraintSatisfaction( S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) { EnterExpressionEvaluationContext ConstantEvaluated( @@ -192,15 +196,15 @@ ExprResult SubstitutedExpression; { TemplateDeductionInfo Info(TemplateNameLoc); - Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(), - Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template, - Info, AtomicExpr->getSourceRange()); + Sema::InstantiatingTemplate Inst( + Creator(AtomicExpr->getBeginLoc(), AtomicExpr->getSourceRange(), + Info)); if (Inst.isInvalid()) return ExprError(); // We do not want error diagnostics escaping here. Sema::SFINAETrap Trap(S); SubstitutedExpression = S.SubstExpr(const_cast(AtomicExpr), - MLTAL); + TemplateArgs); if (SubstitutedExpression.isInvalid()) { // C++2a [temp.constr.atomic]p1 // ...If substitution results in an invalid type or expression, the @@ -226,6 +230,34 @@ } } + if (ContainsUnexpandedParameterPack != nullptr) + *ContainsUnexpandedParameterPack |= + SubstitutedExpression.get()->containsUnexpandedParameterPack(); + + if (SubstitutedExpression.get()->isInstantiationDependent()) { + // This might happen when constraint expressions present somewhere in + // a member declaration of a template are instantiated: + // + // template + // struct S { + // template 1); } + // ) W> + // struct M { }; + // } + // + // Referencing S will trigger the instantiation of the + // nested-requirement, with only the argument, and no the + // argument. We will treat this as satisfied for now because the + // expression will be instantiated again anyway with both the and + // the arguments. + if (IsDependent != nullptr) + *IsDependent = true; + Satisfaction.IsSatisfied = true; + return ExprEmpty(); + } + if (!S.CheckConstraintExpression(SubstitutedExpression.get())) return ExprError(); @@ -233,37 +265,21 @@ }); } -template -static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - if (ConstraintExprs.empty()) { - Satisfaction.IsSatisfied = true; - return false; - } - - for (auto& Arg : TemplateArgs) - if (Arg.isInstantiationDependent()) { - // No need to check satisfaction for dependent constraint expressions. - Satisfaction.IsSatisfied = true; - return false; - } - - Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), - Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs, - TemplateIDRange); - if (Inst.isInvalid()) - return true; - - MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(TemplateArgs); - +template +static bool +CheckConstraintSatisfaction(Sema &S, ArrayRef ConstraintExprs, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceRange TemplateIDRange, + SubstitutionInstantiatingTemplateCreator Creator, + ConstraintSatisfaction &Satisfaction, + bool *ContainsUnexpandedParameterPack = nullptr, + bool *IsDependent = nullptr) { for (const Expr *ConstraintExpr : ConstraintExprs) { - if (calculateConstraintSatisfaction(S, Template, TemplateArgs, - TemplateIDRange.getBegin(), MLTAL, - ConstraintExpr, Satisfaction)) + if (calculateConstraintSatisfaction(S, Creator, TemplateArgs, + TemplateIDRange.getBegin(), + ConstraintExpr, Satisfaction, + ContainsUnexpandedParameterPack, + IsDependent)) return true; if (!Satisfaction.IsSatisfied) // [temp.constr.op] p2 @@ -275,36 +291,53 @@ return false; } -bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); -} +bool Sema::CheckConstraintSatisfaction(NamedDecl *Template, + ArrayRef ConstraintExprs, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { + if (ConstraintExprs.empty()) { + Satisfaction.IsSatisfied = true; + return false; + } + InstantiatingTemplate Inst(*this, TemplateIDRange.getBegin(), + InstantiatingTemplate::ConstraintsCheck{}, Template, + TemplateArgs.getInnermost(), TemplateIDRange); + if (Inst.isInvalid()) + return true; -bool -Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); + return ::CheckConstraintSatisfaction(*this, ConstraintExprs, + TemplateArgs, TemplateIDRange, + [&] (SourceLocation PointOfInstantiation, + SourceRange InstantiationRange, + TemplateDeductionInfo &DeductionInfo) { + return std::move(InstantiatingTemplate(*this, PointOfInstantiation, + InstantiatingTemplate::ConstraintSubstitution{}, Template, + DeductionInfo, InstantiationRange)); + }, Satisfaction); } -bool -Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial, - ArrayRef ConstraintExprs, - ArrayRef TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); +bool Sema::CheckConstraintSatisfaction(NestedRequirement *Req, + const Expr *ConstraintExpr, + const MultiLevelTemplateArgumentList &TemplateArgs, + ConstraintSatisfaction &Satisfaction, + bool &IsDependent, bool &ContainsUnexpandedParameterPack) { + IsDependent = false; + ContainsUnexpandedParameterPack = false; + + InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(), Req, + InstantiatingTemplate::ConstraintsCheck{}, + ConstraintExpr->getSourceRange()); + if (Inst.isInvalid()) + return true; + + return ::CheckConstraintSatisfaction(*this, {ConstraintExpr}, + TemplateArgs, ConstraintExpr->getSourceRange(), + [&] (SourceLocation PointOfInstantiation, + SourceRange InstantiationRange, + TemplateDeductionInfo &DeductionInfo) { + return std::move(InstantiatingTemplate(*this, PointOfInstantiation, + Req, DeductionInfo, InstantiationRange)); + }, Satisfaction, &ContainsUnexpandedParameterPack, &IsDependent); } bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, @@ -320,8 +353,11 @@ TemplateDecl *TD, ArrayRef TemplateArgs, SourceRange TemplateIDRange) { ConstraintSatisfaction Satisfaction; + TemplateArgumentList TAL(TemplateArgumentList::OnStack, TemplateArgs); + MultiLevelTemplateArgumentList MLTAL = + getTemplateInstantiationArgs(TD, /*Innermost=*/&TAL); if (CheckConstraintSatisfaction(TD, TD->getAssociatedConstraints(), - TemplateArgs, TemplateIDRange, Satisfaction)) + MLTAL, TemplateIDRange, Satisfaction)) return true; if (!Satisfaction.IsSatisfied) { @@ -457,25 +493,26 @@ } namespace { struct AtomicConstraint { + const Expr *ConstraintExpr; + llvm::SmallVector ParameterMapping; + AtomicConstraint(const Expr *ConstraintExpr, - const ASTTemplateArgumentListInfo *ParameterMapping = nullptr) : - ConstraintExpr{ConstraintExpr}, ParameterMapping{ParameterMapping} {} + ArrayRef ParameterMapping) : + ConstraintExpr{ConstraintExpr} { + this->ParameterMapping.assign(ParameterMapping.data(), + ParameterMapping.data() + + ParameterMapping.size()); + } bool hasMatchingParameterMapping(ASTContext &C, const AtomicConstraint &Other) const { - if ((!ParameterMapping) != (!Other.ParameterMapping)) - return false; - if (!ParameterMapping) - return true; - if (ParameterMapping->NumTemplateArgs != - Other.ParameterMapping->NumTemplateArgs) + if (ParameterMapping.size() != Other.ParameterMapping.size()) return false; - for (unsigned I = 0, S = ParameterMapping->NumTemplateArgs; I < S; ++I) - if (!C.getCanonicalTemplateArgument( - ParameterMapping->arguments()[I].getArgument()) + for (unsigned I = 0, S = ParameterMapping.size(); I < S; ++I) + if (!C.getCanonicalTemplateArgument(ParameterMapping[I]) .structurallyEquals(C.getCanonicalTemplateArgument( - Other.ParameterMapping->arguments()[I].getArgument()))) + Other.ParameterMapping[I]))) return false; return true; } @@ -499,9 +536,6 @@ // Check that the parameter lists are identical return hasMatchingParameterMapping(C, Other); } - - const Expr *ConstraintExpr; - const ASTTemplateArgumentListInfo *ParameterMapping; }; /// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is @@ -546,9 +580,9 @@ "getAtomicConstraint called on non-atomic constraint."); return Constraint.get(); } - static llvm::Optional fromConstraintExpr( - Sema &S, const Expr *E, TemplateDecl *TD = nullptr, - const ASTTemplateArgumentListInfo *ParameterMapping = nullptr) { + static llvm::Optional fromConstraintExpr(Sema &S, + const Expr *E, + const MultiLevelTemplateArgumentList *ParameterMapping = nullptr) { assert(E != nullptr); // C++ [temp.constr.normal]p1.1 @@ -556,13 +590,13 @@ // - The normal form of an expression (E) is the normal form of E. // [...] if (auto *P = dyn_cast(E)) - return fromConstraintExpr(S, P->getSubExpr(), TD, ParameterMapping); + return fromConstraintExpr(S, P->getSubExpr(), ParameterMapping); if (auto *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { - auto LHS = fromConstraintExpr(S, BO->getLHS(), TD, ParameterMapping); + auto LHS = fromConstraintExpr(S, BO->getLHS(), ParameterMapping); if (!LHS) return llvm::Optional{}; - auto RHS = fromConstraintExpr(S, BO->getRHS(), TD, ParameterMapping); + auto RHS = fromConstraintExpr(S, BO->getRHS(), ParameterMapping); if (!RHS) return llvm::Optional{}; @@ -630,11 +664,12 @@ // // Just treat C as an atomic constraint. return NormalizedConstraint{new (S.Context) - AtomicConstraint(E, Mapping)}; - + AtomicConstraint(E, TempList)}; + MultiLevelTemplateArgumentList MLTAL; + MLTAL.addOuterTemplateArguments(TempList); return fromConstraintExpr(S, CSE->getNamedConcept()->getConstraintExpr(), - CSE->getNamedConcept(), Mapping); + &MLTAL); } // This is not a top level CSE. @@ -645,7 +680,7 @@ // template // concept C2 = C1; -> We are here. // Mapping is {T1=U, T2=T} - // ParameterMapping is {T=X, U=Y}, TD is C2 + // ParameterMapping is {T=X, U=Y} // // template // void foo() requires C2 {} @@ -656,37 +691,14 @@ // Mapping, we instead substitute ParameterMapping into C1 and take // the substituted argument list as the ParameterMapping for the next // level down. - assert(TD && "ParameterMapping provided without TemplateDecl"); - - TemplateArgumentListInfo TALI(ParameterMapping->LAngleLoc, - ParameterMapping->RAngleLoc); - for (auto &Arg : ParameterMapping->arguments()) - TALI.addArgument(Arg); - llvm::SmallVector TempList; - bool InstantiationDependent = false; - bool Success = - !S.CheckTemplateArgumentList(TD, ParameterMapping->LAngleLoc, - TALI, /*PartialTemplateArgs=*/false, - TempList, - /*UpdateArgsWithConversions=*/false, - &InstantiationDependent) && - !InstantiationDependent; - assert(Success && "ParameterMapping should have already been cheked " - "against template argument list earlier."); auto DiagnoseSubstitutionError = [&](unsigned int Diag) { - std::string TemplateArgString = S.getTemplateArgumentBindingsText( - TD->getTemplateParameters(), TempList.data(), TempList.size()); S.Diag(CSE->getBeginLoc(), Diag) - << const_cast(CSE) - << TemplateArgString; + << const_cast(CSE); }; - MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(TempList); - ExprResult Result = S.SubstExpr( - const_cast(CSE), MLTAL); + const_cast(CSE), *ParameterMapping); if (!Result.isUsable() || Result.isInvalid()) { // C++ [temp.constr.normal] // If any such substitution results in an invalid type or @@ -698,18 +710,22 @@ diag::note_could_not_normalize_argument_substitution_failed); return llvm::Optional{}; } - ParameterMapping = cast(Result.get()) + Mapping = cast(Result.get()) ->getTemplateArgsAsWritten(); - TemplateArgumentListInfo SubstTALI(ParameterMapping->LAngleLoc, - ParameterMapping->RAngleLoc); - for (auto &Arg : ParameterMapping->arguments()) + TemplateArgumentListInfo SubstTALI(Mapping->LAngleLoc, + Mapping->RAngleLoc); + for (auto &Arg : Mapping->arguments()) SubstTALI.addArgument(Arg); llvm::SmallVector Converted; + bool InstantiationDependent; bool Failure = S.CheckTemplateArgumentList( CSE->getNamedConcept(), CSE->getBeginLoc(), SubstTALI, /*PartialTemplateArgs=*/false, Converted, /*UpdateArgsWithConversions=*/true, &InstantiationDependent); + MultiLevelTemplateArgumentList MLTAL; + MLTAL.addOuterTemplateArguments(Converted); + // The case is this: // // template @@ -743,29 +759,32 @@ // // Treat the CSE as an atomic expression. return NormalizedConstraint{new (S.Context) - AtomicConstraint(E, ParameterMapping)}; + AtomicConstraint(E, Converted)}; return fromConstraintExpr(S, CSE->getNamedConcept()->getConstraintExpr(), - CSE->getNamedConcept(), ParameterMapping); + &MLTAL); } - return NormalizedConstraint{new (S.Context) - AtomicConstraint(E, ParameterMapping)}; + return NormalizedConstraint{ + new (S.Context) AtomicConstraint(E, + ParameterMapping && ParameterMapping->getNumLevels() != 0 ? + ParameterMapping->getInnermost() : ArrayRef{})}; } static llvm::Optional fromConstraintExprs(Sema &S, - ArrayRef E) { + ArrayRef E, + const MultiLevelTemplateArgumentList *ParameterMapping = nullptr) { assert(E.size() != 0); - auto First = fromConstraintExpr(S, E[0]); + auto First = fromConstraintExpr(S, E[0], ParameterMapping); if (E.size() == 1) return First; - auto Second = fromConstraintExpr(S, E[1]); + auto Second = fromConstraintExpr(S, E[1], ParameterMapping); if (!Second) return llvm::Optional{}; llvm::Optional Conjunction; Conjunction.emplace(S.Context, std::move(*First), std::move(*Second), CCK_Conjunction); for (unsigned I = 2; I < E.size(); ++I) { - auto Next = fromConstraintExpr(S, E[I]); + auto Next = fromConstraintExpr(S, E[I], ParameterMapping); if (!Next) return llvm::Optional{}; NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction), @@ -840,22 +859,15 @@ } template -static bool subsumes(Sema &S, ArrayRef P, - ArrayRef Q, bool &DoesSubsume, +static bool subsumes(Sema &S, NormalizedConstraint &PNormalized, + NormalizedConstraint &QNormalized, bool &DoesSubsume, AtomicSubsumptionEvaluator E) { // C++ [temp.constr.order] p2 // In order to determine if a constraint P subsumes a constraint Q, P is // transformed into disjunctive normal form, and Q is transformed into // conjunctive normal form. [...] - auto PNormalized = NormalizedConstraint::fromConstraintExprs(S, P); - if (!PNormalized) - return true; - const NormalForm PDNF = makeDNF(*PNormalized); - - auto QNormalized = NormalizedConstraint::fromConstraintExprs(S, Q); - if (!QNormalized) - return true; - const NormalForm QCNF = makeCNF(*QNormalized); + const NormalForm PDNF = makeDNF(PNormalized); + const NormalForm QCNF = makeCNF(QNormalized); // C++ [temp.constr.order] p2 // Then, P subsumes Q if and only if, for every disjunctive clause Pi in the @@ -890,8 +902,7 @@ } bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef AC1, - NamedDecl *D2, ArrayRef AC2, - bool NoCache) { + NamedDecl *D2, ArrayRef AC2) { if (AC1.empty()) return AC2.empty(); if (AC2.empty()) @@ -899,26 +910,56 @@ return true; std::pair Key{D1, D2}; - if (!NoCache) { - auto CacheEntry = SubsumptionCache.find(Key); - if (CacheEntry != SubsumptionCache.end()) - return CacheEntry->second; - } + auto CacheEntry = SubsumptionCache.find(Key); + if (CacheEntry != SubsumptionCache.end()) + return CacheEntry->second; + + MultiLevelTemplateArgumentList MLTAL1 = + getTemplateInstantiationArgs(cast(D1->getDeclContext())); + MultiLevelTemplateArgumentList MLTAL2 = + getTemplateInstantiationArgs(cast(D2->getDeclContext())); + bool Subsumes = IsAtLeastAsConstrained(AC1, MLTAL1, AC2, MLTAL2); + SubsumptionCache.try_emplace(Key, Subsumes); + return Subsumes; +} + +bool +Sema::IsAtLeastAsConstrained(ArrayRef AC1, + const MultiLevelTemplateArgumentList &MLTAL1, + ArrayRef AC2, + const MultiLevelTemplateArgumentList &MLTAL2) { + if (AC1.empty()) + return AC2.empty(); + if (AC2.empty()) + // TD1 has associated constraints and TD2 does not. + return true; + + auto Normalized1 = NormalizedConstraint::fromConstraintExprs(*this, AC1, + &MLTAL1); + if (!Normalized1) + // Program is ill-formed at this point. + return false; + + auto Normalized2 = NormalizedConstraint::fromConstraintExprs(*this, AC2, + &MLTAL2); + if (!Normalized2) + // Program is ill-formed at this point. + return false; bool Subsumes; - if (subsumes(*this, AC1, AC2, Subsumes, + if (subsumes(*this, *Normalized1, *Normalized2, Subsumes, [this] (const AtomicConstraint &A, const AtomicConstraint &B) { return A.subsumes(Context, B); })) // Program is ill-formed at this point. return false; - if (!NoCache) - SubsumptionCache.try_emplace(Key, Subsumes); return Subsumes; } bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, - ArrayRef AC1, NamedDecl *D2, ArrayRef AC2) { + ArrayRef AC1, const MultiLevelTemplateArgumentList &MLTAL1, + NamedDecl *D2, ArrayRef AC2, + const MultiLevelTemplateArgumentList &MLTAL2) { if (AC1.empty() || AC2.empty()) return false; @@ -952,15 +993,32 @@ { // The subsumption checks might cause diagnostics SFINAETrap Trap(*this); + + auto Normalized1 = NormalizedConstraint::fromConstraintExprs(*this, AC1, + &MLTAL1); + if (!Normalized1) + // Program is ill-formed at this point. + return false; + + auto Normalized2 = NormalizedConstraint::fromConstraintExprs(*this, AC2, + &MLTAL2); + if (!Normalized2) + // Program is ill-formed at this point. + return false; + bool Is1AtLeastAs2Normally, Is2AtLeastAs1Normally; - if (subsumes(*this, AC1, AC2, Is1AtLeastAs2Normally, NormalExprEvaluator)) + if (subsumes(*this, *Normalized1, *Normalized2, Is1AtLeastAs2Normally, + NormalExprEvaluator)) return false; - if (subsumes(*this, AC2, AC1, Is2AtLeastAs1Normally, NormalExprEvaluator)) + if (subsumes(*this, *Normalized2, *Normalized1, Is2AtLeastAs1Normally, + NormalExprEvaluator)) return false; bool Is1AtLeastAs2, Is2AtLeastAs1; - if (subsumes(*this, AC1, AC2, Is1AtLeastAs2, IdenticalExprEvaluator)) + if (subsumes(*this, *Normalized1, *Normalized2, Is1AtLeastAs2, + IdenticalExprEvaluator)) return false; - if (subsumes(*this, AC2, AC1, Is2AtLeastAs1, IdenticalExprEvaluator)) + if (subsumes(*this, *Normalized2, *Normalized1, Is2AtLeastAs1, + IdenticalExprEvaluator)) return false; if (Is1AtLeastAs2 == Is1AtLeastAs2Normally && Is2AtLeastAs1 == Is2AtLeastAs1Normally) @@ -980,6 +1038,17 @@ return true; } +bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, + ArrayRef AC1, NamedDecl *D2, ArrayRef AC2) { + if (AC1.empty() || AC2.empty()) + return false; + MultiLevelTemplateArgumentList MLTAL1 = + getTemplateInstantiationArgs(cast(D1->getDeclContext())); + MultiLevelTemplateArgumentList MLTAL2 = + getTemplateInstantiationArgs(cast(D2->getDeclContext())); + return MaybeEmitAmbiguousAtomicConstraintsDiagnostic(D1, AC1, MLTAL1, D2, AC2, + MLTAL2); +} ExprRequirement::ExprRequirement(Sema &S, Expr *E, bool IsSimple, @@ -1270,28 +1339,24 @@ } } -NestedRequirement::NestedRequirement(Sema &S, Expr *Constraint) : - Requirement(RK_Nested, Constraint->isInstantiationDependent(), - Constraint->containsUnexpandedParameterPack(), - /*Satisfied=*/false), Value(Constraint) { - if (isDependent()) - return; - S.CheckConstraintSatisfaction(Constraint, Satisfaction); +NestedRequirement::NestedRequirement(Sema &S, Expr *Constraint, + const MultiLevelTemplateArgumentList &TemplateArgs) : + Requirement(RK_Nested, + /*(set below)Dependent=*/false, + /*(set below)ContainsUnexpandedParameterPack=*/false, + /*(set below)Satisfied=*/false), ConstraintExpr(Constraint) { + if (TemplateArgs.getNumLevels() == 0) + S.CheckConstraintSatisfaction(Constraint, Satisfaction); + else { + bool IsDependent, ContainsUnexpandedParameterPack; + S.CheckConstraintSatisfaction(this, Constraint, TemplateArgs, + Satisfaction, IsDependent, ContainsUnexpandedParameterPack); + setDependent(IsDependent); + setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack); + } setSatisfied(Satisfaction.IsSatisfied); } void NestedRequirement::Diagnose(Sema &S, bool First) const { - if (isSubstitutionFailure()) { - auto *SubstDiag = getSubstitutionDiagnostic(); - if (!SubstDiag->DiagMessage.empty()) - S.Diag(SubstDiag->DiagLoc, - diag::note_nested_requirement_substitution_error) << (int)First - << SubstDiag->SubstitutedEntity << SubstDiag->DiagMessage; - else - S.Diag(SubstDiag->DiagLoc, - diag::note_nested_requirement_unknown_substitution_error) - << (int)First << SubstDiag->SubstitutedEntity; - return; - } S.DiagnoseUnsatisfiedConstraint(Satisfaction, First); } \ No newline at end of file Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -337,20 +337,17 @@ // // See if this is a function with constraints that need to be satisfied. if (FunctionDecl *FD = dyn_cast(D)) { - if (Expr *RC = FD->getTrailingRequiresClause()) { - ConstraintSatisfaction Satisfaction; - bool Failed = CheckConstraintSatisfaction(RC, Satisfaction); - if (Failed) - // A diagnostic will have already been generated (non-constant - // constraint expression, for example) - return true; - if (!Satisfaction.IsSatisfied) { - Diag(Loc, - diag::err_reference_to_function_with_unsatisfied_constraints) - << D; - DiagnoseUnsatisfiedConstraint(Satisfaction); - return true; - } + ConstraintSatisfaction Satisfaction; + bool Failed = CheckFunctionConstraints(FD, Satisfaction); + if (Failed) + // A diagnostic will have already been generated (non-constant + // constraint expression, for example) + return true; + if (!Satisfaction.IsSatisfied) { + Diag(Loc, + diag::err_reference_to_function_with_unsatisfied_constraints) << D; + DiagnoseUnsatisfiedConstraint(Satisfaction); + return true; } } Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -34,6 +34,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaLambda.h" +#include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/STLExtras.h" @@ -8120,7 +8121,10 @@ } Requirement *Sema::ActOnNestedRequirement(Expr *Constraint) { - return new (Context) NestedRequirement(*this, Constraint); + if (!Constraint->isInstantiationDependent()) + return new (Context) NestedRequirement(*this, Constraint, + MultiLevelTemplateArgumentList()); + return new (Context) NestedRequirement(Constraint); } RequiresExprBodyDecl * Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -6175,10 +6175,9 @@ return; } - Expr *RequiresClause = Function->getTrailingRequiresClause(); - if (LangOpts.ConceptsTS && RequiresClause) { + if (LangOpts.ConceptsTS) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Function, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -6687,10 +6686,9 @@ return; } - Expr *RequiresClause = Method->getTrailingRequiresClause(); - if (LangOpts.ConceptsTS && RequiresClause) { + if (LangOpts.ConceptsTS) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Method, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -7049,10 +7047,9 @@ return; } - Expr *RequiresClause = Conversion->getTrailingRequiresClause(); - if (LangOpts.ConceptsTS && RequiresClause) { + if (LangOpts.ConceptsTS) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Conversion, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -9675,22 +9672,20 @@ return false; } - if (const Expr *RC = FD->getTrailingRequiresClause()) { - ConstraintSatisfaction Satisfaction; - if (S.CheckConstraintSatisfaction(RC, Satisfaction)) - return false; - if (!Satisfaction.IsSatisfied) { - if (Complain) { - if (InOverloadResolution) - S.Diag(FD->getBeginLoc(), - diag::note_ovl_candidate_unsatisfied_constraints); - else - S.Diag(Loc, diag::err_addrof_function_constraints_not_satisfied) - << FD; - S.DiagnoseUnsatisfiedConstraint(Satisfaction); - } - return false; + ConstraintSatisfaction Satisfaction; + if (S.CheckFunctionConstraints(const_cast(FD), Satisfaction)) + return false; + if (!Satisfaction.IsSatisfied) { + if (Complain) { + if (InOverloadResolution) + S.Diag(FD->getBeginLoc(), + diag::note_ovl_candidate_unsatisfied_constraints); + else + S.Diag(Loc, diag::err_addrof_function_constraints_not_satisfied) + << FD; + S.DiagnoseUnsatisfiedConstraint(Satisfaction); } + return false; } auto I = llvm::find_if(FD->parameters(), [](const ParmVarDecl *P) { @@ -10622,8 +10617,7 @@ diag::note_ovl_candidate_constraints_not_satisfied) << (unsigned) FnKind; ConstraintSatisfaction Satisfaction; - if (S.CheckConstraintSatisfaction(Fn->getTrailingRequiresClause(), - Satisfaction)) + if (S.CheckFunctionConstraints(Fn, Satisfaction)) break; S.DiagnoseUnsatisfiedConstraint(Satisfaction); } @@ -11137,7 +11131,7 @@ -> std::pair> { if (Cand->Specialization) if (FunctionDecl *FD = dyn_cast(Cand->Specialization)) - if (TemplateDecl *TD = FD->getPrimaryTemplate()) + if (auto *TD = FD->getPrimaryTemplate()) return { FD, TD->getAssociatedConstraints() }; return { nullptr, {} }; }); Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -2179,6 +2179,23 @@ NewMismatch->getBeginLoc() : NewParams->getTemplateLoc()); Invalid = true; + } else if (OldParams && NewParams->hasAssociatedConstraints()) { + if (NewParams->getRequiresClause()) + NewParams->setInheritedConstraints(OldParams); + for (unsigned I = 0, C = NewParams->size(); I != C; ++I) { + auto *NewParam = (*NewParams).getParam(I); + auto *OldParam = (*OldParams).getParam(I); + if (auto *NewTTP = dyn_cast(NewParam)) + NewTTP->setInheritedConstraintExpression( + cast(OldParam)); + else if (auto *NewNTTP = dyn_cast(NewParam)) + NewNTTP->setInheritedConstraintExpression( + cast(OldParam)); + else + cast(NewParam)-> + setInheritedConstraintExpression( + cast(OldParam)); + } } bool RemoveDefaultArguments = false; @@ -4160,15 +4177,17 @@ break; } } - if (!IsInstantiationDependent) + if (!IsInstantiationDependent) { + TemplateArgumentList TempList(TemplateArgumentList::OnStack, Converted); if (CheckConstraintSatisfaction(NamedConcept, {NamedConcept->getConstraintExpr()}, - Converted, + MultiLevelTemplateArgumentList(TempList), SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameLoc, TemplateArgs->getRAngleLoc()), Satisfaction)) return ExprError(); + } return ConceptSpecializationExpr::Create(Context, SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, @@ -5012,7 +5031,8 @@ case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - if (CheckTemplateTemplateArgument(TempParm, Params, Arg)) + if (CheckTemplateArgument(TempParm, Params, Arg, ArgumentPackIndex, + Converted)) return true; Converted.push_back(Arg.getArgument()); @@ -6761,9 +6781,11 @@ /// /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. -bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, - TemplateParameterList *Params, - TemplateArgumentLoc &Arg) { +bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, + TemplateParameterList *Params, + TemplateArgumentLoc &Arg, + unsigned ArgumentPackIndex, + ArrayRef Converted) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template) { @@ -6817,14 +6839,33 @@ if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template, Arg.getLocation())) { + TemplateArgumentList ParamsSoFar(TemplateArgumentList::OnStack, + Converted); + // We want the enclosing template arguments along with the template + // arguments provided thus far in this template parameter list: + // + // template + // struct A { + // template class TT> struct B { }; + // }; + // In the above example, for checking TT, we'll need: + // ParamMLTAL: + // Depth 0: + // Depth 1: + DeclContext *TemplatedEntityParent = Param->getDeclContext()->getParent(); + MultiLevelTemplateArgumentList ParamMLTAL = + getTemplateInstantiationArgs(cast(TemplatedEntityParent), + /*Innermost=*/&ParamsSoFar); + MultiLevelTemplateArgumentList ArgMLTAL = + getTemplateInstantiationArgs(Template); // 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]. - if (!IsAtLeastAsConstrained(Param, Params->getAssociatedConstraints(), - Template, + if (!IsAtLeastAsConstrained(Params->getAssociatedConstraints(), + ParamMLTAL, Template->getAssociatedConstraints(), - /*NoCache=*/true)) { + ArgMLTAL)) { Diag(Arg.getLocation(), diag::err_template_template_parameter_not_at_least_as_constrained) << Template << Param << Arg.getSourceRange(); @@ -6832,8 +6873,8 @@ Diag(Template->getLocation(), diag::note_entity_declared_at) << Template; MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, - Params->getAssociatedConstraints(), Template, - Template->getAssociatedConstraints()); + Params->getAssociatedConstraints(), ParamMLTAL, Template, + Template->getAssociatedConstraints(), ArgMLTAL); return true; } return false; Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -2714,9 +2714,16 @@ CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, ArrayRef DeducedArgs, TemplateDeductionInfo& Info) { + TemplateArgumentList TAL(TemplateArgumentList::OnStack, DeducedArgs); + DeclContext *DC = Template->getDeclContext(); + MultiLevelTemplateArgumentList MLTAL; + if (NamedDecl *ND = dyn_cast(DC)) + MLTAL = S.getTemplateInstantiationArgs(ND, /*Innermost=*/&TAL); + else + MLTAL.addOuterTemplateArguments(&TAL); if (S.CheckConstraintSatisfaction(Template, Template->getAssociatedConstraints(), - DeducedArgs, Info.getLocation(), + MLTAL, Info.getLocation(), Info.AssociatedConstraintsSatisfaction) || !Info.AssociatedConstraintsSatisfaction.IsSatisfied) { Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs)); @@ -3408,8 +3415,8 @@ // ([temp.constr.decl]), those constraints are checked for satisfaction // ([temp.constr.constr]). If the constraints are not satisfied, type // deduction fails. - if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(), - Specialization, Builder, Info.AssociatedConstraintsSatisfaction)) + if (CheckFunctionConstraints(Specialization, + Info.AssociatedConstraintsSatisfaction)) return TDK_MiscellaneousDeductionFailure; if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { @@ -4498,7 +4505,7 @@ QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0); NamedDecl *TemplParamPtr = TemplParam; FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt( - Context, Loc, Loc, TemplParamPtr, Loc, nullptr); + Context, Loc, Loc, TemplParamPtr, Loc, nullptr, nullptr); QualType FuncParam = SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false) Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -53,7 +53,7 @@ /// used to determine the proper set of template instantiation arguments for /// friend function template specializations. MultiLevelTemplateArgumentList -Sema::getTemplateInstantiationArgs(NamedDecl *D, +Sema::getTemplateInstantiationArgs(Decl *D, const TemplateArgumentList *Innermost, bool RelativeToPrimary, const FunctionDecl *Pattern) { @@ -451,6 +451,13 @@ } } +Sema:: +InstantiatingTemplate::InstantiatingTemplate(InstantiatingTemplate &&Other) : + SemaRef(Other.SemaRef), Invalid(Other.Invalid), + AlreadyInstantiating(Other.AlreadyInstantiating) { + Other.Invalid = true; +} + bool Sema::InstantiatingTemplate::CheckInstantiationDepth( SourceLocation PointOfInstantiation, SourceRange InstantiationRange) { @@ -1769,9 +1776,25 @@ Req, Info, OrigTPL->getSourceRange()); if (TPLInst.isInvalid()) return nullptr; + + // C++ [expr.prim.req.compound]p1.3.3 + // [...] the expression is deduced against an invented function template + // F using the rules in 17.8.2.1. F is a void function template with a + // single type template parameter T declared with the + // constrained-parameter. + + // This will not instantiate the requires clause, because in any other + // context where instantiating TPLs, we are required by the standard not to + // instantiate the requires clause, but here this TPL's constraint is + // in fact only formed standard-wise while checking for the satisfaction - + // when forming the invented template parameter F, therefore we must + // substitute into it here. + TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL); - if (!TPL) + assert(TPL != nullptr); + ExprResult SubstConstraint = TransformExpr(OrigTPL->getRequiresClause()); + if (SubstConstraint.isInvalid()) TransRetReq.emplace(createSubstDiag(SemaRef, Info, [&] (llvm::raw_string_ostream& OS) { OrigTPL->getRequiresClause()->printPretty(OS, nullptr, @@ -1779,6 +1802,7 @@ })); else { TPLInst.Clear(); + TPL->setRequiresClause(SubstConstraint.get()); Sema::InstantiatingTemplate TypeInst(SemaRef, SourceLocation(), Req, Info, SourceRange()); if (TypeInst.isInvalid()) @@ -1807,39 +1831,7 @@ NestedRequirement * TemplateInstantiator::TransformNestedRequirement(NestedRequirement *Req) { - if (!Req->isDependent() && !AlwaysRebuild()) - return Req; - if (Req->isSubstitutionFailure()) { - if (AlwaysRebuild()) - return RebuildNestedRequirement( - Req->getSubstitutionDiagnostic()); - return Req; - } - Sema::InstantiatingTemplate ReqInst(SemaRef, - Req->getConstraintExpr()->getBeginLoc(), Req, - Sema::InstantiatingTemplate::ConstraintsCheck{}, - Req->getConstraintExpr()->getSourceRange()); - - ExprResult TransConstraint; - TemplateDeductionInfo Info(Req->getConstraintExpr()->getBeginLoc()); - { - EnterExpressionEvaluationContext ContextRAII( - SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); - Sema::SFINAETrap Trap(SemaRef); - Sema::InstantiatingTemplate ConstrInst(SemaRef, - Req->getConstraintExpr()->getBeginLoc(), Req, Info, - Req->getConstraintExpr()->getSourceRange()); - if (ConstrInst.isInvalid()) - return nullptr; - TransConstraint = TransformExpr(Req->getConstraintExpr()); - if (TransConstraint.isInvalid() || Trap.hasErrorOccurred()) - return RebuildNestedRequirement(createSubstDiag(SemaRef, Info, - [&] (llvm::raw_string_ostream& OS) { - Req->getConstraintExpr()->printPretty(OS, nullptr, - SemaRef.getPrintingPolicy()); - })); - } - return RebuildNestedRequirement(TransConstraint.get()); + return RebuildNestedRequirement(Req->getConstraintExpr(), TemplateArgs); } @@ -2912,6 +2904,15 @@ if (TSK == TSK_ExplicitInstantiationDefinition && !Pattern->isDefined()) continue; + // C++2a [temp.explicit]p10: + // [...] provided that the associated constraints, if any, of that + // member are satisfied by the template arguments of the explicit + // instantiation. [...] + ConstraintSatisfaction Satisfaction; + if (CheckFunctionConstraints(Function, Satisfaction) || + !Satisfaction.IsSatisfied) + continue; + Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); if (Function->isDefined()) { Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1704,17 +1704,6 @@ return nullptr; } - Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); - if (TrailingRequiresClause) { - ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, - TemplateArgs); - if (!SubstRC.isUsable() || SubstRC.isInvalid()) - return nullptr; - TrailingRequiresClause = SubstRC.get(); - if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause)) - return nullptr; - } - // If we're instantiating a local function declaration, put the result // in the enclosing namespace; otherwise we need to find the instantiated // context. @@ -1774,7 +1763,7 @@ Params[P]->setOwningFunction(Function); Function->setParams(Params); - if (TrailingRequiresClause) + if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) Function->setTrailingRequiresClause(TrailingRequiresClause); if (TemplateParams) { @@ -2025,15 +2014,6 @@ } Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); - if (TrailingRequiresClause) { - ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, - TemplateArgs); - if (!SubstRC.isUsable() || SubstRC.isInvalid()) - return nullptr; - TrailingRequiresClause = SubstRC.get(); - if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause)) - return nullptr; - } DeclContext *DC = Owner; if (isFriend) { @@ -2307,12 +2287,6 @@ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(), D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack()); Inst->setAccess(AS_public); - if (Expr *CE = D->getConstraintExpression()) { - ExprResult Result = SemaRef.SubstExpr(CE, TemplateArgs); - if (Result.isInvalid()) - return nullptr; - Inst->setConstraintExpression(Result.get()); - } if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { TypeSourceInfo *InstantiatedDefaultArg = SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs, @@ -2321,6 +2295,9 @@ Inst->setDefaultArgument(InstantiatedDefaultArg); } + if (D->getConstraintExpression()) + Inst->setInheritedConstraintExpression(D); + // Introduce this template parameter's instantiation into the instantiation // scope. SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst); @@ -2461,12 +2438,6 @@ if (Invalid) Param->setInvalidDecl(); - if (Expr *CE = D->getConstraintExpression()) { - ExprResult Result = SemaRef.SubstExpr(CE, TemplateArgs); - if (Result.isInvalid()) - return nullptr; - Param->setConstraintExpression(Result.get()); - } if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { EnterExpressionEvaluationContext ConstantEvaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); @@ -2475,6 +2446,9 @@ Param->setDefaultArgument(Value.get()); } + if (D->getConstraintExpression()) + Param->setInheritedConstraintExpression(D); + // Introduce this template parameter's instantiation into the instantiation // scope. SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); @@ -2591,12 +2565,6 @@ SemaRef.Context, Owner, D->getLocation(), D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams); - if (Expr *CE = D->getConstraintExpression()) { - ExprResult Result = SemaRef.SubstExpr(CE, TemplateArgs); - if (Result.isInvalid()) - return nullptr; - Param->setConstraintExpression(Result.get()); - } if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { NestedNameSpecifierLoc QualifierLoc = D->getDefaultArgument().getTemplateQualifierLoc(); @@ -2612,6 +2580,10 @@ D->getDefaultArgument().getTemplateQualifierLoc(), D->getDefaultArgument().getTemplateNameLoc())); } + + if (D->getConstraintExpression()) + Param->setInheritedConstraintExpression(D); + Param->setAccess(AS_public); // Introduce this template parameter's instantiation into the instantiation @@ -3473,21 +3445,12 @@ if (Invalid) return nullptr; - // FIXME: Concepts: Substitution into requires clause should only happen when - // checking satisfaction. - Expr *InstRequiresClause = nullptr; - if (Expr *E = L->getRequiresClause()) { - ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs); - if (Res.isInvalid() || !Res.isUsable()) { - return nullptr; - } - InstRequiresClause = Res.get(); - } - TemplateParameterList *InstL = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(), L->getLAngleLoc(), Params, - L->getRAngleLoc(), InstRequiresClause); + L->getRAngleLoc(), + /*RequiresClause=*/nullptr, + /*InheritedConstraints=*/L); return InstL; } @@ -3969,17 +3932,70 @@ TemplateArgs); } -bool Sema::CheckInstantiatedFunctionTemplateConstraints( - SourceLocation PointOfInstantiation, FunctionDecl *Decl, - ArrayRef TemplateArgs, +bool Sema::CheckFunctionConstraints(FunctionDecl *Decl, ConstraintSatisfaction &Satisfaction) { + NamedDecl *Template = Decl->getPrimaryTemplate(); + llvm::SmallVector AssociatedConstraints; + if (Template) { + AssociatedConstraints = + cast(Template)->getAssociatedConstraints(); + } else { + AssociatedConstraints = Decl->getAssociatedConstraints(); + if (!AssociatedConstraints.empty()) { + DeclContext *DC = Decl->getParent(); + while (!DC->isFileContext()) { + if (auto *Spec = dyn_cast(DC)) { + if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa(Spec)) + break; + if (!isa(Spec)) { + Template = Spec->getSpecializedTemplate(); + } else { + Template = Spec; + } + break; + } + if (auto *Record = dyn_cast(DC)) + if (auto *ClassTemplate = Record->getDescribedClassTemplate()) { + Template = ClassTemplate; + break; + } + if (auto *Function = dyn_cast(DC)) + if (auto *FunctionTemplate = Function->getDescribedTemplate()) { + Template = FunctionTemplate; + break; + } + DC = DC->getParent(); + } + } + } + + if (AssociatedConstraints.empty()) { + Satisfaction.IsSatisfied = true; + return false; + } + + if (!Template) { + // This is a non-template function which is also not a method of a template + // class. + if (Expr *RC = Decl->getTrailingRequiresClause()) + return CheckConstraintSatisfaction(RC, Satisfaction); + + Satisfaction.IsSatisfied = true; + return false; + } + + // This is either an instantiated function template or a non-template method + // of a class template. + // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. Sema::ContextRAII savedContext(*this, Decl); LocalInstantiationScope Scope(*this); MultiLevelTemplateArgumentList MLTAL = - getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); + getTemplateInstantiationArgs(Decl, /*Innermost=*/nullptr, + /*RelativeToPrimary*/true); // If this is not an explicit specialization - we need to get the instantiated // version of the template arguments and add them to scope for the @@ -3990,13 +4006,21 @@ Scope, MLTAL)) return true; - FunctionTemplateDecl *Template = Decl->getPrimaryTemplate(); + // Note - code synthesis context for the constraints check is created // inside CheckConstraintsSatisfaction. - return CheckConstraintSatisfaction(Template, - Template->getAssociatedConstraints(), - TemplateArgs, - PointOfInstantiation, Satisfaction); + if (auto *TD = dyn_cast(Template)) + return CheckConstraintSatisfaction(TD, AssociatedConstraints, MLTAL, + Decl->getPointOfInstantiation(), + Satisfaction); + if (auto *Var = dyn_cast(Template)) + return CheckConstraintSatisfaction(Var, AssociatedConstraints, MLTAL, + Decl->getPointOfInstantiation(), + Satisfaction); + return CheckConstraintSatisfaction( + cast(Template), + AssociatedConstraints, MLTAL, Decl->getPointOfInstantiation(), + Satisfaction); } /// Initializes the common fields of an instantiation function Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -3041,12 +3041,15 @@ } NestedRequirement * - RebuildNestedRequirement(Requirement::SubstitutionDiagnostic *SubstDiag) { - return new (SemaRef.Context) NestedRequirement(SubstDiag); + RebuildNestedRequirement(Expr *Constraint, + const MultiLevelTemplateArgumentList &TemplateArgs) { + return new (SemaRef.Context) NestedRequirement(SemaRef, Constraint, + TemplateArgs); } - NestedRequirement *RebuildNestedRequirement(Expr *Constraint) { - return new (SemaRef.Context) NestedRequirement(SemaRef, Constraint); + NestedRequirement * + RebuildNestedRequirement(Expr *Constraint) { + return new (SemaRef.Context) NestedRequirement(Constraint); } /// \brief Build a new Objective-C boxed expression. @@ -10988,8 +10991,7 @@ template bool TreeTransform::TransformRequiresExprRequirements( - ArrayRef Reqs, - SmallVectorImpl &Transformed) { + ArrayRef Reqs, SmallVectorImpl &Transformed) { for (Requirement *Req : Reqs) { Requirement *TransReq = nullptr; if (auto *TypeReq = dyn_cast(Req)) @@ -11074,12 +11076,6 @@ template NestedRequirement * TreeTransform::TransformNestedRequirement(NestedRequirement *Req) { - if (Req->isSubstitutionFailure()) { - if (getDerived().AlwaysRebuild()) - return getDerived().RebuildNestedRequirement( - Req->getSubstitutionDiagnostic()); - return Req; - } ExprResult TransConstraint = getDerived().TransformExpr(Req->getConstraintExpr()); if (TransConstraint.isInvalid()) Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -8840,6 +8840,7 @@ while (NumParams--) Params.push_back(ReadDeclAs(F, Record, Idx)); + // TODO: Concepts: We do not preserve constraint inheritance here. bool HasRequiresClause = Record[Idx++]; Expr *RequiresClause = HasRequiresClause ? ReadExpr(F) : nullptr; Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -2356,9 +2356,13 @@ D->setDeclaredWithTypename(Record.readInt()); - // TODO: Concepts: Constrained parameters - if (Record.readInt()) - D->setConstraintExpression(Record.readExpr()); + if (Record.readInt()) { + if (Record.readInt()) + D->setConstraintExpression(Record.readExpr()); + else + D->setInheritedConstraintExpression( + Record.readDeclAs()); + } if (Record.readInt()) D->setDefaultArgument(GetTypeSourceInfo()); @@ -2379,9 +2383,13 @@ } else { // Rest of NonTypeTemplateParmDecl. D->ParameterPack = Record.readInt(); - // TODO: Concepts: Constrained parameters - if (Record.readInt()) - D->setConstraintExpression(Record.readExpr()); + if (Record.readInt()) { + if (Record.readInt()) + D->setConstraintExpression(Record.readExpr()); + else + D->setInheritedConstraintExpression( + Record.readDeclAs()); + } if (Record.readInt()) D->setDefaultArgument(Record.readExpr()); } @@ -2399,10 +2407,14 @@ Data[I] = Record.readTemplateParameterList(); } else { // Rest of TemplateTemplateParmDecl. - // TODO: Concepts: Constrained parameters D->ParameterPack = Record.readInt(); - if (Record.readInt()) - D->setConstraintExpression(Record.readExpr()); + if (Record.readInt()) { + if (Record.readInt()) + D->setConstraintExpression(Record.readExpr()); + else + D->setInheritedConstraintExpression( + Record.readDeclAs()); + } if (Record.readInt()) D->setDefaultArgument(Reader.getContext(), Record.readTemplateArgumentLoc()); Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -844,17 +844,10 @@ } } break; case Requirement::RK_Nested: { - if (bool IsSubstitutionDiagnostic = Record.readInt()) { - SourceLocation SubstDiagLocation = Record.readSourceLocation(); - std::string SubstDiagMessage = Record.readString(); - R = new (Record.getContext()) NestedRequirement( - readSubstitutionDiagnostic(Record)); - break; - } Expr *E = Record.readExpr(); - if (E->isInstantiationDependent()) + if (/*IsDependent=*/Record.readInt()) { R = new (Record.getContext()) NestedRequirement(E); - else + } else R = new (Record.getContext()) NestedRequirement(E, readConstraintSatisfaction(Record)); } break; Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -5918,6 +5918,7 @@ Record->push_back(TemplateParams->size()); for (const auto &P : *TemplateParams) AddDeclRef(P); + // TODO: Concepts: We do not preserve constraint inheritance here. if (const Expr *RequiresClause = TemplateParams->getRequiresClause()) { Record->push_back(true); AddStmt(const_cast(RequiresClause)); Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -1586,8 +1586,14 @@ Expr *CE = D->getConstraintExpression(); Record.push_back(CE != nullptr); - if (CE) - Record.AddStmt(CE); + if (CE) { + bool OwnsCE = !D->constraintExpressionWasInherited(); + Record.push_back(OwnsCE); + if (OwnsCE) + Record.AddStmt(CE); + else + Record.AddDeclRef(D->getInheritedFromConstraintExpressionDecl()); + } bool OwnsDefaultArg = D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); @@ -1618,13 +1624,18 @@ Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK; } else { - // TODO: Concepts - constrained parameters. // Rest of NonTypeTemplateParmDecl. Record.push_back(D->isParameterPack()); Expr *CE = D->getConstraintExpression(); Record.push_back(CE != nullptr); - if (CE) - Record.AddStmt(CE); + if (CE) { + bool OwnsCE = !D->constraintExpressionWasInherited(); + Record.push_back(OwnsCE); + if (OwnsCE) + Record.AddStmt(CE); + else + Record.AddDeclRef(D->getInheritedFromConstraintExpressionDecl()); + } bool OwnsDefaultArg = D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); Record.push_back(OwnsDefaultArg); @@ -1652,13 +1663,18 @@ Record.AddTemplateParameterList(D->getExpansionTemplateParameters(I)); Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK; } else { - // TODO: Concepts - constrained parameters. // Rest of TemplateTemplateParmDecl. Record.push_back(D->isParameterPack()); Expr *CE = D->getConstraintExpression(); Record.push_back(CE != nullptr); - if (CE) - Record.AddStmt(CE); + if (CE) { + bool OwnsCE = !D->constraintExpressionWasInherited(); + Record.push_back(OwnsCE); + if (OwnsCE) + Record.AddStmt(CE); + else + Record.AddDeclRef(D->getInheritedFromConstraintExpressionDecl()); + } bool OwnsDefaultArg = D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); Record.push_back(OwnsDefaultArg); Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -484,14 +484,10 @@ auto *NestedReq = cast(R); Record.push_back(Requirement::RK_Nested); - if (auto *SubstDiag = - NestedReq->Value.dyn_cast()){ - addSubstitutionDiagnostic(Record, SubstDiag); - } else { - Record.AddStmt(NestedReq->Value.get()); - if (!NestedReq->isDependent()) - addConstraintSatisfaction(Record, NestedReq->Satisfaction); - } + Record.AddStmt(NestedReq->getConstraintExpr()); + Record.push_back(NestedReq->isDependent()); + if (!NestedReq->isDependent()) + addConstraintSatisfaction(Record, NestedReq->Satisfaction); } } Record.AddSourceLocation(E->getEndLoc()); Index: test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p4.cpp =================================================================== --- test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p4.cpp +++ test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p4.cpp @@ -26,11 +26,19 @@ struct A { static void foo(int) requires (sizeof(T) == 1) {} // expected-note 3{{because 'sizeof(char [2]) == 1' (2 == 1) evaluated to false}} static void bar(int) requires (sizeof(T) == 2) {} // expected-note 3{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}} + template + static void baz(int) requires (sizeof(T) == 2) { + struct { static void goo() requires (sizeof(T) > sizeof(U)) {} } a; + // expected-note@-1{{because 'sizeof(short) > sizeof(int)' (2 > 4) evaluated to false}} + a.goo(); + // expected-error@-1{{invalid reference to function 'goo': constraints not satisfied}} + } }; void baz() { A::foo(1); A::bar(1); // expected-error{{invalid reference to function 'bar': constraints not satisfied}} + A::baz(1); // expected-note{{in instantiation of function template specialization 'methods::A::baz' requested here}} A::foo(1); // expected-error{{invalid reference to function 'foo': constraints not satisfied}} A::bar(1); void (*p1)(int) = A::foo; Index: test/CXX/concepts-ts/expr/expr.prim/expr.prim.req/equivalence.cpp =================================================================== --- test/CXX/concepts-ts/expr/expr.prim/expr.prim.req/equivalence.cpp +++ test/CXX/concepts-ts/expr/expr.prim/expr.prim.req/equivalence.cpp @@ -7,20 +7,20 @@ template using identity_t = T; // Type requirements -template requires requires { typename identity_t; } +template requires requires { typename identity_t; } // expected-note{{template is declared here}} struct r1; -template requires requires { typename identity_t; } // expected-note{{previous template declaration is here}} +template requires requires { typename identity_t; } struct r1; template requires requires { typename identity_t; } // expected-error{{associated constraints differ in template redeclaration}} struct r1; template requires requires { typename ::identity_t; } struct r1; -template requires requires { typename identity::type; } +template requires requires { typename identity::type; } // expected-note 2{{template is declared here}} struct r2; template requires requires { typename identity::type; } struct r2; -template requires requires { typename ::identity::type; } // expected-note 2{{previous template declaration is here}} +template requires requires { typename ::identity::type; } struct r2; template requires requires { typename identity::typr; } // expected-error{{associated constraints differ in template redeclaration}} struct r2; @@ -30,9 +30,9 @@ template requires requires { typename ns::identity::type; } // expected-error{{associated constraints differ in template redeclaration}} struct r2; -template requires requires { typename T::template identity::type; } +template requires requires { typename T::template identity::type; } // expected-note{{template is declared here}} struct r3; -template requires requires { typename U::template identity::type; } // expected-note{{previous template declaration is here}} +template requires requires { typename U::template identity::type; } struct r3; template requires requires { typename T::template identitr::type; } // expected-error{{associated constraints differ in template redeclaration}} struct r3; @@ -43,7 +43,7 @@ struct r4; // Expr requirements -template requires requires { 0; } // expected-note{{previous template declaration is here}} +template requires requires { 0; } // expected-note{{template is declared here}} struct r5; template requires requires { 1; } // expected-error{{associated constraints differ in template redeclaration}} struct r5; @@ -51,13 +51,13 @@ template concept C1 = true; -template requires requires { sizeof(T); } +template requires requires { sizeof(T); } // expected-note 4{{template is declared here}} struct r6; -template requires requires { sizeof(U); } // expected-note{{previous template declaration is here}} +template requires requires { sizeof(U); } struct r6; template requires requires { sizeof(U) - 1; } // expected-error{{associated constraints differ in template redeclaration}} struct r6; -template requires requires { { sizeof(T) }; } // expected-note 3{{previous template declaration is here}} +template requires requires { { sizeof(T) }; } struct r6; template requires requires { { sizeof(T) } -> decltype(sizeof(int)); } // expected-error{{associated constraints differ in template redeclaration}} struct r6; @@ -66,9 +66,9 @@ template requires requires { { sizeof(T) } -> C1; } // expected-error{{associated constraints differ in template redeclaration}} struct r6; -template requires requires { { sizeof(T) } -> int; } +template requires requires { { sizeof(T) } -> int; } // expected-note 3{{template is declared here}} struct r7; -template requires requires { { sizeof(U) } -> int; } // expected-note 3{{previous template declaration is here}} +template requires requires { { sizeof(U) } -> int; } struct r7; template requires requires { { sizeof(T) } -> const int; } // expected-error{{associated constraints differ in template redeclaration}} struct r7; @@ -77,11 +77,11 @@ template requires requires { { sizeof(T) } -> T; } // expected-error{{associated constraints differ in template redeclaration}} struct r7; -template requires requires { { sizeof(T) } -> C1; } +template requires requires { { sizeof(T) } -> C1; } // expected-note 2{{template is declared here}} struct r8; template requires requires { { sizeof(U) } -> C1; } struct r8; -template requires requires { { sizeof(T) } -> C1<>; } // expected-note 2{{previous template declaration is here}} +template requires requires { { sizeof(T) } -> C1<>; } struct r8; template requires requires { { sizeof(U) }; } // expected-error{{associated constraints differ in template redeclaration}} struct r8; @@ -101,9 +101,9 @@ template requires requires { { sizeof(T) } -> volatile C1 const; } struct r9; -template requires requires { { sizeof(T) } -> C1[sizeof(T)]; } +template requires requires { { sizeof(T) } -> C1[sizeof(T)]; } // expected-note 2{{template is declared here}} struct r10; -template requires requires { { sizeof(U) } -> C1[sizeof(U)]; } // expected-note 2{{previous template declaration is here}} +template requires requires { { sizeof(U) } -> C1[sizeof(U)]; } struct r10; template requires requires { { sizeof(T) } -> C1[sizeof(T) - 1]; } // expected-error{{associated constraints differ in template redeclaration}} struct r10; @@ -113,30 +113,30 @@ template concept C2 = true; -template requires requires { { sizeof(T) } -> C2; } +template requires requires { { sizeof(T) } -> C2; } // expected-note{{template is declared here}} struct r11; -template requires requires { { sizeof(U) } -> C2; } // expected-note{{previous template declaration is here}} +template requires requires { { sizeof(U) } -> C2; } struct r11; template requires requires { { sizeof(T) } -> C2; } // expected-error{{associated constraints differ in template redeclaration}} struct r11; // Nested requirements -template requires requires { requires sizeof(T) == 0; } +template requires requires { requires sizeof(T) == 0; } // expected-note{{template is declared here}} struct r12; -template requires requires { requires sizeof(U) == 0; } // expected-note{{previous template declaration is here}} +template requires requires { requires sizeof(U) == 0; } struct r12; template requires requires { requires sizeof(T) == 1; } // expected-error{{associated constraints differ in template redeclaration}} struct r12; // Parameter list -template requires requires { requires true; } +template requires requires { requires true; } // expected-note{{template is declared here}} struct r13; -template requires requires() { requires true; } // expected-note{{previous template declaration is here}} +template requires requires() { requires true; } struct r13; template requires requires(T i) { requires true; } // expected-error{{associated constraints differ in template redeclaration}} struct r13; -template requires requires(T i, T *j) { requires true; } // expected-note 2{{previous template declaration is here}} +template requires requires(T i, T *j) { requires true; } // expected-note 2{{template is declared here}} struct r14; template requires requires(T i) { requires true; } // expected-error{{associated constraints differ in template redeclaration}} struct r14; @@ -144,9 +144,9 @@ struct r14; // Parameter names -template requires requires(int i) { requires sizeof(i) == 1; } +template requires requires(int i) { requires sizeof(i) == 1; } // expected-note 2{{template is declared here}} struct r15; -template requires requires(int j) { requires sizeof(j) == 1; } // expected-note 2{{previous template declaration is here}} +template requires requires(int j) { requires sizeof(j) == 1; } struct r15; template requires requires(int k) { requires sizeof(k) == 2; } // expected-error{{associated constraints differ in template redeclaration}} struct r15; @@ -154,9 +154,9 @@ struct r15; // Order of requirements -template requires requires { requires true; 0; } +template requires requires { requires true; 0; } // expected-note{{template is declared here}} struct r16; -template requires requires { requires true; 0; } // expected-note{{previous template declaration is here}} +template requires requires { requires true; 0; } struct r16; template requires requires { 0; requires true; } // expected-error{{associated constraints differ in template redeclaration}} struct r16; Index: test/CXX/concepts-ts/expr/expr.prim/expr.prim.req/nested-requirement.cpp =================================================================== --- test/CXX/concepts-ts/expr/expr.prim/expr.prim.req/nested-requirement.cpp +++ test/CXX/concepts-ts/expr/expr.prim/expr.prim.req/nested-requirement.cpp @@ -19,11 +19,12 @@ template struct X { - template requires requires (U u) { requires sizeof(u) == sizeof(T); } // expected-note{{because 'sizeof (u) == sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} + template requires requires (U u) { requires decltype(u)::hey == sizeof(T); } + // expected-note@-1{{because substituted constraint expression is ill-formed: type 'decltype(u)' (aka 'int') cannot be used prior to '::' because it has no members}} struct r4 {}; }; -using r4i = X::r4; // expected-error{{constraints not satisfied for class template 'r4' [with U = int]}} +using r4i = X::r4; // expected-error{{constraints not satisfied for class template 'r4' [with U = int]}} // C++ [expr.prim.req.nested] Examples namespace std_example { @@ -43,4 +44,4 @@ requires sizeof(a) == 4; // OK requires a == 0; // expected-error{{constraint variable 'a' cannot be used in an evaluated context}} }; -} \ No newline at end of file +} Index: test/CXX/concepts-ts/over/over.match/over.match.best/p1.cpp =================================================================== --- test/CXX/concepts-ts/over/over.match/over.match.best/p1.cpp +++ test/CXX/concepts-ts/over/over.match/over.match.best/p1.cpp @@ -38,7 +38,7 @@ template void bar() requires (sizeof(T) == 1 && sizeof(T) >= 0) { } // expected-note@-1{{candidate function [with T = char]}} - // expected-note@-2{{'sizeof(char) == 1' in the two declarations is not considered equivalent - move it to a concept and reference it from here:}} + // expected-note@-2{{'sizeof(T) == 1' in the two declarations is not considered equivalent - move it to a concept and reference it from here:}} static_assert(is_same_v()), void>); // expected-error@-1{{call to 'bar' is ambiguous}} @@ -112,4 +112,3 @@ static_assert(goo(1) == 1); static_assert(doo(2) == 1); // expected-error {{call to 'doo' is ambiguous}} } - Index: test/CXX/concepts-ts/temp/temp.arg.template/p3.cpp =================================================================== --- test/CXX/concepts-ts/temp/temp.arg.template/p3.cpp +++ test/CXX/concepts-ts/temp/temp.arg.template/p3.cpp @@ -5,6 +5,8 @@ template concept D = C && T::g(); template concept F = T::f(); // expected-note@-1{{'T::f()' in the two declarations is not considered equivalent - move it to a concept and reference it from here:}} +template concept G = T::f(); + template class P> struct S1 { }; // expected-note 2{{'P' declared here}} template struct X { }; // expected-note{{'X' declared here}} @@ -12,6 +14,8 @@ template struct Y { }; // expected-note 2{{'Y' declared here}} template struct Z { }; template struct W { }; // expected-note{{'W' declared here}} +template> struct U { }; // expected-note{{'U' declared here}} +template> struct V { }; // expected-note 2{{'V' declared here}} S1 s11; S1 s12; // expected-error{{template template argument 'Y' must not be more constrained than template template parameter 'P'}} @@ -23,3 +27,19 @@ S2 s21; // expected-error{{template template argument 'X' must not be more constrained than template template parameter 'P'}} S2 s22; // expected-error{{template template argument 'Y' must not be more constrained than template template parameter 'P'}} S2 s23; + +template> class P> struct S3 { }; +// expected-note@-1{{'P' declared here}} + +S3 s31; +S3 s32; // expected-error{{template template argument 'U' must not be more constrained than template template parameter 'P'}} + +template +struct S4 { + template> class P> struct S { }; + // expected-note@-1 2{{'P' declared here}} +}; + +S4::S s41; +S4::S s42; // expected-error{{template template argument 'V' must not be more constrained than template template parameter 'P'}} +S4::S s43; // expected-error{{template template argument 'V' must not be more constrained than template template parameter 'P'}} \ No newline at end of file Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/non-function-templates.cpp =================================================================== --- test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/non-function-templates.cpp +++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/non-function-templates.cpp @@ -90,3 +90,11 @@ static_assert(C{}); // expected-note{{while checking constraint satisfaction for template 'C' required here}} static_assert(D{}); // expected-note{{while checking constraint satisfaction for template 'D' required here}} + +template +struct dummy { + template + requires (sizeof(U) == 4) + class A; + using type = A; +}; Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp =================================================================== --- test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp +++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp @@ -19,15 +19,15 @@ namespace diag { -template requires true // expected-note{{previous template declaration is here}} +template requires true // expected-note{{template is declared here}} struct A; template struct A; // expected-error{{associated constraints differ in template redeclaration}} -template struct B; // expected-note{{previous template declaration is here}} +template struct B; // expected-note{{template is declared here}} template requires true // expected-error{{associated constraints differ in template redeclaration}} struct B; -template requires true // expected-note{{previous template declaration is here}} +template requires true // expected-note{{template is declared here}} struct C; template requires (!0) // expected-error{{associated constraints differ in template redeclaration}} struct C; @@ -35,7 +35,7 @@ template concept C1 = true; -template // expected-note{{previous template declaration is here}} +template // expected-note{{template is declared here}} struct D; template requires C1 // expected-error{{associated constraints differ in template redeclaration}} struct D; @@ -63,10 +63,10 @@ template struct TA { - template