Author: Mariya Podchishchaeva Date: 2023-05-03T08:54:35-04:00 New Revision: 22e2db6010b029ebd4c6d3d1fd30224d8b3109ef
URL: https://github.com/llvm/llvm-project/commit/22e2db6010b029ebd4c6d3d1fd30224d8b3109ef DIFF: https://github.com/llvm/llvm-project/commit/22e2db6010b029ebd4c6d3d1fd30224d8b3109ef.diff LOG: [clang] Reject flexible array member in a union in C++ It was rejected in C, and in a strange way accepted in C++. However, the support was never properly tested and fully implemented, so just reject it in C++ mode as well. This change also fixes crash on attempt to initialize union with flexible array member. Due to missing check on union, there was a null expression added to init list that caused crash later. Fixes https://github.com/llvm/llvm-project/issues/61746 Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D147626 Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticGroups.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaInit.cpp clang/test/Layout/aix-power-alignment-typedef.cpp clang/test/Sema/MicrosoftExtensions.c clang/test/Sema/init.c clang/test/SemaCXX/flexible-array-test.cpp clang/test/SemaCXX/gnu-flags.cpp clang/test/SemaObjCXX/flexible-array.mm Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 8d0a9c96a9579..416d816796514 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -55,6 +55,7 @@ C++ Specific Potentially Breaking Changes ----------------------------------------- - Clang won't search for coroutine_traits in std::experimental namespace any more. Clang will only search for std::coroutine_traits for coroutines then. +- Clang now rejects unions containing a flexible array member. ABI Changes in This Version --------------------------- diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 0ee43fb8837a1..4313948515752 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -267,7 +267,6 @@ def ExtraSemi : DiagGroup<"extra-semi", [CXX98CompatExtraSemi, CXX11ExtraSemi]>; def GNUFlexibleArrayInitializer : DiagGroup<"gnu-flexible-array-initializer">; -def GNUFlexibleArrayUnionMember : DiagGroup<"gnu-flexible-array-union-member">; def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">; def FormatInsufficientArgs : DiagGroup<"format-insufficient-args">; def FormatExtraArgs : DiagGroup<"format-extra-args">; @@ -1137,7 +1136,7 @@ def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct, GNUConditionalOmittedOperand, GNUDesignator, GNUEmptyStruct, VLAExtension, GNUFlexibleArrayInitializer, - GNUFlexibleArrayUnionMember, GNUFoldingConstant, + GNUFoldingConstant, GNUImaginaryConstant, GNUIncludeNext, GNULabelsAsValue, GNULineMarker, GNUNullPointerArithmetic, GNUOffsetofExtensions, GNUPointerArith, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 17585752edf8e..c3cb6740a5131 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6232,6 +6232,9 @@ def ext_variable_sized_type_in_struct : ExtWarn< def ext_c99_flexible_array_member : Extension< "flexible array members are a C99 feature">, InGroup<C99>; +// Flexible array members in unions are not supported, but union case is still +// present in the diagnostic so it matches TagTypeKind enum and can be emitted +// with Diag(...) << ... << SomeTagDecl->getTagKind(). def err_flexible_array_virtual_base : Error< "flexible array member %0 not allowed in " "%select{struct|interface|union|class|enum}1 which has a virtual base class">; @@ -6254,15 +6257,10 @@ def ext_flexible_array_empty_aggregate_ms : Extension< InGroup<MicrosoftFlexibleArray>; def err_flexible_array_union : Error< "flexible array member %0 in a union is not allowed">; -def ext_flexible_array_union_ms : Extension< - "flexible array member %0 in a union is a Microsoft extension">, - InGroup<MicrosoftFlexibleArray>; def ext_flexible_array_empty_aggregate_gnu : Extension< "flexible array member %0 in otherwise empty " "%select{struct|interface|union|class|enum}1 is a GNU extension">, InGroup<GNUEmptyStruct>; -def ext_flexible_array_union_gnu : Extension< - "flexible array member %0 in a union is a GNU extension">, InGroup<GNUFlexibleArrayUnionMember>; def err_flexible_array_not_at_end : Error< "flexible array member %0 with type %1 is not at the end of" diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 4cdf2982b99d5..a5bab074d08e3 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -18690,8 +18690,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, if (Record) { // Flexible array member. // Microsoft and g++ is more permissive regarding flexible array. - // It will accept flexible array in union and also - // as the sole element of a struct/class. + // It will accept flexible array as the sole element of a struct/class. unsigned DiagID = 0; if (!Record->isUnion() && !IsLastField) { Diag(FD->getLocation(), diag::err_flexible_array_not_at_end) @@ -18701,11 +18700,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, EnclosingDecl->setInvalidDecl(); continue; } else if (Record->isUnion()) - DiagID = getLangOpts().MicrosoftExt - ? diag::ext_flexible_array_union_ms - : getLangOpts().CPlusPlus - ? diag::ext_flexible_array_union_gnu - : diag::err_flexible_array_union; + DiagID = diag::err_flexible_array_union; else if (NumNamedMembers < 1) DiagID = getLangOpts().MicrosoftExt ? diag::ext_flexible_array_empty_aggregate_ms diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 2d5d31f99e500..c8beae3f52e39 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -805,7 +805,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, // order to leave them uninitialized, the ILE is expanded and the extra // fields are then filled with NoInitExpr. unsigned NumElems = numStructUnionElements(ILE->getType()); - if (RDecl->hasFlexibleArrayMember()) + if (!RDecl->isUnion() && RDecl->hasFlexibleArrayMember()) ++NumElems; if (!VerifyOnly && ILE->getNumInits() < NumElems) ILE->resizeInits(SemaRef.Context, NumElems); diff --git a/clang/test/Layout/aix-power-alignment-typedef.cpp b/clang/test/Layout/aix-power-alignment-typedef.cpp index 908415e72e38d..e509a1d4c6abd 100644 --- a/clang/test/Layout/aix-power-alignment-typedef.cpp +++ b/clang/test/Layout/aix-power-alignment-typedef.cpp @@ -19,57 +19,3 @@ int b = sizeof(A); } // namespace test1 -namespace test2 { -typedef double Dbl __attribute__((__aligned__(2))); -typedef Dbl DblArr[]; - -union U { - DblArr da; - char x; -}; - -int x = sizeof(U); - -// CHECK: 0 | union test2::U -// CHECK-NEXT: 0 | DblArr da -// CHECK-NEXT: 0 | char x -// CHECK-NEXT: | [sizeof=2, dsize=2, align=2, preferredalign=2, -// CHECK-NEXT: | nvsize=2, nvalign=2, preferrednvalign=2] - -} // namespace test2 - -namespace test3 { -typedef double DblArr[] __attribute__((__aligned__(2))); - -union U { - DblArr da; - char x; -}; - -int x = sizeof(U); - -// CHECK: 0 | union test3::U -// CHECK-NEXT: 0 | DblArr da -// CHECK-NEXT: 0 | char x -// CHECK-NEXT: | [sizeof=2, dsize=2, align=2, preferredalign=2, -// CHECK-NEXT: | nvsize=2, nvalign=2, preferrednvalign=2] - -} // namespace test3 - -namespace test4 { -typedef double Dbl __attribute__((__aligned__(2))); - -union U { - Dbl DblArr[]; - char x; -}; - -int x = sizeof(U); - -// CHECK: 0 | union test4::U -// CHECK-NEXT: 0 | Dbl[] DblArr -// CHECK-NEXT: 0 | char x -// CHECK-NEXT: | [sizeof=2, dsize=2, align=2, preferredalign=2, -// CHECK-NEXT: | nvsize=2, nvalign=2, preferrednvalign=2] - -} // namespace test4 diff --git a/clang/test/Sema/MicrosoftExtensions.c b/clang/test/Sema/MicrosoftExtensions.c index 50077d9031488..82a441e40023e 100644 --- a/clang/test/Sema/MicrosoftExtensions.c +++ b/clang/test/Sema/MicrosoftExtensions.c @@ -14,8 +14,8 @@ struct PR28407 struct C { int l; union { - int c1[]; /* expected-warning {{flexible array member 'c1' in a union is a Microsoft extension}} */ - char c2[]; /* expected-warning {{flexible array member 'c2' in a union is a Microsoft extension}} */ + int c1[]; /* expected-error {{flexible array member 'c1' in a union is not allowed}} */ + char c2[]; /* expected-error {{flexible array member 'c2' in a union is not allowed}} */ }; }; diff --git a/clang/test/Sema/init.c b/clang/test/Sema/init.c index 7aee651aba225..a487a8dda50eb 100644 --- a/clang/test/Sema/init.c +++ b/clang/test/Sema/init.c @@ -164,3 +164,6 @@ struct vortexstruct vortexvar = { "asdf" }; typedef struct { uintptr_t x : 2; } StructWithBitfield; StructWithBitfield bitfieldvar = { (uintptr_t)&bitfieldvar }; // expected-error {{initializer element is not a compile-time constant}} + +// GH61746 +union { char x[]; } r = {0}; // expected-error {{flexible array member 'x' in a union is not allowed}} diff --git a/clang/test/SemaCXX/flexible-array-test.cpp b/clang/test/SemaCXX/flexible-array-test.cpp index 19f130288b610..c52e0b50471d9 100644 --- a/clang/test/SemaCXX/flexible-array-test.cpp +++ b/clang/test/SemaCXX/flexible-array-test.cpp @@ -16,7 +16,7 @@ void QMap<Key, T>::insert(const Key &, const T &avalue) struct Rec { union { // expected-warning-re {{variable sized type '{{.*}}' not at the end of a struct or class is a GNU extension}} - int u0[]; + int u0[]; // expected-error {{flexible array member 'u0' in a union is not allowed}} }; int x; } rec; @@ -63,7 +63,7 @@ class A { union B { int s; - char c[]; + char c[]; // expected-error {{flexible array member 'c' in a union is not allowed}} }; class C { diff --git a/clang/test/SemaCXX/gnu-flags.cpp b/clang/test/SemaCXX/gnu-flags.cpp index 3cd18cabe9700..6ab619851ff90 100644 --- a/clang/test/SemaCXX/gnu-flags.cpp +++ b/clang/test/SemaCXX/gnu-flags.cpp @@ -8,34 +8,27 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wno-gnu \ // RUN: -Wgnu-anonymous-struct -Wredeclared-class-member \ -// RUN: -Wgnu-flexible-array-union-member -Wgnu-folding-constant \ -// RUN: -Wgnu-empty-struct +// RUN: -Wgnu-folding-constant -Wgnu-empty-struct // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -DALL -Wno-gnu \ // RUN: -Wgnu-anonymous-struct -Wredeclared-class-member \ -// RUN: -Wgnu-flexible-array-union-member -Wgnu-folding-constant \ -// RUN: -Wgnu-empty-struct +// RUN: -Wgnu-folding-constant -Wgnu-empty-struct // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -DALL -Wno-gnu \ // RUN: -Wgnu-anonymous-struct -Wredeclared-class-member \ -// RUN: -Wgnu-flexible-array-union-member -Wgnu-folding-constant \ -// RUN: -Wgnu-empty-struct +// RUN: -Wgnu-folding-constant -Wgnu-empty-struct // RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wgnu \ // RUN: -Wno-gnu-anonymous-struct -Wno-redeclared-class-member \ -// RUN: -Wno-gnu-flexible-array-union-member -Wno-gnu-folding-constant \ -// RUN: -Wno-gnu-empty-struct +// RUN: -Wno-gnu-folding-constant -Wno-gnu-empty-struct // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -DNONE -Wgnu \ // RUN: -Wno-gnu-anonymous-struct -Wno-redeclared-class-member \ -// RUN: -Wno-gnu-flexible-array-union-member -Wno-gnu-folding-constant \ -// RUN: -Wno-gnu-empty-struct +// RUN: -Wno-gnu-folding-constant -Wno-gnu-empty-struct // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -DNONE -Wgnu \ // RUN: -Wno-gnu-anonymous-struct -Wno-redeclared-class-member \ -// RUN: -Wno-gnu-flexible-array-union-member -Wno-gnu-folding-constant \ -// RUN: -Wno-gnu-empty-struct +// RUN: -Wno-gnu-folding-constant -Wno-gnu-empty-struct // Additional disabled tests: // %clang_cc1 -fsyntax-only -verify %s -DANONYMOUSSTRUCT -Wno-gnu -Wgnu-anonymous-struct // %clang_cc1 -fsyntax-only -verify %s -DREDECLAREDCLASSMEMBER -Wno-gnu -Wredeclared-class-member -// %clang_cc1 -fsyntax-only -verify %s -DFLEXIBLEARRAYUNIONMEMBER -Wno-gnu -Wgnu-flexible-array-union-member // %clang_cc1 -fsyntax-only -verify %s -DFOLDINGCONSTANT -Wno-gnu -Wgnu-folding-constant // %clang_cc1 -fsyntax-only -verify %s -DEMPTYSTRUCT -Wno-gnu -Wgnu-empty-struct @@ -70,19 +63,6 @@ namespace rcm { }; } - -#if ALL || FLEXIBLEARRAYUNIONMEMBER -// expected-warning@+6 {{flexible array member 'c1' in a union is a GNU extension}} -#endif - -struct faum { - int l; - union { - int c1[]; - }; -}; - - #if (ALL || FOLDINGCONSTANT) && (__cplusplus <= 199711L) // C++03 or earlier modes // expected-warning@+4 {{in-class initializer for static data member is not a constant expression; folding it to a constant is a GNU extension}} #endif diff --git a/clang/test/SemaObjCXX/flexible-array.mm b/clang/test/SemaObjCXX/flexible-array.mm index 5537876c3039f..831d6667fabd1 100644 --- a/clang/test/SemaObjCXX/flexible-array.mm +++ b/clang/test/SemaObjCXX/flexible-array.mm @@ -4,7 +4,7 @@ union VariableSizeUnion { int s; - char c[]; + char c[]; //expected-error {{flexible array member 'c' in a union is not allowed}} }; @interface LastUnionIvar { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits