[cfe-commits] r63785 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def lib/Sema/Sema.cpp lib/Sema/SemaInit.cpp test/Sema/array-init.c test/Sema/flexible-array-init.c test/SemaCXX/dcl_init_aggr.cpp

Douglas Gregor dgregor at apple.com
Wed Feb 4 14:46:26 PST 2009


Author: dgregor
Date: Wed Feb  4 16:46:25 2009
New Revision: 63785

URL: http://llvm.org/viewvc/llvm-project?rev=63785&view=rev
Log:
Implement semantic analysis for the GNU flexible array initialization
extension. The interaction with designated initializers is a
bit... interesting... but we follow GNU's lead and don't permit too
much crazy code in this area.

Also, make the "excess initializers" error message a bit more
informative.

Addresses PR2561: http://llvm.org/bugs/show_bug.cgi?id=2561

Added:
    cfe/trunk/test/Sema/flexible-array-init.c
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/Sema/array-init.c
    cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Wed Feb  4 16:46:25 2009
@@ -60,6 +60,10 @@
      "initializer overrides prior initialization of this subobject")
 DIAG(note_previous_initializer, NOTE,
      "previous initialization %select{|with side effects }0is here%select{| (side effects may not occur at run time)}0")
+DIAG(err_designator_into_flexible_array_member, ERROR,
+     "designator into flexible array member subobject")
+DIAG(note_flexible_array_member, NOTE,
+     "initialized flexible array member %0 is here")
 
 // Declarations.
 DIAG(ext_vla, EXTENSION,
@@ -547,7 +551,7 @@
 DIAG(err_array_init_list_required, ERROR,
      "initialization with '{...}' expected for array")
 DIAG(err_excess_initializers, ERROR,
-     "excess elements in array initializer")
+     "excess elements in %select{array|vector|scalar|union|struct}0 initializer")
 DIAG(err_excess_initializers_in_char_array_initializer, ERROR,
     "excess elements in char array initializer")
 DIAG(warn_initializer_string_for_char_array_too_long, WARNING,
@@ -593,6 +597,10 @@
      "%0 may not be nested in a struct due to flexible array member")
 DIAG(err_flexible_array_in_array, ERROR,
      "%0 may not be used as an array element due to flexible array member")
+DIAG(err_flexible_array_init_nonempty, ERROR,
+     "non-empty initialization of flexible array member inside subobject")
+DIAG(err_flexible_array_init_needs_braces, ERROR,
+     "flexible array requires brace-enclosed initializer")
 DIAG(err_illegal_decl_array_of_functions, ERROR,
      "'%0' declared as array of functions")
 DIAG(err_illegal_decl_array_incomplete_type, ERROR,

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=63785&r1=63784&r2=63785&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Wed Feb  4 16:46:25 2009
@@ -50,11 +50,13 @@
              "Invalid modifier for DeclarationName argument");
   } else {
     assert(Kind == Diagnostic::ak_nameddecl);
-    assert(ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0 &&
+    if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
+      S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString();
+    else { 
+      assert(ModLen == 0 && ArgLen == 0 &&
            "Invalid modifier for NamedDecl* argument");
-
-    S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString();
-
+      S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString();
+    }
   }
   Output.append(S.begin(), S.end());
 }

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=63785&r1=63784&r2=63785&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Feb  4 16:46:25 2009
@@ -56,15 +56,18 @@
   
   void CheckImplicitInitList(InitListExpr *ParentIList, QualType T, 
                              unsigned &Index, InitListExpr *StructuredList,
-                             unsigned &StructuredIndex);
+                             unsigned &StructuredIndex,
+                             bool TopLevelObject = false);
   void CheckExplicitInitList(InitListExpr *IList, QualType &T,
                              unsigned &Index, InitListExpr *StructuredList,
-                             unsigned &StructuredIndex);
+                             unsigned &StructuredIndex,
+                             bool TopLevelObject = false);
   void CheckListElementTypes(InitListExpr *IList, QualType &DeclType, 
                              bool SubobjectIsDesignatorContext, 
                              unsigned &Index,
                              InitListExpr *StructuredList,
-                             unsigned &StructuredIndex);
+                             unsigned &StructuredIndex,
+                             bool TopLevelObject = false);
   void CheckSubElementType(InitListExpr *IList, QualType ElemType, 
                            unsigned &Index,
                            InitListExpr *StructuredList,
@@ -84,7 +87,8 @@
                              RecordDecl::field_iterator Field, 
                              bool SubobjectIsDesignatorContext, unsigned &Index,
                              InitListExpr *StructuredList,
-                             unsigned &StructuredIndex);
+                             unsigned &StructuredIndex,
+                             bool TopLevelObject = false);
   void CheckArrayType(InitListExpr *IList, QualType &DeclType, 
                       llvm::APSInt elementIndex, 
                       bool SubobjectIsDesignatorContext, unsigned &Index,
@@ -98,7 +102,8 @@
                                   unsigned &Index,
                                   InitListExpr *StructuredList,
                                   unsigned &StructuredIndex,
-                                  bool FinishSubobjectInit = true);
+                                  bool FinishSubobjectInit,
+                                  bool TopLevelObject);
   InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
                                            QualType CurrentObjectType,
                                            InitListExpr *StructuredList,
