From 95d94a67755620c0a2871ac6f056ca8e9731d5e9 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Fri, 19 Aug 2022 12:37:04 -0700 Subject: [PATCH] Revert "Re-apply "Deferred Concept Instantiation Implementation""" This reverts commit d483730d8c3fa2e0d4192b2f3c61c761b124e6ad. This allegedly breaks a significant part of facebooks internal build. Reverting while we wait for them to provide a reproducer of this from @wlei. --- clang/docs/ReleaseNotes.rst | 4 - clang/include/clang/Sema/Sema.h | 108 +----- clang/include/clang/Sema/Template.h | 8 - clang/lib/Sema/SemaConcept.cpp | 299 ++++------------ clang/lib/Sema/SemaExpr.cpp | 3 +- clang/lib/Sema/SemaOverload.cpp | 87 +---- clang/lib/Sema/SemaTemplate.cpp | 68 +--- clang/lib/Sema/SemaTemplateDeduction.cpp | 36 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 108 ++---- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 67 +++- clang/lib/Sema/TreeTransform.h | 9 +- .../temp.constr.constr/non-function-templates.cpp | 21 -- .../class-template-partial-specializations.cpp | 24 -- .../var-template-partial-specializations.cpp | 19 +- clang/test/SemaTemplate/concepts-friends.cpp | 371 -------------------- clang/test/SemaTemplate/concepts.cpp | 384 --------------------- clang/test/SemaTemplate/deferred-concept-inst.cpp | 23 -- .../SemaTemplate/instantiate-requires-clause.cpp | 16 +- .../SemaTemplate/trailing-return-short-circuit.cpp | 62 ---- 19 files changed, 195 insertions(+), 1522 deletions(-) delete mode 100644 clang/test/SemaTemplate/concepts-friends.cpp delete mode 100644 clang/test/SemaTemplate/deferred-concept-inst.cpp delete mode 100644 clang/test/SemaTemplate/trailing-return-short-circuit.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index e313f00..ee9c463 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -149,10 +149,6 @@ C++ Language Changes in Clang C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ -- Clang now correctly delays the instantiation of function constraints until - the time of checking, which should now allow the libstdc++ ranges implementation - to work for at least trivial examples. This fixes - `Issue 44178 `_. - Support capturing structured bindings in lambdas (`P1091R3 `_ and `P1381R1 `). diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 51e526a..28a47a2 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3637,16 +3637,6 @@ public: bool ConsiderCudaAttrs = true, bool ConsiderRequiresClauses = true); - // Calculates whether the expression Constraint depends on an enclosing - // template, for the purposes of [temp.friend] p9. - // TemplateDepth is the 'depth' of the friend function, which is used to - // compare whether a declaration reference is referring to a containing - // template, or just the current friend function. A 'lower' TemplateDepth in - // the AST refers to a 'containing' template. As the constraint is - // uninstantiated, this is relative to the 'top' of the TU. - bool ConstraintExpressionDependsOnEnclosingTemplate(unsigned TemplateDepth, - const Expr *Constraint); - enum class AllowedExplicit { /// Allow no explicit functions to be used. None, @@ -7119,21 +7109,6 @@ private: LocalInstantiationScope &Scope, const MultiLevelTemplateArgumentList &TemplateArgs); - /// used by SetupConstraintCheckingTemplateArgumentsAndScope to recursively(in - /// the case of lambdas) set up the LocalInstantiationScope of the current - /// function. - bool SetupConstraintScope( - FunctionDecl *FD, llvm::Optional> TemplateArgs, - MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope); - - /// Used during constraint checking, sets up the constraint template arguemnt - /// lists, and calls SetupConstraintScope to set up the - /// LocalInstantiationScope to have the proper set of ParVarDecls configured. - llvm::Optional - SetupConstraintCheckingTemplateArgumentsAndScope( - FunctionDecl *FD, llvm::Optional> TemplateArgs, - LocalInstantiationScope &Scope); - public: const NormalizedConstraint * getNormalizedAssociatedConstraints( @@ -7176,39 +7151,6 @@ public: bool CheckConstraintSatisfaction( const NamedDecl *Template, ArrayRef ConstraintExprs, const MultiLevelTemplateArgumentList &TemplateArgLists, - SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { - llvm::SmallVector Converted; - return CheckConstraintSatisfaction(Template, ConstraintExprs, Converted, - TemplateArgLists, TemplateIDRange, - Satisfaction); - } - - /// \brief Check whether the given list of constraint expressions are - /// satisfied (as if in a 'conjunction') given template arguments. - /// Additionally, takes an empty list of Expressions which is populated with - /// the instantiated versions of the ConstraintExprs. - /// \param Template the template-like entity that triggered the constraints - /// check (either a concept or a constrained entity). - /// \param ConstraintExprs a list of constraint expressions, treated as if - /// they were 'AND'ed together. - /// \param ConvertedConstraints a out parameter that will get populated with - /// the instantiated version of the ConstraintExprs if we successfully checked - /// satisfaction. - /// \param TemplateArgList the multi-level list of template arguments to - /// substitute into the constraint expression. This should be relative to the - /// top-level (hence multi-level), since we need to instantiate fully at the - /// time of checking. - /// \param TemplateIDRange The source range of the template id that - /// caused the constraints check. - /// \param Satisfaction if true is returned, will contain details of the - /// satisfaction, with enough information to diagnose an unsatisfied - /// expression. - /// \returns true if an error occurred and satisfaction could not be checked, - /// false otherwise. - bool CheckConstraintSatisfaction( - const NamedDecl *Template, ArrayRef ConstraintExprs, - llvm::SmallVectorImpl &ConvertedConstraints, - const MultiLevelTemplateArgumentList &TemplateArgList, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction); /// \brief Check whether the given non-dependent constraint expression is @@ -7228,8 +7170,8 @@ public: /// \returns true if an error occurred, false otherwise. bool CheckFunctionConstraints(const FunctionDecl *FD, ConstraintSatisfaction &Satisfaction, - SourceLocation UsageLoc = SourceLocation(), - bool ForOverloadResolution = false); + SourceLocation UsageLoc = SourceLocation()); + /// \brief Ensure that the given template arguments satisfy the constraints /// associated with the given template, emitting a diagnostic if they do not. @@ -8985,8 +8927,7 @@ public: MultiLevelTemplateArgumentList getTemplateInstantiationArgs( const NamedDecl *D, const TemplateArgumentList *Innermost = nullptr, - bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr, - bool LookBeyondLambda = false, bool IncludeContainingStruct = false); + bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr); /// A context in which code is being synthesized (where a source location /// alone is not sufficient to identify the context). This covers template @@ -9694,21 +9635,23 @@ public: const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); - TypeSourceInfo *SubstFunctionDeclType( - TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext, - Qualifiers ThisTypeQuals, bool EvaluateConstraints = true); + TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, + DeclarationName Entity, + CXXRecordDecl *ThisContext, + Qualifiers ThisTypeQuals); void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, const MultiLevelTemplateArgumentList &Args); bool SubstExceptionSpec(SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI, SmallVectorImpl &ExceptionStorage, const MultiLevelTemplateArgumentList &Args); - ParmVarDecl * - SubstParmVarDecl(ParmVarDecl *D, - const MultiLevelTemplateArgumentList &TemplateArgs, - int indexAdjustment, Optional NumExpansions, - bool ExpectParameterPack, bool EvaluateConstraints = true); + ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs, + int indexAdjustment, + Optional NumExpansions, + bool ExpectParameterPack); bool SubstParmTypes(SourceLocation Loc, ArrayRef Params, const FunctionProtoType::ExtParameterInfo *ExtParamInfos, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -9718,25 +9661,6 @@ public: ExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); - // A RAII type used by the TemplateDeclInstantiator and TemplateInstantiator - // to disable constraint evaluation, then restore the state. - template struct ConstraintEvalRAII { - InstTy &TI; - bool OldValue; - - ConstraintEvalRAII(InstTy &TI) - : TI(TI), OldValue(TI.getEvaluateConstraints()) { - TI.setEvaluateConstraints(false); - } - ~ConstraintEvalRAII() { TI.setEvaluateConstraints(OldValue); } - }; - - // Unlike the above, this evaluates constraints, which should only happen at - // 'constraint checking' time. - ExprResult - SubstConstraintExpr(Expr *E, - const MultiLevelTemplateArgumentList &TemplateArgs); - /// Substitute the given template arguments into a list of /// expressions, expanding pack expansions if required. /// @@ -9766,6 +9690,7 @@ public: const MultiLevelTemplateArgumentList &TemplateArgs, TemplateArgumentListInfo &Outputs); + Decl *SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); @@ -9856,8 +9781,7 @@ public: const MultiLevelTemplateArgumentList &TemplateArgs); bool SubstTypeConstraint(TemplateTypeParmDecl *Inst, const TypeConstraint *TC, - const MultiLevelTemplateArgumentList &TemplateArgs, - bool EvaluateConstraint); + const MultiLevelTemplateArgumentList &TemplateArgs); bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 2630853..8df92b7 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -503,7 +503,6 @@ enum class TemplateSubstitutionKind : char { const MultiLevelTemplateArgumentList &TemplateArgs; Sema::LateInstantiatedAttrVec* LateAttrs = nullptr; LocalInstantiationScope *StartingScope = nullptr; - bool EvaluateConstraints = true; /// A list of out-of-line class template partial /// specializations that will need to be instantiated after the @@ -527,13 +526,6 @@ enum class TemplateSubstitutionKind : char { SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex), Owner(Owner), TemplateArgs(TemplateArgs) {} - void setEvaluateConstraints(bool B) { - EvaluateConstraints = B; - } - bool getEvaluateConstraints() { - return EvaluateConstraints; - } - // Define all the decl visitors using DeclNodes.inc #define DECL(DERIVED, BASE) \ Decl *Visit ## DERIVED ## Decl(DERIVED ## Decl *D); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 240c656..7545b79 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -18,7 +18,6 @@ #include "clang/Sema/Template.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Initialization.h" -#include "clang/AST/ASTLambda.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/OperatorPrecedence.h" @@ -31,7 +30,6 @@ using namespace sema; namespace { class LogicalBinOp { - SourceLocation Loc; OverloadedOperatorKind Op = OO_None; const Expr *LHS = nullptr; const Expr *RHS = nullptr; @@ -42,14 +40,12 @@ public: Op = BinaryOperator::getOverloadedOperator(BO->getOpcode()); LHS = BO->getLHS(); RHS = BO->getRHS(); - Loc = BO->getExprLoc(); } else if (auto *OO = dyn_cast(E)) { // If OO is not || or && it might not have exactly 2 arguments. if (OO->getNumArgs() == 2) { Op = OO->getOperator(); LHS = OO->getArg(0); RHS = OO->getArg(1); - Loc = OO->getOperatorLoc(); } } } @@ -60,26 +56,6 @@ public: const Expr *getLHS() const { return LHS; } const Expr *getRHS() const { return RHS; } - - ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) const { - return recreateBinOp(SemaRef, LHS, const_cast(getRHS())); - } - - ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS, - ExprResult RHS) const { - assert((isAnd() || isOr()) && "Not the right kind of op?"); - assert((!LHS.isInvalid() && !RHS.isInvalid()) && "not good expressions?"); - - if (!LHS.isUsable() || !RHS.isUsable()) - return ExprEmpty(); - - // We should just be able to 'normalize' these to the builtin Binary - // Operator, since that is how they are evaluated in constriant checks. - return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(), - BinaryOperator::getOverloadedOpcode(Op), - SemaRef.Context.BoolTy, VK_PRValue, - OK_Ordinary, Loc, FPOptionsOverride{}); - } }; } @@ -146,18 +122,16 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression, } template -static ExprResult +static bool calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction, AtomicEvaluator &&Evaluator) { ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); if (LogicalBinOp BO = ConstraintExpr) { - ExprResult LHSRes = calculateConstraintSatisfaction( - S, BO.getLHS(), Satisfaction, Evaluator); - - if (LHSRes.isInvalid()) - return ExprError(); + if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction, + Evaluator)) + return true; bool IsLHSSatisfied = Satisfaction.IsSatisfied; @@ -168,7 +142,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, // is checked. If that is satisfied, the disjunction is satisfied. // Otherwise, the disjunction is satisfied if and only if the second // operand is satisfied. - return BO.recreateBinOp(S, LHSRes); + return false; if (BO.isAnd() && !IsLHSSatisfied) // [temp.constr.op] p2 @@ -177,21 +151,12 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, // is checked. If that is not satisfied, the conjunction is not // satisfied. Otherwise, the conjunction is satisfied if and only if // the second operand is satisfied. - return BO.recreateBinOp(S, LHSRes); - - ExprResult RHSRes = calculateConstraintSatisfaction( - S, BO.getRHS(), Satisfaction, std::forward(Evaluator)); - if (RHSRes.isInvalid()) - return ExprError(); - - return BO.recreateBinOp(S, LHSRes, RHSRes); - } + return false; - if (auto *C = dyn_cast(ConstraintExpr)) { - // These aren't evaluated, so we don't care about cleanups, so we can just - // evaluate these as if the cleanups didn't exist. return calculateConstraintSatisfaction( - S, C->getSubExpr(), Satisfaction, + S, BO.getRHS(), Satisfaction, std::forward(Evaluator)); + } else if (auto *C = dyn_cast(ConstraintExpr)) { + return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction, std::forward(Evaluator)); } @@ -199,11 +164,11 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr); if (SubstitutedAtomicExpr.isInvalid()) - return ExprError(); + return true; if (!SubstitutedAtomicExpr.isUsable()) // Evaluator has decided satisfaction without yielding an expression. - return ExprEmpty(); + return false; EnterExpressionEvaluationContext ConstantEvaluated( S, Sema::ExpressionEvaluationContext::ConstantEvaluated); @@ -220,7 +185,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, << SubstitutedAtomicExpr.get()->getSourceRange(); for (const PartialDiagnosticAt &PDiag : EvaluationDiags) S.Diag(PDiag.first, PDiag.second); - return ExprError(); + return true; } assert(EvalResult.Val.isInt() && @@ -230,10 +195,10 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, Satisfaction.Details.emplace_back(ConstraintExpr, SubstitutedAtomicExpr.get()); - return SubstitutedAtomicExpr; + return false; } -static ExprResult calculateConstraintSatisfaction( +static bool calculateConstraintSatisfaction( Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { @@ -254,8 +219,8 @@ static ExprResult calculateConstraintSatisfaction( return ExprError(); // We do not want error diagnostics escaping here. Sema::SFINAETrap Trap(S); - SubstitutedExpression = - S.SubstConstraintExpr(const_cast(AtomicExpr), MLTAL); + SubstitutedExpression = S.SubstExpr(const_cast(AtomicExpr), + MLTAL); // Substitution might have stripped off a contextual conversion to // bool if this is the operand of an '&&' or '||'. For example, we // might lose an lvalue-to-rvalue conversion here. If so, put it back @@ -305,7 +270,6 @@ static ExprResult calculateConstraintSatisfaction( static bool CheckConstraintSatisfaction( Sema &S, const NamedDecl *Template, ArrayRef ConstraintExprs, - llvm::SmallVectorImpl &Converted, const MultiLevelTemplateArgumentList &TemplateArgsLists, SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { if (ConstraintExprs.empty()) { @@ -330,30 +294,22 @@ static bool CheckConstraintSatisfaction( return true; for (const Expr *ConstraintExpr : ConstraintExprs) { - ExprResult Res = calculateConstraintSatisfaction( - S, Template, TemplateIDRange.getBegin(), TemplateArgsLists, - ConstraintExpr, Satisfaction); - if (Res.isInvalid()) + if (calculateConstraintSatisfaction(S, Template, TemplateIDRange.getBegin(), + TemplateArgsLists, ConstraintExpr, + Satisfaction)) return true; - - Converted.push_back(Res.get()); - if (!Satisfaction.IsSatisfied) { - // Backfill the 'converted' list with nulls so we can keep the Converted - // and unconverted lists in sync. - Converted.append(ConstraintExprs.size() - Converted.size(), nullptr); + if (!Satisfaction.IsSatisfied) // [temp.constr.op] p2 - // [...] To determine if a conjunction is satisfied, the satisfaction - // of the first operand is checked. If that is not satisfied, the - // conjunction is not satisfied. [...] + // [...] To determine if a conjunction is satisfied, the satisfaction + // of the first operand is checked. If that is not satisfied, the + // conjunction is not satisfied. [...] return false; - } } return false; } bool Sema::CheckConstraintSatisfaction( const NamedDecl *Template, ArrayRef ConstraintExprs, - llvm::SmallVectorImpl &ConvertedConstraints, const MultiLevelTemplateArgumentList &TemplateArgsLists, SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) { if (ConstraintExprs.empty()) { @@ -361,9 +317,9 @@ bool Sema::CheckConstraintSatisfaction( return false; } if (!Template) { - return ::CheckConstraintSatisfaction( - *this, nullptr, ConstraintExprs, ConvertedConstraints, - TemplateArgsLists, TemplateIDRange, OutSatisfaction); + return ::CheckConstraintSatisfaction(*this, nullptr, ConstraintExprs, + TemplateArgsLists, TemplateIDRange, + OutSatisfaction); } // A list of the template argument list flattened in a predictible manner for @@ -384,8 +340,8 @@ bool Sema::CheckConstraintSatisfaction( auto Satisfaction = std::make_unique(Template, FlattenedArgs); if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, - ConvertedConstraints, TemplateArgsLists, - TemplateIDRange, *Satisfaction)) { + TemplateArgsLists, TemplateIDRange, + *Satisfaction)) { return true; } OutSatisfaction = *Satisfaction; @@ -399,120 +355,21 @@ bool Sema::CheckConstraintSatisfaction( bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { return calculateConstraintSatisfaction( - *this, ConstraintExpr, Satisfaction, - [this](const Expr *AtomicExpr) -> ExprResult { - // We only do this to immitate lvalue-to-rvalue conversion. - return PerformContextuallyConvertToBool( - const_cast(AtomicExpr)); - }) - .isInvalid(); -} - -bool Sema::SetupConstraintScope( - FunctionDecl *FD, llvm::Optional> TemplateArgs, - MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) { - if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) { - FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate(); - InstantiatingTemplate Inst( - *this, FD->getPointOfInstantiation(), - Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate, - TemplateArgs ? *TemplateArgs : ArrayRef{}, - SourceRange()); - if (Inst.isInvalid()) - return true; - - // addInstantiatedParametersToScope creates a map of 'uninstantiated' to - // 'instantiated' parameters and adds it to the context. For the case where - // this function is a template being instantiated NOW, we also need to add - // the list of current template arguments to the list so that they also can - // be picked out of the map. - if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) { - MultiLevelTemplateArgumentList JustTemplArgs(*SpecArgs); - if (addInstantiatedParametersToScope( - FD, PrimaryTemplate->getTemplatedDecl(), Scope, JustTemplArgs)) - return true; - } - - // If this is a member function, make sure we get the parameters that - // reference the original primary template. - if (const auto *FromMemTempl = - PrimaryTemplate->getInstantiatedFromMemberTemplate()) { - if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(), - Scope, MLTAL)) - return true; - } - - return false; - } - - if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization || - FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) { - FunctionDecl *InstantiatedFrom = - FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization - ? FD->getInstantiatedFromMemberFunction() - : FD->getInstantiatedFromDecl(); - - InstantiatingTemplate Inst( - *this, FD->getPointOfInstantiation(), - Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom, - TemplateArgs ? *TemplateArgs : ArrayRef{}, - SourceRange()); - if (Inst.isInvalid()) - return true; - - // Case where this was not a template, but instantiated as a - // child-function. - if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL)) - return true; - } - - return false; -} - -// This function collects all of the template arguments for the purposes of -// constraint-instantiation and checking. -llvm::Optional -Sema::SetupConstraintCheckingTemplateArgumentsAndScope( - FunctionDecl *FD, llvm::Optional> TemplateArgs, - LocalInstantiationScope &Scope) { - MultiLevelTemplateArgumentList MLTAL; - - // Collect the list of template arguments relative to the 'primary' template. - // We need the entire list, since the constraint is completely uninstantiated - // at this point. - MLTAL = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary*/ true, - /*Pattern*/ nullptr, - /*LookBeyondLambda*/ true); - if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope)) - return {}; - - return MLTAL; + *this, ConstraintExpr, Satisfaction, + [this](const Expr *AtomicExpr) -> ExprResult { + // We only do this to immitate lvalue-to-rvalue conversion. + return PerformContextuallyConvertToBool(const_cast(AtomicExpr)); + }); } bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, ConstraintSatisfaction &Satisfaction, - SourceLocation UsageLoc, - bool ForOverloadResolution) { - // Don't check constraints if the function is dependent. Also don't check if - // this is a function template specialization, as the call to - // CheckinstantiatedFunctionTemplateConstraints after this will check it - // better. - if (FD->isDependentContext() || - FD->getTemplatedKind() == - FunctionDecl::TK_FunctionTemplateSpecialization) { + SourceLocation UsageLoc) { + const Expr *RC = FD->getTrailingRequiresClause(); + if (RC->isInstantiationDependent()) { Satisfaction.IsSatisfied = true; return false; } - - ContextRAII SavedContext{ - *this, cast( - const_cast(FD)->getNonClosureContext())}; - LocalInstantiationScope Scope(*this, !ForOverloadResolution || - isLambdaCallOperator(FD)); - llvm::Optional MLTAL = - SetupConstraintCheckingTemplateArgumentsAndScope( - const_cast(FD), {}, Scope); - Qualifiers ThisQuals; CXXRecordDecl *Record = nullptr; if (auto *Method = dyn_cast(FD)) { @@ -523,23 +380,10 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, // We substitute with empty arguments in order to rebuild the atomic // constraint in a constant-evaluated context. // FIXME: Should this be a dedicated TreeTransform? - const Expr *RC = FD->getTrailingRequiresClause(); - llvm::SmallVector Converted; - - if (CheckConstraintSatisfaction( - FD, {RC}, Converted, *MLTAL, - SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), - Satisfaction)) - return true; - - // FIXME: we need to do this for the function constraints for - // comparison of constraints to work, but do we also need to do it for - // CheckInstantiatedFunctionConstraints? That one is more difficult, but we - // seem to always just pick up the constraints from the primary template. - assert(Converted.size() <= 1 && "Got more expressions converted?"); - if (!Converted.empty() && Converted[0] != nullptr) - const_cast(FD)->setTrailingRequiresClause(Converted[0]); - return false; + return CheckConstraintSatisfaction( + FD, {RC}, /*TemplateArgs=*/{}, + SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), + Satisfaction); } bool Sema::EnsureTemplateArgumentListConstraints( @@ -588,14 +432,26 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( // PushDeclContext because we don't have a scope. Sema::ContextRAII savedContext(*this, Decl); LocalInstantiationScope Scope(*this); - - Optional MLTAL = - SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs, - Scope); - - if (!MLTAL) - return true; - + MultiLevelTemplateArgumentList MLTAL; + // FIXME: This will be replaced with some logic to get all the template + // arguments when we switch to deferred template instantiation. + MLTAL.addOuterTemplateArguments(TemplateArgs); + + // 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 + // substitution. + if (Decl->isTemplateInstantiation()) { + InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(), + InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(), + TemplateArgs, SourceRange()); + if (Inst.isInvalid()) + return true; + MultiLevelTemplateArgumentList MLTAL( + *Decl->getTemplateSpecializationArgs()); + if (addInstantiatedParametersToScope( + Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL)) + return true; + } Qualifiers ThisQuals; CXXRecordDecl *Record = nullptr; if (auto *Method = dyn_cast(Decl)) { @@ -603,8 +459,7 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( Record = Method->getParent(); } CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); - llvm::SmallVector Converted; - return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL, + return CheckConstraintSatisfaction(Template, TemplateAC, MLTAL, PointOfInstantiation, Satisfaction); } @@ -879,22 +734,22 @@ Sema::getNormalizedAssociatedConstraints( return CacheEntry->second; } -static bool -substituteParameterMappings(Sema &S, NormalizedConstraint &N, - ConceptDecl *Concept, - const MultiLevelTemplateArgumentList &MLTAL, - const ASTTemplateArgumentListInfo *ArgsAsWritten) { +static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, + ConceptDecl *Concept, ArrayRef TemplateArgs, + const ASTTemplateArgumentListInfo *ArgsAsWritten) { if (!N.isAtomic()) { - if (substituteParameterMappings(S, N.getLHS(), Concept, MLTAL, + if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs, ArgsAsWritten)) return true; - return substituteParameterMappings(S, N.getRHS(), Concept, MLTAL, + return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs, ArgsAsWritten); } TemplateParameterList *TemplateParams = Concept->getTemplateParameters(); AtomicConstraint &Atomic = *N.getAtomicConstraint(); TemplateArgumentListInfo SubstArgs; + MultiLevelTemplateArgumentList MLTAL; + MLTAL.addOuterTemplateArguments(TemplateArgs); if (!Atomic.ParameterMapping) { llvm::SmallBitVector OccurringIndices(TemplateParams->size()); S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false, @@ -935,20 +790,6 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N, return false; } -static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, - const ConceptSpecializationExpr *CSE) { - TemplateArgumentList TAL{TemplateArgumentList::OnStack, - CSE->getTemplateArguments()}; - MultiLevelTemplateArgumentList MLTAL = - S.getTemplateInstantiationArgs(CSE->getNamedConcept(), &TAL, - /*RelativeToPrimary*/ true, - /*Pattern*/ nullptr, - /*LookBeyondLambda*/ true); - - return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL, - CSE->getTemplateArgsAsWritten()); -} - Optional NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef E) { @@ -1011,7 +852,9 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { Optional New; New.emplace(S.Context, *SubNF); - if (substituteParameterMappings(S, *New, CSE)) + if (substituteParameterMappings( + S, *New, CSE->getNamedConcept(), + CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten())) return None; return New; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 377bfaa..5991846 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -283,8 +283,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, // definition. if (FD->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckFunctionConstraints(FD, Satisfaction, Loc, - /*ForOverloadResolution*/ true)) + if (CheckFunctionConstraints(FD, Satisfaction, Loc)) // A diagnostic will have already been generated (non-constant // constraint expression, for example) return true; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 623bd28..91e308d 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -992,78 +992,6 @@ static bool checkArgPlaceholdersForOverload(Sema &S, MultiExprArg Args, return false; } -// Figure out the to-translation-unit depth for this function declaration for -// the purpose of seeing if they differ by constraints. This isn't the same as -// getTemplateDepth, because it includes already instantiated parents. -static unsigned CalculateTemplateDepthForConstraints(Sema &S, - FunctionDecl *FD) { - MultiLevelTemplateArgumentList MLTAL = - S.getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary*/ true, - /*Pattern*/ nullptr, - /*LookBeyondLambda*/ true); - return MLTAL.getNumSubstitutedLevels(); -} - -// Friend definitions can appear identical but be different declarations based -// on the last sentence of the rule below (others included for clarification): -// C++20 [temp.friend] p9: A non-template friend declaration -// with a requires-clause shall be a definition. A friend function template -// with a constraint that depends on a template parameter from an enclosing -// template shall be a definition. Such a constrained friend function or -// function template declaration does not declare the same function or function -// template as a declaration in any other scope. -static bool FriendsDifferByConstraints(Sema &S, DeclContext *CurContext, - FunctionDecl *Old, FunctionDecl *New, - Scope *Scope) { - // If these aren't friends, than they aren't friends that differe by - // constraints. - if (!Old->getFriendObjectKind() || !New->getFriendObjectKind()) - return false; - - // If the the two functions share lexical declaration context, they are not in - // separate instantations, and thus in the same scope. - if (New->getLexicalDeclContext() == Old->getLexicalDeclContext()) - return false; - - if (!Old->getDescribedFunctionTemplate()) { - assert(!New->getDescribedFunctionTemplate() && - "How would these be the same if they aren't both templates?"); - - // If these friends don't have constraints, they aren't constrained, and - // thus don't fall under temp.friend p9. Else the simple presence of a - // constraint makes them unique. - return Old->getTrailingRequiresClause(); - } - - SmallVector OldAC; - Old->getDescribedFunctionTemplate()->getAssociatedConstraints(OldAC); - -#ifndef NDEBUG - SmallVector NewAC; - New->getDescribedFunctionTemplate()->getAssociatedConstraints(NewAC); - assert(OldAC.size() == NewAC.size() && - "Difference should have been noticed earlier if sizes of constraints " - "aren't the same"); -#endif - // If there are no constraints, these are not constrained friend function or - // friend function templates. - if (OldAC.size() == 0) - return false; - - unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(S, Old); - - // At this point, if the constrained function template declaration depends on - // a template parameter from an enclosing template, they are not the same - // function. Since these were deemed identical before we got here, we only - // have to look into 1 side to see if they refer to a containing template. - for (const Expr *Constraint : OldAC) - if (S.ConstraintExpressionDependsOnEnclosingTemplate(OldTemplateDepth, - Constraint)) - return true; - - return false; -} - /// Determine whether the given New declaration is an overload of the /// declarations in Old. This routine returns Ovl_Match or Ovl_NonFunction if /// New and Old cannot be overloaded, e.g., if New has the same signature as @@ -1140,15 +1068,6 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, !shouldLinkPossiblyHiddenDecl(*I, New)) continue; - // C++20 [temp.friend] p9: A non-template friend declaration with a - // requires-clause shall be a definition. A friend function template - // with a constraint that depends on a template parameter from an - // enclosing template shall be a definition. Such a constrained friend - // function or function template declaration does not declare the same - // function or function template as a declaration in any other scope. - if (FriendsDifferByConstraints(*this, CurContext, OldF, New, S)) - continue; - Match = *I; return Ovl_Match; } @@ -6596,8 +6515,7 @@ void Sema::AddOverloadCandidate( if (Function->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckFunctionConstraints(Function, Satisfaction, /*Loc*/ {}, - /*ForOverloadResolution*/ true) || + if (CheckFunctionConstraints(Function, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -7103,8 +7021,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, if (Method->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckFunctionConstraints(Method, Satisfaction, /*Loc*/ {}, - /*ForOverloadResolution*/ true) || + if (CheckFunctionConstraints(Method, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 6bc1a35..1d9c364 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1686,59 +1686,6 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S, return Param; } -namespace { -class ConstraintRefersToContainingTemplateChecker - : public TreeTransform { - bool Result = false; - unsigned TemplateDepth = 0; - -public: - using inherited = TreeTransform; - - ConstraintRefersToContainingTemplateChecker(Sema &SemaRef, - unsigned TemplateDepth) - : inherited(SemaRef), TemplateDepth(TemplateDepth) {} - bool getResult() const { return Result; } - - // This should be the only template parm type that we have to deal with. - // SubstTempalteTypeParmPack, SubstNonTypeTemplateParmPack, and - // FunctionParmPackExpr are all partially substituted, which cannot happen - // with concepts at this point in translation. - QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL) { - assert(TL.getDecl()->getDepth() <= TemplateDepth && - "Nothing should reference a value below the actual template depth, " - "depth is likely wrong"); - if (TL.getDecl()->getDepth() != TemplateDepth) - Result = true; - return inherited::TransformTemplateTypeParmType(TLB, TL); - } - - Decl *TransformDecl(SourceLocation Loc, Decl *D) { - // FIXME : This is possibly an incomplete list, but it is unclear what other - // Decl kinds could be used to refer to the template parameters. This is a - // best guess so far based on examples currently available, but the - // unreachable should catch future instances/cases. - if (auto *TD = dyn_cast(D)) - TransformType(TD->getUnderlyingType()); - else if (auto *VD = dyn_cast(D)) - TransformType(VD->getType()); - else if (auto *TD = dyn_cast(D)) - TransformTemplateParameterList(TD->getTemplateParameters()); - else - llvm_unreachable("Don't know how to handle this declaration type yet"); - return D; - } -}; -} // namespace - -bool Sema::ConstraintExpressionDependsOnEnclosingTemplate( - unsigned TemplateDepth, const Expr *Constraint) { - ConstraintRefersToContainingTemplateChecker Checker(*this, TemplateDepth); - Checker.TransformExpr(const_cast(Constraint)); - return Checker.getResult(); -} - /// ActOnTemplateParameterList - Builds a TemplateParameterList, optionally /// constrained by RequiresClause, that contains the template parameters in /// Params. @@ -2340,8 +2287,7 @@ private: TTP->isExpandedParameterPack() ? llvm::Optional(TTP->getNumExpansionParameters()) : None); if (const auto *TC = TTP->getTypeConstraint()) - SemaRef.SubstTypeConstraint(NewTTP, TC, Args, - /*EvaluateConstraint*/ true); + SemaRef.SubstTypeConstraint(NewTTP, TC, Args); if (TTP->hasDefaultArgument()) { TypeSourceInfo *InstantiatedDefaultArg = SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args, @@ -6027,12 +5973,10 @@ bool Sema::CheckTemplateArgumentList( TemplateArgs = std::move(NewArgs); if (!PartialTemplateArgs) { - TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack, - Converted); - MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs( - Template, &StackTemplateArgs, /*RelativeToPrimary*/ true, - /*Pattern*/ nullptr, - /*LookBeyondLambda*/ true, /*IncludeContainingStruct*/ true); + // FIXME: This will be changed a bit once deferred concept instantiation is + // implemented. + MultiLevelTemplateArgumentList MLTAL; + MLTAL.addOuterTemplateArguments(Converted); if (EnsureTemplateArgumentListConstraints( Template, MLTAL, SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) { @@ -7569,9 +7513,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, // are not considered. if (ParamsAC.empty()) return false; - Template->getAssociatedConstraints(TemplateAC); - bool IsParamAtLeastAsConstrained; if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, IsParamAtLeastAsConstrained)) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index bddf2c0..99119bc 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2827,20 +2827,6 @@ template<> struct IsPartialSpecialization { static constexpr bool value = true; }; -template -static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) { - return false; -} -template <> -bool DeducedArgsNeedReplacement( - VarTemplatePartialSpecializationDecl *Spec) { - return !Spec->isClassScopeExplicitSpecialization(); -} -template <> -bool DeducedArgsNeedReplacement( - ClassTemplatePartialSpecializationDecl *Spec) { - return !Spec->isClassScopeExplicitSpecialization(); -} template static Sema::TemplateDeductionResult @@ -2849,25 +2835,13 @@ CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, TemplateDeductionInfo& Info) { llvm::SmallVector AssociatedConstraints; Template->getAssociatedConstraints(AssociatedConstraints); + // FIXME: This will change quite a bit once deferred concept instantiation is + // implemented. MultiLevelTemplateArgumentList MLTAL; + MLTAL.addOuterTemplateArguments(DeducedArgs); - bool NeedsReplacement = DeducedArgsNeedReplacement(Template); - TemplateArgumentList DeducedTAL{TemplateArgumentList::OnStack, DeducedArgs}; - - MLTAL = S.getTemplateInstantiationArgs( - Template, /*InnerMost*/ NeedsReplacement ? nullptr : &DeducedTAL, - /*RelativeToPrimary*/ true, /*Pattern*/ - nullptr, /*LookBeyondLambda*/ true); - - // getTemplateInstantiationArgs picks up the non-deduced version of the - // template args when this is a variable template partial specialization and - // not class-scope explicit specialization, so replace with Deduced Args - // instead of adding to inner-most. - if (NeedsReplacement) - MLTAL.replaceInnermostTemplateArguments(DeducedArgs); - - if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL, - Info.getLocation(), + if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, + MLTAL, Info.getLocation(), Info.AssociatedConstraintsSatisfaction) || !Info.AssociatedConstraintsSatisfaction.IsSatisfied) { Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs)); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 44c714c..1dd4baf 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -57,18 +57,9 @@ using namespace sema; /// instantiating the definition of the given declaration, \p D. This is /// used to determine the proper set of template instantiation arguments for /// friend function template specializations. -/// -/// \param LookBeyondLambda Indicates that this collection of arguments should -/// continue looking when it encounters a lambda generic call operator. -/// -/// \param IncludeContainingStructArgs Indicates that this collection of -/// arguments should include arguments for any class template that this -/// declaration is included inside of. - MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( const NamedDecl *D, const TemplateArgumentList *Innermost, - bool RelativeToPrimary, const FunctionDecl *Pattern, bool LookBeyondLambda, - bool IncludeContainingStructArgs) { + bool RelativeToPrimary, const FunctionDecl *Pattern) { // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; @@ -164,13 +155,11 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( break; // If this function is a generic lambda specialization, we are done. - if (!LookBeyondLambda && - isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) + if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) break; } else if (Function->getDescribedFunctionTemplate()) { - assert((IncludeContainingStructArgs || - Result.getNumSubstitutedLevels() == 0) && + assert(Result.getNumSubstitutedLevels() == 0 && "Outer template not instantiated?"); } @@ -187,18 +176,10 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( } } else if (const auto *Rec = dyn_cast(Ctx)) { if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { - assert((IncludeContainingStructArgs || - Result.getNumSubstitutedLevels() == 0) && + assert(Result.getNumSubstitutedLevels() == 0 && "Outer template not instantiated?"); if (ClassTemplate->isMemberSpecialization()) break; - if (IncludeContainingStructArgs) { - QualType RecordType = Context.getTypeDeclType(Rec); - QualType Injected = cast(RecordType) - ->getInjectedSpecializationType(); - const auto *InjectedType = cast(Injected); - Result.addOuterTemplateArguments(InjectedType->template_arguments()); - } } } @@ -949,23 +930,16 @@ namespace { const MultiLevelTemplateArgumentList &TemplateArgs; SourceLocation Loc; DeclarationName Entity; - bool EvaluateConstraints = true; public: typedef TreeTransform inherited; TemplateInstantiator(Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation Loc, DeclarationName Entity) - : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc), - Entity(Entity) {} - - void setEvaluateConstraints(bool B) { - EvaluateConstraints = B; - } - bool getEvaluateConstraints() { - return EvaluateConstraints; - } + SourceLocation Loc, + DeclarationName Entity) + : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc), + Entity(Entity) { } /// Determine whether the given type \p T has already been /// transformed. @@ -1172,9 +1146,7 @@ namespace { ExprResult TransformLambdaExpr(LambdaExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - Sema::ConstraintEvalRAII RAII(*this); - ExprResult Res = inherited::TransformLambdaExpr(E); - return Res; + return inherited::TransformLambdaExpr(E); } ExprResult TransformRequiresExpr(RequiresExpr *E) { @@ -1219,7 +1191,6 @@ namespace { DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext(); TemplateDeclInstantiator DeclInstantiator(getSema(), /* DeclContext *Owner */ Owner, TemplateArgs); - DeclInstantiator.setEvaluateConstraints(EvaluateConstraints); return DeclInstantiator.SubstTemplateParams(OrigTPL); } @@ -1795,9 +1766,9 @@ TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, Optional NumExpansions, bool ExpectParameterPack) { - auto NewParm = SemaRef.SubstParmVarDecl( - OldParm, TemplateArgs, indexAdjustment, NumExpansions, - ExpectParameterPack, EvaluateConstraints); + auto NewParm = + SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment, + NumExpansions, ExpectParameterPack); if (NewParm && SemaRef.getLangOpts().OpenCL) SemaRef.deduceOpenCLAddressSpace(NewParm); return NewParm; @@ -2015,7 +1986,8 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { Req, Info, OrigTPL->getSourceRange()); if (TPLInst.isInvalid()) return nullptr; - TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL); + TemplateParameterList *TPL = + TransformTemplateParameterList(OrigTPL); if (!TPL) TransRetReq.emplace(createSubstDiag(SemaRef, Info, [&] (llvm::raw_ostream& OS) { @@ -2225,8 +2197,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext, - Qualifiers ThisTypeQuals, - bool EvaluateConstraints) { + Qualifiers ThisTypeQuals) { assert(!CodeSynthesisContexts.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); @@ -2235,7 +2206,6 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, return T; TemplateInstantiator Instantiator(*this, Args, Loc, Entity); - Instantiator.setEvaluateConstraints(EvaluateConstraints); TypeLocBuilder TLB; @@ -2380,19 +2350,9 @@ namespace { bool Sema::SubstTypeConstraint( TemplateTypeParmDecl *Inst, const TypeConstraint *TC, - const MultiLevelTemplateArgumentList &TemplateArgs, - bool EvaluateConstraints) { + const MultiLevelTemplateArgumentList &TemplateArgs) { const ASTTemplateArgumentListInfo *TemplArgInfo = TC->getTemplateArgsAsWritten(); - - if (!EvaluateConstraints) { - Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(), - TC->getConceptNameInfo(), TC->getNamedConcept(), - TC->getNamedConcept(), TemplArgInfo, - TC->getImmediatelyDeclaredConstraint()); - return false; - } - TemplateArgumentListInfo InstArgs; if (TemplArgInfo) { @@ -2411,11 +2371,11 @@ bool Sema::SubstTypeConstraint( : SourceLocation()); } -ParmVarDecl * -Sema::SubstParmVarDecl(ParmVarDecl *OldParm, - const MultiLevelTemplateArgumentList &TemplateArgs, - int indexAdjustment, Optional NumExpansions, - bool ExpectParameterPack, bool EvaluateConstraint) { +ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, + const MultiLevelTemplateArgumentList &TemplateArgs, + int indexAdjustment, + Optional NumExpansions, + bool ExpectParameterPack) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); TypeSourceInfo *NewDI = nullptr; @@ -2473,7 +2433,9 @@ Sema::SubstParmVarDecl(ParmVarDecl *OldParm, // template's described function, but we might also get here later. // Make sure we do not instantiate the TypeConstraint more than once. if (Inst && !Inst->getTypeConstraint()) { - if (SubstTypeConstraint(Inst, TC, TemplateArgs, EvaluateConstraint)) + // TODO: Concepts: do not instantiate the constraint (delayed constraint + // substitution) + if (SubstTypeConstraint(Inst, TC, TemplateArgs)) return nullptr; } } @@ -3560,9 +3522,11 @@ bool Sema::SubstTemplateArguments( ArrayRef Args, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateArgumentListInfo &Out) { - TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), + TemplateInstantiator Instantiator(*this, TemplateArgs, + SourceLocation(), DeclarationName()); - return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out); + return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), + Out); } ExprResult @@ -3576,23 +3540,11 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) { return Instantiator.TransformExpr(E); } -ExprResult -Sema::SubstConstraintExpr(Expr *E, - const MultiLevelTemplateArgumentList &TemplateArgs) { - if (!E) - return E; - - // This is where we need to make sure we 'know' constraint checking needs to - // happen. - TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), - DeclarationName()); - return Instantiator.TransformExpr(E); -} - ExprResult Sema::SubstInitializer(Expr *Init, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit) { - TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), + TemplateInstantiator Instantiator(*this, TemplateArgs, + SourceLocation(), DeclarationName()); return Instantiator.TransformInitializer(Init, CXXDirectInit); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7c43aa7..140844c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1823,7 +1823,6 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // merged with the local instantiation scope for the function template // itself. LocalInstantiationScope Scope(SemaRef); - Sema::ConstraintEvalRAII RAII(*this); TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); @@ -2063,7 +2062,19 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( return nullptr; } + // FIXME: Concepts: Do not substitute into constraint expressions Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); + if (TrailingRequiresClause) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, + TemplateArgs); + if (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 @@ -2414,6 +2425,23 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( return nullptr; } + // FIXME: Concepts: Do not substitute into constraint expressions + Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); + if (TrailingRequiresClause) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + auto *ThisContext = dyn_cast_or_null(Owner); + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, + D->getMethodQualifiers(), ThisContext); + ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, + TemplateArgs); + if (SubstRC.isInvalid()) + return nullptr; + TrailingRequiresClause = SubstRC.get(); + if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause)) + return nullptr; + } + DeclContext *DC = Owner; if (isFriend) { if (QualifierLoc) { @@ -2431,9 +2459,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( if (!DC) return nullptr; } - CXXRecordDecl *Record = cast(DC); - Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); - DeclarationNameInfo NameInfo = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); @@ -2441,6 +2466,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo); // Build the instantiated method declaration. + CXXRecordDecl *Record = cast(DC); CXXMethodDecl *Method = nullptr; SourceLocation StartLoc = D->getInnerLocStart(); @@ -2745,11 +2771,13 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( Inst->setImplicit(D->isImplicit()); if (auto *TC = D->getTypeConstraint()) { if (!D->isImplicit()) { - // Invented template parameter type constraints will be instantiated - // with the corresponding auto-typed parameter as it might reference - // other parameters. - if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs, - EvaluateConstraints)) + // Invented template parameter type constraints will be instantiated with + // the corresponding auto-typed parameter as it might reference other + // parameters. + + // TODO: Concepts: do not instantiate the constraint (delayed constraint + // substitution) + if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs)) return nullptr; } } @@ -3993,7 +4021,18 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { if (Invalid) return nullptr; - Expr *InstRequiresClause = L->getRequiresClause(); + // FIXME: Concepts: Substitution into requires clause should only happen when + // checking satisfaction. + Expr *InstRequiresClause = nullptr; + if (Expr *E = L->getRequiresClause()) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs); + if (Res.isInvalid() || !Res.isUsable()) { + return nullptr; + } + InstRequiresClause = Res.get(); + } TemplateParameterList *InstL = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(), @@ -4287,9 +4326,11 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, ThisTypeQuals = Method->getMethodQualifiers(); } - TypeSourceInfo *NewTInfo = SemaRef.SubstFunctionDeclType( - OldTInfo, TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName(), - ThisContext, ThisTypeQuals, EvaluateConstraints); + TypeSourceInfo *NewTInfo + = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs, + D->getTypeSpecStartLoc(), + D->getDeclName(), + ThisContext, ThisTypeQuals); if (!NewTInfo) return nullptr; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index db9fa77..142e00a 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13081,6 +13081,13 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { NewCallOpType); } + // Transform the trailing requires clause + ExprResult NewTrailingRequiresClause; + if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause()) + // FIXME: Concepts: Substitution into requires clause should only happen + // when checking satisfaction. + NewTrailingRequiresClause = getDerived().TransformExpr(TRC); + // Create the local class that will describe the lambda. // FIXME: DependencyKind below is wrong when substituting inside a templated @@ -13115,7 +13122,7 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { E->getCallOperator()->getEndLoc(), NewCallOpTSI->getTypeLoc().castAs().getParams(), E->getCallOperator()->getConstexprKind(), - E->getCallOperator()->getTrailingRequiresClause()); + NewTrailingRequiresClause.get()); LSI->CallOperator = NewCallOperator; diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp index 15e00e4..dd6bfe8 100644 --- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp +++ b/clang/test/CXX/temp/temp.constr/temp.constr.constr/non-function-templates.cpp @@ -90,24 +90,3 @@ struct D { }; 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}} - -// Test the delayed instantiation, the 'foo' implementation shouldn't cause the -// constraint failure(or crash!) until the use to create 'y'. -namespace DelayedInst { -template -struct AAA { - template - requires(sizeof(T) == I) // expected-note {{because 'sizeof(int) == 5U' (4 == 5) evaluated to false}} - struct B { - static constexpr int a = 0; - }; - - static constexpr auto foo() { - return B::a; // expected-error{{constraints not satisfied for class template 'B' [with T = int]}} - } -}; - -constexpr auto x = AAA<4>::foo(); -constexpr auto y = AAA<5>::foo(); // expected-note {{in instantiation of member function 'DelayedInst::AAA<5>::foo' requested here}} - -} // namespace DelayedInst diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp index 7772eec..ceb5af8 100644 --- a/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp +++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/class-template-partial-specializations.cpp @@ -52,30 +52,6 @@ static_assert(F::value == 2); static_assert(F::value == 3); static_assert(F::value == 1); -template -struct S { - template - struct F { - enum { value = 1 }; - }; - - template - requires C1 && C2 - struct F { - enum { value = 2 }; - }; - - template - requires C1 || C2 - struct F { - enum { value = 3 }; - }; -}; - -static_assert(S<1>::F::value == 2); -static_assert(S<1>::F::value == 3); -static_assert(S<1>::F::value == 1); - // Make sure atomic constraints subsume each other only if their parameter // mappings are identical. diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp index 972a4fd..98bfaea 100644 --- a/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp +++ b/clang/test/CXX/temp/temp.constr/temp.constr.order/var-template-partial-specializations.cpp @@ -51,20 +51,5 @@ static_assert(f == 2); static_assert(f == 3); static_assert(f == 1); -template -struct S { - template - static constexpr int f = 1; - - template - requires C1 && C2 - static constexpr int f = 2; - - template - requires C1 || C2 - static constexpr int f = 3; -}; - -static_assert(S<1>::f == 2); -static_assert(S<1>::f == 3); -static_assert(S<1>::f == 1); + + diff --git a/clang/test/SemaTemplate/concepts-friends.cpp b/clang/test/SemaTemplate/concepts-friends.cpp deleted file mode 100644 index 6503767..0000000 --- a/clang/test/SemaTemplate/concepts-friends.cpp +++ /dev/null @@ -1,371 +0,0 @@ -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s - -template -concept constraint = false; -namespace temp_friend_9 { -// A non-template friend declaration with a requires-clause shall be a -// definition. ...Such a constrained friend function ... does not declare the -// same function or function template as a declaration in any other scope. -template -struct NonTemplateFriend { - friend void foo() - requires true - {} -}; - -// A friend function template with a constraint that depends on a template -// parameter from an enclosing template shall be a definition. Such a ... -// function template declaration does not declare the same function or -// function template as a declaration in any other scope. -template -struct TemplateFromEnclosing { - template - friend void foo() - requires constraint - {} - - T variable; - template - friend void foo2() - requires constraint - {} - - template - friend void foo3(T parmvar) - requires constraint - {} - - template - friend void foo4() - requires requires(T &req) { (void)req; } - {} - - using Alias = T; - template - friend void foo5() - requires constraint - {} - - // All of these refer to a parent, so these are not duplicate definitions. - struct ChildOfEnclosing { - template - friend void foo6() - requires constraint - {} - template - friend void foo7() - requires constraint - {} - template - friend void foo8(T parmvar) - requires constraint - {} - // This is NOT a duplicate since it itself is not a template. - friend void foo9() - requires true - {} - }; - template - struct TemplChildOfEnclosing { - template - friend void foo10() - requires constraint - {} - }; -}; - -// Doesn't meet either of the requirements in the above as they don't refer to -// an enclosing scope. -template -struct Redefinition { - template - friend void foo() // #REDEF - requires constraint - {} - - struct ChildOfRedef { - template - friend void foo2() // #REDEF2 - requires constraint - {} - }; - template - struct ChildOfRedef2 { - template - friend void foo3() // #REDEF3 - requires constraint - {} - }; -}; - -void bar() { - NonTemplateFriend S1; - NonTemplateFriend S2; - TemplateFromEnclosing S3; - TemplateFromEnclosing::ChildOfEnclosing S3b; - TemplateFromEnclosing S4; - TemplateFromEnclosing::ChildOfEnclosing S4b; - Redefinition S5; - Redefinition S6; - // expected-error@#REDEF {{redefinition of 'foo'}} - // expected-note@-2{{in instantiation of template class }} - // expected-note@#REDEF {{previous definition is here}} - Redefinition::ChildOfRedef S7; - Redefinition::ChildOfRedef S8; - // expected-error@#REDEF2 {{redefinition of 'foo2'}} - // expected-note@-2{{in instantiation of member class }} - // expected-note@#REDEF2 {{previous definition is here}} - - Redefinition::ChildOfRedef2 S9; - Redefinition::ChildOfRedef2 S10; - // expected-error@#REDEF3 {{redefinition of 'foo3'}} - // expected-note@-2{{in instantiation of template class }} - // expected-note@#REDEF3 {{previous definition is here}} -} -} // namespace temp_friend_9 - -namespace SameScopeRedefs { -template -struct NonTemplateFriend { - friend void foo() // #NTF1 - requires true - {} - friend void foo() // #NTF2 - requires true - {} -}; - -template -struct TemplateFromEnclosing { - template - friend void foo() // #TFE1 - requires constraint - {} - template - friend void foo() // #TFE2 - requires constraint - {} -}; -// Same as above, but doesn't require an instantiation pair to cause. -template -struct Redefinition { - template - friend void foo() // #RD1 - requires constraint - {} - template - friend void foo() // #RD2 - requires constraint - {} -}; -void bar() { - NonTemplateFriend S1; - // expected-error@#NTF2 {{redefinition of 'foo'}} - // expected-note@-2{{in instantiation of template class}} - // expected-note@#NTF1 {{previous definition is here}} - - TemplateFromEnclosing S2; - // expected-error@#TFE2 {{redefinition of 'foo'}} - // expected-note@-2{{in instantiation of template class}} - // expected-note@#TFE1 {{previous definition is here}} - - Redefinition S3; - // expected-error@#RD2 {{redefinition of 'foo'}} - // expected-note@-2{{in instantiation of template class}} - // expected-note@#RD1 {{previous definition is here}} -} -} // namespace SameScopeRedefs - -namespace LibCXXOperatorRedef { -template struct is_same { - static constexpr bool value = false; -}; -template struct is_same { - static constexpr bool value = false; -}; - -template -concept same_as = is_same::value; - -// An issue found from libcxx when trying to commit the deferred concepts patch. -// This caused an error of 'redefinition of funcN'. -template struct __range_adaptor_closure { - template - requires same_as<_Tp, _Closure> - friend constexpr decltype(auto) R1func1(_View &&__view, - _Closure &&__closure){}; - template - friend constexpr decltype(auto) R1func2(_View &&__view, - _Closure &&__closure) - requires same_as<_Tp, _Closure> - {}; - template _View, typename _Closure> - friend constexpr decltype(auto) R1func3(_View &&__view, - _Closure &&__closure){}; -}; - -struct A : __range_adaptor_closure {}; -struct B : __range_adaptor_closure {}; - -// These three fail because after the 1st pass of instantiation, they are still -// identical. -template struct __range_adaptor_closure2 { - template - requires same_as<_View, _Closure> - friend constexpr decltype(auto) R2func1(_View &&__view, // #FUNC1 - _Closure &&__closure){}; - template - friend constexpr decltype(auto) R2func2(_View &&__view, // #FUNC2 - _Closure &&__closure) - requires same_as<_View, _Closure> - {}; - template _Closure> - friend constexpr decltype(auto) R2func3(_View &&__view, // #FUNC3 - _Closure &&__closure){}; -}; - -struct A2 : __range_adaptor_closure2 {}; -struct B2 : __range_adaptor_closure2 {}; -// expected-error@#FUNC1{{redefinition of 'R2func1'}} -// expected-note@-2{{in instantiation of template class}} -// expected-note@#FUNC1{{previous definition is here}} -// expected-error@#FUNC2{{redefinition of 'R2func2'}} -// expected-note@#FUNC2{{previous definition is here}} -// expected-error@#FUNC3{{redefinition of 'R2func3'}} -// expected-note@#FUNC3{{previous definition is here}} - -// These three are fine, they all depend on the parent template parameter, so -// are different despite ::type not being valid. -template struct __range_adaptor_closure3 { - template - requires same_as - friend constexpr decltype(auto) R3func1(_View &&__view, - _Closure &&__closure){}; - template - friend constexpr decltype(auto) R3func2(_View &&__view, - _Closure &&__closure) - requires same_as - {}; - template _View, typename _Closure> - friend constexpr decltype(auto) R3func3(_View &&__view, - _Closure &&__closure){}; -}; - -struct A3 : __range_adaptor_closure3 {}; -struct B3 : __range_adaptor_closure3 {}; - -template struct __range_adaptor_closure4 { - template - requires same_as<_Tp, _View> - // expected-note@+1{{previous definition is here}} - void foo1(_View &&, _Closure &&) {} - template - requires same_as<_Tp, _View> - // expected-error@+1{{class member cannot be redeclared}} - void foo1(_View &&, _Closure &&) {} - - template - // expected-note@+1{{previous definition is here}} - void foo2(_View &&, _Closure &&) - requires same_as<_Tp, _View> - {} - template - // expected-error@+1{{class member cannot be redeclared}} - void foo2(_View &&, _Closure &&) - requires same_as<_Tp, _View> - {} - - template _View, typename _Closure> - // expected-note@+1{{previous definition is here}} - void foo3(_View &&, _Closure &&) {} - template _View, typename _Closure> - // expected-error@+1{{class member cannot be redeclared}} - void foo3(_View &&, _Closure &&) {} -}; - -// Requires instantiation to fail, so no errors here. -template struct __range_adaptor_closure5 { - template U> - friend void foo() {} - template U> - friend void foo() {} -}; - -template struct __range_adaptor_closure6 { - template U> - friend void foo() {} // #RAC6FOO1 - template U> - friend void foo() {} // #RAC6FOO2 -}; -struct A6 : __range_adaptor_closure6 {}; -// expected-error@#RAC6FOO2{{redefinition of 'foo'}} -// expected-note@-2{{in instantiation of template class}} -// expected-note@#RAC6FOO1{{previous definition is here}} - -template struct S1 { - template - friend void dupe() {} // #S1DUPE - - template - requires same_as - friend void dupe2() {} // #S1DUPE2 -}; -template struct S2 { - template - friend void dupe() {} // #S2DUPE - - template - requires same_as - friend void dupe2() {} // #S2DUPE2 -}; - -template struct S3 { - template - requires same_as - friend void dupe() {} -}; -template struct S4 { - template - requires same_as - friend void dupe() {} -}; - -// Same as S3 and S4, but aren't instantiated with the same T. -template struct S5 { - template - requires same_as - friend void not_dupe() {} -}; -template struct S6 { - template - requires same_as - friend void not_dupe() {} -}; - -template struct S7 { - void not_dupe() - requires same_as - {} -}; - -void useS() { - S1 s1; - S2 s2; - // expected-error@#S2DUPE{{redefinition}} - // expected-note@-2{{in instantiation of template class}} - // expected-note@#S1DUPE{{previous definition is here}} - // expected-error@#S2DUPE2{{redefinition}} - // expected-note@#S1DUPE2{{previous definition is here}} - - // OK, they have different 'scopes'. - S3 s3; - S4 s4; - - // OK, because only instantiated with different T. - S5 s5; - S6 s6; - - S7 s7; -} - -} // namespace LibCXXOperatorRedef diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index 836ab6f..23c7942 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -256,387 +256,3 @@ C auto **j1 = g(); // expected-error {{deduced type 'int' does not satisfy 'C' C auto **&j2 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}} C auto **&&j3 = g(); // expected-error {{deduced type 'int' does not satisfy 'C'}} } - -namespace SubConstraintChecks { -template -concept TrueConstraint = true; -template -concept FalseConstraint = false; - -template -class ContainsConstrainedFuncTrue { -public: - template - static void func(V &&, Constrained &&C); -}; -template -class ContainsConstrainedFuncFalse { -public: - template - static void func(V &&, Constrained &&C); -}; - -template -concept TrueConstraint2 = - requires(float &&t) { - ContainsConstrainedFuncTrue::func(5, 0.0); - }; -template -concept FalseConstraint2 = - requires(float &&t) { - ContainsConstrainedFuncFalse::func(5, 0.0); // #FC2_CONSTR - }; - -template -void useTrue(int F) - requires TrueConstraint2 -{} - -template -void useFalse(int F) // #USE_FALSE - requires FalseConstraint2 // #USE_FALSE_CONSTR -{} - -// Should only diagnose 'false' once instantiated. -void UseUse() { - useTrue(5); - useFalse(5); - // expected-error@-1{{no matching function for call to 'useFalse'}} - // expected-note@#USE_FALSE{{constraints not satisfied}} - // expected-note@#USE_FALSE_CONSTR{{because 'int' does not satisfy 'FalseConstraint2'}} - // expected-note@#FC2_CONSTR {{would be invalid: no matching function for call to 'func'}} -} -} // namespace SubConstraintChecks - -namespace DeducedTemplateArgs { -template struct ItrTraits { - template struct Ptr { - }; - template - requires requires { typename PtrItr::pointer; } - struct Ptr { - using type = typename Itr::pointer; - }; - using pointer = typename Ptr::type; // #TRAITS_PTR -}; - -struct complete_itr { - using pointer = int; -}; - -template class Complete { - using ItrType = ItrTraits; - ItrType begin() noexcept { return ItrType(); } -}; - -// This version doesn't have 'pointer', so error confirms we are in the first -// verison of 'Ptr'. -struct not_complete_itr { -}; - -template class NotComplete { - using ItrType = ItrTraits; - ItrType begin() noexcept { return ItrType(); } - // expected-error@#TRAITS_PTR{{no type named 'type' in }} - // expected-note@-2{{in instantiation of template class }} -}; -} // namespace DeducedTemplateArgs - -namespace DeferredInstantiationInstScope { -template -struct remove_ref { - using type = T; -}; -template -struct remove_ref { - using type = T; -}; -template -struct remove_ref { - using type = T; -}; - -template -constexpr bool IsInt = PR54443::is_same::type, - int>::value; - -template -void SingleDepthReferencesTop(U &&u) { - struct lc { - void operator()() // #SDRT_OP - requires IsInt // #SDRT_REQ - {} - }; - lc lv; - lv(); // #SDRT_CALL -} - -template -void SingleDepthReferencesTopNotCalled(U &&u) { - struct lc { - void operator()() - requires IsInt - {} - }; - lc lv; -} - -template -void SingleDepthReferencesTopCalled(U &&u) { - struct lc { - void operator()() // #CALLOP - requires IsInt // #CONSTR - {} - }; - lc lv; - lv(); - // expected-error@-1{{no matching function for call to object of type 'lc'}} - // expected-note@#SDRTC{{in instantiation of function template}} - // expected-note@#CALLOP{{constraints not satisfied}} - // expected-note@#CONSTR{{substituted constraint expression is ill-formed}} -} - -template -void SingleDepthReferencesTopLambda(U &&u) { - []() - requires IsInt - {}(); -} - -template -void DoubleDepthReferencesTop(U &&u) { - struct lc { // #DDRT_STRCT - void operator()() { - struct lc2 { - void operator()() // #DDRT_OP - requires IsInt // #DDRT_REQ - {} - }; - lc2 lv2; - lv2(); // #DDRT_CALL - } - }; - lc lv; - lv(); -} - -template -void DoubleDepthReferencesTopLambda(U &&u) { - []() { []() - requires IsInt - {}(); }(); -} - -template -void DoubleDepthReferencesAll(U &&u) { - struct lc { // #DDRA_STRCT - void operator()(U &&u2) { - struct lc2 { - void operator()(U &&u3) // #DDRA_OP - requires IsInt && // #DDRA_REQ - IsInt && IsInt - {} - }; - lc2 lv2; - lv2(u2); // #DDRA_CALL - } - }; - lc lv; - lv(u); -} - -template -void DoubleDepthReferencesAllLambda(U &&u) { - [](U &&u2) { - [](U && u3) - requires IsInt && - IsInt && IsInt - {}(u2); - }(u); -} - -template -struct CausesFriendConstraint { - template - friend void FriendFunc(CausesFriendConstraint, V) // #FF_DECL - requires IsInt && - IsInt // #FF_REQ - {} -}; -// FIXME: Re-enable this test when constraints are allowed to refer to captures. -// template -// void ChecksCapture(T x) { -// [y = x]() requires(IsInt){}(); -// } - -template -void ChecksLocalVar(T x) { - T Local; - []() - requires(IsInt) - {}(); -} - -template -void LocalStructMemberVar(T x) { - struct S { - T local; - void foo() - requires(IsInt) // #LSMV_REQ - {} - } s; - s.foo(); // #LSMV_CALL -}; - -template -struct ChecksMemberVar { - T t; - void foo() - requires(IsInt) // #CMV_FOO - {} - template - void foo2() // #CMV_FOO2 - requires(IsInt) // #CMV_FOO2_REQ - {} -}; - -void test_dependent() { - int v = 0; - float will_fail; - SingleDepthReferencesTop(v); - SingleDepthReferencesTop(will_fail); - // expected-error@#SDRT_CALL{{no matching function for call to object of type 'lc'}} - // expected-note@-2{{in instantiation of function template specialization}} - // expected-note@#SDRT_OP{{candidate function not viable}} - // expected-note@#SDRT_REQ{{'IsInt' evaluated to false}} - - SingleDepthReferencesTopNotCalled(v); - // Won't error unless we try to call it. - SingleDepthReferencesTopNotCalled(will_fail); - SingleDepthReferencesTopCalled(v); // #SDRTC - SingleDepthReferencesTopLambda(v); - // FIXME: This should error on constraint failure! (Lambda!) - SingleDepthReferencesTopLambda(will_fail); - DoubleDepthReferencesTop(v); - DoubleDepthReferencesTop(will_fail); - // expected-error@#DDRT_CALL{{no matching function for call to object of type 'lc2'}} - // expected-note@-2{{in instantiation of function template specialization}} - // expected-note@#DDRT_STRCT{{in instantiation of member function}} - // expected-note@#DDRT_OP{{candidate function not viable}} - // expected-note@#DDRT_REQ{{'IsInt' evaluated to false}} - - DoubleDepthReferencesTopLambda(v); - // FIXME: This should error on constraint failure! (Lambda!) - DoubleDepthReferencesTopLambda(will_fail); - DoubleDepthReferencesAll(v); - DoubleDepthReferencesAll(will_fail); - // expected-error@#DDRA_CALL{{no matching function for call to object of type 'lc2'}} - // expected-note@-2{{in instantiation of function template specialization}} - // expected-note@#DDRA_STRCT{{in instantiation of member function}} - // expected-note@#DDRA_OP{{candidate function not viable}} - // expected-note@#DDRA_REQ{{'IsInt' evaluated to false}} - - DoubleDepthReferencesAllLambda(v); - // FIXME: This should error on constraint failure! (Lambda!) - DoubleDepthReferencesAllLambda(will_fail); - - CausesFriendConstraint CFC; - FriendFunc(CFC, 1); - FriendFunc(CFC, 1.0); - // expected-error@-1{{no matching function for call to 'FriendFunc'}} - // expected-note@#FF_DECL{{constraints not satisfied}} - // expected-note@#FF_REQ{{because 'IsInt' evaluated to false}} - - // FIXME: Re-enable this test when constraints are allowed to refer to captures. - // ChecksCapture(v); - - ChecksLocalVar(v); - // FIXME: This should error on constraint failure! (Lambda!) - ChecksLocalVar(will_fail); - - LocalStructMemberVar(v); - LocalStructMemberVar(will_fail); - // expected-error@#LSMV_CALL{{invalid reference to function 'foo'}} - // expected-note@-2{{in instantiation of function template specialization}} - // expected-note@#LSMV_REQ{{because 'IsIntlocal)>' evaluated to false}} - - ChecksMemberVar CMV; - CMV.foo(); - CMV.foo2(); - - ChecksMemberVar CMV2; - CMV2.foo(); - // expected-error@-1{{invalid reference to function 'foo'}} - // expected-note@#CMV_FOO{{because 'IsIntt)>' evaluated to false}} - CMV2.foo2(); - // expected-error@-1{{no matching member function for call to 'foo2'}} - // expected-note@#CMV_FOO2{{constraints not satisfied}} - // expected-note@#CMV_FOO2_REQ{{because 'IsIntt)>' evaluated to false}} -} -} // namespace DeferredInstantiationInstScope - -// Ane example of evaluating a concept at two different depths in the same -// evaluation. No diagnostic is expected. -namespace SameConceptDifferentDepth { -template -concept sentinel_for = - requires(_Ip __i) { - __i++; - }; - -template -concept bidirectional_iterator = - sentinel_for<_Ip>; - -template -class move_iterator { -public: - auto operator++(int) - requires sentinel_for<_Iter>{} -}; - -static_assert(bidirectional_iterator>); -} // namespace SameConceptDifferentDepth - -namespace VarInit { -template -concept __can_reference = true; - -template -class common_iterator { -public: - common_iterator() { - constexpr auto x = requires(_Iter & __i) { { __i } -> __can_reference; }; - } -}; - -void test() { - auto commonIter1 = common_iterator(); -} -} // namespace VarInit - - -namespace InlineFriendOperator { -template -concept C = true; -template -class counted_iterator { - _Iter I; -public: - constexpr counted_iterator() = default; - friend constexpr auto operator+( // expected-note {{candidate function not viable}} - int __n, const counted_iterator &__x) - requires C - { - return __x + __n; // expected-error{{invalid operands to binary expression}} - } -}; - -constexpr bool test() { - counted_iterator iter; - auto x = 2 + iter; // expected-note{{in instantiation of member function 'InlineFriendOperator::operator+'}} - - return true; -} -} // namespace InlineFriendOperator - diff --git a/clang/test/SemaTemplate/deferred-concept-inst.cpp b/clang/test/SemaTemplate/deferred-concept-inst.cpp deleted file mode 100644 index dd9a408..0000000 --- a/clang/test/SemaTemplate/deferred-concept-inst.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify -fsyntax-only -Wno-unused-value -// expected-no-diagnostics - -namespace GithubBug44178 { -template -struct CRTP { - void call_foo() - requires requires(D &v) { v.foo(); } - { - static_cast(this)->foo(); - } -}; - -struct Test : public CRTP { - void foo() {} -}; - -int main() { - Test t; - t.call_foo(); - return 0; -} -} // namespace GithubBug44178 diff --git a/clang/test/SemaTemplate/instantiate-requires-clause.cpp b/clang/test/SemaTemplate/instantiate-requires-clause.cpp index 3f438d8..73dd20d 100644 --- a/clang/test/SemaTemplate/instantiate-requires-clause.cpp +++ b/clang/test/SemaTemplate/instantiate-requires-clause.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -x c++ %s -Wno-unused-value -verify +// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify template requires ((sizeof(Args) == 1), ...) // expected-note@-1 {{because '(sizeof(int) == 1) , (sizeof(char) == 1) , (sizeof(int) == 1)' evaluated to false}} @@ -40,20 +40,6 @@ struct S { static_assert(S::f(1)); -// Similar to the 'S' test, but tries to use 'U' in the requires clause. -template -struct S1 { - // expected-note@+3 {{candidate template ignored: constraints not satisfied [with U = int]}} - // expected-note@+3 {{because substituted constraint expression is ill-formed: type 'int' cannot be used prior to '::' because it has no members}} - template - static constexpr auto f(U const index) - requires(U::foo) - { return true; } -}; - -// expected-error@+1 {{no matching function for call to 'f'}} -static_assert(S1::f(1)); - constexpr auto value = 0; template diff --git a/clang/test/SemaTemplate/trailing-return-short-circuit.cpp b/clang/test/SemaTemplate/trailing-return-short-circuit.cpp deleted file mode 100644 index 0d1c9b5..0000000 --- a/clang/test/SemaTemplate/trailing-return-short-circuit.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// RUN: %clang_cc1 -std=c++20 -verify %s - -template - requires(sizeof(T) > 2) || T::value // #FOO_REQ -void Foo(T){}; // #FOO - -template -void TrailingReturn(T) // #TRAILING - requires(sizeof(T) > 2) || // #TRAILING_REQ - T::value // #TRAILING_REQ_VAL -{}; -template -struct HasValue { - static constexpr bool value = B; -}; -static_assert(sizeof(HasValue) <= 2); - -template -struct HasValueLarge { - static constexpr bool value = B; - int I; -}; -static_assert(sizeof(HasValueLarge) > 2); - -void usage() { - // Passes the 1st check, short-circuit so the 2nd ::value is not evaluated. - Foo(1.0); - TrailingReturn(1.0); - - // Fails the 1st check, but has a ::value, so the check happens correctly. - Foo(HasValue{}); - TrailingReturn(HasValue{}); - - // Passes the 1st check, but would have passed the 2nd one. - Foo(HasValueLarge{}); - TrailingReturn(HasValueLarge{}); - - // Fails the 1st check, fails 2nd because there is no ::value. - Foo(true); - // expected-error@-1{{no matching function for call to 'Foo'}} - // expected-note@#FOO{{candidate template ignored: constraints not satisfied [with T = bool]}} - // expected-note@#FOO_REQ{{because 'sizeof(_Bool) > 2' (1 > 2) evaluated to false}} - // expected-note@#FOO_REQ{{because substituted constraint expression is ill-formed: type 'bool' cannot be used prior to '::' because it has no members}} - - TrailingReturn(true); - // expected-error@-1{{no matching function for call to 'TrailingReturn'}} - // expected-note@#TRAILING{{candidate template ignored: constraints not satisfied [with T = bool]}} - // expected-note@#TRAILING_REQ{{because 'sizeof(_Bool) > 2' (1 > 2) evaluated to false}} - // expected-note@#TRAILING_REQ_VAL{{because substituted constraint expression is ill-formed: type 'bool' cannot be used prior to '::' because it has no members}} - - // Fails the 1st check, fails 2nd because ::value is false. - Foo(HasValue{}); - // expected-error@-1 {{no matching function for call to 'Foo'}} - // expected-note@#FOO{{candidate template ignored: constraints not satisfied [with T = HasValue]}} - // expected-note@#FOO_REQ{{because 'sizeof(HasValue) > 2' (1 > 2) evaluated to false}} - // expected-note@#FOO_REQ{{and 'HasValue::value' evaluated to false}} - TrailingReturn(HasValue{}); - // expected-error@-1 {{no matching function for call to 'TrailingReturn'}} - // expected-note@#TRAILING{{candidate template ignored: constraints not satisfied [with T = HasValue]}} - // expected-note@#TRAILING_REQ{{because 'sizeof(HasValue) > 2' (1 > 2) evaluated to false}} - // expected-note@#TRAILING_REQ_VAL{{and 'HasValue::value' evaluated to false}} -} -- 2.7.4