]> granicus.if.org Git - clang/commitdiff
Clean up empty struct/union recognition.
authorSerge Pavlov <sepavloff@gmail.com>
Mon, 17 Jun 2013 17:18:51 +0000 (17:18 +0000)
committerSerge Pavlov <sepavloff@gmail.com>
Mon, 17 Jun 2013 17:18:51 +0000 (17:18 +0000)
Make use of getTypeSizeInChars to detect structs/unions of zero size. It allows
more accurate detection of types of zero size. It however has a side effect -
sequence of used types may change, that is why the test 'override-layout' was
modified.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184088 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDecl.cpp
test/CodeGen/override-layout.c
test/Sema/empty1.c

index cb207a6c6dc110c6f34b326fb5a0ab8651990e3f..7be10c8e70683e2531ffd383e5628c7a8c521ee7 100644 (file)
@@ -5493,10 +5493,8 @@ def ext_empty_struct_union : Extension<
   "empty %select{struct|union}0 is a GNU extension">, InGroup<GNU>;
 def ext_no_named_members_in_struct_union : Extension<
   "%select{struct|union}0 without named members is a GNU extension">, InGroup<GNU>;
-def warn_empty_struct_union_compat : Warning<"empty %select{struct|union}0 "
-  "has size 0 in C, size 1 in C++">, InGroup<CXXCompat>, DefaultIgnore;
-def warn_zero_size_struct_union_compat : Warning<"%select{struct|union}0 "
-  "with only bit-fields of width 0 has size 0 in C, size 1 in C++">,
+def warn_zero_size_struct_union_compat : Warning<"%select{|empty }0"
+  "%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">,
   InGroup<CXXCompat>, DefaultIgnore;
 } // End of general sema category.
 