@@ -220,7 +225,8 @@
   unsigned newStructuredIndex = 0;
   FullyStructuredList 
     = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, SourceRange());
-  CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex);
+  CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex,
+                        /*TopLevelObject=*/true);
 
   if (!hadError)
     FillInValueInitializations(FullyStructuredList);
@@ -253,7 +259,8 @@
 void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, 
                                             QualType T, unsigned &Index,
                                             InitListExpr *StructuredList,
-                                            unsigned &StructuredIndex) {
+                                            unsigned &StructuredIndex,
+                                            bool TopLevelObject) {
   int maxElements = 0;
   
   if (T->isArrayType())
@@ -284,7 +291,8 @@
   unsigned StartIndex = Index;
   CheckListElementTypes(ParentIList, T, false, Index,
                         StructuredSubobjectInitList, 
-                        StructuredSubobjectInitIndex);
+                        StructuredSubobjectInitIndex,
+                        TopLevelObject);
   unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
   
   // Update the structured sub-object initialize so that it's ending
@@ -299,12 +307,13 @@
 void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
                                             unsigned &Index,
                                             InitListExpr *StructuredList,
-                                            unsigned &StructuredIndex) {
+                                            unsigned &StructuredIndex,
+                                            bool TopLevelObject) {
   assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
   SyntacticToSemantic[IList] = StructuredList;
   StructuredList->setSyntacticForm(IList);
   CheckListElementTypes(IList, T, true, Index, StructuredList, 
-                        StructuredIndex);
+                        StructuredIndex, TopLevelObject);
   IList->setType(T);
   StructuredList->setType(T);
   if (hadError)
@@ -322,9 +331,16 @@
     } else if (!T->isIncompleteType()) {
       // Don't complain for incomplete types, since we'll get an error
       // elsewhere
+      QualType CurrentObjectType = StructuredList->getType();
+      int initKind = 
+        CurrentObjectType->isArrayType()? 0 :
+        CurrentObjectType->isVectorType()? 1 :
+        CurrentObjectType->isScalarType()? 2 :
+        CurrentObjectType->isUnionType()? 3 :
+        4;
       SemaRef->Diag(IList->getInit(Index)->getLocStart(), 
                     diag::err_excess_initializers)
-        << IList->getInit(Index)->getSourceRange();
+        << initKind << IList->getInit(Index)->getSourceRange();
     }
   }
 
@@ -338,7 +354,8 @@
                                             bool SubobjectIsDesignatorContext,
                                             unsigned &Index,
                                             InitListExpr *StructuredList,
