https://github.com/StefanPaulet updated 
https://github.com/llvm/llvm-project/pull/191419

>From 3e8d8ddd869cb5e41e02f3c590c7e318de0d42dd Mon Sep 17 00:00:00 2001
From: StefanPaulet <[email protected]>
Date: Fri, 10 Apr 2026 16:04:51 +0300
Subject: [PATCH 1/2] Add diagnostic for friend declaration of lambda member

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +
 clang/lib/Sema/SemaDeclCXX.cpp                |  5 ++
 .../test/SemaCXX/cxx1z-constexpr-lambdas.cpp  |  4 +-
 clang/test/SemaCXX/lambda-expressions.cpp     | 58 ++++++++++++++++---
 clang/test/SemaTemplate/GH75426.cpp           |  3 +-
 clang/test/SemaTemplate/concepts.cpp          |  2 +-
 6 files changed, 61 insertions(+), 13 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6d2fae551566f..6563dc11e39f1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8907,6 +8907,8 @@ let CategoryName = "Lambda Issue" in {
     "capture of variable '%0' as type %1 calls %select{private|protected}3 "
     "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}2constructor">,
     AccessControl;
+  def err_friend_lambda_decl : Error<
+    "a member of a lambda should not be the target of a friend declaration">;
   def note_lambda_to_block_conv : Note<
     "implicit capture of lambda object due to conversion to block pointer "
     "here">;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index c1d3960e65ef6..ba1b4c4e5ef7e 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -18465,6 +18465,11 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, 
Declarator &D,
       Diag(Loc, diag::err_introducing_special_friend) << DiagArg;
       return nullptr;
     }
+  } else {
+    CXXRecordDecl *RC = dyn_cast<CXXRecordDecl>(DC);
+    if (RC->isLambda()) {
+      Diag(NameInfo.getBeginLoc(), diag::err_friend_lambda_decl);
+    }
   }
 
   // FIXME: This is an egregious hack to cope with cases where the scope stack
diff --git a/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp 
b/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
index aa8d055e44971..20922f2fdaa4f 100644
--- a/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
+++ b/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
@@ -57,8 +57,8 @@ struct test_never_constant {
   // expected-error@+3 {{non-constexpr declaration of 'operator()' follows 
constexpr declaration}}
   // expected-error@+3 {{non-constexpr declaration of 'operator()' follows 
constexpr declaration}}
   #endif
-  friend auto decltype(never_constant_1)::operator()() const;
-  friend int decltype(never_constant_2)::operator()() const;
+  friend auto decltype(never_constant_1)::operator()() const; // 
expected-error {{a member of a lambda should not be the target of a friend 
declaration}}
+  friend int decltype(never_constant_2)::operator()() const; // expected-error 
{{a member of a lambda should not be the target of a friend declaration}}
 };
 
 } // end ns test_constexpr_checking
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp 
b/clang/test/SemaCXX/lambda-expressions.cpp
index 00c52efb78a7d..6ae7ac9888b41 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -657,26 +657,29 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
 
   struct X {
 #if __cplusplus > 201402L
-    friend constexpr auto T::operator()(int) const;
-    friend constexpr T::operator ExpectedTypeT() const noexcept;
+    friend constexpr auto T::operator()(int) const; // expected-error {{a 
member of a lambda should not be the target of a friend declaration}}
+    friend constexpr T::operator ExpectedTypeT() const noexcept; // 
expected-error {{a member of a lambda should not be the target of a friend 
declaration}}
 
     template<typename T>
-      friend constexpr void U::operator()(T&) const;
+      friend constexpr void U::operator()(T&) const; // expected-error {{a 
member of a lambda should not be the target of a friend declaration}}
     // FIXME: This should not match; the return type is specified as behaving
     // "as if it were a decltype-specifier denoting the return type of
     // [operator()]", which is not equivalent to this alias template.
     template<typename T>
-      friend constexpr U::operator ExpectedTypeU<T>() const noexcept;
+      friend constexpr U::operator ExpectedTypeU<T>() const noexcept; // 
expected-error {{a member of a lambda should not be the target of a friend 
declaration}}
 #else
     friend auto T::operator()(int) const; // cxx11-error {{'auto' return 
without trailing return type; deduced return types are a C++14 extension}} \
-                                             cxx03-error {{'auto' not allowed 
in function return type}}
-    friend T::operator ExpectedTypeT() const;
+                                             cxx03-error {{'auto' not allowed 
in function return type}} \
+                                             expected-error {{a member of a 
lambda should not be the target of a friend declaration}}
+    friend T::operator ExpectedTypeT() const; // expected-error {{a member of 
a lambda should not be the target of a friend declaration}}
 
     template<typename T>
-      friend void U::operator()(T&) const; // cxx03-cxx11-error {{friend 
declaration of 'operator()' does not match any declaration}}
+      friend void U::operator()(T&) const; // cxx03-cxx11-error {{friend 
declaration of 'operator()' does not match any declaration}} \
+                                              expected-error {{a member of a 
lambda should not be the target of a friend declaration}}
     // FIXME: This should not match, as above.
     template<typename T>
-      friend U::operator ExpectedTypeU<T>() const; // cxx03-cxx11-error 
{{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not 
match any declaration}}
+      friend U::operator ExpectedTypeU<T>() const; // cxx03-cxx11-error 
{{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not 
match any declaration}} \
+                                                      expected-error {{a 
member of a lambda should not be the target of a friend declaration}}
 #endif
 
   private:
@@ -812,3 +815,42 @@ void test_lambda_return_type() {
   };
 }
 }
