diff options
author | Mital Ashok <mital@mitalashok.co.uk> | 2024-06-20 18:44:06 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-20 19:44:06 +0200 |
commit | 482c41e992c1edf8833a4577b56ff9dda49fbc83 (patch) | |
tree | 6a606c6bb325ce7e825bdc50a07ce6e734badb7a /clang | |
parent | 6cea40400df542a1a4a6d35b45cbe3367f2c32b7 (diff) | |
download | llvm-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')
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; }; |