r215347 - Sema: Handle declspecs without declarators in records properly in C mode

David Majnemer david.majnemer at gmail.com
Mon Aug 11 00:29:54 PDT 2014


Author: majnemer
Date: Mon Aug 11 02:29:54 2014
New Revision: 215347

URL: http://llvm.org/viewvc/llvm-project?rev=215347&view=rev
Log:
Sema: Handle declspecs without declarators in records properly in C mode

We had two bugs:
- We wouldn't properly warn when a struct/union/enum was mentioned
  inside of a record definition if no declarator was provided.  We
  should have mentioned that this declaration declares nothing.
- We didn't properly support Microsoft's extension where certain
  declspecs without declarators would act as anonymous structs/unions.
  * We completely ignored the case where such a declspec could be a
    union.
  * We didn't properly handle the case where a record was defined inside
    another record:
      struct X {
        int a;
        struct Y {
          int b;
        };
      };

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/Parser/declarators.c
    cfe/trunk/test/Sema/MicrosoftExtensions.c
    cfe/trunk/test/Sema/anonymous-struct-union.c
    cfe/trunk/test/SemaObjC/ivar-lookup.m

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=215347&r1=215346&r2=215347&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Aug 11 02:29:54 2014
@@ -6149,8 +6149,9 @@ def err_anonymous_record_bad_member : Er
 def err_anonymous_record_nonpublic_member : Error<
   "anonymous %select{struct|union}0 cannot contain a "
   "%select{private|protected}1 data member">;
-def ext_ms_anonymous_struct : ExtWarn<
-  "anonymous structs are a Microsoft extension">, InGroup<Microsoft>;
+def ext_ms_anonymous_record : ExtWarn<
+  "anonymous %select{structs|unions}0 are a Microsoft extension">,
+  InGroup<Microsoft>;
 
 // C++ local classes
 def err_reference_to_local_var_in_enclosing_function : Error<

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=215347&r1=215346&r2=215347&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Aug 11 02:29:54 2014
@@ -3444,21 +3444,36 @@ Decl *Sema::ParsedFreeStandingDeclSpec(S
     }
   }
 
-  // Check for Microsoft C extension: anonymous struct member.
-  if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus &&
-      CurContext->isRecord() &&
+  // C11 6.7.2.1p2:
+  //   A struct-declaration that does not declare an anonymous structure or
+  //   anonymous union shall contain a struct-declarator-list.
+  if (!getLangOpts().CPlusPlus && CurContext->isRecord() &&
       DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
-    // Handle 2 kinds of anonymous struct:
+    // Check for Microsoft C extension: anonymous struct/union member.
+    // Handle 2 kinds of anonymous struct/union:
     //   struct STRUCT;
+    //   union UNION;
     // and
     //   STRUCT_TYPE;  <- where STRUCT_TYPE is a typedef struct.
-    RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag);
-    if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) ||
-        (DS.getTypeSpecType() == DeclSpec::TST_typename &&
-         DS.getRepAsType().get()->isStructureType())) {
-      Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct)
-        << DS.getSourceRange();
-      return BuildMicrosoftCAnonymousStruct(S, DS, Record);
+    //   UNION_TYPE;   <- where UNION_TYPE is a typedef union.
+    if ((Tag && Tag->getDeclName()) ||
+        DS.getTypeSpecType() == DeclSpec::TST_typename) {
+      RecordDecl *Record = nullptr;
+      if (Tag)
+        Record = dyn_cast<RecordDecl>(Tag);
+      else if (const RecordType *RT =
+                   DS.getRepAsType().get()->getAsStructureType())
+        Record = RT->getDecl();
+      else if (const RecordType *UT = DS.getRepAsType().get()->getAsUnionType())
+        Record = UT->getDecl();
+
+      if (Record && getLangOpts().MicrosoftExt) {
+        Diag(DS.getLocStart(), diag::ext_ms_anonymous_record)
+          << Record->isUnion() << DS.getSourceRange();
+        return BuildMicrosoftCAnonymousStruct(S, DS, Record);
+      }
+
+      DeclaresAnything = false;
     }
   }
 
