]> granicus.if.org Git - clang/commitdiff
Recognition of empty structures and unions is moved to semantic stage
authorSerge Pavlov <sepavloff@gmail.com>
Sat, 8 Jun 2013 13:29:58 +0000 (13:29 +0000)
committerSerge Pavlov <sepavloff@gmail.com>
Sat, 8 Jun 2013 13:29:58 +0000 (13:29 +0000)
Differential Revision: http://llvm-reviews.chandlerc.com/D586

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

include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
lib/Parse/ParseDecl.cpp
lib/Sema/SemaDecl.cpp
test/Parser/declarators.c
test/Sema/array-init.c
test/Sema/empty1.c [new file with mode: 0644]
test/Sema/empty2.c [new file with mode: 0644]

index 74b94d341374d596d7f8e9b91560a0a9cdae2bb2..44d3acfc17e8cab8e32a4b73a14de17aee29ebda 100644 (file)
@@ -57,10 +57,6 @@ def ext_integer_complex : Extension<
   "complex integer types are a GNU extension">, InGroup<GNU>;
 def ext_thread_before : Extension<"'__thread' before '%0'">;
 
-def ext_empty_struct_union : Extension<
-  "empty %select{struct|union}0 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 error_empty_enum : Error<"use of empty enum">;
 def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">;
 def err_invalid_short_spec : Error<"'short %0' is invalid">;
index 40ef1ac75aef9ef102e7ca927c17f3946ae7d328..f79233e52e16218facea20e5cd00d04845970a8f 100644 (file)
@@ -5464,6 +5464,15 @@ def err_expected_ident_or_lparen : Error<"expected identifier or '('">;
 
 def err_typecheck_cond_incompatible_operands_null : Error<
   "non-pointer operand type %0 incompatible with %select{NULL|nullptr}1">;
+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++">,
+  InGroup<CXXCompat>, DefaultIgnore;
 } // End of general sema category.
 
 // inline asm.
index 03e4879db68826cce890ed0711836aad364f4976..b3e8412dcf21cd1bedf62ed2d7fc6fa4fdc19881 100644 (file)
@@ -3216,12 +3216,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
   ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
   Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
 
-  // Empty structs are an extension in C (C99 6.7.2.1p7).
-  if (Tok.is(tok::r_brace)) {
-    Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union);
-    Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union);
-  }
-
   SmallVector<Decl *, 32> FieldDecls;
 
   // While we still have something to read, read the declarations in the struct.
index 7be376e60f07d165a2ac15c6dc69c5baf2971b5d..e6a89461b4593a57ea39e614f46d1dc374fe9cd1 100644 (file)
@@ -11235,6 +11235,41 @@ void Sema::ActOnFields(Scope* S,
 
     if (Record->hasAttrs())
       CheckAlignasUnderalignment(Record);
+
+    // Check if the structure/union declaration is a language extension.
+    if (!getLangOpts().CPlusPlus) {
+      bool ZeroSize = true;
+      bool UnnamedOnly = true;
+      unsigned UnnamedCnt = 0;
+      for (RecordDecl::field_iterator I = Record->field_begin(),
+                                      E = Record->field_end(); UnnamedOnly && I != E; ++I) {
+        if (I->isUnnamedBitfield()) {
+          UnnamedCnt++;
+          if (I->getBitWidthValue(Context) > 0)
+            ZeroSize = false;
+        } else {
+          UnnamedOnly = 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();
+      }
+
+      // Structs without named members are extension in C (C99 6.7.2.1p7), but
+      // are accepted by GCC.
+      if (UnnamedOnly) {
+        if (UnnamedCnt == 0)
+          Diag(RecLoc, diag::ext_empty_struct_union) << Record->isUnion();
+        else
+          Diag(RecLoc, diag::ext_no_named_members_in_struct_union) << Record->isUnion();
+      }
+    }
   } else {
     ObjCIvarDecl **ClsFields =
       reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
index f63b59f7caa64bf0a236bacbfa1a451018a642ae..210a8e2befc7bc47d5a0f990a01a01ad6ac69053 100644 (file)
@@ -108,7 +108,8 @@ void test18() {
 }
 
 enum E1 { e1 }: // expected-error {{expected ';'}}
-struct EnumBitfield {
+struct EnumBitfield { // expected-warning {{struct without named members is a GNU extension}}
   enum E2 { e2 } : 4; // ok
   struct S { int n; }: // expected-error {{expected ';'}}
+
 };
index f92852f341b66db3a189940bc15103b42fc34298..ae2c7425662be11604ec79888725e7e88a8cda53 100644 (file)
@@ -226,7 +226,8 @@ void emptyInit() {struct {} x[] = {6};} //expected-warning{{empty struct is a GN
 // expected-error{{initializer for aggregate with no elements}}
 
 void noNamedInit() {
-  struct {int:5;} x[] = {6}; //expected-error{{initializer for aggregate with no elements}}
+  struct {int:5;} x[] = {6}; //expected-error{{initializer for aggregate with no elements}} \
+// expected-warning {{struct without named members is a GNU extension}}
 }
 struct {int a; int:5;} noNamedImplicit[] = {1,2,3};
 int noNamedImplicitCheck[sizeof(noNamedImplicit) == 3 * sizeof(*noNamedImplicit) ? 1 : -1];
diff --git a/test/Sema/empty1.c b/test/Sema/empty1.c
new file mode 100644 (file)
index 0000000..cd4aca8
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -Wc++-compat
+
+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++}}
+  int : 0;
+};
+
+union emp_4 { // expected-warning {{union with only bit-fields of width 0 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++}}
+  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++}}
+  int : 0;
+  int : 0;
+};
diff --git a/test/Sema/empty2.c b/test/Sema/empty2.c
new file mode 100644 (file)
index 0000000..68da5a8
--- /dev/null
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
+
+struct emp_1 { // expected-warning {{empty struct is a GNU extension}}
+};
+
+union emp_2 { // expected-warning {{empty union is a GNU extension}}
+};
+
+struct emp_3 { // expected-warning {{struct without named members is a GNU extension}}
+  int : 0;
+};
+
+union emp_4 { // expected-warning {{union without named members is a GNU extension}}
+  int : 0;
+};
+
+struct emp_5 { // expected-warning {{struct without named members is a GNU extension}}
+  int : 0;
+  int : 0;
+};
+
+union emp_6 { // expected-warning {{union without named members is a GNU extension}}
+  int : 0;
+  int : 0;
+};
+
+struct nonamed_1 { // expected-warning {{struct without named members is a GNU extension}}
+  int : 4;
+};
+
+union nonamed_2 { // expected-warning {{union without named members is a GNU extension}}
+  int : 4;
+};
+
+struct nonamed_3 { // expected-warning {{struct without named members is a GNU extension}}
+  int : 4;
+  unsigned int : 4;
+};
+
+union nonamed_4 { // expected-warning {{union without named members is a GNU extension}}
+  int : 4;
+  unsigned int : 4;
+};