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

>From 932906f313bd0760fe1a0c4b52a9f0adc8479068 Mon Sep 17 00:00:00 2001
From: StefanPaulet <[email protected]>
Date: Sun, 19 Apr 2026 14:13:52 +0300
Subject: [PATCH 1/8] Improved diagnostics for explicit
 specialization/instantiation of a lambda member

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 ++-
 clang/lib/Sema/SemaDecl.cpp                   |  8 ++++--
 clang/lib/Sema/SemaTemplate.cpp               | 12 +++++++-
 clang/test/CXX/drs/cwg17xx.cpp                | 28 +++++++++++++------
 clang/test/SemaCXX/lambda-expressions.cpp     | 11 +++++---
 5 files changed, 45 insertions(+), 18 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 193758221c0a9..a94a3552cde88 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8949,7 +8949,9 @@ let CategoryName = "Lambda Issue" in {
     "generic lambdas are incompatible with C++11">,
     InGroup<CXXPre14Compat>, DefaultIgnore;
   def err_lambda_explicit_spec : Error<
-    "lambda call operator should not be explicitly specialized or 
instantiated">;
+    "a member of a lambda should not be explicitly specialized">;
+  def err_lambda_explicit_inst : Error<
+    "a member of a lambda should not be explicitly instantiated">;
 
   // C++17 '*this' captures.
   def warn_cxx14_compat_star_this_lambda_capture : Warning<
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 6afdd73328eba..033c7fddc47d6 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16331,10 +16331,12 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope 
*FnBodyScope, Decl *D,
   // have the LSI properly restored.
   if (isGenericLambdaCallOperatorSpecialization(FD)) {
     // C++2c 7.5.5.2p17 A member of a closure type shall not be explicitly
-    // instantiated, explicitly specialized.
-    if (FD->getTemplateSpecializationInfo()
-            ->isExplicitInstantiationOrSpecialization()) {
+    // specialized.
+    if (FD->getTemplateSpecializationInfo()->isExplicitSpecialization()) {
       Diag(FD->getLocation(), diag::err_lambda_explicit_spec);
+      CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getParent());
+      Diag(RD->getLocation(), diag::note_defined_here) << RD;
+
       FD->setInvalidDecl();
       PushFunctionScope();
     } else {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 16b4815be2010..d150619fb290f 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -11052,8 +11052,18 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
     // Let the ASTConsumer know that this function has been explicitly
     // instantiated now, and its linkage might have changed.
     Consumer.HandleTopLevelDecl(DeclGroupRef(Specialization));
-  } else if (TSK == TSK_ExplicitInstantiationDefinition)
+  } else if (TSK == TSK_ExplicitInstantiationDefinition) {
+    // C++2c [expr.prim.lambda#closure-19] A member of a closure type shall not
+    // be explicitly instantiated.
+    if (CXXRecordDecl *RD =
+            dyn_cast<CXXRecordDecl>(Specialization->getParent());
+        RD && RD->isLambda()) {
+      Diag(D.getBeginLoc(), diag::err_lambda_explicit_inst);
+      Diag(RD->getLocation(), diag::note_defined_here) << RD;
+      return (Decl *)nullptr;
+    }
     InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization);
+  }
 
   // C++0x [temp.explicit]p2:
   //   If the explicit instantiation is for a member function, a member class
diff --git a/clang/test/CXX/drs/cwg17xx.cpp b/clang/test/CXX/drs/cwg17xx.cpp
index d2ea5b6f2ae52..0d0ccbcf0bc6a 100644
--- a/clang/test/CXX/drs/cwg17xx.cpp
+++ b/clang/test/CXX/drs/cwg17xx.cpp
@@ -226,28 +226,38 @@ using Bind = Instantiate<Internal<Template>::template 
Bind, Argument>;
 namespace cwg1780 { // cwg1780: 23
 #if __cplusplus >= 201103L
 
+#if __cplusplus >= 201703L
+#define CONSTEXPR constexpr
+#elif __cplusplus >= 201103L
+#define CONSTEXPR
+#endif
+
 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
+    friend CONSTEXPR auto L::operator()() const -> int;
+    // since-cxx11-error@-1{{a member of a lambda should not be the target of 
a friend declaration}}
 };
 
+#undef CONSTEXPR
+
 #if __cplusplus >= 201402L
-auto gl = [](auto a) { return 5; };
+auto gl = [](auto a) { return 5; }; // #cwg1780-spec
 using GL = decltype(gl);
 
 template <>
-auto GL::operator()(int a) const { // expected-error{{lambda call operator 
should not be explicitly specialized or instantiated}}
+auto GL::operator()(int a) const {
+// since-cxx11-error@-1{{a member of a lambda should not be explicitly 
specialized}}
+//   since-cxx11-note-re@#cwg1780-spec{{{{'\(lambda at .+\)'}} defined here}}
     return 6;
 }
 