@@ -3999,15 +4014,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(
 ///
 /// void foo() {
 ///   B var;
-///   var.a = 3; 
+///   var.a = 3;
 /// }
 ///
 Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
                                            RecordDecl *Record) {
-  
-  // If there is no Record, get the record via the typedef.
-  if (!Record)
-    Record = DS.getRepAsType().get()->getAsStructureType()->getDecl();
+  assert(Record && "expected a record!");
 
   // Mock up a declarator.
   Declarator Dc(DS, Declarator::TypeNameContext);

Modified: cfe/trunk/test/Parser/declarators.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/declarators.c?rev=215347&r1=215346&r2=215347&view=diff
==============================================================================
--- cfe/trunk/test/Parser/declarators.c (original)
+++ cfe/trunk/test/Parser/declarators.c Mon Aug 11 02:29:54 2014
@@ -113,6 +113,7 @@ enum E1 { e1 }: // expected-error {{expe
 struct EnumBitfield { // expected-warning {{struct without named members is a GNU extension}}
   enum E2 { e2 } : 4; // ok
   struct S { int n; }: // expected-error {{expected ';'}}
+                       // expected-warning at -1 {{declaration does not declare anything}}
 
 };
 

Modified: cfe/trunk/test/Sema/MicrosoftExtensions.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/MicrosoftExtensions.c?rev=215347&r1=215346&r2=215347&view=diff
==============================================================================
--- cfe/trunk/test/Sema/MicrosoftExtensions.c (original)
+++ cfe/trunk/test/Sema/MicrosoftExtensions.c Mon Aug 11 02:29:54 2014
@@ -39,9 +39,24 @@ struct nested2 {
   NESTED1;  // expected-warning {{anonymous structs are a Microsoft extension}}
 };
 
+struct nested3 {
+  long d;
+  struct nested4 { // expected-warning {{anonymous structs are a Microsoft extension}}
+    long e;
+  };
+  union nested5 { // expected-warning {{anonymous unions are a Microsoft extension}}
+    long f;
+  };
+};
+
+typedef union nested6 {
+  long f;
+} NESTED6;
+
 struct test {
   int c;
   struct nested2;   // expected-warning {{anonymous structs are a Microsoft extension}}
+  NESTED6;   // expected-warning {{anonymous unions are a Microsoft extension}}
 };
 
 void foo()

Modified: cfe/trunk/test/Sema/anonymous-struct-union.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/anonymous-struct-union.c?rev=215347&r1=215346&r2=215347&view=diff
==============================================================================
--- cfe/trunk/test/Sema/anonymous-struct-union.c (original)
+++ cfe/trunk/test/Sema/anonymous-struct-union.c Mon Aug 11 02:29:54 2014
@@ -37,7 +37,7 @@ void test_unqual_references(struct X x,
 
 struct Redecl {
   int x; // expected-note{{previous declaration is here}}
-  struct y { };
+  struct y { }; // expected-warning{{declaration does not declare anything}}
 
   union {
     int x; // expected-error{{member of anonymous union redeclares 'x'}}

Modified: cfe/trunk/test/SemaObjC/ivar-lookup.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/ivar-lookup.m?rev=215347&r1=215346&r2=215347&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/ivar-lookup.m (original)
+++ cfe/trunk/test/SemaObjC/ivar-lookup.m Mon Aug 11 02:29:54 2014
@@ -99,9 +99,9 @@ extern struct foo x;
   };
   struct S {
     __typeof(myStatus) __in;  // fails.
-    struct S1 {
+    struct S1 { // expected-warning {{declaration does not declare anything}}
       __typeof(myStatus) __in;  // fails.
-      struct S {
+      struct S { // expected-warning {{declaration does not declare anything}}
         __typeof(myStatus) __in;  // fails.
       };
     };





More information about the cfe-commits mailing list