-                                            unsigned &StructuredIndex) {
+                                            unsigned &StructuredIndex,
+                                            bool TopLevelObject) {
   if (DeclType->isScalarType()) {
     CheckScalarType(IList, DeclType, Index, StructuredList, StructuredIndex);
   } else if (DeclType->isVectorType()) {
@@ -348,7 +365,8 @@
       RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
       CheckStructUnionTypes(IList, DeclType, RD->field_begin(), 
                             SubobjectIsDesignatorContext, Index,
-                            StructuredList, StructuredIndex);
+                            StructuredList, StructuredIndex,
+                            TopLevelObject);
     } else if (DeclType->isArrayType()) {
       llvm::APSInt Zero(
                       SemaRef->Context.getTypeSize(SemaRef->Context.getSizeType()),
@@ -643,7 +661,8 @@
       // updated to be the next array element we'll initialize.
       if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(), 
                                      DeclType, 0, &elementIndex, Index,
-                                     StructuredList, StructuredIndex)) {
+                                     StructuredList, StructuredIndex, true,
+                                     false)) {
         hadError = true;
         continue;
       }
@@ -699,7 +718,8 @@
                                             bool SubobjectIsDesignatorContext, 
                                             unsigned &Index,
                                             InitListExpr *StructuredList,
-                                            unsigned &StructuredIndex) {
+                                            unsigned &StructuredIndex,
+                                            bool TopLevelObject) {
   RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
     
   // If the record is invalid, some of it's members are invalid. To avoid
@@ -744,7 +764,8 @@
       // the next field that we'll be initializing.
       if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(), 
                                      DeclType, &Field, 0, Index,
-                                     StructuredList, StructuredIndex))
+                                     StructuredList, StructuredIndex,
+                                     true, TopLevelObject))
         hadError = true;
 
       // Abort early for unions: the designator handled the
@@ -782,9 +803,24 @@
     ++Field;
   }
 
-  // FIXME: Implement flexible array initialization GCC extension (it's a 
-  // really messy extension to implement, unfortunately...the necessary
-  // information isn't actually even here!)
+  if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() || 
+      Index >= IList->getNumInits() || 
+      !isa<InitListExpr>(IList->getInit(Index)))
+    return;
+
+  // Handle GNU flexible array initializers.
+  if (!TopLevelObject && 
+      cast<InitListExpr>(IList->getInit(Index))->getNumInits() > 0) {
+    SemaRef->Diag(IList->getInit(Index)->getSourceRange().getBegin(), 
+                  diag::err_flexible_array_init_nonempty)
+      << IList->getInit(Index)->getSourceRange().getBegin();
+    SemaRef->Diag(Field->getLocation(), diag::note_flexible_array_member)
+      << *Field;
+    hadError = true;
+  }
+
+  CheckSubElementType(IList, Field->getType(), Index, StructuredList,
+                      StructuredIndex);
 }
 
 /// @brief Check the well-formedness of a C99 designated initializer.
@@ -831,7 +867,8 @@
                                       unsigned &Index,
                                       InitListExpr *StructuredList,
                                       unsigned &StructuredIndex,
