Enforce the rest of C99 6.7.2.1p2, emitting diagnostics like:

t.c:10:15: warning: 'bonk' may not be nested in a struct due to flexible array member
  struct bink bonk;
              ^
t.c:13:14: error: 'struct bink' may not be used as an array element due to flexible array member
struct bink A[123];
             ^
for:

struct bink {
  struct bink *a;
  int X[];  // ok.
};

struct foo {
  int A;
  struct bink bonk;
};

struct bink A[123];

llvm-svn: 39296
diff --git a/clang/AST/SemaDecl.cpp b/clang/AST/SemaDecl.cpp
index 88e2747..ba0a41b 100644
--- a/clang/AST/SemaDecl.cpp
+++ b/clang/AST/SemaDecl.cpp
@@ -332,10 +332,15 @@
   
   // Otherwise, if this is the first time we've seen this tag, create the decl.
   TagDecl *New;
-  if (Kind != Decl::Enum)
+  switch (Kind) {
+  default: assert(0 && "Unknown tag kind!");
+  case Decl::Enum: assert(0 && "Enum tags not implemented yet!");
+  case Decl::Union:
+  case Decl::Struct:
+  case Decl::Class:
     New = new RecordDecl(Kind, Loc, Name);
-  else
-    assert(0 && "Enum tags not implemented yet!");
+    break;
+  }    
   
   //if (TK == TK_Definition)
   //  New->setDefinition(true);
@@ -397,9 +402,12 @@
   for (unsigned i = 0; i != NumFields; ++i) {
     FieldDecl *FD = cast_or_null<FieldDecl>(static_cast<Decl*>(Fields[i]));
     if (!FD) continue;  // Already issued a diagnostic.
-
+    
+    // Get the type for the field.
+    Type *FDTy = FD->getType()->getCanonicalType();
+    
     // C99 6.7.2.1p2 - A field may not be a function type.
-    if (isa<FunctionType>(FD->getType())) {
+    if (isa<FunctionType>(FDTy)) {
       Diag(FD->getLocation(), diag::err_field_declared_as_function,
            FD->getName());
       delete FD;
@@ -407,23 +415,53 @@
     }
 
     // C99 6.7.2.1p2 - A field may not be an incomplete type except...
-    if (FD->getType()->isIncompleteType()) {
+    if (FDTy->isIncompleteType()) {
       if (i != NumFields-1 ||                   // ... that the last member ...
           Record->getKind() != Decl::Struct ||  // ... of a structure ...
-          !isa<ArrayType>(FD->getType())) {//... may have incomplete array type.
+          !isa<ArrayType>(FDTy)) {         //... may have incomplete array type.
         Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName());
         delete FD;
         continue;
       }
-      if (NumNamedMembers < 1) {           //... with more than named member ...
+      if (NumNamedMembers < 1) {      //... must have more than named member ...
         Diag(FD->getLocation(), diag::err_flexible_array_empty_struct,
              FD->getName());
         delete FD;
         continue;
       }
+      
+      // Okay, we have a legal flexible array member at the end of the struct.
+      cast<RecordDecl>(Record)->setHasFlexibleArrayMember(true);
     }
-      
-      
+    
+    
+    /// C99 6.7.2.1p2 - a struct ending in a flexible array member cannot be the
+    /// field of another structure or the element of an array.
+    if (RecordType *FDTTy = dyn_cast<RecordType>(FDTy)) {
+      if (FDTTy->getDecl()->hasFlexibleArrayMember()) {
+        // If this is a member of a union, then entire union becomes "flexible".
+        if (Record->getKind() == Decl::Union) {
+          cast<RecordDecl>(Record)->setHasFlexibleArrayMember(true);
+        } else {
+          // If this is a struct/class and this is not the last element, reject
+          // it.  Note that GCC supports variable sized arrays in the middle of
+          // structures.
+          if (i != NumFields-1) {
+            Diag(FD->getLocation(), diag::err_variable_sized_type_in_struct,
+                 FD->getName());
+            delete FD;
+            continue;
+          }
+
+          // We support flexible arrays at the end of structs in other structs
+          // as an extension.
+          Diag(FD->getLocation(), diag::ext_flexible_array_in_struct,
+               FD->getName());
+          cast<RecordDecl>(Record)->setHasFlexibleArrayMember(true);
+        }
+      }
+    }
+    
     // Keep track of the number of named members.
     if (FD->getIdentifier())
       ++NumNamedMembers;