index 92e0042bccd22e388f9ac8cc729e7e4d29dd81cb..e62834ba1da3f12f13ad8974a9372648a717ac76 100644 (file)
@@ -11236,32 +11236,34 @@ void Sema::ActOnFields(Scope* S,
     // Check if the structure/union declaration is a language extension.
     if (!getLangOpts().CPlusPlus) {
       bool ZeroSize = true;
-      bool UnnamedOnly = true;
-      unsigned UnnamedCnt = 0;
+      bool IsEmpty = true;
+      unsigned NonBitFields = 0;
       for (RecordDecl::field_iterator I = Record->field_begin(),
-                                      E = Record->field_end(); UnnamedOnly && I != E; ++I) {
+                                      E = Record->field_end();
+           (NonBitFields == 0 || ZeroSize) && I != E; ++I) {
+        IsEmpty = false;
         if (I->isUnnamedBitfield()) {
-          UnnamedCnt++;
           if (I->getBitWidthValue(Context) > 0)
             ZeroSize = false;
         } else {
-          UnnamedOnly = ZeroSize = false;
+          ++NonBitFields;
+          QualType FieldType = I->getType();
+          if (FieldType->isIncompleteType() ||
+              !Context.getTypeSizeInChars(FieldType).isZero())
+            ZeroSize = false;
         }
       }
 
       // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
       // C++.
-      if (ZeroSize) {
-        if (UnnamedCnt == 0)
-          Diag(RecLoc, diag::warn_empty_struct_union_compat) << Record->isUnion();
-        else
-          Diag(RecLoc, diag::warn_zero_size_struct_union_compat) << Record->isUnion();
-      }
+      if (ZeroSize)
+        Diag(RecLoc, diag::warn_zero_size_struct_union_compat) << IsEmpty
+            << Record->isUnion() << (NonBitFields > 1);
 
       // Structs without named members are extension in C (C99 6.7.2.1p7), but
       // are accepted by GCC.
-      if (UnnamedOnly) {
-        if (UnnamedCnt == 0)
+      if (NonBitFields == 0) {
+        if (IsEmpty)
           Diag(RecLoc, diag::ext_empty_struct_union) << Record->isUnion();
         else
           Diag(RecLoc, diag::ext_no_named_members_in_struct_union) << Record->isUnion();
index 99c2cd656ec08de1ce128a309f3a7f71e4a3c9b7..8a108a9f50c9a9993954eff3013f04edafb437ba 100644 (file)
@@ -19,24 +19,32 @@ struct X0 {
   int x[6] PACKED; 
 };
 
+void use_X0() { struct X0 x0; x0.x[5] = sizeof(struct X0); };
+
 // CHECK: Type: struct X1
 struct X1 { 
   char x[13]; 
   struct X0 y; 
 } PACKED;
 
+void use_X1() { struct X1 x1; x1.x[5] = sizeof(struct X1); };
+
 // CHECK: Type: struct X2
 struct PACKED X2 {
   short x;
   int y;
 };
 
+void use_X2() { struct X2 x2; x2.y = sizeof(struct X2); };
+
 // CHECK: Type: struct X3
 struct X3 {
   short x PACKED;
   int y;
 };
 
+void use_X3() { struct X3 x3; x3.y = sizeof(struct X3); };
+
 #pragma pack(push,2)
 // CHECK: Type: struct X4
 struct X4 {
@@ -45,18 +53,26 @@ struct X4 {
 };
 #pragma pack(pop)
 
+void use_X4() { struct X4 x4; x4.y = sizeof(struct X4); };
+
 // CHECK: Type: struct X5
 struct PACKED X5 { double a[19];  signed char b; };
 
+void use_X5() { struct X5 x5; x5.b = sizeof(struct X5); };
+
 // CHECK: Type: struct X6
 struct PACKED X6 { long double a; char b; };
 
+void use_X6() { struct X6 x6; x6.b = sizeof(struct X6); };
+
 // CHECK: Type: struct X7
 struct X7 {
         unsigned x;
         unsigned char y;
 } PACKED;
 
+void use_X7() { struct X7 x7; x7.y = x7.x = sizeof(struct X7); }
+
 // CHECK: Type: union X8
 union X8 {
   struct X7 x;
@@ -114,32 +130,6 @@ struct ALIGNED16 X16 {
 };
 
 void use_structs() {
-  struct X0 x0;
-  x0.x[5] = sizeof(struct X0);
-
-  struct X1 x1;
-  x1.x[5] = sizeof(struct X1);
-
-  struct X2 x2;
-  x2.y = sizeof(struct X2);
-
-  struct X3 x3;
-  x3.y = sizeof(struct X3);
-
-  struct X4 x4;
-  x4.y = sizeof(struct X4);
-
-  struct X5 x5;
-  x5.b = sizeof(struct X5);
-
-  struct X6 x6;
-  x6.b = sizeof(struct X6);
-
-  struct X7 x7;
-  typedef int X7array[sizeof(struct X7)];
-  x7.x = sizeof(struct X7);
-  x7.y = x7.x;
-
   union X8 x8;
   typedef int X8array[sizeof(union X8)];
   x8.y = sizeof(union X8);
index cd4aca8e473253208b7464d30760f8f890dd4033..d716ba52bb4fc27d67daa17936ca69276233daaa 100644 (file)
@@ -6,20 +6,33 @@ struct emp_1 { // expected-warning {{empty struct has size 0 in C, size 1 in C++
 union emp_2 { // expected-warning {{empty union has size 0 in C, size 1 in C++}}
 };
 
-struct emp_3 { // expected-warning {{struct with only bit-fields of width 0 has size 0 in C, size 1 in C++}}
+struct emp_3 { // expected-warning {{struct has size 0 in C, size 1 in C++}}
   int : 0;
 };
 
-union emp_4 { // expected-warning {{union with only bit-fields of width 0 has size 0 in C, size 1 in C++}}
+union emp_4 { // expected-warning {{union has size 0 in C, size 1 in C++}}
   int : 0;
 };
 
-struct emp_5 { // expected-warning {{struct with only bit-fields of width 0 has size 0 in C, size 1 in C++}}
+struct emp_5 { // expected-warning {{struct has size 0 in C, size 1 in C++}}
   int : 0;
   int : 0;
 };
 
-union emp_6 { // expected-warning {{union with only bit-fields of width 0 has size 0 in C, size 1 in C++}}
+union emp_6 { // expected-warning {{union has size 0 in C, size 1 in C++}}
   int : 0;
   int : 0;
 };
+
+struct emp_7 { // expected-warning {{struct has size 0 in C, size 1 in C++}}
+  struct emp_1 f1;
+};
+
+union emp_8 { // expected-warning {{union has size 0 in C, size 1 in C++}}
+  struct emp_1 f1;
+};
+
+struct emp_9 { // expected-warning {{struct has size 0 in C, non-zero size in C++}}
+  struct emp_1 f1;
+  union emp_2 f2;
+};