-                                      bool FinishSubobjectInit) {
+                                            bool FinishSubobjectInit,
+                                            bool TopLevelObject) {
   if (D == DIE->designators_end()) {
     // Check the actual initialization for the designated object type.
     bool prevHadError = hadError;
@@ -949,12 +986,74 @@
     if (FieldIndex >= StructuredList->getNumInits())
       StructuredList->resizeInits(SemaRef->Context, FieldIndex + 1);
 
-    // Recurse to check later designated subobjects.
-    QualType FieldType = (*Field)->getType();
-    unsigned newStructuredIndex = FieldIndex;
-    if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index,
-                                   StructuredList, newStructuredIndex))
-      return true;
+    // This designator names a flexible array member.
+    if (Field->getType()->isIncompleteArrayType()) {
+      bool Invalid = false;
+      DesignatedInitExpr::designators_iterator NextD = D;
+      ++NextD;
+      if (NextD != DIE->designators_end()) {
+        // We can't designate an object within the flexible array
+        // member (because GCC doesn't allow it).
+        SemaRef->Diag(NextD->getStartLocation(), 
+                      diag::err_designator_into_flexible_array_member)
+          << SourceRange(NextD->getStartLocation(), 
+                         DIE->getSourceRange().getEnd());
+        SemaRef->Diag(Field->getLocation(), diag::note_flexible_array_member)
+          << *Field;
+        Invalid = true;
+      }
+
+      if (!hadError && !isa<InitListExpr>(DIE->getInit())) {
+        // The initializer is not an initializer list.
+        SemaRef->Diag(DIE->getInit()->getSourceRange().getBegin(),
+                      diag::err_flexible_array_init_needs_braces)
+          << DIE->getInit()->getSourceRange();
+        SemaRef->Diag(Field->getLocation(), diag::note_flexible_array_member)
+          << *Field;
+        Invalid = true;
+      }
+
+      // Handle GNU flexible array initializers.
+      if (!Invalid && !TopLevelObject && 
+          cast<InitListExpr>(DIE->getInit())->getNumInits() > 0) {
+        SemaRef->Diag(DIE->getSourceRange().getBegin(), 
+                      diag::err_flexible_array_init_nonempty)
+          << DIE->getSourceRange().getBegin();
+        SemaRef->Diag(Field->getLocation(), diag::note_flexible_array_member)
+          << *Field;
+        Invalid = true;
+      }
+
+      if (Invalid) {
+        ++Index;
+        return true;
+      }
+
+      // Initialize the array.
+      bool prevHadError = hadError;
+      unsigned newStructuredIndex = FieldIndex;
+      unsigned OldIndex = Index;
+      IList->setInit(Index, DIE->getInit());
+      CheckSubElementType(IList, Field->getType(), Index, 
+                          StructuredList, newStructuredIndex);
+      IList->setInit(OldIndex, DIE);
+      if (hadError && !prevHadError) {
+        ++Field;
+        ++FieldIndex;
+        if (NextField)
+          *NextField = Field;
+        StructuredIndex = FieldIndex;
+        return true;
+      }
+    } else {
+      // Recurse to check later designated subobjects.
+      QualType FieldType = (*Field)->getType();
+      unsigned newStructuredIndex = FieldIndex;
+      if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index,
+                                     StructuredList, newStructuredIndex,
+                                     true, false))
+        return true;
+    }
 
     // Find the position of the next field to be initialized in this
     // subobject.
@@ -1075,7 +1174,8 @@
     Index = OldIndex;
     if (CheckDesignatedInitializer(IList, DIE, D, ElementType, 0, 0, Index,
                                    StructuredList, ElementIndex,
-                                   (DesignatedStartIndex == DesignatedEndIndex)))
+                                   (DesignatedStartIndex == DesignatedEndIndex),
+                                   false))
       return true;
 
     // Move to the next index in the array that we'll be initializing.

Modified: cfe/trunk/test/Sema/array-init.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/array-init.c?rev=63785&r1=63784&r2=63785&view=diff

==============================================================================
--- cfe/trunk/test/Sema/array-init.c (original)
+++ cfe/trunk/test/Sema/array-init.c Wed Feb  4 16:46:25 2009
@@ -20,7 +20,7 @@
 
   int x3[x] = { 1, 2 }; // expected-error{{variable-sized object may not be initialized}}
 
