Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -248,7 +248,10 @@ - Fix false-positive diagnostic issued for consteval initializers of temporary objects. (`#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. + (`#61748 `_) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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(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(NewFD)) 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,23 @@ // expected-error@+1{{expected expression}} auto *p = new void(*)(char) requires true; + +namespace GH61748 { +template +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 +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) {} +} +}