diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 416d816796514..8d0a9c96a9579 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -55,7 +55,6 @@ 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 4313948515752..0ee43fb8837a1 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -267,6 +267,7 @@ 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">; @@ -1136,7 +1137,7 @@ def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct, GNUConditionalOmittedOperand, GNUDesignator, GNUEmptyStruct, VLAExtension, GNUFlexibleArrayInitializer, - GNUFoldingConstant, + GNUFlexibleArrayUnionMember, 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 c3cb6740a5131..17585752edf8e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6232,9 +6232,6 @@ def ext_variable_sized_type_in_struct : ExtWarn< def ext_c99_flexible_array_member : Extension< "flexible array members are a C99 feature">, InGroup; -// 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">; @@ -6257,10 +6254,15 @@ def ext_flexible_array_empty_aggregate_ms : Extension< InGroup; 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; 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; +def ext_flexible_array_union_gnu : Extension< + "flexible array member %0 in a union is a GNU extension">, InGroup; 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 a5bab074d08e3..4cdf2982b99d5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -18690,7 +18690,8 @@ 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 as the sole element of a struct/class. + // It will accept flexible array in union and also + // 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) @@ -18700,7 +18701,11 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, EnclosingDecl->setInvalidDecl(); continue; } else if (Record->isUnion()) - DiagID = diag::err_flexible_array_union; + DiagID = getLangOpts().MicrosoftExt + ? diag::ext_flexible_array_union_ms + : getLangOpts().CPlusPlus + ? diag::ext_flexible_array_union_gnu + : 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 c8beae3f52e39..2d5d31f99e500 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->isUnion() && RDecl->hasFlexibleArrayMember()) + if (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 e509a1d4c6abd..908415e72e38d 100644 --- a/clang/test/Layout/aix-power-alignment-typedef.cpp +++ b/clang/test/Layout/aix-power-alignment-typedef.cpp @@ -19,3 +19,57 @@ 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 82a441e40023e..50077d9031488 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-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}} */ + 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}} */ }; }; diff --git a/clang/test/Sema/init.c b/clang/test/Sema/init.c index a487a8dda50eb..7aee651aba225 100644 --- a/clang/test/Sema/init.c +++ b/clang/test/Sema/init.c @@ -164,6 +164,3 @@ 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 c52e0b50471d9..19f130288b610 100644 --- a/clang/test/SemaCXX/flexible-array-test.cpp +++ b/clang/test/SemaCXX/flexible-array-test.cpp @@ -16,7 +16,7 @@ void QMap::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[]; // expected-error {{flexible array member 'u0' in a union is not allowed}} + int u0[]; }; int x; } rec; @@ -63,7 +63,7 @@ class A { union B { int s; - char c[]; // expected-error {{flexible array member 'c' in a union is not allowed}} + char c[]; }; class C { diff --git a/clang/test/SemaCXX/gnu-flags.cpp b/clang/test/SemaCXX/gnu-flags.cpp index 6ab619851ff90..3cd18cabe9700 100644 --- a/clang/test/SemaCXX/gnu-flags.cpp +++ b/clang/test/SemaCXX/gnu-flags.cpp @@ -8,27 +8,34 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -DALL -Wno-gnu \ // RUN: -Wgnu-anonymous-struct -Wredeclared-class-member \ -// RUN: -Wgnu-folding-constant -Wgnu-empty-struct +// RUN: -Wgnu-flexible-array-union-member -Wgnu-folding-constant \ +// RUN: -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-folding-constant -Wgnu-empty-struct +// RUN: -Wgnu-flexible-array-union-member -Wgnu-folding-constant \ +// RUN: -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-folding-constant -Wgnu-empty-struct +// RUN: -Wgnu-flexible-array-union-member -Wgnu-folding-constant \ +// RUN: -Wgnu-empty-struct // RUN: %clang_cc1 -fsyntax-only -verify %s -DNONE -Wgnu \ // RUN: -Wno-gnu-anonymous-struct -Wno-redeclared-class-member \ -// RUN: -Wno-gnu-folding-constant -Wno-gnu-empty-struct +// RUN: -Wno-gnu-flexible-array-union-member -Wno-gnu-folding-constant \ +// RUN: -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-folding-constant -Wno-gnu-empty-struct +// RUN: -Wno-gnu-flexible-array-union-member -Wno-gnu-folding-constant \ +// RUN: -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-folding-constant -Wno-gnu-empty-struct +// RUN: -Wno-gnu-flexible-array-union-member -Wno-gnu-folding-constant \ +// RUN: -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 @@ -63,6 +70,19 @@ 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 831d6667fabd1..5537876c3039f 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[]; //expected-error {{flexible array member 'c' in a union is not allowed}} + char c[]; }; @interface LastUnionIvar {