-auto gll = [](auto a) { return 5; }; // expected-error{{lambda call operator 
should not be explicitly specialized or instantiated}}
+auto gll = [](auto a) -> int { return 5; }; // #cwg1780-inst
+
 using GLL = decltype(gll);
-template auto GLL::operator()<int>(int a) const; // expected-note{{in 
instantiation of function template specialization 
'cwg1780::(lambda)::operator()<int>' requested here}}
+template auto GLL::operator()<int>(int a) const -> int;
+// since-cxx11-error@-1{{a member of a lambda should not be explicitly 
instantiated}}
+//   since-cxx11-note-re@#cwg1780-inst{{{{'\(lambda at .+\)'}} defined here}}
 #endif
 
 #endif
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp 
b/clang/test/SemaCXX/lambda-expressions.cpp
index 6ae7ac9888b41..25cc2e14c1897 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -788,18 +788,21 @@ void GH67492() {
 // FIXME: This currently causes clang to crash in C++11 mode.
 #if __cplusplus >= 201402L
 namespace GH83267 {
-auto l = [](auto a) { return 1; };
+auto l = [](auto a) { return 1; }; // expected-note {{defined here}}
 using type = decltype(l);
 
 template<>
-auto type::operator()(int a) const { // expected-error{{lambda call operator 
should not be explicitly specialized or instantiated}}
+auto type::operator()(int a) const { // expected-error {{a member of a lambda 
should not be explicitly specialized}}
   return c; // expected-error {{use of undeclared identifier 'c'}}
 }
 
-auto ll = [](auto a) { return 1; }; // expected-error{{lambda call operator 
should not be explicitly specialized or instantiated}}
+auto ll = [](auto a) -> int { return 1; }; // expected-note 2 {{defined here}}
 using t = decltype(ll);
-template auto t::operator()<int>(int a) const; // expected-note {{in 
instantiation}}
+template auto t::operator()<int>(int a) const -> int; // expected-error {{a 
member of a lambda should not be explicitly instantiated}}
 
+template <typename T>
+using cll = int(*)(T);
+template t::operator cll<int>() const; // expected-error {{a member of a 
lambda should not be explicitly instantiated}}
 }
 #endif
 

>From b17ff6f869190998ab02736c581c4dcbc1a28a1a Mon Sep 17 00:00:00 2001
From: StefanPaulet <[email protected]>
Date: Tue, 21 Apr 2026 16:40:28 +0300
Subject: [PATCH 2/8] Merged diagnostics using %select

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 ++----
 clang/lib/Sema/SemaDecl.cpp                      | 3 ++-
 clang/lib/Sema/SemaTemplate.cpp                  | 3 ++-
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a94a3552cde88..8dfac0a614614 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8948,10 +8948,8 @@ let CategoryName = "Lambda Issue" in {
   def warn_cxx11_compat_generic_lambda : Warning<
     "generic lambdas are incompatible with C++11">,
     InGroup<CXXPre14Compat>, DefaultIgnore;
-  def err_lambda_explicit_spec : Error<
-    "a member of a lambda should not be explicitly specialized">;
-  def err_lambda_explicit_inst : Error<
-    "a member of a lambda should not be explicitly instantiated">;
+  def err_lambda_explicit_temp_spec : Error<
+    "a member of a lambda should not be explicitly 
%select{specialized|instantiated}0">;
 
   // C++17 '*this' captures.
   def warn_cxx14_compat_star_this_lambda_capture : Warning<
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 033c7fddc47d6..c4e11a87f4a2a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16333,7 +16333,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, 
Decl *D,
     // C++2c 7.5.5.2p17 A member of a closure type shall not be explicitly
     // specialized.
     if (FD->getTemplateSpecializationInfo()->isExplicitSpecialization()) {
-      Diag(FD->getLocation(), diag::err_lambda_explicit_spec);
+      Diag(FD->getLocation(), diag::err_lambda_explicit_temp_spec)
+          << 0 /*specialization*/;
       CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getParent());
       Diag(RD->getLocation(), diag::note_defined_here) << RD;
 
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index d150619fb290f..261145fab60e4 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -11058,7 +11058,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
     if (CXXRecordDecl *RD =
             dyn_cast<CXXRecordDecl>(Specialization->getParent());
         RD && RD->isLambda()) {
-      Diag(D.getBeginLoc(), diag::err_lambda_explicit_inst);
+      Diag(D.getBeginLoc(), diag::err_lambda_explicit_temp_spec)
+          << 1 /*instantiation*/;
       Diag(RD->getLocation(), diag::note_defined_here) << RD;
       return (Decl *)nullptr;
     }

>From 8bcfb17c707250dd1ef68d76eac94271b5809e0a Mon Sep 17 00:00:00 2001
From: StefanPaulet <[email protected]>
Date: Wed, 22 Apr 2026 17:21:00 +0300
Subject: [PATCH 3/8] Apply suggestions from code review

Co-authored-by: Vlad Serebrennikov <[email protected]>
---
 clang/test/CXX/drs/cwg17xx.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/test/CXX/drs/cwg17xx.cpp b/clang/test/CXX/drs/cwg17xx.cpp
index 0d0ccbcf0bc6a..53d8e664f642b 100644
--- a/clang/test/CXX/drs/cwg17xx.cpp
+++ b/clang/test/CXX/drs/cwg17xx.cpp
@@ -236,7 +236,7 @@ auto l = []() -> int { return 5; };
 using L = decltype(l);
 class A {
     friend CONSTEXPR auto L::operator()() const -> int;
-    // since-cxx11-error@-1{{a member of a lambda should not be the target of 
a friend declaration}}
+    // since-cxx11-error@-1 {{a member of a lambda should not be the target of 
a friend declaration}}
 };
 
 #undef CONSTEXPR
