Author: Mital Ashok
Date: 2024-06-20T19:44:06+02:00
New Revision: 482c41e992c1edf8833a4577b56ff9dda49fbc83

URL: 
https://github.com/llvm/llvm-project/commit/482c41e992c1edf8833a4577b56ff9dda49fbc83
DIFF: 
https://github.com/llvm/llvm-project/commit/482c41e992c1edf8833a4577b56ff9dda49fbc83.diff

LOG: [Clang] [Sema] Diagnose unknown std::initializer_list layout in SemaInit 
(#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 #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).

Added: 
    

Modified: 
    clang-tools-extra/clangd/unittests/ASTTests.cpp
    clang-tools-extra/clangd/unittests/HoverTests.cpp
    clang-tools-extra/clangd/unittests/InlayHintTests.cpp
    clang-tools-extra/clangd/unittests/XRefsTests.cpp
    clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
    
clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp
    
clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace-ignore-implicit-constructors.cpp
    clang-tools-extra/test/clang-tidy/checkers/modernize/use-emplace.cpp
    
clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation.cpp
    
clang-tools-extra/test/clang-tidy/checkers/readability/isolate-declaration-cxx17.cpp
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/AST/ExprConstant.cpp
    clang/lib/CodeGen/CGExprAgg.cpp
    clang/lib/Sema/SemaInit.cpp
    clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
    clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp
    clang/test/CodeCompletion/ctor-signature.cpp
    clang/test/Coverage/unresolved-ctor-expr.cpp
    clang/test/Modules/Inputs/initializer_list/direct.h
    clang/test/Modules/pr60775.cppm
    clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp
    clang/test/Preprocessor/macro_with_initializer_list.cpp
    clang/test/SemaCXX/PR20334-std_initializer_list_diagnosis_assertion.cpp
    clang/test/SemaCXX/auto-invalid-init-crash.cpp
    clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
    clang/test/SemaCXX/cxx11-call-to-deleted-constructor.cpp
    clang/test/SemaCXX/cxx98-compat.cpp
    clang/test/SemaCXX/invalid-member-expr.cpp
    clang/test/SemaTemplate/instantiate-init.cpp
    clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
    clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
    clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp 
b/clang-tools-extra/clangd/unittests/ASTTests.cpp
index 3101bf34acd71..32c8e8a63a215 100644
--- a/clang-tools-extra/clangd/unittests/ASTTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp
@@ -80,7 +80,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) {
               namespace std
               {
                 template<class _E>
-                class [[initializer_list]] {};
+                class [[initializer_list]] { const _E *a, *b; };
               }
 
               ^auto i = {1,2};

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/clangd/unittests/XRefsTests.cpp 
b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index cbceb9a343f87..d393c72974d44 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -771,7 +771,7 @@ TEST(LocateSymbol, All) {
         namespace std
         {
           template<class _E>
-          class [[initializer_list]] {};
+          class [[initializer_list]] { const _E *a, *b; };
         }
 
         ^auto i = {1,2};

diff  --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp 
b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
index dac3f39e1a658..282abce3246ca 100644
--- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -534,7 +534,7 @@ TEST(WalkAST, Enums) {
 TEST(WalkAST, InitializerList) {
   testWalk(R"cpp(
        namespace std {
-        template <typename T> struct $implicit^initializer_list {};
+        template <typename T> struct $implicit^initializer_list { const T *a, 
*b; };
        })cpp",
            R"cpp(
        const char* s = "";

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 35091eb77c4c5..e1e25d76d4909 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 p;
+  size_t 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/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 36e23981cc5df..92ada517acae3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -598,6 +598,10 @@ Improvements to Clang's diagnostics
 - Clang no longer emits a "declared here" note for a builtin function that has 
no declaration in source.
   Fixes #GH93369.
 
+- Clang now diagnoses unsupported class declarations for 
``std::initializer_list<E>`` when they are
+  used rather than when they are needed for constant evaluation or when code 
is generated for them.
+  The check is now stricter to prevent crashes for some unsupported 
declarations (Fixes #GH95495).
+
 Improvements to Clang's time-trace
 ----------------------------------
 

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d3993dda9e316..9defaed8b36a7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12207,6 +12207,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 non-polymorphic class type with no 
bases and 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 782fdfa1d7a4c..8124069cdf805 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10545,48 +10545,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 0c87558521924..c3c10e73ff05e 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -426,53 +426,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 dbe2231412e14..f820db5233f53 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -9479,6 +9479,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()) {
+        QualType ElementType;
+        [[maybe_unused]] bool IsStdInitializerList =
+            S.isStdInitializerList(Step->Type, &ElementType);
+        assert(IsStdInitializerList &&
+               "StdInitializerList step to non-std::initializer_list");
+        const CXXRecordDecl *Record =
+            Step->Type->getAsCXXRecordDecl()->getDefinition();
+        assert(Record && Record->isCompleteDefinition() &&
+               "std::initializer_list should have already be "
+               "complete/instantiated by this point");
+
+        auto InvalidType = [&] {
+          S.Diag(Record->getLocation(),
+                 diag::err_std_initializer_list_malformed)
+              << Step->Type.getUnqualifiedType();
+          return ExprError();
+        };
+
+        if (Record->isUnion() || Record->getNumBases() != 0 ||
+            Record->isPolymorphic())
+          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 (const auto *PT = Field->getType()->getAs<PointerType>()) {
+          if (!S.Context.hasSameType(PT->getPointeeType(),
+                                     ElementType.withConst()))
+            return InvalidType();
+        } else {
+          if (Field->isBitField() ||
+              !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..fa8cbe2795b6b 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,17 @@
-// 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
+// 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 
-fexperimental-new-constant-interpreter
 
 
 namespace std {
   template <class _E>
-  class initializer_list
-  {};
+  class initializer_list {};
+  // cxx11-error@-1 {{'std::initializer_list<int>' layout not recognized. Must 
be a non-polymorphic class type with no bases and two fields: a 'const E *' and 
either another 'const E *' or a 'std::size_t'}}
 }
 
 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.cpp
@@ -1,8 +1,8 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -fno-recovery-ast -verify %s
 
 namespace std {
-template <typename>
-class initializer_list{};
+template <typename E>
+class initializer_list { const E *a, *b; };
 int a;
 auto c = a, &d = {a}; // expected-error {{'auto' deduced as 'int'}} \
                          expected-error {{non-const lvalue reference to type}}

diff  --git a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp 
b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
index 143d93cefc7c4..74aa7cb2abe83 100644
--- a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -1,5 +1,18 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -DUNION_TEST -verify %s
 
+#ifdef UNION_TEST
+namespace std {
+  template<class E>
+  union initializer_list {
+  // expected-error@-1 {{'std::initializer_list<int>' layout not recognized.}}
+    const E* begin;
+    decltype(sizeof 0) size;
+  };
+
+  auto x = { 1, 2, 3 };
+};
+#else
 // This must obviously come before the definition of std::initializer_list.
 void missing_initializerlist() {
   auto l = {1, 2, 3, 4}; // expected-error {{std::initializer_list was not 
found}}
@@ -367,14 +380,49 @@ namespace designated_init {
 }
 
 namespace weird_initlist {
+  template<int>
   struct weird {};
 }
-template<> struct std::initializer_list<weird_initlist::weird> { int a, b, c; 
};
+template<> struct std::initializer_list<weird_initlist::weird<0>> { int a, b, 
c; };
+// expected-error@-1 2 {{'std::initializer_list<weird<0>>' layout not 
recognized}}
+template<> struct std::initializer_list<weird_initlist::weird<1>> { 
std::size_t sz; const weird_initlist::weird<1>* p; };
+// expected-error@-1 {{'std::initializer_list<weird<1>>' layout not 
recognized}}
+template<> struct std::initializer_list<weird_initlist::weird<2>> { const 
weird_initlist::weird<2>* first; const weird_initlist::weird<2>* last; };
+template<> struct std::initializer_list<weird_initlist::weird<3>> { 
weird_initlist::weird<3>* p; std::size_t sz; };
+// expected-error@-1 {{'std::initializer_list<weird<3>>' layout not 
recognized}}
+template<> struct std::initializer_list<weird_initlist::weird<4>> { const 
weird_initlist::weird<4>& p; std::size_t sz; };
+// expected-error@-1 {{'std::initializer_list<weird<4>>' layout not 
recognized}}
+template<> struct std::initializer_list<weird_initlist::weird<5>> { const 
weird_initlist::weird<5>* p; std::size_t : sizeof(std::size_t) * __CHAR_BIT__; 
};
+// expected-error@-1 {{'std::initializer_list<weird<5>>' layout not 
recognized}}
+template<> struct std::initializer_list<weird_initlist::weird<6>> { const 
weird_initlist::weird<6>* p; std::size_t sz : sizeof(std::size_t) * 
__CHAR_BIT__; };
+// expected-error@-1 {{'std::initializer_list<weird<6>>' layout not 
recognized}}
+struct empty_base {};
+template<> struct std::initializer_list<weird_initlist::weird<7>> : empty_base 
{ const weird_initlist::weird<7>* p; std::size_t sz; };
+// expected-error@-1 {{'std::initializer_list<weird<7>>' layout not 
recognized}}
+template<> struct std::initializer_list<weird_initlist::weird<8>> { const 
weird_initlist::weird<8>* p; std::size_t sz; ~initializer_list(); };
+template<> struct std::initializer_list<weird_initlist::weird<9>> { const 
weird_initlist::weird<9>* p; std::size_t sz; virtual void f(); };
+// expected-error@-1 {{'std::initializer_list<weird<9>>' layout not 
recognized}}
+template<> struct std::initializer_list<weird_initlist::weird<10>> { const 
weird_initlist::weird<10>* p; alignas(64) std::size_t sz; };
+template<> struct std::initializer_list<weird_initlist::weird<11>>;
+// expected-note@-1 {{forward declaration of 
'std::initializer_list<weird_initlist::weird<11>>'}}
 namespace weird_initlist {
-  // We don't check the struct layout in Sema.
-  auto x = {weird{}, weird{}, weird{}, weird{}, weird{}};
-  // ... but we do in constant evaluation.
-  constexpr auto y = {weird{}, weird{}, weird{}, weird{}, weird{}}; // 
expected-error {{constant}} expected-note {{type 'const 
std::initializer_list<weird>' has unexpected layout}}
+  auto _0 = {weird<0>{}, weird<0>{}, weird<0>{}, weird<0>{}, weird<0>{}};
+  constexpr auto _0c = {weird<0>{}, weird<0>{}, weird<0>{}, weird<0>{}, 
weird<0>{}};
+  auto _1 = {weird<1>{}, weird<1>{}};
+  auto _2 = {weird<2>{}, weird<2>{}, weird<2>{}};
+  constexpr auto _2c = {weird<2>{}, weird<2>{}, weird<2>{}}; // (Two pointer 
representation is supported)
+  static_assert(_2c.first + 3 == _2c.last, "");
+  auto _3 = {weird<3>{}, weird<3>{}};
+  auto _4 = {weird<4>{}, weird<4>{}};
+  auto _5 = {weird<5>{}, weird<5>{}};
+  auto _6 = {weird<6>{}, weird<6>{}};
+  auto _7 = {weird<7>{}, weird<7>{}};
+  auto _8 = {weird<8>{}, weird<8>{}};
+  auto _9 = {weird<9>{}, weird<9>{}};
+  auto _10 = {weird<10>{}, weird<10>{}};
+  constexpr auto _10c = {weird<10>{}, weird<10>{}, weird<10>{}};
+  static_assert(_10c.sz == 3, "");
+  const auto& _11 = {weird<11>{}, weird<11>{}}; // expected-error 
{{initialization of incomplete type 'const std::initializer_list<weird<11>>'}}
 }
 
 auto v = std::initializer_list<int>{1,2,3}; // expected-warning {{array 
backing local initializer list 'v' will be destroyed at the end of the 
full-expression}}
@@ -386,3 +434,4 @@ std::initializer_list<int> get(int cond) {
     return {1, 2, 3}; // expected-warning {{returning address of local 
temporary object}}
   return std::initializer_list<int>{1, 2, 3}; // expected-warning {{returning 
