[cfe-commits] r120000 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/Sema/SemaDecl.cpp test/CodeGen/ms-anonymous-struct.c test/Sema/MicrosoftExtensions.c

Francois Pichet pichet2000 at gmail.com
Mon Nov 22 22:07:28 PST 2010


Author: fpichet
Date: Tue Nov 23 00:07:27 2010
New Revision: 120000

URL: http://llvm.org/viewvc/llvm-project?rev=120000&view=rev
Log:
Microsoft C anonymous struct implementation.
Documentation: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx

Added:
    cfe/trunk/test/CodeGen/ms-anonymous-struct.c
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/Sema/MicrosoftExtensions.c

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=120000&r1=119999&r2=120000&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Nov 23 00:07:27 2010
@@ -3030,6 +3030,8 @@
 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>;
 
 // C++ local classes
 def err_reference_to_local_var_in_enclosing_function : Error<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=120000&r1=119999&r2=120000&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Nov 23 00:07:27 2010
@@ -787,6 +787,9 @@
                                     AccessSpecifier AS,
                                     RecordDecl *Record);
 
+  Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, 
+                                       RecordDecl *Record);
+
   bool isAcceptableTagRedeclaration(const TagDecl *Previous,
                                     TagTypeKind NewTag,
                                     SourceLocation NewTagLoc,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=120000&r1=119999&r2=120000&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Nov 23 00:07:27 2010
@@ -1646,12 +1646,24 @@
       Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators)
         << DS.getSourceRange();
     }
+  }
 
-    // Microsoft allows unnamed struct/union fields. Don't complain
-    // about them.
-    // FIXME: Should we support Microsoft's extensions in this area?
-    if (Record->getDeclName() && getLangOptions().Microsoft)
-      return Tag;
+  // Check for Microsoft C extension: anonymous struct.
+  if (getLangOptions().Microsoft && !getLangOptions().CPlusPlus &&
+      CurContext->isRecord() &&
+      DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
+    // Handle 2 kinds of anonymous struct:
+    //   struct STRUCT;
+    // and
+    //   STRUCT_TYPE;  <- where STRUCT_TYPE is a typedef struct.
+    RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag);
+    if ((Record && Record->getDeclName() && !Record->isDefinition()) ||
+        (DS.getTypeSpecType() == DeclSpec::TST_typename &&
+         DS.getRepAsType().get()->isStructureType())) {
+      Diag(DS.getSourceRange().getBegin(), diag::ext_ms_anonymous_struct)
+        << DS.getSourceRange();
+      return BuildMicrosoftCAnonymousStruct(S, DS, Record);
+    }
   }
   
   if (getLangOptions().CPlusPlus && 
@@ -1749,18 +1761,23 @@
                                                 DeclContext *Owner,
                                                 RecordDecl *AnonRecord,
                                                 AccessSpecifier AS,
-                              llvm::SmallVector<NamedDecl*, 2> &Chaining) {
+                              llvm::SmallVector<NamedDecl*, 2> &Chaining,
+                                                      bool MSAnonStruct) {
   unsigned diagKind
     = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl
                             : diag::err_anonymous_struct_member_redecl;
 
   bool Invalid = false;
-  for (RecordDecl::field_iterator F = AnonRecord->field_begin(),
-                               FEnd = AnonRecord->field_end();
-       F != FEnd; ++F) {
-    if ((*F)->getDeclName()) {
-      if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, (*F)->getDeclName(),
-                                       (*F)->getLocation(), diagKind)) {
+
+  // Look every FieldDecl and IndirectFieldDecl with a name.
+  for (RecordDecl::decl_iterator D = AnonRecord->decls_begin(),
+                               DEnd = AnonRecord->decls_end();
+       D != DEnd; ++D) {
+    if ((isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D)) &&
+        cast<NamedDecl>(*D)->getDeclName()) {
+      ValueDecl *VD = cast<ValueDecl>(*D);
+      if (CheckAnonMemberRedeclaration(SemaRef, S, Owner, VD->getDeclName(),
+                                       VD->getLocation(), diagKind)) {
         // C++ [class.union]p2:
         //   The names of the members of an anonymous union shall be
         //   distinct from the names of any other entity in the
@@ -1772,7 +1789,14 @@
         //   definition, the members of the anonymous union are
         //   considered to have been defined in the scope in which the
         //   anonymous union is declared.
-        Chaining.push_back(*F);
+        unsigned OldChainingSize = Chaining.size();
+        if (IndirectFieldDecl *IF = dyn_cast<IndirectFieldDecl>(VD))
+          for (IndirectFieldDecl::chain_iterator PI = IF->chain_begin(),
+               PE = IF->chain_end(); PI != PE; ++PI)
+            Chaining.push_back(*PI);
+        else
+          Chaining.push_back(VD);
+
         assert(Chaining.size() >= 2);
         NamedDecl **NamedChain =
           new (SemaRef.Context)NamedDecl*[Chaining.size()];
@@ -1780,8 +1804,8 @@
           NamedChain[i] = Chaining[i];
 
         IndirectFieldDecl* IndirectField =
-          IndirectFieldDecl::Create(SemaRef.Context, Owner, F->getLocation(),
-                                    F->getIdentifier(), F->getType(),
+          IndirectFieldDecl::Create(SemaRef.Context, Owner, VD->getLocation(),
+                                    VD->getIdentifier(), VD->getType(),
                                     NamedChain, Chaining.size());
 
         IndirectField->setAccess(AS);
@@ -1789,20 +1813,10 @@
         SemaRef.PushOnScopeChains(IndirectField, S);
 
         // That includes picking up the appropriate access specifier.
-        if (AS != AS_none) (*F)->setAccess(AS);
+        if (AS != AS_none) IndirectField->setAccess(AS);
 
-        Chaining.pop_back();
+        Chaining.resize(OldChainingSize);
       }
-    } else if (const RecordType *InnerRecordType
-                 = (*F)->getType()->getAs<RecordType>()) {
-      RecordDecl *InnerRecord = InnerRecordType->getDecl();
-
-      Chaining.push_back(*F);
-      if (InnerRecord->isAnonymousStructOrUnion())
-        Invalid = Invalid ||
-          InjectAnonymousStructOrUnionMembers(SemaRef, S, Owner,
-                                              InnerRecord, AS, Chaining);
-      Chaining.pop_back();
     }
   }
 
@@ -1847,7 +1861,7 @@
   llvm_unreachable("unknown storage class specifier");
 }
 
-/// ActOnAnonymousStructOrUnion - Handle the declaration of an
+/// BuildAnonymousStructOrUnion - Handle the declaration of an
 /// anonymous structure or union. Anonymous unions are a C++ feature
 /// (C++ [class.union]) and a GNU C extension; anonymous structures
 /// are a GNU C and GNU C++ extension.
@@ -2020,7 +2034,8 @@
   llvm::SmallVector<NamedDecl*, 2> Chain;
   Chain.push_back(Anon);
 
-  if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, Chain))
+  if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS,
+                                          Chain, false))
     Invalid = true;
 
   // Mark this as an anonymous struct/union type. Note that we do not