@@ -247,7 +247,7 @@ using GL = decltype(gl);
 
 template <>
 auto GL::operator()(int a) const {
-// since-cxx11-error@-1{{a member of a lambda should not be explicitly 
specialized}}
+// since-cxx11-error@-1 {{a member of a lambda should not be explicitly 
specialized}}
 //   since-cxx11-note-re@#cwg1780-spec{{{{'\(lambda at .+\)'}} defined here}}
     return 6;
 }
@@ -256,8 +256,8 @@ auto gll = [](auto a) -> int { return 5; }; // #cwg1780-inst
 
 using GLL = decltype(gll);
 template auto GLL::operator()<int>(int a) const -> int;
-// since-cxx11-error@-1{{a member of a lambda should not be explicitly 
instantiated}}
-//   since-cxx11-note-re@#cwg1780-inst{{{{'\(lambda at .+\)'}} defined here}}
+// since-cxx11-error@-1 {{a member of a lambda should not be explicitly 
instantiated}}
+//   since-cxx11-note-re@#cwg1780-inst {{{{'\(lambda at .+\)'}} defined here}}
 #endif
 
 #endif

>From 1cc4eaeedd6ee1bfce67b5f148652e40b9bf7519 Mon Sep 17 00:00:00 2001
From: StefanPaulet <[email protected]>
Date: Wed, 22 Apr 2026 17:21:57 +0300
Subject: [PATCH 4/8] Apply suggestions from code review

Co-authored-by: Vlad Serebrennikov <[email protected]>
---
 clang/test/CXX/drs/cwg17xx.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CXX/drs/cwg17xx.cpp b/clang/test/CXX/drs/cwg17xx.cpp
index 53d8e664f642b..7466c0cfb6048 100644
--- a/clang/test/CXX/drs/cwg17xx.cpp
+++ b/clang/test/CXX/drs/cwg17xx.cpp
@@ -248,7 +248,7 @@ using GL = decltype(gl);
 template <>
 auto GL::operator()(int a) const {
 // since-cxx11-error@-1 {{a member of a lambda should not be explicitly 
specialized}}
-//   since-cxx11-note-re@#cwg1780-spec{{{{'\(lambda at .+\)'}} defined here}}
+//   since-cxx11-note-re@#cwg1780-spec {{{{'\(lambda at .+\)'}} defined here}}
     return 6;
 }
 

>From e0d38cf9955fed9714ebbeaec7bb491bc28d267c Mon Sep 17 00:00:00 2001
From: StefanPaulet <[email protected]>
Date: Wed, 22 Apr 2026 17:31:09 +0300
Subject: [PATCH 5/8] Addressed recommendations from review

---
 clang/lib/Sema/SemaDecl.cpp               | 2 +-
 clang/lib/Sema/SemaTemplate.cpp           | 2 +-
 clang/test/SemaCXX/lambda-expressions.cpp | 7 +++++--
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index c4e11a87f4a2a..2563a59cde811 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16334,7 +16334,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, 
Decl *D,
     // specialized.
     if (FD->getTemplateSpecializationInfo()->isExplicitSpecialization()) {
       Diag(FD->getLocation(), diag::err_lambda_explicit_temp_spec)
-          << 0 /*specialization*/;
+          << /*specialization*/ 0;
       CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getParent());
       Diag(RD->getLocation(), diag::note_defined_here) << RD;
 
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 261145fab60e4..45a44796a486d 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -11059,7 +11059,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
             dyn_cast<CXXRecordDecl>(Specialization->getParent());
         RD && RD->isLambda()) {
       Diag(D.getBeginLoc(), diag::err_lambda_explicit_temp_spec)
-          << 1 /*instantiation*/;
+          << /*instantiation*/ 1;
       Diag(RD->getLocation(), diag::note_defined_here) << RD;
       return (Decl *)nullptr;
     }
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp 
b/clang/test/SemaCXX/lambda-expressions.cpp
index 25cc2e14c1897..1b96005f8d442 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -788,21 +788,24 @@ void GH67492() {
 // FIXME: This currently causes clang to crash in C++11 mode.
 #if __cplusplus >= 201402L
 namespace GH83267 {
-auto l = [](auto a) { return 1; }; // expected-note {{defined here}}
+auto l = [](auto a) { return 1; }; // #l-gh83267
 using type = decltype(l);
 
 template<>
 auto type::operator()(int a) const { // expected-error {{a member of a lambda 
should not be explicitly specialized}}
+                                     //   expected-note@#l-gh83267 {{defined 
here}}
   return c; // expected-error {{use of undeclared identifier 'c'}}
 }
 
