[cfe-commits] r39296 - in /cfe/cfe/trunk: AST/SemaDecl.cpp AST/SemaType.cpp AST/Type.cpp Sema/SemaDecl.cpp Sema/SemaType.cpp include/clang/AST/Decl.h include/clang/AST/Type.h include/clang/Basic/DiagnosticKinds.def

sabre at cs.uiuc.edu sabre at cs.uiuc.edu
Wed Jul 11 09:42:39 PDT 2007


Author: sabre
Date: Wed Jul 11 11:42:38 2007
New Revision: 39296

URL: http://llvm.org/viewvc/llvm-project?rev=39296&view=rev
Log:
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];

Modified:
    cfe/cfe/trunk/AST/SemaDecl.cpp
    cfe/cfe/trunk/AST/SemaType.cpp
    cfe/cfe/trunk/AST/Type.cpp
    cfe/cfe/trunk/Sema/SemaDecl.cpp
    cfe/cfe/trunk/Sema/SemaType.cpp
    cfe/cfe/trunk/include/clang/AST/Decl.h
    cfe/cfe/trunk/include/clang/AST/Type.h
    cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def

Modified: cfe/cfe/trunk/AST/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaDecl.cpp?rev=39296&r1=39295&r2=39296&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/SemaDecl.cpp (original)
+++ cfe/cfe/trunk/AST/SemaDecl.cpp Wed Jul 11 11:42:38 2007
@@ -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;

Modified: cfe/cfe/trunk/AST/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/SemaType.cpp?rev=39296&r1=39295&r2=39296&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/SemaType.cpp (original)
+++ cfe/cfe/trunk/AST/SemaType.cpp Wed Jul 11 11:42:38 2007
@@ -130,6 +130,17 @@
       else
         ASM = ArrayType::Normal;
       
+      // If the element type is a struct or union that contains a variadic
+      // array, reject it: C99 6.7.2.1p2.
+      if (RecordType *EltTy = dyn_cast<RecordType>(T->getCanonicalType())) {
+        if (EltTy->getDecl()->hasFlexibleArrayMember()) {
+          std::string Name;
+          T->getAsString(Name);
+          Diag(DeclType.Loc, diag::err_flexible_array_in_array, Name);
+          return TypeRef();
+        }
+      }
+      
       T = Context.getArrayType(T, ASM, ATI.TypeQuals, ATI.NumElts);
       break;
     }

Modified: cfe/cfe/trunk/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/AST/Type.cpp?rev=39296&r1=39295&r2=39296&view=diff

==============================================================================
--- cfe/cfe/trunk/AST/Type.cpp (original)
+++ cfe/cfe/trunk/AST/Type.cpp Wed Jul 11 11:42:38 2007
@@ -75,6 +75,13 @@
   }
 }
 
+bool RecordType::classof(const Type *T) {
+  if (const TaggedType *TT = dyn_cast<TaggedType>(T))
+    return isa<RecordDecl>(TT->getDecl());
+  return false;
+}
+
+
 //===----------------------------------------------------------------------===//
 // Type Printing
 //===----------------------------------------------------------------------===//

Modified: cfe/cfe/trunk/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaDecl.cpp?rev=39296&r1=39295&r2=39296&view=diff

==============================================================================
--- cfe/cfe/trunk/Sema/SemaDecl.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaDecl.cpp Wed Jul 11 11:42:38 2007
@@ -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;

Modified: cfe/cfe/trunk/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Sema/SemaType.cpp?rev=39296&r1=39295&r2=39296&view=diff

==============================================================================
--- cfe/cfe/trunk/Sema/SemaType.cpp (original)
+++ cfe/cfe/trunk/Sema/SemaType.cpp Wed Jul 11 11:42:38 2007
@@ -130,6 +130,17 @@
       else
         ASM = ArrayType::Normal;
       
+      // If the element type is a struct or union that contains a variadic
+      // array, reject it: C99 6.7.2.1p2.
+      if (RecordType *EltTy = dyn_cast<RecordType>(T->getCanonicalType())) {
+        if (EltTy->getDecl()->hasFlexibleArrayMember()) {
+          std::string Name;
+          T->getAsString(Name);
+          Diag(DeclType.Loc, diag::err_flexible_array_in_array, Name);
+          return TypeRef();
+        }
+      }
+      
       T = Context.getArrayType(T, ASM, ATI.TypeQuals, ATI.NumElts);
       break;
     }

Modified: cfe/cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Decl.h?rev=39296&r1=39295&r2=39296&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Decl.h Wed Jul 11 11:42:38 2007
@@ -238,11 +238,19 @@
 
 /// RecordDecl - Represents a struct/union/class.
 class RecordDecl : public TagDecl {
+  /// HasFlexibleArrayMember - This is true if this struct ends with a flexible
+  /// array member (e.g. int X[]) or if this union contains a struct that does.
+  /// If so, this cannot be contained in arrays or other structs as a member.
+  bool HasFlexibleArrayMember;
 public:
   RecordDecl(Kind DK, SourceLocation L, IdentifierInfo *Id) :TagDecl(DK, L, Id){
+    HasFlexibleArrayMember = false;
     assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
   }
   
+  bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
+  void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; }
+  
   static bool classof(const Decl *D) {
     return D->getKind() == Struct || D->getKind() == Union ||
            D->getKind() == Class;
@@ -250,7 +258,6 @@
   static bool classof(const RecordDecl *D) { return true; }
 };
 
-  
 }  // end namespace clang
 }  // end namespace llvm
 

Modified: cfe/cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/AST/Type.h?rev=39296&r1=39295&r2=39296&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/cfe/trunk/include/clang/AST/Type.h Wed Jul 11 11:42:38 2007
@@ -22,9 +22,11 @@
 namespace llvm {
 namespace clang {
   class ASTContext;
+  class Type;
   class TypeDecl;
   class TagDecl;
-  class Type;
+  class RecordDecl;
+  class EnumDecl;
   
 /// TypeRef - For efficiency, we don't store CVR-qualified types as nodes on
 /// their own: instead each reference to a type stores the qualifiers.  This
@@ -387,6 +389,19 @@
   static bool classof(const TaggedType *) { return true; }
 };
 
+/// RecordType - This is a helper class that allows the use of isa/cast/dyncast
+/// to detect TaggedType objects of structs/unions/classes.
+class RecordType : public TaggedType {
+  RecordType(); // DO NOT IMPLEMENT
+public:
+    
+  RecordDecl *getDecl() const {
+    return reinterpret_cast<RecordDecl*>(TaggedType::getDecl());
+  }
+  
+  static bool classof(const Type *T);
+  static bool classof(const RecordType *) { return true; }
+};
 
 
 /// ...

Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=39296&r1=39295&r2=39296&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:42:38 2007
@@ -441,8 +441,14 @@
      "field '%s' declared as a function")
 DIAG(err_field_incomplete, ERROR,
      "field '%s' has incomplete type")
+DIAG(err_variable_sized_type_in_struct, EXTENSION,
+     "variable sized type '%s' must be at end of struct or class")
 DIAG(err_flexible_array_empty_struct, ERROR,
      "flexible array '%s' not allowed in otherwise empty struct")
+DIAG(ext_flexible_array_in_struct, EXTENSION,
+     "'%s' may not be nested in a struct due to flexible array member")
+DIAG(err_flexible_array_in_array, ERROR,
+     "'%s' may not be used as an array element due to flexible array member")
 
 // Expressions.
 DIAG(ext_sizeof_function_type, EXTENSION,





More information about the cfe-commits mailing list