@@ -2037,6 +2052,57 @@
   return Anon;
 }
 
+/// BuildMicrosoftCAnonymousStruct - Handle the declaration of an
+/// Microsoft C anonymous structure.
+/// Ref: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx
+/// Example:
+///
+/// struct A { int a; };
+/// struct B { struct A; int b; };
+///
+/// void foo() {
+///   B var;
+///   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();
+
+  // Mock up a declarator.
+  Declarator Dc(DS, Declarator::TypeNameContext);
+  TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
+  assert(TInfo && "couldn't build declarator info for anonymous struct");
+
+  // Create a declaration for this anonymous struct.
+  NamedDecl* Anon = FieldDecl::Create(Context,
+                             cast<RecordDecl>(CurContext),
+                             DS.getSourceRange().getBegin(),
+                             /*IdentifierInfo=*/0,
+                             Context.getTypeDeclType(Record),
+                             TInfo,
+                             /*BitWidth=*/0, /*Mutable=*/false);
+  Anon->setImplicit();
+
+  // Add the anonymous struct object to the current context.
+  CurContext->addDecl(Anon);
+
+  // Inject the members of the anonymous struct into the current
+  // context and into the identifier resolver chain for name lookup
+  // purposes.
+  llvm::SmallVector<NamedDecl*, 2> Chain;
+  Chain.push_back(Anon);
+
+  if (InjectAnonymousStructOrUnionMembers(*this, S, CurContext,
+                                          Record->getDefinition(),
+                                          AS_none, Chain, true))
+    Anon->setInvalidDecl();
+
+  return Anon;
+}
 
 /// GetNameForDeclarator - Determine the full declaration name for the
 /// given Declarator.

