https://github.com/offsetof updated 
https://github.com/llvm/llvm-project/pull/133822

>From b5798e04281fb6d9475a1ae6af8b94bc0ed85a43 Mon Sep 17 00:00:00 2001
From: offsetof <offse...@mailo.com>
Date: Mon, 31 Mar 2025 23:17:47 +0000
Subject: [PATCH 1/2] [clang] Check `std::initializer_list` more strictly

Require `std::initializer_list` to be a class template with a
template-head equivalent to `template<class>` and no default arguments.
---
 .../clang/Basic/DiagnosticSemaKinds.td        | 10 ++-
 clang/lib/Sema/SemaDeclCXX.cpp                | 49 +++++++++---
 .../SemaCXX/invalid-std-initializer-list.cpp  | 77 +++++++++++++++++++
 3 files changed, 124 insertions(+), 12 deletions(-)
 create mode 100644 clang/test/SemaCXX/invalid-std-initializer-list.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5e45482584946..4476751f9952a 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2590,8 +2590,14 @@ def err_auto_non_deduced_not_alone : Error<
 def err_implied_std_initializer_list_not_found : Error<
   "cannot deduce type of initializer list because std::initializer_list was "
   "not found; include <initializer_list>">;
-def err_malformed_std_initializer_list : Error<
-  "std::initializer_list must be a class template with a single type 
parameter">;
+def err_malformed_std_initializer_list
+    : Error<"std::initializer_list %select{"
+            "must have exactly one template parameter|"
+            "cannot have associated constraints|"
+            "must have a type template parameter|"
+            "cannot have default template arguments|"
+            "cannot be a variadic template|"
+            "must be a class template}0">;
 def err_auto_init_list_from_c : Error<
   "cannot use %select{'auto'|<ERROR>|'__auto_type'}0 with "
   "%select{initializer list|array}1 in C">;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 676d53a1f4b45..77f8b6e36fcb3 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -12071,6 +12071,37 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() {
   return getStdNamespace();
 }
 
+/// Check that the template-head of this class template is acceptable for
+/// a declaration of 'std::initializer_list', and optionally diagnose if
+/// it is not.
+/// \returns true if any issues were found.
+static bool CheckStdInitializerList(Sema &S, ClassTemplateDecl *Template,
+                                    bool Diagnose) {
+  TemplateParameterList *Params = Template->getTemplateParameters();
+  int ErrorKind = -1;
+
+  if (Params->size() != 1)
+    ErrorKind = 0; // must have exactly one template parameter
+  else if (Template->hasAssociatedConstraints())
+    ErrorKind = 1; // cannot have associated constraints
+  else {
+    auto *Param = dyn_cast<TemplateTypeParmDecl>(Params->getParam(0));
+    if (!Param)
+      ErrorKind = 2; // must have a type template parameter
+    else if (Param->hasDefaultArgument())
+      ErrorKind = 3; // cannot have default template arguments
+    else if (Param->isTemplateParameterPack())
+      ErrorKind = 4; // cannot be a variadic template
+    else
+      return false;
+  }
+
+  if (Diagnose)
+    S.Diag(Template->getLocation(), diag::err_malformed_std_initializer_list)
+        << Params->getSourceRange() << ErrorKind;
+  return true;
+}
+
 bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
   assert(getLangOpts().CPlusPlus &&
          "Looking for std::initializer_list outside of C++.");
