diff options
33 files changed, 195 insertions, 108 deletions
diff --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp index 3101bf3..32c8e8a 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 d9e97e5..8d6d422 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 5b1531e..a5a349e 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 cbceb9a..d393c72 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 dac3f39..282abce 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 1f2dad2..c7632fe 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 2004993..150e3ac 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 f7b1ad5..3f4a14c 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 35091eb..e1e25d7 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 @@ public: 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 f42f2f3..b50ad4c 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 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; }; |