Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1982,20 +1982,6 @@ 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 // context. @@ -2033,7 +2019,7 @@ SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo, D->getCanonicalDecl()->getStorageClass(), D->UsesFPIntrin(), D->isInlineSpecified(), D->hasWrittenPrototype(), D->getConstexprKind(), - TrailingRequiresClause); + D->getTrailingRequiresClause()); Function->setRangeEnd(D->getSourceRange().getEnd()); } @@ -2060,7 +2046,7 @@ Params[P]->setOwningFunction(Function); Function->setParams(Params); - if (TrailingRequiresClause) + if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) Function->setTrailingRequiresClause(TrailingRequiresClause); if (TemplateParams) { Index: clang/test/SemaTemplate/trailing-return-short-circuit.cpp =================================================================== --- /dev/null +++ clang/test/SemaTemplate/trailing-return-short-circuit.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -std=c++20 -verify %s + +template <class T> +requires(sizeof(T) > 2) || T::value // #FOO_REQ +void Foo(T){}; // #FOO + +template <class T> +void TrailingReturn(T) // #TRAILING +requires(sizeof(T) > 2) || T::value // #TRAILING_REQ +{}; +template<bool B> +struct HasValue { + static constexpr bool value = B; +}; +static_assert(sizeof(HasValue<true>) <= 2); + +template<bool B> +struct HasValueLarge { + static constexpr bool value = B; + int I; +}; +static_assert(sizeof(HasValueLarge<true>) > 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<true>{}); + TrailingReturn(HasValue<true>{}); + + // Passes the 1st check, but would have passed the 2nd one. + Foo(HasValueLarge<true>{}); + TrailingReturn(HasValueLarge<true>{}); + + // 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{{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<false>{}); + // expected-error@-1 {{no matching function for call to 'Foo'}} + // expected-note@#FOO{{candidate template ignored: constraints not satisfied [with T = HasValue<false>]}} + // expected-note@#FOO_REQ{{because 'sizeof(HasValue<false>) > 2' (1 > 2) evaluated to false}} + // expected-note@#FOO_REQ{{and 'HasValue<false>::value' evaluated to false}} + TrailingReturn(HasValue<false>{}); + // expected-error@-1 {{no matching function for call to 'TrailingReturn'}} + // expected-note@#TRAILING{{candidate template ignored: constraints not satisfied [with T = HasValue<false>]}} + // expected-note@#TRAILING_REQ{{because 'sizeof(HasValue<false>) > 2' (1 > 2) evaluated to false}} + // expected-note@#TRAILING_REQ{{and 'HasValue<false>::value' evaluated to false}} +}