@@ -12118,10 +12149,7 @@ bool Sema::isStdInitializerList(QualType Ty, QualType 
*Element) {
       return false;
     // This is a template called std::initializer_list, but is it the right
     // template?
-    TemplateParameterList *Params = Template->getTemplateParameters();
-    if (Params->getMinRequiredArguments() != 1)
-      return false;
-    if (!isa<TemplateTypeParmDecl>(Params->getParam(0)))
+    if (CheckStdInitializerList(*this, Template, /*Diagnose=*/false))
       return false;
 
     // It's the right template.
@@ -12137,7 +12165,8 @@ bool Sema::isStdInitializerList(QualType Ty, QualType 
*Element) {
   return true;
 }
 
-static ClassTemplateDecl *LookupStdInitializerList(Sema &S, SourceLocation 
Loc){
+static ClassTemplateDecl *LookupStdInitializerList(Sema &S,
+                                                   SourceLocation Loc) {
   NamespaceDecl *Std = S.getStdNamespace();
   if (!Std) {
     S.Diag(Loc, diag::err_implied_std_initializer_list_not_found);
@@ -12155,16 +12184,16 @@ static ClassTemplateDecl 
*LookupStdInitializerList(Sema &S, SourceLocation Loc){
     Result.suppressDiagnostics();
     // We found something weird. Complain about the first thing we found.
     NamedDecl *Found = *Result.begin();
-    S.Diag(Found->getLocation(), diag::err_malformed_std_initializer_list);
+    S.Diag(Found->getLocation(), diag::err_malformed_std_initializer_list)
+        << 5 /* must be a class template */;
+    S.Diag(Loc, diag::note_used_here);
     return nullptr;
   }
 
   // We found some template called std::initializer_list. Now verify that it's
   // correct.
-  TemplateParameterList *Params = Template->getTemplateParameters();
-  if (Params->getMinRequiredArguments() != 1 ||
-      !isa<TemplateTypeParmDecl>(Params->getParam(0))) {
-    S.Diag(Template->getLocation(), diag::err_malformed_std_initializer_list);
+  if (CheckStdInitializerList(S, Template, /*Diagnose=*/true)) {
+    S.Diag(Loc, diag::note_used_here);
     return nullptr;
   }
 
diff --git a/clang/test/SemaCXX/invalid-std-initializer-list.cpp 
b/clang/test/SemaCXX/invalid-std-initializer-list.cpp
new file mode 100644
index 0000000000000..339accefbb6d1
--- /dev/null
+++ b/clang/test/SemaCXX/invalid-std-initializer-list.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 %s -verify=expected,type-param -std=c++23 -DTYPE_PARAM
+// RUN: %clang_cc1 %s -verify=expected,others -std=c++23 -DCONSTANT_PARAM
+// RUN: %clang_cc1 %s -verify=expected,others -std=c++23 -DTYPE_TEMPLATE_PARAM
+// RUN: %clang_cc1 %s -verify=expected,others -std=c++23 -DDEFAULT_ARG
+// RUN: %clang_cc1 %s -verify=expected,others -std=c++23 -DMULTIPLE_PARAMS
+// RUN: %clang_cc1 %s -verify=expected,others -std=c++23 -DPARAM_PACK
+// RUN: %clang_cc1 %s -verify=expected,others -std=c++23 -DCONSTRAINED_PARAM
+// RUN: %clang_cc1 %s -verify=expected,others -std=c++23 -DREQUIRES_CLAUSE
+// RUN: %clang_cc1 %s -verify=expected,others -std=c++23 -DNONCLASS_TEMPLATE
+// RUN: %clang_cc1 %s -verify=expected,others -std=c++23 -DNONTEMPLATE
+
+namespace std {
+
+#ifdef TYPE_PARAM
+template<class> class initializer_list;
+// expected-note@-1 2 {{template is declared here}}
+#elifdef CONSTANT_PARAM
+template<int> class initializer_list;
+// expected-error@-1 2 {{std::initializer_list must have a type template 
parameter}}
+#elifdef TYPE_TEMPLATE_PARAM
+template<template<class> class> class initializer_list;
+// expected-error@-1 2 {{std::initializer_list must have a type template 
parameter}}
+#elifdef DEFAULT_ARG
+template<class = int> class initializer_list;
+// expected-error@-1 2 {{std::initializer_list cannot have default template 
arguments}}
+#elifdef MULTIPLE_PARAMS
+template<class, class> class initializer_list;
+// expected-error@-1 2 {{std::initializer_list must have exactly one template 
parameter}}
+#elifdef PARAM_PACK
+template<class...> class initializer_list;
+// expected-error@-1 2 {{std::initializer_list cannot be a variadic template}}
+#elifdef CONSTRAINED_PARAM
+template<class> concept C = true;
+template<C> class initializer_list;
+// expected-error@-1 2 {{std::initializer_list cannot have associated 
constraints}}
+#elifdef REQUIRES_CLAUSE
+template<class> requires true class initializer_list;
+// expected-error@-1 2 {{std::initializer_list cannot have associated 
constraints}}
+#elifdef NONCLASS_TEMPLATE
+template<class> class IL;
+template<class T> using initializer_list = IL<T>;
+// expected-error@-1 2 {{std::initializer_list must be a class template}}
+#elifdef NONTEMPLATE
+class initializer_list;
+// expected-error@-1 2 {{std::initializer_list must be a class template}}
+#else
+#error Unexpected test kind
+#endif
+
+}
+
+struct Test { // expected-note 2 {{candidate constructor}}
+#ifdef CONSTANT_PARAM
+    Test(std::initializer_list<1>); // expected-note {{candidate constructor}}
+#elifdef TYPE_TEMPLATE_PARAM
+    template<class> using A = double;
+    Test(std::initializer_list<A>); // expected-note {{candidate constructor}}
+#elifdef MULTIPLE_PARAMS
+    Test(std::initializer_list<double, double>); // expected-note {{candidate 
constructor}}
+#elifdef NONTEMPLATE
+    Test(std::initializer_list); // expected-note {{candidate constructor}}
+#else
+    Test(std::initializer_list<double>); // expected-note {{candidate 
constructor}}
+#endif
+};
+Test test {1.2, 3.4}; // expected-error {{no matching constructor}}
+
+auto x = {1};
+// type-param-error@-1 {{implicit instantiation of undefined template}}
+// others-note@-2 {{used here}}
+
+void f() {
+    for(int x : {1, 2});
+    // type-param-error@-1 {{implicit instantiation of undefined template}}
+    // type-param-error@-2 {{invalid range expression}}
+    // others-note@-3 {{used here}}
+}