+
+namespace GH26540 {
+#if __cplusplus >= 201703L
+#define CONSTEXPR17 constexpr
+#define NOEXCEPT17 noexcept
+#else
+#define CONSTEXPR17
+#define NOEXCEPT17
+#endif
+    auto l = []() -> int {
+        return 5;
+    };
+    using L = decltype(l);
+    using ConvertL = int(*)();
+
+    class NonGenericLambdaFriend {
+        friend CONSTEXPR17 int L::operator()() const; // expected-error{{a 
member of a lambda should not be the target of a friend declaration}}
+        friend CONSTEXPR17 L::operator ConvertL() const NOEXCEPT17; // 
expected-error{{a member of a lambda should not be the target of a friend 
declaration}}
+    };
+
+#if __cplusplus > 201103L
+    auto gl = [](auto t) -> int {
+        return t.x;
+    };
+    using GL = decltype(gl);
+    template <typename T>
+    using ConvertGL = int(*)(T);
+
+    class GenericLambdaFriend {
+        int x{2};
+        template <typename T>
+        friend CONSTEXPR17 auto GL::operator()(T t) const -> int; // 
expected-error{{a member of a lambda should not be the target of a friend 
declaration}}
+        template <typename T>
+        friend CONSTEXPR17 GL::operator ConvertGL<T>() const NOEXCEPT17; // 
expected-error{{a member of a lambda should not be the target of a friend 
declaration}}
+    };
+#endif
+#undef NOEXCEPT17
+#undef CONSTEXPR17
+}
diff --git a/clang/test/SemaTemplate/GH75426.cpp 
b/clang/test/SemaTemplate/GH75426.cpp
index faf70699f9c5f..776db332358a8 100644
--- a/clang/test/SemaTemplate/GH75426.cpp
+++ b/clang/test/SemaTemplate/GH75426.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
-// expected-no-diagnostics
 
 template<typename T> concept C = true;
 
@@ -12,5 +11,5 @@ auto L = []<C T>{};
 template<typename X>
 class Friends {
     template<C T> friend void A::f();
-    template<C T> friend void decltype(L)::operator()();
+    template<C T> friend void decltype(L)::operator()(); // expected-error {{a 
member of a lambda should not be the target of a friend declaration}}
 };
diff --git a/clang/test/SemaTemplate/concepts.cpp 
b/clang/test/SemaTemplate/concepts.cpp
index ac80d16b4ccf8..b2faf13d53033 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -849,7 +849,7 @@ template<typename T, typename U> concept C = true;
 template<typename T> auto L = []<C<T> U>() {};
 
 struct Q {
-  template<C<int> U> friend constexpr auto decltype(L<int>)::operator()() 
const;
+  template<C<int> U> friend constexpr auto decltype(L<int>)::operator()() 
const; // expected-error {{a member of a lambda should not be the target of a 
friend declaration}}
 };
 
 template <class T>

>From 1eddfbf5f7c481b9418230e90f7e284aa676a049 Mon Sep 17 00:00:00 2001
From: StefanPaulet <[email protected]>
Date: Tue, 14 Apr 2026 16:43:50 +0300
Subject: [PATCH 2/2] Added release note; Added test in cwg and regenerated dr
 status html

---
 clang/docs/ReleaseNotes.rst    |  1 +
 clang/test/CXX/drs/cwg17xx.cpp | 16 ++++++++++++++++
 clang/www/cxx_dr_status.html   |  2 +-
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b2e62106506f0..99281237b4ada 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -408,6 +408,7 @@ Bug Fixes in This Version
 - Fixed incorrect rejection of ``auto`` with reordered declaration specifiers 
in C23. (#GH164121)
 - Fixed a crash where constexpr evaluation encountered invalid overrides. 
(#GH183290)
 - Fixed a crash when assigning to an element of an ``ext_vector_type`` with 
``bool`` element type. (#GH189260)
+- Clang now emits an error for friend declarations of lambda members. 
(#GH26540)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/test/CXX/drs/cwg17xx.cpp b/clang/test/CXX/drs/cwg17xx.cpp
index 46693eaa5a169..228182b12805e 100644
--- a/clang/test/CXX/drs/cwg17xx.cpp
+++ b/clang/test/CXX/drs/cwg17xx.cpp
@@ -222,3 +222,19 @@ template <template <typename> class Template, typename 
Argument>
 using Bind = Instantiate<Internal<Template>::template Bind, Argument>;
 #endif
 } // namespace cwg1794
+
+namespace cwg1780 { // cwg1780: 22
+#if __cplusplus >= 201103L
+
+auto l = []() -> int { return 5; };
+using L = decltype(l);
+class A {
+#if __cplusplus >= 201703L
+    friend constexpr auto L::operator()() const -> int; // expected-error{{a 
member of a lambda should not be the target of a friend declaration}}
+#else
+    friend auto L::operator()() const -> int; // expected-error{{a member of a 
lambda should not be the target of a friend declaration}}
+#endif
+};
+
+#endif
+} // namespace cwg1780
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index cb0236b46e580..864fe425867c7 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -12245,7 +12245,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
     <td>[<a 
href="https://wg21.link/expr.prim.lambda.closure";>expr.prim.lambda.closure</a>]</td>
     <td>CD4</td>
     <td>Explicit instantiation/specialization of generic lambda 
<TT>operator()</TT></td>
-    <td class="unknown" align="center">Unknown</td>
+    <td class="unreleased" align="center">Clang 22</td>
   </tr>
   <tr id="1781">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/1781.html";>1781</a></td>

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to