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