>From 64690442bac8b05f0df03c94b22d70c429422db3 Mon Sep 17 00:00:00 2001
From: offsetof <offse...@mailo.com>
Date: Wed, 2 Apr 2025 14:37:35 +0000
Subject: [PATCH 2/2] fixup! [clang] Check `std::initializer_list` more
 strictly

---
 .../clang/Basic/DiagnosticSemaKinds.td        | 14 +++++++-------
 clang/lib/Sema/SemaDeclCXX.cpp                | 19 ++++++++++---------
 2 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4476751f9952a..575f13336e441 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2591,13 +2591,13 @@ def err_implied_std_initializer_list_not_found : Error<
   "cannot deduce type of initializer list because std::initializer_list was "
   "not found; include <initializer_list>">;
 def err_malformed_std_initializer_list
-    : Error<"std::initializer_list %select{"
-            "must have exactly one template parameter|"
-            "cannot have associated constraints|"
-            "must have a type template parameter|"
-            "cannot have default template arguments|"
-            "cannot be a variadic template|"
-            "must be a class template}0">;
+    : Error<"std::initializer_list %enum_select<MalformedStdInitializerList>{"
+            "%TooManyParams{must have exactly one template parameter}|"
+            "%Constrained{cannot have associated constraints}|"
+            "%BadParamKind{must have a type template parameter}|"
+            "%DefaultArg{cannot have default template arguments}|"
+            "%ParamPack{cannot be a variadic template}|"
+            "%BadEntityKind{must be a class template}}0">;
 def err_auto_init_list_from_c : Error<
   "cannot use %select{'auto'|<ERROR>|'__auto_type'}0 with "
   "%select{initializer list|array}1 in C">;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 77f8b6e36fcb3..e51512283ccac 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -27,6 +27,7 @@
 #include "clang/AST/TypeLoc.h"
 #include "clang/AST/TypeOrdering.h"
 #include "clang/Basic/AttributeCommonInfo.h"
+#include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Basic/TargetInfo.h"
@@ -12075,23 +12076,23 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() {
 /// a declaration of 'std::initializer_list', and optionally diagnose if
 /// it is not.
 /// \returns true if any issues were found.
-static bool CheckStdInitializerList(Sema &S, ClassTemplateDecl *Template,
+static bool CheckStdInitializerList(Sema &S, const ClassTemplateDecl *Template,
                                     bool Diagnose) {
-  TemplateParameterList *Params = Template->getTemplateParameters();
+  const TemplateParameterList *Params = Template->getTemplateParameters();
   int ErrorKind = -1;
 
   if (Params->size() != 1)
-    ErrorKind = 0; // must have exactly one template parameter
+    ErrorKind = diag::MalformedStdInitializerList::TooManyParams;
   else if (Template->hasAssociatedConstraints())
-    ErrorKind = 1; // cannot have associated constraints
+    ErrorKind = diag::MalformedStdInitializerList::Constrained;
   else {
-    auto *Param = dyn_cast<TemplateTypeParmDecl>(Params->getParam(0));
+    const auto *Param = dyn_cast<TemplateTypeParmDecl>(Params->getParam(0));
     if (!Param)
-      ErrorKind = 2; // must have a type template parameter
+      ErrorKind = diag::MalformedStdInitializerList::BadParamKind;
     else if (Param->hasDefaultArgument())
-      ErrorKind = 3; // cannot have default template arguments
+      ErrorKind = diag::MalformedStdInitializerList::DefaultArg;
     else if (Param->isTemplateParameterPack())
-      ErrorKind = 4; // cannot be a variadic template
+      ErrorKind = diag::MalformedStdInitializerList::ParamPack;
     else
       return false;
   }
@@ -12185,7 +12186,7 @@ static ClassTemplateDecl *LookupStdInitializerList(Sema 
&S,
     // We found something weird. Complain about the first thing we found.
     NamedDecl *Found = *Result.begin();
     S.Diag(Found->getLocation(), diag::err_malformed_std_initializer_list)
-        << 5 /* must be a class template */;
+        << diag::MalformedStdInitializerList::BadEntityKind;
     S.Diag(Loc, diag::note_used_here);
     return nullptr;
   }

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to