Added: cfe/trunk/test/CodeGen/ms-anonymous-struct.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/ms-anonymous-struct.c?rev=120000&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/ms-anonymous-struct.c (added)
+++ cfe/trunk/test/CodeGen/ms-anonymous-struct.c Tue Nov 23 00:07:27 2010
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -fms-extensions -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: %struct.nested1 = type { i32, i32 }
+typedef struct nested1 {
+    long a1;
+    long b1;
+} NESTED1;
+
+// CHECK: %struct.nested2 = type { i32, %struct.nested1, i32 }
+struct nested2 {
+    long a;
+    NESTED1; 
+    long b;
+};
+
+// CHECK: %struct.test = type { i32, %struct.nested2, i32 }
+struct test {
+    int    x;
+    struct nested2; 
+    int    y;
+};
+
+
+void foo()
+{
+  // CHECK: %var = alloca %struct.test, align 4
+  struct test var;
+
+  // CHECK: getelementptr inbounds %struct.test* %var, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 0
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var.a;
+
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %var, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 2
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var.b;
+
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %var, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested1* %{{.*}}, i32 0, i32 0
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var.a1;
+
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}var, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested1* %{{.*}}, i32 0, i32 1
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var.b1;
+
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %var, i32 0, i32 0
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var.x;
+
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %var, i32 0, i32 2
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var.y;
+}
+
+void foo2(struct test* var)
+{
+  // CHECK: alloca %struct.test*, align 4
+  // CHECK-NEXT: store %struct.test* %var, %struct.test** %{{.*}}, align 4
+  // CHECK-NEXT: load %struct.test** %{{.*}}, align 4
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 0
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var->a;
+
+  // CHECK-NEXT: load %struct.test** %{{.*}}, align 4
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 2
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var->b;
+
+  // CHECK-NEXT: load %struct.test** %{{.*}}, align 4
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested1* %{{.*}}, i32 0, i32 0
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var->a1;
+
+  // CHECK-NEXT: load %struct.test** %{{.*}}, align 4
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested2* %{{.*}}, i32 0, i32 1
+  // CHECK-NEXT: getelementptr inbounds %struct.nested1* %{{.*}}, i32 0, i32 1
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var->b1;
+
+  // CHECK-NEXT: load %struct.test** %{{.*}}, align 4
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 0
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var->x;
+
+  // CHECK-NEXT: load %struct.test** %{{.*}}, align 4
+  // CHECK-NEXT: getelementptr inbounds %struct.test* %{{.*}}, i32 0, i32 2
+  // CHECK-NEXT: load i32* %{{.*}}, align 4
+  var->y;
+}

Modified: cfe/trunk/test/Sema/MicrosoftExtensions.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/MicrosoftExtensions.c?rev=120000&r1=119999&r2=120000&view=diff
==============================================================================
--- cfe/trunk/test/Sema/MicrosoftExtensions.c (original)
+++ cfe/trunk/test/Sema/MicrosoftExtensions.c Tue Nov 23 00:07:27 2010
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -Wmicrosoft -verify -fms-extensions
+// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions
 
 
 struct A
@@ -27,7 +27,43 @@
 
 
 enum ENUM2 {
-	ENUM2_a = (enum ENUM2) 4,
-	ENUM2_b = 0x9FFFFFFF, // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
-	ENUM2_c = 0x100000000 // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
+  ENUM2_a = (enum ENUM2) 4,
+  ENUM2_b = 0x9FFFFFFF, // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
+  ENUM2_c = 0x100000000 // expected-warning {{enumerator value is not representable in the underlying type 'int'}}
 };
+
+
+
+
+typedef struct notnested {
+  long bad1;
+  long bad2;
+} NOTNESTED;
+
+
+typedef struct nested1 {
+  long a;
+  struct notnested var1;
+  NOTNESTED var2;
+} NESTED1;
+
+struct nested2 {
+  long b;
+  NESTED1;  // expected-warning {{anonymous structs are a Microsoft extension}}
+};
+
+struct test {
+  int c;
+  struct nested2;   // expected-warning {{anonymous structs are a Microsoft extension}}
+};
+
+void foo()
+{
+  struct test var;
+  var.a;
+  var.b;
+  var.c;
+  var.bad1;   // expected-error {{no member named 'bad1' in 'struct test'}}
+  var.bad2;   // expected-error {{no member named 'bad2' in 'struct test'}}
+}
+





More information about the cfe-commits mailing list