-auto ll = [](auto a) -> int { return 1; }; // expected-note 2 {{defined here}}
+auto ll = [](auto a) -> int { return 1; }; // #ll-gh83267
 using t = decltype(ll);
 template auto t::operator()<int>(int a) const -> int; // expected-error {{a 
member of a lambda should not be explicitly instantiated}}
+                                                      //   
expected-note@#ll-gh83267 {{defined here}}
 
 template <typename T>
 using cll = int(*)(T);
 template t::operator cll<int>() const; // expected-error {{a member of a 
lambda should not be explicitly instantiated}}
+                                       //   expected-note@#ll-gh83267 
{{defined here}}
 }
 #endif
 

>From fc18fdc053a3de866874cb60cb05503ea2baac31 Mon Sep 17 00:00:00 2001
From: StefanPaulet <[email protected]>
Date: Sat, 25 Apr 2026 13:19:30 +0300
Subject: [PATCH 6/8] Added release note for implementing cwg1780

---
 clang/docs/ReleaseNotes.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 638a813ca105b..25ef5d672792a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -146,6 +146,8 @@ C++17 Feature Support
 
 Resolutions to C++ Defect Reports
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Implemented `CWG1780 Explicit instantiation/specialization of generic lambda
+  operator() <https://cplusplus.github.io/CWG/issues/1780.html>`_
 
 C Language Changes
 ------------------

>From 7ce3f60d335cc027968452c86c5c40f0d5e32372 Mon Sep 17 00:00:00 2001
From: StefanPaulet <[email protected]>
Date: Thu, 30 Apr 2026 22:19:34 +0300
Subject: [PATCH 7/8] Addressed requests from review

---
 clang/lib/Sema/SemaDecl.cpp     | 2 +-
 clang/lib/Sema/SemaTemplate.cpp | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 2563a59cde811..c076469d4881d 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16335,7 +16335,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, 
Decl *D,
     if (FD->getTemplateSpecializationInfo()->isExplicitSpecialization()) {
       Diag(FD->getLocation(), diag::err_lambda_explicit_temp_spec)
           << /*specialization*/ 0;
-      CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getParent());
+      CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getParent());
       Diag(RD->getLocation(), diag::note_defined_here) << RD;
 
       FD->setInvalidDecl();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 45a44796a486d..1cdd5ae1f98fe 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -11055,8 +11055,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
   } else if (TSK == TSK_ExplicitInstantiationDefinition) {
     // C++2c [expr.prim.lambda#closure-19] A member of a closure type shall not
     // be explicitly instantiated.
-    if (CXXRecordDecl *RD =
-            dyn_cast<CXXRecordDecl>(Specialization->getParent());
+    if (const auto *RD = dyn_cast<CXXRecordDecl>(Specialization->getParent());
         RD && RD->isLambda()) {
       Diag(D.getBeginLoc(), diag::err_lambda_explicit_temp_spec)
           << /*instantiation*/ 1;

>From 7c8a684c86c925ce539ca0fb8f0f6692ca95a9bc Mon Sep 17 00:00:00 2001
From: StefanPaulet <[email protected]>
Date: Fri, 8 May 2026 16:05:06 +0300
Subject: [PATCH 8/8] Fixed c++ draft reference

---
 clang/lib/Sema/SemaTemplate.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1cdd5ae1f98fe..7ce80472f90fd 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -11053,7 +11053,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
     // instantiated now, and its linkage might have changed.
     Consumer.HandleTopLevelDecl(DeclGroupRef(Specialization));
   } else if (TSK == TSK_ExplicitInstantiationDefinition) {
-    // C++2c [expr.prim.lambda#closure-19] A member of a closure type shall not
+    // C++2c [expr.prim.lambda.closure]/19 A member of a closure type shall not
     // be explicitly instantiated.
     if (const auto *RD = dyn_cast<CXXRecordDecl>(Specialization->getParent());
         RD && RD->isLambda()) {

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

Reply via email to