address of local temporary object}}
 }
+#endif // UNION_TEST

diff  --git a/clang/test/SemaCXX/cxx11-call-to-deleted-constructor.cpp 
b/clang/test/SemaCXX/cxx11-call-to-deleted-constructor.cpp
index d77cebdeba500..86738ab10b4cc 100644
--- a/clang/test/SemaCXX/cxx11-call-to-deleted-constructor.cpp
+++ b/clang/test/SemaCXX/cxx11-call-to-deleted-constructor.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
 
 namespace std {
-template<class _Ep> class initializer_list { };
+template<class _Ep> class initializer_list { const _Ep *a, *b; };
 }
 
 namespace cva {

diff  --git a/clang/test/SemaCXX/cxx98-compat.cpp 
b/clang/test/SemaCXX/cxx98-compat.cpp
index b31bee672bbe3..3ce69d6908c5b 100644
--- a/clang/test/SemaCXX/cxx98-compat.cpp
+++ b/clang/test/SemaCXX/cxx98-compat.cpp
@@ -6,11 +6,11 @@ namespace std {
   struct type_info;
   using size_t = decltype(sizeof(0)); // expected-warning {{decltype}} 
expected-warning {{alias}}
   template<typename T> struct initializer_list {
-    initializer_list(T*, size_t);
-    T *p;
+    initializer_list(const T*, size_t);
+    const T *p;
     size_t n;
-    T *begin();
-    T *end();
+    const T *begin();
+    const T *end();
   };
 }
 

diff  --git a/clang/test/SemaCXX/invalid-member-expr.cpp 
b/clang/test/SemaCXX/invalid-member-expr.cpp
index 6ef33ea575a12..235db185c9330 100644
--- a/clang/test/SemaCXX/invalid-member-expr.cpp
+++ b/clang/test/SemaCXX/invalid-member-expr.cpp
@@ -26,7 +26,7 @@ void test2() {
 // PR6327
 namespace test3 {
   template <class A, class B> struct pair {};
-  template <class _E> class initializer_list {};
+  template <class _E> class initializer_list { const _E *a, *b; };
   template <typename _Tp> pair<_Tp, _Tp> minmax(initializer_list<_Tp> __l) {};
 
   void test0() {

diff  --git a/clang/test/SemaTemplate/instantiate-init.cpp 
b/clang/test/SemaTemplate/instantiate-init.cpp
index 6db33a972f86d..5fc3e83114e28 100644
--- a/clang/test/SemaTemplate/instantiate-init.cpp
+++ b/clang/test/SemaTemplate/instantiate-init.cpp
@@ -2,9 +2,9 @@
 
 namespace std {
   template<typename T> struct initializer_list {
-    T *p;
+    const T *p;
     __SIZE_TYPE__ n;
-    initializer_list(T*, __SIZE_TYPE__);
+    initializer_list(const T*, __SIZE_TYPE__);
   };
 }
 

diff  --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 2e42b85808953..f2eaf19d61402 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1427,8 +1427,8 @@ TEST_P(ASTMatchersTest,
     return;
   }
   StringRef code = "namespace std {"
-                   "template <typename> class initializer_list {"
-                   "  public: initializer_list() noexcept {}"
+                   "template <typename E> class initializer_list {"
+                   "  public: const E *a, *b;"
                    "};"
                    "}"
                    "struct A {"

diff  --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 2a74d7fa63fd7..cfbc64c77b0cc 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -3265,7 +3265,7 @@ TEST(TransferTest, 
ResultObjectLocationForStdInitializerListExpr) {
   std::string Code = R"(
     namespace std {
     template <typename T>
-    struct initializer_list {};
+    struct initializer_list { const T *a, *b; };
     } // namespace std
 
     void target() {

diff  --git 
a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
index f16472ef17141..53dd223f06b5e 100644
--- 
a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
+++ 
b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
@@ -552,6 +552,7 @@ namespace std {
 template <typename T>
 class initializer_list {
  public:
+  const T *a, *b;
   initializer_list() noexcept;
 };
 


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

Reply via email to