Skip to content

[Clang] [Sema] Diagnose unknown std::initializer_list layout in SemaInit #95580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 20, 2024

Conversation

MitalAshok
Copy link
Contributor

@MitalAshok MitalAshok commented Jun 14, 2024

This checks if the layout of std::initializer_list is something Clang can handle much earlier and deduplicates the checks in CodeGen/CGExprAgg.cpp and AST/ExprConstant.cpp

Also now diagnose union initializer_list (Fixes #95495), bit-field for the size (Fixes a crash that would happen during codegen if it were unnamed), base classes (that wouldn't be initialized) and polymorphic classes (whose vtable pointer wouldn't be initialized).

@llvmbot llvmbot added clang Clang issues not falling into any other category clang-tools-extra clangd clang-tidy clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang:codegen IR generation bugs: mangling, exceptions, etc. clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang:openmp OpenMP related changes to Clang labels Jun 14, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 14, 2024

@llvm/pr-subscribers-clang-tools-extra
@llvm/pr-subscribers-clangd
@llvm/pr-subscribers-clang-tidy
@llvm/pr-subscribers-clang-modules

@llvm/pr-subscribers-clang

Author: Mital Ashok (MitalAshok)

Changes

This checks if the layout of std::initializer_list is something Clang can handle much earlier and deduplicates the checks in CodeGen/CGExprAgg.cpp and AST/ExprConstant.cpp

Also now diagnose union initializer_list (Fixes #95495) and unnamed bit-field for the size (Fixes a crash that would happen during codegen)


Patch is 27.79 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/95580.diff

29 Files Affected:

  • (modified) clang-tools-extra/clangd/unittests/HoverTests.cpp (+1-1)
  • (modified) clang-tools-extra/clangd/unittests/InlayHintTests.cpp (+1-1)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp (+1)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace-ignore-implicit-constructors.cpp (+2-1)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace.cpp (+2-1)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation.cpp (+3-1)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp (+1-1)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3)
  • (modified) clang/lib/AST/ExprConstant.cpp (+20-31)
  • (modified) clang/lib/CodeGen/CGExprAgg.cpp (+18-26)
  • (modified) clang/lib/Sema/SemaInit.cpp (+51)
  • (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp (+1-1)
  • (modified) clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp (+1-3)
  • (modified) clang/test/CodeCompletion/ctor-signature.cpp (+1-1)
  • (modified) clang/test/Coverage/unresolved-ctor-expr.cpp (+1-1)
  • (modified) clang/test/Modules/Inputs/initializer_list/direct.h (+1-1)
  • (modified) clang/test/Modules/pr60775.cppm (+3-2)
  • (modified) clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp (+1-1)
  • (modified) clang/test/Preprocessor/macro_with_initializer_list.cpp (+1-1)
  • (modified) clang/test/SemaCXX/PR20334-std_initializer_list_diagnosis_assertion.cpp (+6-11)
  • (modified) clang/test/SemaCXX/auto-invalid-init-crash.cpp (+2-2)
  • (modified) clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp (+34-5)
  • (modified) clang/test/SemaCXX/cxx11-call-to-deleted-constructor.cpp (+1-1)
  • (modified) clang/test/SemaCXX/cxx98-compat.cpp (+4-4)
  • (modified) clang/test/SemaCXX/invalid-member-expr.cpp (+1-1)
  • (modified) clang/test/SemaTemplate/instantiate-init.cpp (+2-2)
  • (modified) clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp (+2-2)
  • (modified) clang/unittests/Analysis/FlowSensitive/TransferTest.cpp (+1-1)
  • (modified) clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp (+1)
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index d9e97e5215a26..8d6d4223d7260 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -2284,7 +2284,7 @@ TEST(Hover, All) {
             namespace std
             {
               template<class _E>
-              class initializer_list {};
+              class initializer_list { const _E *a, *b; };
             }
             void foo() {
               ^[[auto]] i = {1,2};
diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index 5b1531eb2fa60..a5a349e93037a 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -945,7 +945,7 @@ TEST(ParameterHints, ConstructorStdInitList) {
   // Do not show hints for std::initializer_list constructors.
   assertParameterHints(R"cpp(
     namespace std {
-      template <typename> class initializer_list {};
+      template <typename E> class initializer_list { const E *a, *b; };
     }
     struct S {
       S(std::initializer_list<int> param);
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp
index 1f2dad2b933ca..c7632fe007a4f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp
@@ -11,6 +11,7 @@ T max(T a, T b) {
 namespace std {
 template< class T >
 struct initializer_list {
+  const T *a, *b;
   initializer_list()=default;
   initializer_list(T*,int){}
   const T* begin() const {return nullptr;}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace-ignore-implicit-constructors.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace-ignore-implicit-constructors.cpp
index 2004993ebde51..150e3ac6494e3 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace-ignore-implicit-constructors.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace-ignore-implicit-constructors.cpp
@@ -4,10 +4,11 @@
 // RUN:                true}}"
 
 namespace std {
-template <typename>
+template <typename E>
 class initializer_list
 {
 public:
+  const E *a, *b;
   initializer_list() noexcept {}
 };
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace.cpp
index f7b1ad55f5df5..3f4a14cd9bb64 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace.cpp
@@ -8,9 +8,10 @@
 // RUN:                '::std::make_pair; ::std::make_tuple; ::test::MakeSingle'}}"
 
 namespace std {
-template <typename>
+template <typename E>
 class initializer_list {
 public:
+  const E *a, *b;
   initializer_list() noexcept {}
 };
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation.cpp
index c28592f4d6368..c295f48f89aed 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation.cpp
@@ -5,7 +5,7 @@
 
 namespace std {
 
-typedef int size_t;
+typedef decltype(sizeof 0) size_t;
 
 template<class E> class initializer_list {
 public:
@@ -15,6 +15,8 @@ template<class E> class initializer_list {
   using size_type = size_t;
   using iterator = const E*;
   using const_iterator = const E*;
+  iterator ptr;
+  size_type sz;
   initializer_list();
   size_t size() const; // number of elements
   const E* begin() const; // first element
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
index f42f2f37155af..b50ad4ce25839 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
@@ -31,7 +31,7 @@ struct SomeClass {
 
 namespace std {
 template <typename T>
-class initializer_list {};
+class initializer_list { const T *a, *b; };
 
 template <typename T>
 class vector {
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ab223f2b806d5..d27c61f511afa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12216,6 +12216,9 @@ def err_std_source_location_impl_not_found : Error<
 def err_std_source_location_impl_malformed : Error<
   "'std::source_location::__impl' must be standard-layout and have only two 'const char *' fields '_M_file_name' and '_M_function_name', and two integral fields '_M_line' and '_M_column'">;
 
+def err_std_initializer_list_malformed : Error<
+  "%0 layout not recognized. Must be a struct with two fields, a 'const E *' and either another 'const E *' or a 'std::size_t'">;
+
 // HLSL Diagnostics
 def err_hlsl_attr_unsupported_in_stage : Error<"attribute %0 is unsupported in '%1' shaders, requires %select{|one of the following: }2%3">;
 def err_hlsl_attr_invalid_type : Error<
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7178f081d9cf3..4aa19793fa099 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10528,48 +10528,37 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
   // Get a pointer to the first element of the array.
   Array.addArray(Info, E, ArrayType);
 
-  auto InvalidType = [&] {
-    Info.FFDiag(E, diag::note_constexpr_unsupported_layout)
-      << E->getType();
-    return false;
-  };
-
-  // FIXME: Perform the checks on the field types in SemaInit.
-  RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
-  RecordDecl::field_iterator Field = Record->field_begin();
-  if (Field == Record->field_end())
-    return InvalidType();
-
-  // Start pointer.
-  if (!Field->getType()->isPointerType() ||
-      !Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
-                            ArrayType->getElementType()))
-    return InvalidType();
-
   // FIXME: What if the initializer_list type has base classes, etc?
   Result = APValue(APValue::UninitStruct(), 0, 2);
   Array.moveInto(Result.getStructField(0));
 
-  if (++Field == Record->field_end())
-    return InvalidType();
-
-  if (Field->getType()->isPointerType() &&
-      Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
-                           ArrayType->getElementType())) {
+  RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
+  RecordDecl::field_iterator Field = Record->field_begin();
+  assert(Field != Record->field_end() &&
+         Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
+                              ArrayType->getElementType()) &&
+         "Expected std::initializer_list first field to be const E *");
+  ++Field;
+  assert(Field != Record->field_end() &&
+         "Expected std::initializer_list to have two fields");
+
+  if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType())) {
+    // Length.
+    Result.getStructField(1) = APValue(APSInt(ArrayType->getSize()));
+  } else {
     // End pointer.
+    assert(Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
+                                ArrayType->getElementType()) &&
+           "Expected std::initializer_list second field to be const E *");
     if (!HandleLValueArrayAdjustment(Info, E, Array,
                                      ArrayType->getElementType(),
                                      ArrayType->getZExtSize()))
       return false;
     Array.moveInto(Result.getStructField(1));
-  } else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType()))
-    // Length.
-    Result.getStructField(1) = APValue(APSInt(ArrayType->getSize()));
-  else
-    return InvalidType();
+  }
 
-  if (++Field != Record->field_end())
-    return InvalidType();
+  assert(++Field == Record->field_end() &&
+         "Expected std::initializer_list to only have two fields");
 
   return true;
 }
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index b2a5ceeeae08b..aeb72385515c4 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -429,53 +429,45 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
       Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
   assert(ArrayType && "std::initializer_list constructed from non-array");
 
-  // FIXME: Perform the checks on the field types in SemaInit.
   RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
   RecordDecl::field_iterator Field = Record->field_begin();
-  if (Field == Record->field_end()) {
-    CGF.ErrorUnsupported(E, "weird std::initializer_list");
-    return;
-  }
+  assert(Field != Record->field_end() &&
+         Ctx.hasSameType(Field->getType()->getPointeeType(),
+                         ArrayType->getElementType()) &&
+         "Expected std::initializer_list first field to be const E *");
 
   // Start pointer.
-  if (!Field->getType()->isPointerType() ||
-      !Ctx.hasSameType(Field->getType()->getPointeeType(),
-                       ArrayType->getElementType())) {
-    CGF.ErrorUnsupported(E, "weird std::initializer_list");
-    return;
-  }
-
   AggValueSlot Dest = EnsureSlot(E->getType());
   LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
   LValue Start = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
   llvm::Value *ArrayStart = ArrayPtr.emitRawPointer(CGF);
   CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start);
   ++Field;
-
-  if (Field == Record->field_end()) {
-    CGF.ErrorUnsupported(E, "weird std::initializer_list");
-    return;
-  }
+  assert(Field != Record->field_end() &&
+         "Expected std::initializer_list to have two fields");
 
   llvm::Value *Size = Builder.getInt(ArrayType->getSize());
   LValue EndOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *Field);
-  if (Field->getType()->isPointerType() &&
-      Ctx.hasSameType(Field->getType()->getPointeeType(),
-                      ArrayType->getElementType())) {
+  if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) {
+    // Length.
+    CGF.EmitStoreThroughLValue(RValue::get(Size), EndOrLength);
+
+  } else {
     // End pointer.
+    assert(Field->getType()->isPointerType() &&
+           Ctx.hasSameType(Field->getType()->getPointeeType(),
+                           ArrayType->getElementType()) &&
+           "Expected std::initializer_list second field to be const E *");
     llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0);
     llvm::Value *IdxEnd[] = { Zero, Size };
     llvm::Value *ArrayEnd = Builder.CreateInBoundsGEP(
         ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxEnd,
         "arrayend");
     CGF.EmitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength);
-  } else if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) {
-    // Length.
-    CGF.EmitStoreThroughLValue(RValue::get(Size), EndOrLength);
-  } else {
-    CGF.ErrorUnsupported(E, "weird std::initializer_list");
-    return;
   }
+
+  assert(++Field == Record->field_end() &&
+         "Expected std::initializer_list to only have two fields");
 }
 
 /// Determine if E is a trivial array filler, that is, one that is
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index e805834c0fd38..404495f4cdfd3 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -9392,6 +9392,57 @@ ExprResult InitializationSequence::Perform(Sema &S,
       // Wrap it in a construction of a std::initializer_list<T>.
       CurInit = new (S.Context) CXXStdInitializerListExpr(Step->Type, MTE);
 
+      if (!Step->Type->isDependentType()) {
+        assert(S.isCompleteType(CurInit.get()->getExprLoc(), Step->Type,
+                                Sema::CompleteTypeKind::Normal) &&
+               "std::initializer_list<E> incomplete when used during "
+               "initialization");
+        QualType ElementType;
+        [[maybe_unused]] bool IsStdInitializerList =
+            S.isStdInitializerList(Step->Type, &ElementType);
+        assert(IsStdInitializerList &&
+               "StdInitializerList step to non-std::initializer_list");
+        RecordDecl *Record = Step->Type->castAs<RecordType>()->getDecl();
+
+        auto InvalidType = [&] {
+          S.Diag(Record->getLocation(),
+                 diag::err_std_initializer_list_malformed)
+              << Step->Type.getUnqualifiedType();
+          return ExprError();
+        };
+
+        // FIXME: What if the initializer_list type has base classes, etc?
+        if (Record->isUnion())
+          return InvalidType();
+
+        RecordDecl::field_iterator Field = Record->field_begin();
+        if (Field == Record->field_end())
+          return InvalidType();
+
+        // Start pointer
+        if (!Field->getType()->isPointerType() ||
+            !S.Context.hasSameType(Field->getType()->getPointeeType(),
+                                   ElementType.withConst()))
+          return InvalidType();
+
+        if (++Field == Record->field_end())
+          return InvalidType();
+
+        // Size or end pointer
+        if (Field->getType()->isPointerType()) {
+          if (!S.Context.hasSameType(Field->getType()->getPointeeType(),
+                                     ElementType.withConst()))
+            return InvalidType();
+        } else {
+          if (Field->isUnnamedBitField() ||
+              !S.Context.hasSameType(Field->getType(), S.Context.getSizeType()))
+            return InvalidType();
+        }
+
+        if (++Field != Record->field_end())
+          return InvalidType();
+      }
+
       // Bind the result, in case the library has given initializer_list a
       // non-trivial destructor.
       if (shouldBindAsTemporary(Entity))
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
index bf1b3092e08e8..cad42014802e7 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
@@ -43,7 +43,7 @@ struct S {
 const int S::b;
 const auto S::c = 0;
 
-namespace std { template<typename T> struct initializer_list { initializer_list(); }; }
+namespace std { template<typename T> struct initializer_list { const T *a, *b; initializer_list(); }; }
 
 // In an initializer of the form ( expression-list ), the expression-list
 // shall be a single assigment-expression.
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp
index 97e860f91dcd3..89fa6ec670a65 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp
@@ -4,9 +4,7 @@
 
 namespace std {
   template<typename T> struct initializer_list {
-    const T *p;
-    unsigned long n;
-    initializer_list(const T *p, unsigned long n);
+    const T *a, *b;
   };
 }
 
diff --git a/clang/test/CodeCompletion/ctor-signature.cpp b/clang/test/CodeCompletion/ctor-signature.cpp
index d9bb2e566c51b..556fc4db0136f 100644
--- a/clang/test/CodeCompletion/ctor-signature.cpp
+++ b/clang/test/CodeCompletion/ctor-signature.cpp
@@ -17,7 +17,7 @@ void foo() {
 }
 
 namespace std {
-template <typename> struct initializer_list {};
+template <typename E> struct initializer_list { const E *a, *b; };
 } // namespace std
 
 struct Bar {
diff --git a/clang/test/Coverage/unresolved-ctor-expr.cpp b/clang/test/Coverage/unresolved-ctor-expr.cpp
index 10286c79f569d..2c57320949f7b 100644
--- a/clang/test/Coverage/unresolved-ctor-expr.cpp
+++ b/clang/test/Coverage/unresolved-ctor-expr.cpp
@@ -4,7 +4,7 @@
 // GH62105 demonstrated a crash with this example code when calculating
 // coverage mapping because some source location information was being dropped.
 // Demonstrate that we do not crash on this code.
-namespace std { template <typename> class initializer_list {}; }
+namespace std { template <typename E> class initializer_list { const E *a, *b; }; }
 
 template <typename> struct T {
   T(std::initializer_list<int>, int = int());
diff --git a/clang/test/Modules/Inputs/initializer_list/direct.h b/clang/test/Modules/Inputs/initializer_list/direct.h
index 6058f803a3dde..6f3978ef13284 100644
--- a/clang/test/Modules/Inputs/initializer_list/direct.h
+++ b/clang/test/Modules/Inputs/initializer_list/direct.h
@@ -2,7 +2,7 @@ namespace std {
   using size_t = decltype(sizeof(0));
 
   template<typename T> struct initializer_list {
-    initializer_list(T*, size_t);
+    const T* ptr; size_t sz;
   };
 
   template<typename T> int min(initializer_list<T>);
diff --git a/clang/test/Modules/pr60775.cppm b/clang/test/Modules/pr60775.cppm
index 35eb92512f427..76aec48808867 100644
--- a/clang/test/Modules/pr60775.cppm
+++ b/clang/test/Modules/pr60775.cppm
@@ -29,9 +29,10 @@
 namespace std {
   typedef decltype(sizeof(int)) size_t;
   template<typename T> struct initializer_list {
+    const T* ptr; size_t sz;
     initializer_list(const T *, size_t);
-    T* begin();
-    T* end();
+    const T* begin();
+    const T* end();
   };
 }
 
diff --git a/clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp b/clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp
index 7689cfc11f627..76c5675c83856 100644
--- a/clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp
+++ b/clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp
@@ -16,7 +16,7 @@
 #ifndef HEADER
 #define HEADER
 
-typedef long unsigned a;
+typedef decltype(sizeof 0) a;
 namespace std {
 template <class> class initializer_list {
   const int *b;
diff --git a/clang/test/Preprocessor/macro_with_initializer_list.cpp b/clang/test/Preprocessor/macro_with_initializer_list.cpp
index 287eeb4a843cb..40f53164b263d 100644
--- a/clang/test/Preprocessor/macro_with_initializer_list.cpp
+++ b/clang/test/Preprocessor/macro_with_initializer_list.cpp
@@ -3,7 +3,7 @@
 namespace std {
   template <class X>
   class initializer_list {
-    public:
+    public: const X *a, *b;
     initializer_list();
   };
 }
diff --git a/clang/test/SemaCXX/PR20334-std_initializer_list_diagnosis_assertion.cpp b/clang/test/SemaCXX/PR20334-std_initializer_list_diagnosis_assertion.cpp
index fb1feee01b29f..0df5d2e7f0aec 100644
--- a/clang/test/SemaCXX/PR20334-std_initializer_list_diagnosis_assertion.cpp
+++ b/clang/test/SemaCXX/PR20334-std_initializer_list_diagnosis_assertion.cpp
@@ -1,23 +1,18 @@
-// RUN: %clang_cc1 -std=c++11 -verify -emit-llvm-only %s
-// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s -DCPP98
-// RUN: %clang_cc1 -std=c++11 -verify -emit-llvm-only %s -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s -DCPP98 -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++11 -verify=cxx11 -emit-llvm-only %s
+// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify=cxx98 %s -DCPP98
+// RUN: %clang_cc1 -std=c++11 -verify=cxx11 -emit-llvm-only %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify=cxx98 %s -DCPP98 -fexperimental-new-constant-interpreter
 
 
 namespace std {
   template <class _E>
   class initializer_list
   {};
+  // cxx11-error@-2 {{'std::initializer_list<int>' layout not recognized}}
 }
 
 template<class E> int f(std::initializer_list<E> il);
 	
 
 int F = f({1, 2, 3});
-#ifdef CPP98
-//expected-error@-2{{expected expression}}
-#else
-//expected-error@-4{{cannot compile}}
-#endif
-
-
+// cxx98-error@-1 {{expected expression}}
diff --git a/clang/test/SemaCXX/auto-invalid-init-crash.cpp b/clang/test/SemaCXX/auto-invalid-init-crash.cpp
index f727473dd6085..ec921a4286aa2 100644
--- a/clang/test/SemaCXX/auto-invalid-init-crash.cpp
+++ b/clang/test/SemaCXX/auto-invalid-init-crash.c...
[truncated]

Copy link
Member

@Sirraide Sirraide left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving this into Sema seems like a good idea to me. While we’re at it, we might also want to add a few additional checks for things that—from what I can tell—are currently not supported anyway.

@Sirraide Sirraide removed clang Clang issues not falling into any other category clang-tools-extra clangd clang-tidy clang:modules C++20 modules and Clang Header Modules clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang:openmp OpenMP related changes to Clang labels Jun 19, 2024
@llvmbot llvmbot added clang Clang issues not falling into any other category clang-tools-extra clangd clang-tidy clang:modules C++20 modules and Clang Header Modules clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang:openmp OpenMP related changes to Clang labels Jun 19, 2024
@MitalAshok MitalAshok force-pushed the initializer-list-early-layout-check branch from a09ab24 to ed95059 Compare June 19, 2024 15:39
Copy link
Member

@Sirraide Sirraide left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Sirraide
Copy link
Member

Oh yeah, I only noticed this now, but this is missing a release note isn’t it?

@Sirraide Sirraide merged commit 482c41e into llvm:main Jun 20, 2024
6 of 7 checks passed
AlexisPerry pushed a commit to llvm-project-tlp/llvm-project that referenced this pull request Jul 9, 2024
…nit (llvm#95580)

This checks if the layout of `std::initializer_list` is something Clang
can handle much earlier and deduplicates the checks in
CodeGen/CGExprAgg.cpp and AST/ExprConstant.cpp

Also now diagnose `union initializer_list` (Fixes llvm#95495), bit-field for
the size (Fixes a crash that would happen during codegen if it were
unnamed), base classes (that wouldn't be initialized) and polymorphic
classes (whose vtable pointer wouldn't be initialized).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang:openmp OpenMP related changes to Clang clang Clang issues not falling into any other category clang-tidy clang-tools-extra clangd
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Clang-19 crash: const clang::FieldDecl* clang::APValue::getUnionField() const: Assertion `isUnion() && "Invalid accessor"' failed.
3 participants