From 57acbaece1ace979e6a9382d9d517d48895b9ef7 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 15 Apr 2020 13:23:56 -0700 Subject: [PATCH] Improve diagnostic when constant-evaluating a std::initializer_list with an unexpected form. --- clang/lib/AST/ExprConstant.cpp | 16 +++++++++++----- .../SemaCXX/cxx0x-initializer-stdinitializerlist.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 2eabf59..5b3866d 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9338,24 +9338,30 @@ 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()->getDecl(); RecordDecl::field_iterator Field = Record->field_begin(); if (Field == Record->field_end()) - return Error(E); + return InvalidType(); // Start pointer. if (!Field->getType()->isPointerType() || !Info.Ctx.hasSameType(Field->getType()->getPointeeType(), ArrayType->getElementType())) - return Error(E); + 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 Error(E); + return InvalidType(); if (Field->getType()->isPointerType() && Info.Ctx.hasSameType(Field->getType()->getPointeeType(), @@ -9370,10 +9376,10 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr( // Length. Result.getStructField(1) = APValue(APSInt(ArrayType->getSize())); else - return Error(E); + return InvalidType(); if (++Field != Record->field_end()) - return Error(E); + return InvalidType(); return true; } diff --git a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index b5d6bd6..9380330 100644 --- a/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/clang/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -365,3 +365,14 @@ namespace designated_init { static_assert(c.size() == 5, ""); static_assert(d.size() == 1, ""); } + +namespace weird_initlist { + struct weird {}; +} +template<> struct std::initializer_list { int a, b, c; }; +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' has unexpected layout}} +} -- 2.7.4