From 69ab8b46b84daa42f334ea2dc7a097f7b81bae77 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 2 Mar 2020 18:33:12 +0000 Subject: [PATCH] [Sema][SVE] Fix handling of initialisers for built-in SVE types The built-in SVE types are supposed to be treated as opaque types. This means that for initialisation purposes they should be treated as a single unit, much like a scalar type. However, as Eli pointed out, actually using "scalar" in the diagnostics is likely to cause confusion, given the types are logically vectors. The patch therefore uses custom diagnostics or generalises existing ones. Some of the messages use the word "indivisible" to try to make it clear(er) that these types can't be initialised elementwise. I don't think it's possible to trigger warn_braces_around_(scalar_)init for sizeless types as things stand, since the types can't be used as members or elements of more complex types. But it seemed better to be consistent with ext_many_braces_around_(scalar_)init, so the patch changes it anyway. Differential Revision: https://reviews.llvm.org/D76689 --- clang/docs/DiagnosticsReference.rst | 28 ++++++++--- .../clang/Basic/DiagnosticSemaKinds.td | 24 ++++++--- clang/lib/Sema/SemaInit.cpp | 50 ++++++++++++------- clang/test/Sema/sizeless-1.c | 8 +++ clang/test/SemaCXX/sizeless-1.cpp | 22 ++++++++ 5 files changed, 103 insertions(+), 29 deletions(-) diff --git a/clang/docs/DiagnosticsReference.rst b/clang/docs/DiagnosticsReference.rst index 38618f4530270..402ec9d4eba6f 100644 --- a/clang/docs/DiagnosticsReference.rst +++ b/clang/docs/DiagnosticsReference.rst @@ -1032,9 +1032,13 @@ This diagnostic is enabled by default. **Diagnostic text:** -+-----------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`braces around scalar initializer`| -+-----------------------------------------------------------------------+ ++------------------------------------------------------------+----------------------------+-----------------------+ +|:warning:`warning:` |nbsp| :diagtext:`braces around` |nbsp| |+--------------------------+|:diagtext:`initializer`| +| ||:diagtext:`scalar` |nbsp| || | +| |+--------------------------+| | +| || || | +| |+--------------------------+| | ++------------------------------------------------------------+----------------------------+-----------------------+ -Wbridge-cast @@ -2151,6 +2155,10 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ |:warning:`warning:` |nbsp| :diagtext:`scalar initialized from empty initializer list is incompatible with C++98`| +----------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`initializing` |nbsp| :placeholder:`A` |nbsp| :diagtext:`from an empty initializer list is incompatible with C++98`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`enumeration types with a fixed underlying type are incompatible with C++98`| +-----------------------------------------------------------------------------------------------------------------+ @@ -4501,6 +4509,10 @@ This diagnostic is enabled by default. | |+------------------+| | +-----------------------------------------------------------------+--------------------+-------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`excess elements in initializer for indivisible sizeless type` |nbsp| :placeholder:`A`| ++---------------------------------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`excess elements in char array initializer`| +--------------------------------------------------------------------------------+ @@ -7429,9 +7441,13 @@ This diagnostic is enabled by default. **Diagnostic text:** -+--------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`too many braces around scalar initializer`| -+--------------------------------------------------------------------------------+ ++---------------------------------------------------------------------+----------------------------+-----------------------+ +|:warning:`warning:` |nbsp| :diagtext:`too many braces around` |nbsp| |+--------------------------+|:diagtext:`initializer`| +| ||:diagtext:`scalar` |nbsp| || | +| |+--------------------------+| | +| || || | +| |+--------------------------+| | ++---------------------------------------------------------------------+----------------------------+-----------------------+ -Wmax-tokens diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7624fd7107c81..b3f6f66a8c562 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -171,8 +171,9 @@ def err_field_designator_unknown : Error< def err_field_designator_nonfield : Error< "field designator %0 does not refer to a non-static data member">; def note_field_designator_found : Note<"field designator refers here">; -def err_designator_for_scalar_init : Error< - "designator in initializer for scalar type %0">; +def err_designator_for_scalar_or_sizeless_init : Error< + "designator in initializer for %select{scalar|indivisible sizeless}0 " + "type %1">; def warn_initializer_overrides : Warning< "initializer %select{partially |}0overrides prior initialization of " "this subobject">, InGroup; @@ -5398,6 +5399,11 @@ def err_excess_initializers : Error< def ext_excess_initializers : ExtWarn< "excess elements in %select{array|vector|scalar|union|struct}0 initializer">, InGroup; +def err_excess_initializers_for_sizeless_type : Error< + "excess elements in initializer for indivisible sizeless type %0">; +def ext_excess_initializers_for_sizeless_type : ExtWarn< + "excess elements in initializer for indivisible sizeless type %0">, + InGroup; def err_excess_initializers_in_char_array_initializer : Error< "excess elements in char array initializer">; def ext_excess_initializers_in_char_array_initializer : ExtWarn< @@ -5411,18 +5417,24 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn< def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; -def warn_braces_around_scalar_init : Warning< - "braces around scalar initializer">, InGroup>; -def ext_many_braces_around_scalar_init : ExtWarn< - "too many braces around scalar initializer">, +def warn_braces_around_init : Warning< + "braces around %select{scalar |}0initializer">, + InGroup>; +def ext_many_braces_around_init : ExtWarn< + "too many braces around %select{scalar |}0initializer">, InGroup>, SFINAEFailure; def ext_complex_component_init : Extension< "complex initialization specifying real and imaginary components " "is an extension">, InGroup>; def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">; +def err_empty_sizeless_initializer : Error< + "initializer for sizeless type %0 cannot be empty">; def warn_cxx98_compat_empty_scalar_initializer : Warning< "scalar initialized from empty initializer list is incompatible with C++98">, InGroup, DefaultIgnore; +def warn_cxx98_compat_empty_sizeless_initializer : Warning< + "initializing %0 from an empty initializer list is incompatible with C++98">, + InGroup, DefaultIgnore; def warn_cxx98_compat_reference_list_init : Warning< "reference initialized from initializer list is incompatible with C++98">, InGroup, DefaultIgnore; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 9c6c9f103af21..e64b6d64f632f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -1119,14 +1119,14 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity, case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Result: // Extra braces here are suspicious. - DiagID = diag::warn_braces_around_scalar_init; + DiagID = diag::warn_braces_around_init; break; case InitializedEntity::EK_Member: // Warn on aggregate initialization but not on ctor init list or // default member initializer. if (Entity.getParent()) - DiagID = diag::warn_braces_around_scalar_init; + DiagID = diag::warn_braces_around_init; break; case InitializedEntity::EK_Variable: @@ -1157,9 +1157,9 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity, if (DiagID) { S.Diag(Braces.getBegin(), DiagID) - << Braces - << FixItHint::CreateRemoval(Braces.getBegin()) - << FixItHint::CreateRemoval(Braces.getEnd()); + << Entity.getType()->isSizelessBuiltinType() << Braces + << FixItHint::CreateRemoval(Braces.getBegin()) + << FixItHint::CreateRemoval(Braces.getEnd()); } } @@ -1203,6 +1203,12 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, : diag::ext_excess_initializers_in_char_array_initializer; SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK) << IList->getInit(Index)->getSourceRange(); + } else if (T->isSizelessBuiltinType()) { + unsigned DK = ExtraInitsIsError + ? diag::err_excess_initializers_for_sizeless_type + : diag::ext_excess_initializers_for_sizeless_type; + SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK) + << T << IList->getInit(Index)->getSourceRange(); } else { int initKind = T->isArrayType() ? 0 : T->isVectorType() ? 1 : @@ -1295,7 +1301,8 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, if (!VerifyOnly) SemaRef.Diag(IList->getBeginLoc(), diag::err_init_objc_class) << DeclType; hadError = true; - } else if (DeclType->isOCLIntelSubgroupAVCType()) { + } else if (DeclType->isOCLIntelSubgroupAVCType() || + DeclType->isSizelessBuiltinType()) { // Checks for scalar type are sufficient for these types too. CheckScalarType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); @@ -1508,12 +1515,20 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, InitListExpr *StructuredList, unsigned &StructuredIndex) { if (Index >= IList->getNumInits()) { - if (!VerifyOnly) - SemaRef.Diag(IList->getBeginLoc(), - SemaRef.getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_empty_scalar_initializer - : diag::err_empty_scalar_initializer) - << IList->getSourceRange(); + if (!VerifyOnly) { + if (DeclType->isSizelessBuiltinType()) + SemaRef.Diag(IList->getBeginLoc(), + SemaRef.getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_empty_sizeless_initializer + : diag::err_empty_sizeless_initializer) + << DeclType << IList->getSourceRange(); + else + SemaRef.Diag(IList->getBeginLoc(), + SemaRef.getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_empty_scalar_initializer + : diag::err_empty_scalar_initializer) + << IList->getSourceRange(); + } hadError = !SemaRef.getLangOpts().CPlusPlus11; ++Index; ++StructuredIndex; @@ -1525,17 +1540,18 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, // FIXME: This is invalid, and accepting it causes overload resolution // to pick the wrong overload in some corner cases. if (!VerifyOnly) - SemaRef.Diag(SubIList->getBeginLoc(), - diag::ext_many_braces_around_scalar_init) - << SubIList->getSourceRange(); + SemaRef.Diag(SubIList->getBeginLoc(), diag::ext_many_braces_around_init) + << DeclType->isSizelessBuiltinType() << SubIList->getSourceRange(); CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList, StructuredIndex); return; } else if (isa(expr)) { if (!VerifyOnly) - SemaRef.Diag(expr->getBeginLoc(), diag::err_designator_for_scalar_init) - << DeclType << expr->getSourceRange(); + SemaRef.Diag(expr->getBeginLoc(), + diag::err_designator_for_scalar_or_sizeless_init) + << DeclType->isSizelessBuiltinType() << DeclType + << expr->getSourceRange(); hadError = true; ++Index; ++StructuredIndex; diff --git a/clang/test/Sema/sizeless-1.c b/clang/test/Sema/sizeless-1.c index 8fe8e7b30cf6e..dd6492c44b622 100644 --- a/clang/test/Sema/sizeless-1.c +++ b/clang/test/Sema/sizeless-1.c @@ -83,6 +83,14 @@ void func(int sel) { svint8_t bad_init_int8 = for; // expected-error {{expected expression}} int empty_brace_init_int = {}; // expected-error {{scalar initializer cannot be empty}} + svint8_t empty_brace_init_int8 = {}; // expected-error {{initializer for sizeless type 'svint8_t' (aka '__SVInt8_t') cannot be empty}} + svint8_t brace_init_int8 = {local_int8}; + svint8_t bad_brace_init_int8_1 = {local_int8, 0}; // expected-warning {{excess elements in initializer for indivisible sizeless type 'svint8_t'}} + svint8_t bad_brace_init_int8_2 = {0}; // expected-error {{incompatible type 'int'}} + svint8_t bad_brace_init_int8_3 = {local_int16}; // expected-error {{incompatible type 'svint16_t'}} + svint8_t bad_brace_init_int8_4 = {[0] = local_int8}; // expected-error {{designator in initializer for indivisible sizeless type 'svint8_t'}} + svint8_t bad_brace_init_int8_5 = {{local_int8}}; // expected-warning {{too many braces around initializer}} + svint8_t bad_brace_init_int8_6 = {{local_int8, 0}}; // expected-warning {{too many braces around initializer}} const svint8_t const_int8 = local_int8; // expected-note {{declared const here}} const svint8_t uninit_const_int8; diff --git a/clang/test/SemaCXX/sizeless-1.cpp b/clang/test/SemaCXX/sizeless-1.cpp index a7c02343cb489..46a183f7ad0c0 100644 --- a/clang/test/SemaCXX/sizeless-1.cpp +++ b/clang/test/SemaCXX/sizeless-1.cpp @@ -94,9 +94,18 @@ void func(int sel) { #if __cplusplus >= 201103L int empty_brace_init_int = {}; + svint8_t empty_brace_init_int8 = {}; #else int empty_brace_init_int = {}; // expected-error {{scalar initializer cannot be empty}} + svint8_t empty_brace_init_int8 = {}; // expected-error {{initializer for sizeless type 'svint8_t' (aka '__SVInt8_t') cannot be empty}} #endif + svint8_t brace_init_int8 = {local_int8}; + svint8_t bad_brace_init_int8_1 = {local_int8, 0}; // expected-error {{excess elements in initializer for indivisible sizeless type 'svint8_t'}} + svint8_t bad_brace_init_int8_2 = {0}; // expected-error {{rvalue of type 'int'}} + svint8_t bad_brace_init_int8_3 = {local_int16}; // expected-error {{lvalue of type 'svint16_t'}} + svint8_t bad_brace_init_int8_4 = {[0] = local_int8}; // expected-error {{designator in initializer for indivisible sizeless type 'svint8_t'}} expected-warning {{array designators are a C99 extension}} + svint8_t bad_brace_init_int8_5 = {{local_int8}}; // expected-warning {{too many braces around initializer}} + svint8_t bad_brace_init_int8_6 = {{local_int8, 0}}; // expected-warning {{too many braces around initializer}} const svint8_t const_int8 = local_int8; // expected-note {{declared const here}} const svint8_t uninit_const_int8; // expected-error {{default initialization of an object of const type 'const svint8_t'}} @@ -455,6 +464,14 @@ void cxx_only(int sel) { local_int8 = ref_int8; #if __cplusplus >= 201103L + svint8_t zero_init_int8{}; + svint8_t init_int8{local_int8}; + svint8_t bad_brace_init_int8_1{local_int8, 0}; // expected-error {{excess elements in initializer for indivisible sizeless type 'svint8_t'}} + svint8_t bad_brace_init_int8_2{0}; // expected-error {{rvalue of type 'int'}} + svint8_t bad_brace_init_int8_3{local_int16}; // expected-error {{lvalue of type 'svint16_t'}} + svint8_t bad_brace_init_int8_4{[0] = local_int8}; // expected-error {{designator in initializer for indivisible sizeless type 'svint8_t'}} expected-warning {{array designators are a C99 extension}} + svint8_t bad_brace_init_int8_5{{local_int8}}; // expected-warning {{too many braces around initializer}} + svint8_t bad_brace_init_int8_6{{local_int8, 0}}; // expected-warning {{too many braces around initializer}} svint8_t wrapper_init_int8{wrapper()}; svint8_t &ref_init_int8{local_int8}; @@ -601,4 +618,9 @@ void cxx_only(int sel) { #if __cplusplus >= 201103L svint8_t ret_bad_conv() { return explicit_conv(); } // expected-error {{no viable conversion from returned value of type 'explicit_conv' to function return type 'svint8_t'}} + +#pragma clang diagnostic warning "-Wc++98-compat" + +void incompat_init() { __attribute__((unused)) svint8_t foo = {}; } // expected-warning {{initializing 'svint8_t' (aka '__SVInt8_t') from an empty initializer list is incompatible with C++98}} + #endif