[clang] 22e2db6 - [clang] Reject flexible array member in a union in C++

Mariya Podchishchaeva via cfe-commits cfe-commits at lists.llvm.org
Wed May 3 05:59:05 PDT 2023


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 at +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 at +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 {


        


More information about the cfe-commits mailing list