aboutsummaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
authorMital Ashok <mital@mitalashok.co.uk>2024-06-20 18:44:06 +0100
committerGitHub <noreply@github.com>2024-06-20 19:44:06 +0200
commit482c41e992c1edf8833a4577b56ff9dda49fbc83 (patch)
tree6a606c6bb325ce7e825bdc50a07ce6e734badb7a /clang
parent6cea40400df542a1a4a6d35b45cbe3367f2c32b7 (diff)
downloadllvm-482c41e992c1edf8833a4577b56ff9dda49fbc83.zip
llvm-482c41e992c1edf8833a4577b56ff9dda49fbc83.tar.gz
llvm-482c41e992c1edf8833a4577b56ff9dda49fbc83.tar.bz2
[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).
Diffstat (limited to 'clang')
-rw-r--r--clang/docs/ReleaseNotes.rst4
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--clang/lib/AST/ExprConstant.cpp51
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp44
-rw-r--r--clang/lib/Sema/SemaInit.cpp51
-rw-r--r--clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp2
-rw-r--r--clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p7-cxx14.cpp4
-rw-r--r--clang/test/CodeCompletion/ctor-signature.cpp2
-rw-r--r--clang/test/Coverage/unresolved-ctor-expr.cpp2
-rw-r--r--clang/test/Modules/Inputs/initializer_list/direct.h2
-rw-r--r--clang/test/Modules/pr60775.cppm5
-rw-r--r--clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp2
-rw-r--r--clang/test/Preprocessor/macro_with_initializer_list.cpp2
-rw-r--r--clang/test/SemaCXX/PR20334-std_initializer_list_diagnosis_assertion.cpp20
-rw-r--r--clang/test/SemaCXX/auto-invalid-init-crash.cpp4
-rw-r--r--clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp59
-rw-r--r--clang/test/SemaCXX/cxx11-call-to-deleted-constructor.cpp2
-rw-r--r--clang/test/SemaCXX/cxx98-compat.cpp8
-rw-r--r--clang/test/SemaCXX/invalid-member-expr.cpp2
-rw-r--r--clang/test/SemaTemplate/instantiate-init.cpp4
-rw-r--r--clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp4
-rw-r--r--clang/unittests/Analysis/FlowSensitive/TransferTest.cpp2
-rw-r--r--clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp1
23 files changed, 181 insertions, 99 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 36e2398..92ada51 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 d3993dd..9defaed 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 782fdfa..8124069 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 0c87558..c3c10e7 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 dbe2231..f820db5 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 bf1b309..cad4201 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 97e860f..89fa6ec 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 d9bb2e5..556fc4d 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 10286c7..2c57320 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 6058f80..6f3978e 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 35eb925..76aec48 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 7689cfc..76c5675 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 287eeb4..40f5316 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 fb1feee..fa8cbe2 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 f727473..ec921a4 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 143d93c..74aa7cb 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 d77cebd..86738ab 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 b31bee6..3ce69d6 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 6ef33ea..235db18 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 6db33a9..5fc3e83 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 2e42b85..f2eaf19 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 2a74d7f..cfbc64c 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 f16472e..53dd223 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;
};