[clang] fb04e8f - [clang] Improved diagnostics for explicit specialization/instantiation of closure type members (#192843)
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 8 07:12:02 PDT 2026
Author: StefanPaulet
Date: 2026-05-08T18:11:57+04:00
New Revision: fb04e8fbb5db10d3dedffbafa86d2b24234123cf
URL: https://github.com/llvm/llvm-project/commit/fb04e8fbb5db10d3dedffbafa86d2b24234123cf
DIFF: https://github.com/llvm/llvm-project/commit/fb04e8fbb5db10d3dedffbafa86d2b24234123cf.diff
LOG: [clang] Improved diagnostics for explicit specialization/instantiation of closure type members (#192843)
Follow-up from #191419:
- Added separate diagnostics for explicit instantiation and explicit
specialization of a closure type member.
- Diagnostic for explicit instantiation is now issued at the point of
instantiation and not at the lambda declaration.
- Added note with `defined here` pointing to lambda declaration for both
diagnostics.
---------
Co-authored-by: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/test/CXX/drs/cwg17xx.cpp
clang/test/SemaCXX/lambda-expressions.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d700af6a82290..700fbe4304141 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -165,6 +165,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>`_
- Clang now allows omitting ``typename`` before a template name in a
conversion operator, implementing `CWG2413 <https://wg21.link/cwg2413>`_.
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c15a9ec1ff0f6..9605c02b819d4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8951,8 +8951,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<
- "lambda call operator should not be explicitly specialized or 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 eb5b6d65b4d58..7c5bcd56b346c 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16318,10 +16318,13 @@ 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()) {
- Diag(FD->getLocation(), diag::err_lambda_explicit_spec);
+ // specialized.
+ if (FD->getTemplateSpecializationInfo()->isExplicitSpecialization()) {
+ Diag(FD->getLocation(), diag::err_lambda_explicit_temp_spec)
+ << /*specialization*/ 0;
+ CXXRecordDecl *RD = 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 8c6ae204d6d19..174f42caac506 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -11138,8 +11138,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 (const auto *RD = dyn_cast<CXXRecordDecl>(Specialization->getParent());
+ RD && RD->isLambda()) {
+ Diag(D.getBeginLoc(), diag::err_lambda_explicit_temp_spec)
+ << /*instantiation*/ 1;
+ 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..7466c0cfb6048 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 at -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 at -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 at -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..1b96005f8d442 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -788,18 +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; };
+auto l = [](auto a) { return 1; }; // #l-gh83267
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}}
+ // expected-note@#l-gh83267 {{defined here}}
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; }; // #ll-gh83267
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}}
+ // 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
More information about the cfe-commits
mailing list