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/7] 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/7] 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/7] 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/7] 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/7] 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/7] 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/7] 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; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
