Implement support for anonymous structs and unions in C. Both C and
C++ handle anonymous structs/unions in the same way. Addresses several
bugs:

  <rdar://problem/6259534>
  <rdar://problem/6481130>
  <rdar://problem/6483159>

The test case in PR clang/1750 now passes with -fsyntax-only, but
CodeGen for inline assembler still fails.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62112 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index f3f0a08..6aeda8b 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -861,7 +861,20 @@
 /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
 /// no declarator (e.g. "struct foo;") is parsed.
 Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
-  // FIXME: Isn't that more of a parser diagnostic than a sema diagnostic?
+  TagDecl *Tag 
+    = dyn_cast_or_null<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
+  if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
+    if (!Record->getDeclName() && Record->isDefinition() &&
+        DS.getStorageClassSpec() != DeclSpec::SCS_typedef)
+      return BuildAnonymousStructOrUnion(S, DS, Record);
+
+    // 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;
+  }
+
   if (!DS.isMissingDeclaratorOk()) {
     // FIXME: This diagnostic is emitted even when various previous
     // errors occurred (see e.g. test/Sema/decl-invalid.c). However,
@@ -872,14 +885,6 @@
     return 0;
   }
   
-  TagDecl *Tag 
-    = dyn_cast_or_null<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
-  if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
-    if (!Record->getDeclName() && Record->isDefinition() && 
-        !Record->isInvalidDecl())
-      return BuildAnonymousStructOrUnion(S, DS, Record);
-  }
-
   return Tag;
 }
 
@@ -1031,10 +1036,16 @@
     }
   } else {
     // FIXME: Check GNU C semantics
+    if (Record->isUnion() && !Owner->isRecord()) {
+      Diag(Record->getLocation(), diag::err_anonymous_union_not_member)
+        << (int)getLangOptions().CPlusPlus;
+      Invalid = true;
+    }
   }
 
   if (!Record->isUnion() && !Owner->isRecord()) {
-    Diag(Record->getLocation(), diag::err_anonymous_struct_not_member);
+    Diag(Record->getLocation(), diag::err_anonymous_struct_not_member)
+      << (int)getLangOptions().CPlusPlus;
     Invalid = true;
   }
 
@@ -1084,7 +1095,8 @@
   // Inject the members of the anonymous struct/union into the owning
   // context and into the identifier resolver chain for name lookup
   // purposes.
-  Invalid = Invalid || InjectAnonymousStructOrUnionMembers(S, Owner, Record);
+  if (InjectAnonymousStructOrUnionMembers(S, Owner, Record))
+    Invalid = true;
 
   // Mark this as an anonymous struct/union type. Note that we do not
   // do this until after we have already checked and injected the
@@ -2890,6 +2902,7 @@
   case DeclSpec::TST_enum:   Kind = TagDecl::TK_enum; break;
   }
   
+  DeclContext *SearchDC = CurContext;
   DeclContext *DC = CurContext;
   DeclContext *LexicalContext = CurContext;
   ScopedDecl *PrevDecl = 0;
@@ -2924,8 +2937,8 @@
       // with C structs, unions, and enums when looking for a matching
       // tag declaration or definition. See the similar lookup tweak
       // in Sema::LookupDecl; is there a better way to deal with this?
-      while (isa<RecordDecl>(DC) || isa<EnumDecl>(DC))
-        DC = DC->getParent();
+      while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC))
+        SearchDC = SearchDC->getParent();
     }
   }
 
@@ -2943,7 +2956,7 @@
       // If this is a use of a previous tag, or if the tag is already declared
       // in the same scope (so that the definition/declaration completes or
       // rementions the tag), reuse the decl.
-      if (TK == TK_Reference || isDeclInScope(PrevDecl, DC, S)) {
+      if (TK == TK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) {
         // Make sure that this wasn't declared as an enum and now used as a
         // struct or something similar.
         if (PrevTagDecl->getTagKind() != Kind) {
@@ -2991,7 +3004,7 @@
       // PrevDecl. If it's NULL, we have a new definition.
     } else {
       // PrevDecl is a namespace.
-      if (isDeclInScope(PrevDecl, DC, S)) {
+      if (isDeclInScope(PrevDecl, SearchDC, S)) {
         // The tag name clashes with a namespace name, issue an error and
         // recover by making this tag be anonymous.
         Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
@@ -3024,6 +3037,8 @@
     // C structs and unions.
 
     // Find the context where we'll be declaring the tag.
+    // FIXME: We would like to maintain the current DeclContext as the
+    // lexical context, 
     while (DC->isRecord())
       DC = DC->getParent();
     LexicalContext = DC;
@@ -3110,11 +3125,7 @@
       CurContext = OldContext;
     } else 
       PushOnScopeChains(New, S);
-  } else if (getLangOptions().CPlusPlus) {
-    // FIXME: We also want to do this for C, but if this tag is
-    // defined within a structure CurContext will point to the context
-    // enclosing the structure, and we would end up inserting the tag
-    // type into the wrong place.
+  } else {
     LexicalContext->addDecl(Context, New);
   }