-  int x4 = { 1, 2 }; // expected-warning{{braces around scalar initializer}} expected-error{{excess elements in array initializer}}
+  int x4 = { 1, 2 }; // expected-warning{{braces around scalar initializer}} expected-error{{excess elements in scalar initializer}}
 
   int y[4][3] = { 
     { 1, 3, 5 },
@@ -53,7 +53,7 @@
 
 void test() {
   int y1[3] = { 
-    { 1, 2, 3 } // expected-warning{{braces around scalar initializer}} expected-error{{excess elements in array initializer}}
+    { 1, 2, 3 } // expected-warning{{braces around scalar initializer}} expected-error{{excess elements in scalar initializer}}
   };
   int y3[4][3] = {  
     { 1, 3, 5 },
@@ -201,14 +201,13 @@
   return z.z; 
 } 
 struct s3 {void (*a)(void);} t5 = {autoStructTest};
-// FIXME: GCC extension; flexible array init. Once this is implemented, the warning should be removed.
 // Note that clang objc implementation depends on this extension.
-struct {int a; int b[];} t6 = {1, {1, 2, 3}}; //expected-error{{excess elements in array initializer}}
+struct {int a; int b[];} t6 = {1, {1, 2, 3}};
 union {char a; int b;} t7[] = {1, 2, 3};
 int t8[sizeof t7 == (3*sizeof(int)) ? 1 : -1];
 
 struct bittest{int : 31, a, :21, :12, b;};
-struct bittest bittestvar = {1, 2, 3, 4}; //expected-error{{excess elements in array initializer}}
+struct bittest bittestvar = {1, 2, 3, 4}; //expected-error{{excess elements in struct initializer}}
 
 // Not completely sure what should happen here...
 int u1 = {}; //expected-warning{{use of GNU empty initializer extension}} expected-error{{scalar initializer cannot be empty}}
@@ -243,7 +242,7 @@
 };
 
 static void sppp_ipv6cp_up();
-const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct extension}} expected-error{{excess elements in array initializer}}
+const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct extension}} expected-error{{excess elements in struct initializer}}
 
 struct _Matrix { union { float m[4][4]; }; }; //expected-warning{{anonymous unions are a GNU extension in C}}
 typedef struct _Matrix Matrix;

Added: cfe/trunk/test/Sema/flexible-array-init.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/flexible-array-init.c?rev=63785&view=auto

==============================================================================
--- cfe/trunk/test/Sema/flexible-array-init.c (added)
+++ cfe/trunk/test/Sema/flexible-array-init.c Wed Feb  4 16:46:25 2009
@@ -0,0 +1,38 @@
+// RUN: clang -fsyntax-only -verify %s
+struct one {
+  int a;
+  int values[];
+} x = {5, {1, 2, 3}};
+
+struct one x2 = { 5, 1, 2, 3 }; // expected-error{{excess elements in struct initializer}}
+
+void test() {
+  struct one x3 = {5, {1, 2, 3}};
+}
+
+struct foo { 
+  int x; 
+  int y[]; // expected-note{{initialized flexible array member 'y' is here}}
+}; 
+struct bar { struct foo z; };
+     
+struct foo a = { 1, { 2, 3, 4 } };        // Valid.
+struct bar b = { { 1, { 2, 3, 4 } } };    // expected-error{{non-empty initialization of flexible array member inside subobject}}
+struct bar c = { { 1, { } } };            // Valid.
+struct foo d[1] = { { 1, { 2, 3, 4 } } };  // expected-error{{'struct foo' may not be used as an array element due to flexible array member}}
+
+struct foo desig_foo = { .y = {2, 3, 4} };
+struct bar desig_bar = { .z.y = { } };
+struct bar desig_bar2 = { .z.y = { 2, 3, 4} }; // expected-error{{non-empty initialization of flexible array member inside subobject}}
+struct foo design_foo2 = { .y = 2 }; // expected-error{{flexible array requires brace-enclosed initializer}}
+
+struct point {
+  int x, y;
+};
+
+struct polygon {
+  int numpoints;
+  struct point points[]; // expected-note{{initialized flexible array member 'points' is here}}
+};
+struct polygon poly = { 
+  .points[2] = { 1, 2} }; // expected-error{{designator into flexible array member subobject}}

Modified: cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp?rev=63785&r1=63784&r2=63785&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp (original)
+++ cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp Wed Feb  4 16:46:25 2009
@@ -118,5 +118,5 @@
 u u1 = { 1 }; 
 u u2 = u1; 
 u u3 = 1; // expected-error{{cannot initialize 'u3' with an rvalue of type 'int'}}
-u u4 = { 0, "asdf" };  // expected-error{{excess elements in array initializer}}
+u u4 = { 0, "asdf" };  // expected-error{{excess elements in union initializer}}
 u u5 = { "asdf" }; // expected-error{{incompatible type initializing 'char const [5]', expected 'int'}}





More information about the cfe-commits mailing list