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

Reply via email to