erichkeane updated this revision to Diff 509101. erichkeane added a comment.
Took Corentin's advice and tried to test the lambda condition. THIS made me discover that we didn't properly implement this for lambdas at all! So this patch NOW also implements the restriction for lambdas. @cor3ntin : Please double check on this for me? I had to touch some lambda tests you worked on. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147070/new/ https://reviews.llvm.org/D147070 Files: clang/docs/ReleaseNotes.rst clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaLambda.cpp clang/test/CXX/dcl.decl/dcl.decl.general/p4-20.cpp clang/test/Parser/cxx2b-lambdas.cpp clang/test/SemaCXX/lambda-capture-type-deduction.cpp
Index: clang/test/SemaCXX/lambda-capture-type-deduction.cpp =================================================================== --- clang/test/SemaCXX/lambda-capture-type-deduction.cpp +++ clang/test/SemaCXX/lambda-capture-type-deduction.cpp @@ -48,6 +48,7 @@ static_assert(noexcept([&] mutable noexcept(is_same<int &, decltype((y))>) {}())); } +template<typename T> void test_requires() { int x; @@ -77,6 +78,10 @@ [x = 1]() mutable requires is_same<int &, decltype((x))> {} (); } +void use() { + test_requires<int>(); +} + void err() { int y, z; (void)[x = 1]<typename T> Index: clang/test/Parser/cxx2b-lambdas.cpp =================================================================== --- clang/test/Parser/cxx2b-lambdas.cpp +++ clang/test/Parser/cxx2b-lambdas.cpp @@ -18,7 +18,7 @@ auto L10 = []<typename T> noexcept { return true; }; auto L11 = []<typename T> -> bool { return true; }; auto L12 = [] consteval {}; -auto L13 = []() requires true {}; +auto L13 = []() requires true {}; // expected-error{{non-templated function cannot have a requires clause}} auto L14 = []<auto> requires true() requires true {}; auto L15 = []<auto> requires true noexcept {}; auto L16 = [] [[maybe_unused]]{}; Index: clang/test/CXX/dcl.decl/dcl.decl.general/p4-20.cpp =================================================================== --- clang/test/CXX/dcl.decl/dcl.decl.general/p4-20.cpp +++ clang/test/CXX/dcl.decl/dcl.decl.general/p4-20.cpp @@ -23,3 +23,36 @@ // expected-error@+1{{expected expression}} auto *p = new void(*)(char) requires true; + +namespace GH61748 { +template<typename T> +struct S { + // expected-error@+1 {{non-templated function cannot have a requires clause}} + friend void declared_friend() requires(sizeof(T) > 1); + // OK, is a definition. + friend void defined_friend() requires(sizeof(T) > 1){} + // OK, is a member. + void member() requires(sizeof(T) > 1); +}; + +template<typename T> +void ContainingFunction() { + // expected-error@+1 {{non-templated function cannot have a requires clause}} + void bad() requires(sizeof(T) > 1); + // expected-error@+1 {{function definition is not allowed here}} + void still_bad() requires(sizeof(T) > 1) {} + +} + +void NonTemplContainingFunction() { + // expected-error@+1 {{non-templated function cannot have a requires clause}} + (void)[]() requires (sizeof(int)>1){}; + // OK, a template. + auto X = [](auto) requires (sizeof(int)>1){}; + // OK, a template. + auto Y = []<typename T>(T t) requires (sizeof(int)>1){}; + + X(1); + Y(1); +} +} Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -1380,6 +1380,38 @@ PushOnScopeChains(P, CurScope); } + // C++20: dcl.decl.general p4: + // The optional requires-clause ([temp.pre]) in an init-declarator or + // member-declarator shall be present only if the declarator declares a + // templated function ([dcl.fct]). + if (Expr *TRC = Method->getTrailingRequiresClause()) { + // [temp.pre]/8: + // An entity is templated if it is + // - a template, + // - an entity defined ([basic.def]) or created ([class.temporary]) in a + // templated entity, + // - a member of a templated entity, + // - an enumerator for an enumeration that is a templated entity, or + // - the closure type of a lambda-expression ([expr.prim.lambda.closure]) + // appearing in the declaration of a templated entity. [Note 6: A local + // class, a local or block variable, or a friend function defined in a + // templated entity is a templated entity. â end note] + // + // A templated function is a function template or a function that is + // templated. A templated class is a class template or a class that is + // templated. A templated variable is a variable template or a variable + // that is templated. + + // Note: we only have to check if this is defined in a template entity, OR + // if we are a template, since the rest don't apply. The requires clause + // applies to the call operator, which we already know is a member function, + // AND defined. + if (!Method->getDescribedFunctionTemplate() && + !Method->isTemplated()) { + Diag(TRC->getBeginLoc(), diag::err_constrained_non_templated_function); + } + } + // Enter a new evaluation context to insulate the lambda from any // cleanups from the enclosing full-expression. PushExpressionEvaluationContext( Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -11876,8 +11876,33 @@ // member-declarator shall be present only if the declarator declares a // templated function ([dcl.fct]). if (Expr *TRC = NewFD->getTrailingRequiresClause()) { - if (!NewFD->isTemplated() && !NewFD->isTemplateInstantiation()) + // [temp.pre]/8: + // An entity is templated if it is + // - a template, + // - an entity defined ([basic.def]) or created ([class.temporary]) in a + // templated entity, + // - a member of a templated entity, + // - an enumerator for an enumeration that is a templated entity, or + // - the closure type of a lambda-expression ([expr.prim.lambda.closure]) + // appearing in the declaration of a templated entity. [Note 6: A local + // class, a local or block variable, or a friend function defined in a + // templated entity is a templated entity. â end note] + // + // A templated function is a function template or a function that is + // templated. A templated class is a class template or a class that is + // templated. A templated variable is a variable template or a variable + // that is templated. + + if (!NewFD->getDescribedFunctionTemplate() && // -a template + // defined... in a templated entity + !(DeclIsDefn && NewFD->isTemplated()) && + // a member of a templated entity + !(isa<CXXMethodDecl>(NewFD) && NewFD->isTemplated()) && + // Don't complain about instantiations, they've already had these + // rules + others enforced. + !NewFD->isTemplateInstantiation()) { Diag(TRC->getBeginLoc(), diag::err_constrained_non_templated_function); + } } if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD)) Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -248,7 +248,11 @@ - Fix false-positive diagnostic issued for consteval initializers of temporary objects. (`#60286 <https://github.com/llvm/llvm-project/issues/60286>`_) - +- Correct restriction of trailing requirements clauses on a templated function. + Previously we only rejected non-'templated' things, but the restrictions ALSO need + to limit non-defined/non-member functions as well. Additionally, we now diagnose + requires on lambdas when not allowed, which we previously missed. + (`#61748 <https://github.com/llvm/llvm-project/issues/61748>`_) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits