]> granicus.if.org Git - clang/commitdiff
Initial implementation of semantic analysis and ASTs for C99
authorDouglas Gregor <dgregor@apple.com>
Thu, 22 Jan 2009 00:58:24 +0000 (00:58 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 22 Jan 2009 00:58:24 +0000 (00:58 +0000)
designated initializers. This implementation should cover all of the
constraints in C99 6.7.8, including long, complex designations and
computing the size of incomplete array types initialized with a
designated initializer. Please see the new test-case and holler if you
find cases where this doesn't work.

There are still some wrinkles with GNU's anonymous structs and
anonymous unions (it isn't clear how these should work; we'll just
follow GCC's lead) and with designated initializers for the members of a
union. I'll tackle those very soon.

CodeGen is still nonexistent, and there's some leftover code in the
parser's representation of designators that I'll also need to clean up.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62737 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/AST/Expr.h
include/clang/AST/StmtNodes.def
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/Action.h
include/clang/Parse/Designator.h
lib/AST/Expr.cpp
lib/AST/StmtPrinter.cpp
lib/Parse/ParseInit.cpp
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaInit.cpp
test/Sema/designated-initializers.c [new file with mode: 0644]

index 2f2d4a6e39ab78c4342dcdcf4cfccc989db8b140..9d7370735966f48cee597001dea592212e521537 100644 (file)
@@ -1706,6 +1706,224 @@ private:
   InitListExpr() : Expr(InitListExprClass, QualType()) {}
 };
 
+/// @brief Represents a C99 designated initializer expression.
+///
+/// A designated initializer expression (C99 6.7.8) contains one or
+/// more designators (which can be field designators, array
+/// designators, or GNU array-range designators) followed by an
+/// expression that initializes the field or element(s) that the
+/// designators refer to. For example, given:
+/// 
+/// @code
+/// struct point {
+///   double x;
+///   double y;
+/// };
+/// struct point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 };
+/// @endcode
+///
+/// The InitListExpr contains three DesignatedInitExprs, the first of
+/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two
+/// designators, one array designator for @c [2] followed by one field
+/// designator for @c .y. The initalization expression will be 1.0.
+class DesignatedInitExpr : public Expr {
+  /// The location of the '=' or ':' prior to the actual initializer
+  /// expression.
+  SourceLocation EqualOrColonLoc;
+
+  /// Whether this designated initializer used the GNU deprecated ':'
+  /// syntax rather than the C99 '=' syntax.
+  bool UsesColonSyntax : 1;
+
+  /// The number of designators in this initializer expression.
+  unsigned NumDesignators : 15;
+
+  /// The number of subexpressions of this initializer expression,
+  /// which contains both the initializer and any additional
+  /// expressions used by array and array-range designators.
+  unsigned NumSubExprs : 16;
+
+  DesignatedInitExpr(QualType Ty, unsigned NumDesignators, 
+                     SourceLocation EqualOrColonLoc, bool UsesColonSyntax,
+                     unsigned NumSubExprs)
+    : Expr(DesignatedInitExprClass, Ty), 
+      EqualOrColonLoc(EqualOrColonLoc), UsesColonSyntax(UsesColonSyntax), 
+      NumDesignators(NumDesignators), NumSubExprs(NumSubExprs) { }
+
+public:
+  /// A field designator, e.g., ".x".
+  struct FieldDesignator {
+    /// Refers to the field that is being initialized. The low bit
+    /// of this field determines whether this is actually a pointer
+    /// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When
+    /// initially constructed, a field designator will store an
+    /// IdentifierInfo*. After semantic analysis has resolved that
+    /// name, the field designator will instead store a FieldDecl*.
+    uintptr_t NameOrField;
+    
+    /// The location of the '.' in the designated initializer.
+    unsigned DotLoc;
+    
+    /// The location of the field name in the designated initializer.
+    unsigned FieldLoc;
+  };
+
+  /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]".
+  struct ArrayOrRangeDesignator {
+    /// Location of the first index expression within the designated
+    /// initializer expression's list of subexpressions.
+    unsigned Index;
+    /// The location of the '[' starting the array range designator.
+    unsigned LBracketLoc;
+    /// The location of the ellipsis separating the start and end
+    /// indices. Only valid for GNU array-range designators.
+    unsigned EllipsisLoc;
+    /// The location of the ']' terminating the array range designator.
+    unsigned RBracketLoc;    
+  };
+
+  /// @brief Represents a single C99 designator.
+  ///
+  /// @todo This class is infuriatingly similar to clang::Designator,
+  /// but minor differences (storing indices vs. storing pointers)
+  /// keep us from reusing it. Try harder, later, to rectify these
+  /// differences.
+  class Designator {
+    /// @brief The kind of designator this describes.
+    enum {
+      FieldDesignator,
+      ArrayDesignator,
+      ArrayRangeDesignator
+    } Kind;
+
+    union {
+      /// A field designator, e.g., ".x".
+      struct FieldDesignator Field;
+      /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]".
+      struct ArrayOrRangeDesignator ArrayOrRange;
+    };
+    friend class DesignatedInitExpr;
+
+  public:
+    /// @brief Initializes a field designator.
+    Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc, 
+               SourceLocation FieldLoc) 
+      : Kind(FieldDesignator) {
+      Field.NameOrField = reinterpret_cast<uintptr_t>(FieldName) | 0x01;
+      Field.DotLoc = DotLoc.getRawEncoding();
+      Field.FieldLoc = FieldLoc.getRawEncoding();
+    }
+
+    /// @brief Initializes an array designator.
+    Designator(unsigned Index, SourceLocation LBracketLoc, 
+               SourceLocation RBracketLoc)
+      : Kind(ArrayDesignator) {
+      ArrayOrRange.Index = Index;
+      ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding();
+      ArrayOrRange.EllipsisLoc = SourceLocation().getRawEncoding();
+      ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding();
+    }
+
+    /// @brief Initializes a GNU array-range designator.
+    Designator(unsigned Index, SourceLocation LBracketLoc, 
+               SourceLocation EllipsisLoc, SourceLocation RBracketLoc)
+      : Kind(ArrayRangeDesignator) {
+      ArrayOrRange.Index = Index;
+      ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding();
+      ArrayOrRange.EllipsisLoc = EllipsisLoc.getRawEncoding();
+      ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding();
+    }
+
+    bool isFieldDesignator() const { return Kind == FieldDesignator; }
+    bool isArrayDesignator() const { return Kind == ArrayDesignator; }
+    bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; }
+
+    IdentifierInfo * getFieldName();
+
+    FieldDecl *getField() {
+      assert(Kind == FieldDesignator && "Only valid on a field designator");
+      if (Field.NameOrField & 0x01)
+        return 0;
+      else
+        return reinterpret_cast<FieldDecl *>(Field.NameOrField);
+    }
+
+    void setField(FieldDecl *FD) {
+      assert(Kind == FieldDesignator && "Only valid on a field designator");
+      Field.NameOrField = reinterpret_cast<uintptr_t>(FD);
+    }
+
+    SourceLocation getFieldLoc() const {
+      assert(Kind == FieldDesignator && "Only valid on a field designator");
+      return SourceLocation::getFromRawEncoding(Field.FieldLoc);
+    }
+
+    SourceLocation getLBracketLoc() const {
+      assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) &&
+             "Only valid on an array or array-range designator");
+      return SourceLocation::getFromRawEncoding(ArrayOrRange.LBracketLoc);
+    }
+
+    SourceLocation getRBracketLoc() const {
+      assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) &&
+             "Only valid on an array or array-range designator");
+      return SourceLocation::getFromRawEncoding(ArrayOrRange.RBracketLoc);
+    }
+
+    SourceLocation getEllipsisLoc() const {
+      assert(Kind == ArrayRangeDesignator &&
+             "Only valid on an array-range designator");
+      return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc);
+    }
+  };
+
+  static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators, 
+                                    unsigned NumDesignators,
+                                    Expr **IndexExprs, unsigned NumIndexExprs,
+                                    SourceLocation EqualOrColonLoc,
+                                    bool UsesColonSyntax, Expr *Init);
+
+  /// @brief Returns the number of designators in this initializer.
+  unsigned size() const { return NumDesignators; }
+
+  // Iterator access to the designators.
+  typedef Designator* designators_iterator;
+  designators_iterator designators_begin();
+  designators_iterator designators_end();
+
+  Expr *getArrayIndex(const Designator& D);
+  Expr *getArrayRangeStart(const Designator& D);
+  Expr *getArrayRangeEnd(const Designator& D);
+
+  /// @brief Retrieve the location of the '=' that precedes the
+  /// initializer value itself, if present.
+  SourceLocation getEqualOrColonLoc() const { return EqualOrColonLoc; }
+
+  /// @brief Determines whether this designated initializer used the
+  /// GNU 'fieldname:' syntax or the C99 '=' syntax.
+  bool usesColonSyntax() const { return UsesColonSyntax; }
+
+  /// @brief Retrieve the initializer value.
+  Expr *getInit() const { 
+    return cast<Expr>(*const_cast<DesignatedInitExpr*>(this)->child_begin());
+  }
+
+  void setInit(Expr *init) {
+    *child_begin() = init;
+  }
+
+  virtual SourceRange getSourceRange() const;
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == DesignatedInitExprClass; 
+  }
+  static bool classof(const DesignatedInitExpr *) { return true; }
+
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end(); 
+};
+
 //===----------------------------------------------------------------------===//
 // Clang Extensions
 //===----------------------------------------------------------------------===//
index 2f86c93e6d767a753118fda68fbae52cfee5ea00..e8d4a56c5075ecf3fc162ccc282ed628217f4b4b 100644 (file)
@@ -85,6 +85,7 @@ STMT(CStyleCastExpr        , ExplicitCastExpr)
 STMT(CompoundLiteralExpr   , Expr)
 STMT(ExtVectorElementExpr  , Expr)
 STMT(InitListExpr          , Expr)
+STMT(DesignatedInitExpr    , Expr)
 STMT(VAArgExpr             , Expr)
 
 // GNU Extensions.
index a43bbbb5ec399fa43cf437e34d195a92a2932887..664d3af3653918b1f287659fc8ba3e22e3020d13 100644 (file)
@@ -698,6 +698,28 @@ DIAG(err_hex_escape_no_digits, ERROR,
 DIAG(ext_predef_outside_function, WARNING,
      "predefined identifier is only valid inside function")
 
+// C99 Designated Initializers
+DIAG(err_array_designator_nonconstant, ERROR,
+     "array designator value must be a constant expression")
+DIAG(err_array_designator_negative, ERROR,
+     "array designator value '%0' is negative")
+DIAG(err_array_designator_empty_range, ERROR,
+     "array designator range [%0, %1] is empty")
+DIAG(err_array_designator_non_array, ERROR,
+     "array designator cannot initialize non-array type %0")
+DIAG(err_array_designator_too_large, ERROR,
+     "array designator index (%0) exceeds array bounds (%1)")
+DIAG(err_field_designator_non_aggr, ERROR,
+     "field designator cannot initialize a %select{non-struct, non-union|non-class}0 type %1")
+DIAG(err_field_designator_unknown, ERROR,
+     "field designator %0 does not refer to any field in type %1")
+DIAG(err_field_designator_nonfield, ERROR,
+     "field designator %0 does not refer to a non-static data member")
+DIAG(note_field_designator_found, NOTE,
+     "field designator refers here")
+DIAG(err_designator_for_scalar_init, ERROR,
+     "designator in initializer for scalar type %0")
+
 // Declarations.
 DIAG(err_typename_requires_specqual, ERROR,
      "type name requires a specifier or qualifier")
index 559512701a1807b6125b4aefc9b95cf2bac931da..5d87b1722105d1dda1ae1e4dc00795f67a2c3413 100644 (file)
@@ -32,6 +32,7 @@ namespace clang {
   class Scope;
   class Action;
   class Selector;
+  class Designation;
   class InitListDesignations;
   // Lex.
   class Preprocessor;
@@ -641,6 +642,26 @@ public:
                                          SourceLocation RParenLoc) {
     return ExprEmpty();
   }
+  /// @brief Parsed a C99 designated initializer. 
+  /// 
+  /// @param Desig Contains the designation with one or more designators.
+  ///
+  /// @param Loc The location of the '=' or ':' prior to the
+  /// initialization expression.
+  ///
+  /// @param UsedColonSyntax If true, then this designated initializer
+  /// used the deprecated GNU syntax @c fieldname:foo rather than the
+  /// C99 syntax @c .fieldname=foo.
+  ///
+  /// @param Init The value that the entity (or entities) described by
+  /// the designation will be initialized with.
+  virtual OwningExprResult ActOnDesignatedInitializer(Designation &Desig,
+                                                      SourceLocation Loc,
+                                                      bool UsedColonSyntax,
+                                                      OwningExprResult Init) {
+    return ExprEmpty();
+  }
+
   virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
                                          SourceLocation RParenLoc, ExprArg Op) {
     return ExprEmpty();
index cf3f8777d554ed5f302b055900f4c170e812cc0d..a76fff3ef240100865d42a5ddd19d7e4c8137a77 100644 (file)
@@ -37,12 +37,18 @@ private:
   
   struct FieldDesignatorInfo {
     const IdentifierInfo *II;
+    unsigned DotLoc;
+    unsigned NameLoc;
   };
   struct ArrayDesignatorInfo {
     Action::ExprTy *Index;
+    unsigned LBracketLoc;
+    mutable unsigned  RBracketLoc;
   };
   struct ArrayRangeDesignatorInfo {
     Action::ExprTy *Start, *End;
+    unsigned LBracketLoc, EllipsisLoc;
+    mutable unsigned RBracketLoc;
   };
   
   union {
@@ -62,6 +68,16 @@ public:
     assert(isFieldDesignator() && "Invalid accessor");
     return FieldInfo.II;
   }
+
+  SourceLocation getDotLoc() const {
+    assert(isFieldDesignator() && "Invalid accessor");
+    return SourceLocation::getFromRawEncoding(FieldInfo.DotLoc);
+  }
+
+  SourceLocation getFieldLoc() const {
+    assert(isFieldDesignator() && "Invalid accessor");
+    return SourceLocation::getFromRawEncoding(FieldInfo.NameLoc);
+  }
   
   Action::ExprTy *getArrayIndex() const {
     assert(isArrayDesignator() && "Invalid accessor");
@@ -77,28 +93,69 @@ public:
     return ArrayRangeInfo.End;
   }
   
-  
-  static Designator getField(const IdentifierInfo *II) {
+  SourceLocation getLBracketLoc() const {
+    assert((isArrayDesignator() || isArrayRangeDesignator()) && 
+           "Invalid accessor");
+    if (isArrayDesignator())
+      return SourceLocation::getFromRawEncoding(ArrayInfo.LBracketLoc);
+    else 
+      return SourceLocation::getFromRawEncoding(ArrayRangeInfo.LBracketLoc);
+  }
+
+  SourceLocation getRBracketLoc() const {
+    assert((isArrayDesignator() || isArrayRangeDesignator()) && 
+           "Invalid accessor");
+    if (isArrayDesignator())
+      return SourceLocation::getFromRawEncoding(ArrayInfo.RBracketLoc);
+    else 
+      return SourceLocation::getFromRawEncoding(ArrayRangeInfo.RBracketLoc);
+  }
+
+  SourceLocation getEllipsisLoc() const {
+    assert(isArrayRangeDesignator() && "Invalid accessor");
+    return SourceLocation::getFromRawEncoding(ArrayRangeInfo.EllipsisLoc);
+  }
+
+  static Designator getField(const IdentifierInfo *II, SourceLocation DotLoc,
+                             SourceLocation NameLoc) {
     Designator D;
     D.Kind = FieldDesignator;
     D.FieldInfo.II = II;
+    D.FieldInfo.DotLoc = DotLoc.getRawEncoding();
+    D.FieldInfo.NameLoc = NameLoc.getRawEncoding();
     return D;
   }
 
-  static Designator getArray(Action::ExprTy *Index) {
+  static Designator getArray(Action::ExprTy *Index, SourceLocation LBracketLoc) {
     Designator D;
     D.Kind = ArrayDesignator;
     D.ArrayInfo.Index = Index;
+    D.ArrayInfo.LBracketLoc = LBracketLoc.getRawEncoding();
+    D.ArrayInfo.RBracketLoc = 0;
     return D;
   }
   
-  static Designator getArrayRange(Action::ExprTy *Start, Action::ExprTy *End) {
+  static Designator getArrayRange(Action::ExprTy *Start, Action::ExprTy *End,
+                                  SourceLocation LBracketLoc, 
+                                  SourceLocation EllipsisLoc) {
     Designator D;
     D.Kind = ArrayRangeDesignator;
     D.ArrayRangeInfo.Start = Start;
     D.ArrayRangeInfo.End = End;
+    D.ArrayRangeInfo.LBracketLoc = LBracketLoc.getRawEncoding();
+    D.ArrayRangeInfo.EllipsisLoc = EllipsisLoc.getRawEncoding();
+    D.ArrayRangeInfo.RBracketLoc = 0;
     return D;
   }
+
+  void setRBracketLoc(SourceLocation RBracketLoc) const {
+    assert((isArrayDesignator() || isArrayRangeDesignator()) && 
+           "Invalid accessor");
+    if (isArrayDesignator())
+      ArrayInfo.RBracketLoc = RBracketLoc.getRawEncoding();
+    else
+      ArrayRangeInfo.RBracketLoc = RBracketLoc.getRawEncoding();
+  }
   
   /// ClearExprs - Null out any expression references, which prevents them from
   /// being 'delete'd later.
index 03b49499ee286f8ecad2c2969bad7e1927f198e3..70b63fea1bd6cf0897538f33f9e37005a684ba7b 100644 (file)
@@ -1348,6 +1348,106 @@ void SizeOfAlignOfExpr::Destroy(ASTContext& C) {
     Expr::Destroy(C);
 }
 
+//===----------------------------------------------------------------------===//
+//  DesignatedInitExpr
+//===----------------------------------------------------------------------===//
+
+IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() {
+  assert(Kind == FieldDesignator && "Only valid on a field designator");
+  if (Field.NameOrField & 0x01)
+    return reinterpret_cast<IdentifierInfo *>(Field.NameOrField&~0x01);
+  else
+    return getField()->getIdentifier();
+}
+
+DesignatedInitExpr *
+DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, 
+                           unsigned NumDesignators,
+                           Expr **IndexExprs, unsigned NumIndexExprs,
+                           SourceLocation ColonOrEqualLoc,
+                           bool UsesColonSyntax, Expr *Init) {
+  void *Mem = C.getAllocator().Allocate(sizeof(DesignatedInitExpr) +
+                                        sizeof(Designator) * NumDesignators +
+                                        sizeof(Stmt *) * (NumIndexExprs + 1),
+                                        8);
+  DesignatedInitExpr *DIE 
+    = new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators,
+                                   ColonOrEqualLoc, UsesColonSyntax,
+                                   NumIndexExprs + 1);
+
+  // Fill in the designators
+  unsigned ExpectedNumSubExprs = 0;
+  designators_iterator Desig = DIE->designators_begin();
+  for (unsigned Idx = 0; Idx < NumDesignators; ++Idx, ++Desig) {
+    new (static_cast<void*>(Desig)) Designator(Designators[Idx]);
+    if (Designators[Idx].isArrayDesignator())
+      ++ExpectedNumSubExprs;
+    else if (Designators[Idx].isArrayRangeDesignator())
+      ExpectedNumSubExprs += 2;
+  }
+  assert(ExpectedNumSubExprs == NumIndexExprs && "Wrong number of indices!");
+
+  // Fill in the subexpressions, including the initializer expression.
+  child_iterator Child = DIE->child_begin();
+  *Child++ = Init;
+  for (unsigned Idx = 0; Idx < NumIndexExprs; ++Idx, ++Child)
+    *Child = IndexExprs[Idx];
+
+  return DIE;
+}
+
+SourceRange DesignatedInitExpr::getSourceRange() const {
+  SourceLocation StartLoc;
+  Designator &First = *const_cast<DesignatedInitExpr*>(this)->designators_begin();
+  if (First.isFieldDesignator()) {
+    if (UsesColonSyntax)
+      StartLoc = SourceLocation::getFromRawEncoding(First.Field.FieldLoc);
+    else
+      StartLoc = SourceLocation::getFromRawEncoding(First.Field.DotLoc);
+  } else
+    StartLoc = SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc);
+  return SourceRange(StartLoc, getInit()->getSourceRange().getEnd());
+}
+
+DesignatedInitExpr::designators_iterator DesignatedInitExpr::designators_begin() {
+  char* Ptr = static_cast<char*>(static_cast<void *>(this));
+  Ptr += sizeof(DesignatedInitExpr);
+  return static_cast<Designator*>(static_cast<void*>(Ptr));
+}
+
+DesignatedInitExpr::designators_iterator DesignatedInitExpr::designators_end() {
+  return designators_begin() + NumDesignators;
+}
+
+Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) {
+  assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
+  char* Ptr = static_cast<char*>(static_cast<void *>(this));
+  Ptr += sizeof(DesignatedInitExpr);
+  Ptr += sizeof(Designator) * NumDesignators;
+  Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+  return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
+}
+
+Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) {
+  assert(D.Kind == Designator::ArrayRangeDesignator && 
+         "Requires array range designator");
+  char* Ptr = static_cast<char*>(static_cast<void *>(this));
+  Ptr += sizeof(DesignatedInitExpr);
+  Ptr += sizeof(Designator) * NumDesignators;
+  Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+  return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
+}
+
+Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
+  assert(D.Kind == Designator::ArrayRangeDesignator && 
+         "Requires array range designator");
+  char* Ptr = static_cast<char*>(static_cast<void *>(this));
+  Ptr += sizeof(DesignatedInitExpr);
+  Ptr += sizeof(Designator) * NumDesignators;
+  Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+  return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2));
+}
+
 //===----------------------------------------------------------------------===//
 //  ExprIterator.
 //===----------------------------------------------------------------------===//
@@ -1533,6 +1633,17 @@ Stmt::child_iterator InitListExpr::child_end() {
   return InitExprs.size() ? &InitExprs[0] + InitExprs.size() : 0;
 }
 
+/// DesignatedInitExpr
+Stmt::child_iterator DesignatedInitExpr::child_begin() {
+  char* Ptr = static_cast<char*>(static_cast<void *>(this));
+  Ptr += sizeof(DesignatedInitExpr);
+  Ptr += sizeof(Designator) * NumDesignators;
+  return reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+}
+Stmt::child_iterator DesignatedInitExpr::child_end() {
+  return child_iterator(&*child_begin() + NumSubExprs);
+}
+
 // ObjCStringLiteral
 Stmt::child_iterator ObjCStringLiteral::child_begin() { 
   return child_iterator();
index a3a16aec5bbbc765e4a36c550d77294d7e018260..80de5b8ae4540df332f663bbb72cae99aeb31efd 100644 (file)
@@ -877,6 +877,10 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
   OS << " }";
 }
 
+void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
+  // FIXME!
+}
+
 void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
   OS << "va_arg(";
   PrintExpr(Node->getSubExpr());
index ff73b0b9e1536f68424003aac4e89f58b9ef7901..b5d0ec05dbc20dbb2129b3a3c089a4826b210d0a 100644 (file)
@@ -68,13 +68,16 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
   if (Tok.is(tok::identifier)) {
     Diag(Tok, diag::ext_gnu_old_style_field_designator);
     
-    Designation &D = Designations.CreateDesignation(InitNum);
-    D.AddDesignator(Designator::getField(Tok.getIdentifierInfo()));
-    ConsumeToken(); // Eat the identifier.
+    const IdentifierInfo *FieldName = Tok.getIdentifierInfo();
+    SourceLocation NameLoc = ConsumeToken(); // Eat the identifier.
     
     assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!");
-    ConsumeToken();
-    return ParseInitializer();
+    SourceLocation ColonLoc = ConsumeToken();
+
+    Designation &D = Designations.CreateDesignation(InitNum);
+    D.AddDesignator(Designator::getField(FieldName, SourceLocation(), NameLoc));
+    return Actions.ActOnDesignatedInitializer(D, ColonLoc, true, 
+                                              ParseInitializer());
   }
   
   // Desig - This is initialized when we see our first designator.  We may have
@@ -86,7 +89,7 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
   while (Tok.is(tok::period) || Tok.is(tok::l_square)) {
     if (Tok.is(tok::period)) {
       // designator: '.' identifier
-      ConsumeToken();
+      SourceLocation DotLoc = ConsumeToken();
       
       // Create designation if we haven't already.
       if (Desig == 0)
@@ -97,7 +100,8 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
         return ExprError();
       }
       
-      Desig->AddDesignator(Designator::getField(Tok.getIdentifierInfo()));
+      Desig->AddDesignator(Designator::getField(Tok.getIdentifierInfo(), DotLoc,
+                                                Tok.getLocation()));
       ConsumeToken(); // Eat the identifier.
       continue;
     }
@@ -179,11 +183,12 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
     
     // If this is a normal array designator, remember it.
     if (Tok.isNot(tok::ellipsis)) {
-      Desig->AddDesignator(Designator::getArray(Idx.release()));
+      Desig->AddDesignator(Designator::getArray(Idx.release(),
+                                                StartLoc));
     } else {
       // Handle the gnu array range extension.
       Diag(Tok, diag::ext_gnu_array_range);
-      ConsumeToken();
+      SourceLocation EllipsisLoc = ConsumeToken();
 
       OwningExprResult RHS(ParseConstantExpression());
       if (RHS.isInvalid()) {
@@ -191,10 +196,12 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
         return move(RHS);
       }
       Desig->AddDesignator(Designator::getArrayRange(Idx.release(),
-                                                     RHS.release()));
+                                                     RHS.release(),
+                                                     StartLoc, EllipsisLoc));
     }
 
-    MatchRHSPunctuation(tok::r_square, StartLoc);
+    SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc);
+    Desig->getDesignator(Desig->getNumDesignators() - 1).setRBracketLoc(EndLoc);
   }
 
   // Okay, we're done with the designator sequence.  We know that there must be
@@ -205,8 +212,9 @@ ParseInitializerWithPotentialDesignator(InitListDesignations &Designations,
 
   // Handle a normal designator sequence end, which is an equal.
   if (Tok.is(tok::equal)) {
-    ConsumeToken();
-    return ParseInitializer();
+    SourceLocation EqualLoc = ConsumeToken();
+    return Actions.ActOnDesignatedInitializer(*Desig, EqualLoc, false,
+                                              ParseInitializer());
   }
 
   // We read some number of designators and found something that isn't an = or
@@ -274,7 +282,7 @@ Parser::OwningExprResult Parser::ParseBraceInitializer() {
       // If we had an erroneous initializer, and we had a potentially valid
       // designator, make sure to remove the designator from
       // InitExprDesignations, otherwise we'll end up with a designator with no
-      // making initializer.
+      // matching initializer.
       if (SubElt.isInvalid())
         InitExprDesignations.EraseDesignation(InitExprs.size());
     }
index 423b049124567aab7c4056a78b1cf95400170c7c..a8cc40490725d40a4eb4a9a1f1fdccf91f502093 100644 (file)
@@ -179,10 +179,10 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) {
 }
 
 void Sema::DeleteExpr(ExprTy *E) {
-  static_cast<Expr*>(E)->Destroy(Context);
+  if (E) static_cast<Expr*>(E)->Destroy(Context);
 }
 void Sema::DeleteStmt(StmtTy *S) {
-  static_cast<Stmt*>(S)->Destroy(Context);
+  if (S) static_cast<Stmt*>(S)->Destroy(Context);
 }
 
 /// ActOnEndOfTranslationUnit - This is called at the very end of the
index 49e3eb8b5c0df5dfb70d1fd750857e189f57517f..b574dc360e3ff5da676d0386cdd67c34f653cb84 100644 (file)
@@ -43,6 +43,7 @@ namespace clang {
   class Stmt;
   class Expr;
   class InitListExpr;
+  class DesignatedInitExpr;
   class CallExpr;
   class DeclRefExpr;
   class VarDecl;
@@ -1043,6 +1044,11 @@ public:
                                          InitListDesignations &Designators,
                                          SourceLocation RParenLoc);
 
+  virtual OwningExprResult ActOnDesignatedInitializer(Designation &Desig,
+                                                      SourceLocation Loc,
+                                                      bool UsedColonSyntax,
+                                                      OwningExprResult Init);
+
   virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
                                       tok::TokenKind Kind,
                                       ExprArg LHS, ExprArg RHS);
@@ -1833,15 +1839,17 @@ class InitListChecker {
   void CheckListElementTypes(InitListExpr *IList, QualType &DeclType, 
                              unsigned &Index);
   void CheckSubElementType(InitListExpr *IList, QualType ElemType, 
-                           unsigned &Index);
+                           Expr *expr, unsigned &Index);
   // FIXME: Does DeclType need to be a reference type?
   void CheckScalarType(InitListExpr *IList, QualType &DeclType, 
-                       unsigned &Index);
+                       Expr *expr, unsigned &Index);
   void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index);
   void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, 
                              unsigned &Index);
   void CheckArrayType(InitListExpr *IList, QualType &DeclType, unsigned &Index);
-  
+  bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE, 
+                                  QualType DeclType, FieldDecl *&DesignatedField, 
+                                  llvm::APSInt &DesignatedIndex, unsigned &Index);
   int numArrayElements(QualType DeclType);
   int numStructUnionElements(QualType DeclType);
 public:
index c1741da3b6e371e3ae81017a679a320f9f79174f..dbf1e7b41659ab638d369897db88824842a8089e 100644 (file)
@@ -2184,6 +2184,9 @@ bool Sema::CheckArithmeticConstantExpression(const Expr* Init) {
 }
 
 bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
+  if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init))
+    Init = DIE->getInit();
+
   Init = Init->IgnoreParens();
 
   if (Init->isEvaluatable(Context))
index f9c91ecaab04e76552928595732c6a187a6f5117..163dac94b92bd486bf1e3f3d5c21b11bc0959a34 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "Sema.h"
+#include "clang/Parse/Designator.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Expr.h"
 #include "clang/Basic/Diagnostic.h"
 #include <algorithm> // for std::count_if
 #include <functional> // for std::mem_fun
 
-namespace clang {
+using namespace clang;
 
 InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) {
   hadError = false;
@@ -131,7 +132,7 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
                                             QualType &DeclType, 
                                             unsigned &Index) {
   if (DeclType->isScalarType()) {
-    CheckScalarType(IList, DeclType, Index);
+    CheckScalarType(IList, DeclType, 0, Index);
   } else if (DeclType->isVectorType()) {
     CheckVectorType(IList, DeclType, Index);
   } else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
@@ -156,8 +157,8 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
 
 void InitListChecker::CheckSubElementType(InitListExpr *IList,
                                           QualType ElemType, 
+                                          Expr *expr,
                                           unsigned &Index) {
-  Expr* expr = IList->getInit(Index);
   if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
     unsigned newIndex = 0;
     CheckExplicitInitList(SubInitList, ElemType, newIndex);
@@ -167,7 +168,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
     SemaRef->CheckStringLiteralInit(lit, ElemType);
     Index++;
   } else if (ElemType->isScalarType()) {
-    CheckScalarType(IList, ElemType, Index);
+    CheckScalarType(IList, ElemType, expr, Index);
   } else if (expr->getType()->getAsRecordType() &&
              SemaRef->Context.typesAreCompatible(
                expr->getType().getUnqualifiedType(),
@@ -180,10 +181,11 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList,
   }
 }
 
-void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType, 
-                                      unsigned &Index) {
+void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
+                                      Expr *expr, unsigned &Index) {
   if (Index < IList->getNumInits()) {
-    Expr* expr = IList->getInit(Index);
+    if (!expr)
+      expr = IList->getInit(Index);
     if (isa<InitListExpr>(expr)) {
       SemaRef->Diag(IList->getLocStart(),
                     diag::err_many_braces_around_scalar_init)
@@ -191,13 +193,26 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
       hadError = true;
       ++Index;
       return;
+    } else if (isa<DesignatedInitExpr>(expr)) {
+      SemaRef->Diag(expr->getSourceRange().getBegin(), 
+                    diag::err_designator_for_scalar_init)
+        << DeclType << expr->getSourceRange();
+      hadError = true;
+      ++Index;
+      return;
     }
+
     Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
     if (SemaRef->CheckSingleInitializer(expr, DeclType, false))
       hadError = true; // types weren't compatible.
-    else if (savExpr != expr)
+    else if (savExpr != expr) {
       // The type was promoted, update initializer list.
-      IList->setInit(Index, expr);
+      if (DesignatedInitExpr *DIE 
+            = dyn_cast<DesignatedInitExpr>(IList->getInit(Index)))
+        DIE->setInit(expr);
+      else
+        IList->setInit(Index, expr);
+    }
     ++Index;
   } else {
     SemaRef->Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
@@ -218,7 +233,7 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
       // Don't attempt to go past the end of the init list
       if (Index >= IList->getNumInits())
         break;
-      CheckSubElementType(IList, elementType, Index);
+      CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
     }
   }
 }
@@ -246,29 +261,63 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
     return;
   }
 
-  int maxElements = numArrayElements(DeclType);
+  // FIXME: Will 32 bits always be enough? I hope so.
+  const unsigned ArraySizeBits = 32;
+  llvm::APSInt elementIndex(ArraySizeBits, 0);
+
+  // We might know the maximum number of elements in advance.
+  llvm::APSInt maxElements(ArraySizeBits, 0);
+  bool maxElementsKnown = false;
+  if (const ConstantArrayType *CAT =
+        SemaRef->Context.getAsConstantArrayType(DeclType)) {
+    maxElements = CAT->getSize();
+    maxElementsKnown = true;
+  }
+
   QualType elementType = SemaRef->Context.getAsArrayType(DeclType)
                              ->getElementType();
-  int numElements = 0;
-  for (int i = 0; i < maxElements; ++i, ++numElements) {
-    // Don't attempt to go past the end of the init list
-    if (Index >= IList->getNumInits())
+  while (Index < IList->getNumInits()) {
+    Expr *Init = IList->getInit(Index);
+    if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
+      // C99 6.7.8p17:
+      //   [...] In contrast, a designation causes the following
+      //   initializer to begin initialization of the subobject
+      //   described by the designator. 
+      FieldDecl *DesignatedField = 0;
+      if (CheckDesignatedInitializer(IList, DIE, DeclType, DesignatedField, 
+                                     elementIndex, Index))
+        hadError = true;
+
+      ++elementIndex;
+      continue;
+    }
+
+    // If we know the maximum number of elements, and we've already
+    // hit it, stop consuming elements in the initializer list.
+    if (maxElementsKnown && elementIndex == maxElements)
       break;
-    CheckSubElementType(IList, elementType, Index);
+
+    // Check this element.
+    CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
+    ++elementIndex;
+
+    // If the array is of incomplete type, keep track of the number of
+    // elements in the initializer.
+    if (!maxElementsKnown && elementIndex > maxElements)
+      maxElements = elementIndex;
   }
   if (DeclType->isIncompleteArrayType()) {
     // If this is an incomplete array type, the actual type needs to
     // be calculated here.
-    if (numElements == 0) {
+    llvm::APInt Zero(ArraySizeBits, 0);
+    if (maxElements == Zero) {
       // Sizing an array implicitly to zero is not allowed by ISO C,
       // but is supported by GNU.
       SemaRef->Diag(IList->getLocStart(),
                     diag::ext_typecheck_zero_array_size);
     }
 
-    llvm::APSInt ConstVal(32);
-    ConstVal = numElements;
-    DeclType = SemaRef->Context.getConstantArrayType(elementType, ConstVal, 
+    DeclType = SemaRef->Context.getConstantArrayType(elementType, maxElements, 
                                                      ArrayType::Normal, 0);
   }
 }
@@ -284,34 +333,310 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
     hadError = true;
     return;
   }    
-  // If structDecl is a forward declaration, this loop won't do anything;
-  // That's okay, because an error should get printed out elsewhere. It
-  // might be worthwhile to skip over the rest of the initializer, though.
+  // If structDecl is a forward declaration, this loop won't do
+  // anything except look at designated initializers; That's okay,
+  // because an error should get printed out elsewhere. It might be
+  // worthwhile to skip over the rest of the initializer, though.
   RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
-  for (RecordDecl::field_iterator Field = RD->field_begin(),
-                               FieldEnd = RD->field_end();
-       Field != FieldEnd; ++Field) {
-    // If we've hit the flexible array member at the end, we're done.
-    if (Field->getType()->isIncompleteArrayType())
+  RecordDecl::field_iterator Field = RD->field_begin(), 
+                          FieldEnd = RD->field_end();
+  while (Index < IList->getNumInits()) {
+    Expr *Init = IList->getInit(Index);
+
+    if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) {
+      // C99 6.7.8p17:
+      //   [...] In contrast, a designation causes the following
+      //   initializer to begin initialization of the subobject
+      //   described by the designator. Initialization then continues
+      //   forward in order, beginning with the next subobject after
+      //   that described by the designator. 
+      FieldDecl *DesignatedField = 0;
+      llvm::APSInt LastElement;
+      if (CheckDesignatedInitializer(IList, DIE, DeclType, DesignatedField, 
+                                     LastElement, Index)) {
+        hadError = true;
+        continue;
+      }
+
+      Field = RecordDecl::field_iterator(
+                           DeclContext::decl_iterator(DesignatedField),
+                           DeclType->getAsRecordType()->getDecl()->decls_end());
+      ++Field;
+      continue;
+    }
+
+    if (Field == FieldEnd) {
+      // We've run out of fields. We're done.
       break;
+    }
 
-    // Don't attempt to go past the end of the init list
-    if (Index >= IList->getNumInits())
+    // If we've hit the flexible array member at the end, we're done.
+    if (Field->getType()->isIncompleteArrayType())
       break;
 
     if (!Field->getIdentifier()) {
       // Don't initialize unnamed fields, e.g. "int : 20;"
+      ++Field;
       continue;
     }
 
-    CheckSubElementType(IList, Field->getType(), Index);
-    if (DeclType->isUnionType())
+    CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index);
+    if (DeclType->isUnionType()) // FIXME: designated initializers?
       break;
+
+    ++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!)
 }
-} // end namespace clang
 
+/// @brief Check the well-formedness of a C99 designated initializer.
+///
+/// Determines whether the designated initializer @p DIE, which
+/// resides at the given @p Index within the initializer list @p
+/// IList, is well-formed for a current object of type @p DeclType
+/// (C99 6.7.8). The actual subobject that this designator refers to
+/// within the current subobject is returned in either 
+/// @p DesignatedField or @p DesignatedIndex (whichever is
+/// appropriate).
+///
+/// @param IList  The initializer list in which this designated
+/// initializer occurs.
+///
+/// @param DIE  The designated initializer and its initialization
+/// expression.
+///
+/// @param DeclType  The type of the "current object" (C99 6.7.8p17),
+/// into which the designation in @p DIE should refer.
+///
+/// @param DesignatedField  If the first designator in @p DIE is a field,
+/// this will be set to the field declaration corresponding to the
+/// field named by the designator.
+///
+/// @param DesignatedIndex  If the first designator in @p DIE is an
+/// array designator or GNU array-range designator, this will be set
+/// to the last index initialized by this designator.
+///
+/// @param Index  Index into @p IList where the designated initializer
+/// @p DIE occurs.
+///
+/// @returns true if there was an error, false otherwise.
+bool InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
+                                                 DesignatedInitExpr *DIE, 
+                                                 QualType DeclType,
+                                                 FieldDecl *&DesignatedField, 
+                                                 llvm::APSInt &DesignatedIndex,
+                                                 unsigned &Index) {
+  // DeclType is always the type of the "current object" (C99 6.7.8p17).
+
+  for (DesignatedInitExpr::designators_iterator D = DIE->designators_begin(),
+                                             DEnd = DIE->designators_end();
+       D != DEnd; ++D) {
+    if (D->isFieldDesignator()) {
+      // C99 6.7.8p7:
+      //
+      //   If a designator has the form
+      //
+      //      . identifier
+      //
+      //   then the current object (defined below) shall have
+      //   structure or union type and the identifier shall be the
+      //   name of a member of that type. 
+      const RecordType *RT = DeclType->getAsRecordType();
+      if (!RT) {
+        SemaRef->Diag(DIE->getSourceRange().getBegin(), 
+                      diag::err_field_designator_non_aggr)
+          << SemaRef->getLangOptions().CPlusPlus << DeclType;
+        ++Index;
+        return true;
+      }
+
+      IdentifierInfo *FieldName = D->getFieldName();
+      DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
+      FieldDecl *ThisField = 0;
+      if (Lookup.first == Lookup.second) {
+        // Lookup did not find anything with this name.
+        SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
+          << FieldName << DeclType;
+      } else if (isa<FieldDecl>(*Lookup.first)) {
+        // Name lookup found a field.
+        ThisField = cast<FieldDecl>(*Lookup.first);
+        // FIXME: Make sure this isn't a field in an anonymous
+        // struct/union.
+      } else {
+        // Name lookup found something, but it wasn't a field.
+        SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
+          << FieldName;
+        SemaRef->Diag((*Lookup.first)->getLocation(), 
+                      diag::note_field_designator_found);
+      }
+
+      if (!ThisField) {
+        ++Index;
+        return true;
+      }
+        
+      // Update the designator with the field declaration.
+      D->setField(ThisField);
+      
+      if (D == DIE->designators_begin())
+        DesignatedField = ThisField;
+
+      // The current object is now the type of this field.
+      DeclType = ThisField->getType();
+    } else {
+      // C99 6.7.8p6:
+      //
+      //   If a designator has the form
+      //
+      //      [ constant-expression ]
+      //
+      //   then the current object (defined below) shall have array
+      //   type and the expression shall be an integer constant
+      //   expression. If the array is of unknown size, any
+      //   nonnegative value is valid.
+      const ArrayType *AT = SemaRef->Context.getAsArrayType(DeclType);
+      if (!AT) {
+        SemaRef->Diag(D->getLBracketLoc(), diag::err_array_designator_non_array)
+          << DeclType;
+        ++Index;
+        return true;
+      }
+
+      Expr *IndexExpr = 0;
+      llvm::APSInt ThisIndex;
+      if (D->isArrayDesignator())
+        IndexExpr = DIE->getArrayIndex(*D);
+      else {
+        assert(D->isArrayRangeDesignator() && "Need array-range designator");
+        IndexExpr = DIE->getArrayRangeEnd(*D);
+      }
+
+      bool ConstExpr 
+        = IndexExpr->isIntegerConstantExpr(ThisIndex, SemaRef->Context);
+      assert(ConstExpr && "Expression must be constant"); (void)ConstExpr;
+        
+      if (isa<ConstantArrayType>(AT)) {
+        llvm::APSInt MaxElements(cast<ConstantArrayType>(AT)->getSize(), false);
+        if (ThisIndex >= MaxElements) {
+          SemaRef->Diag(IndexExpr->getSourceRange().getBegin(),
+                        diag::err_array_designator_too_large)
+            << ThisIndex.toString(10) << MaxElements.toString(10);
+          ++Index;
+          return true;
+        }
+      }
+
+      if (D == DIE->designators_begin())
+        DesignatedIndex = ThisIndex;
+
+      // The current object is now the element type of this array.
+      DeclType = AT->getElementType();
+    }
+  }
+
+  // Check the actual initialization for the designated object type.
+  bool prevHadError = hadError;
+  CheckSubElementType(IList, DeclType, DIE->getInit(), Index);
+  return hadError && !prevHadError;
+}
+
+/// Check that the given Index expression is a valid array designator
+/// value. This is essentailly just a wrapper around
+/// Expr::isIntegerConstantExpr that also checks for negative values
+/// and produces a reasonable diagnostic if there is a
+/// failure. Returns true if there was an error, false otherwise.  If
+/// everything went okay, Value will receive the value of the constant
+/// expression.
+static bool 
+CheckArrayDesignatorExpr(Sema &Self, Expr *Index, llvm::APSInt &Value) {
+  SourceLocation Loc = Index->getSourceRange().getBegin();
+
+  // Make sure this is an integer constant expression.
+  if (!Index->isIntegerConstantExpr(Value, Self.Context, &Loc))
+    return Self.Diag(Loc, diag::err_array_designator_nonconstant)
+      << Index->getSourceRange();
+
+  // Make sure this constant expression is non-negative.
+  llvm::APSInt Zero(llvm::APSInt::getNullValue(Value.getBitWidth()), false);
+  if (Value < Zero)
+    return Self.Diag(Loc, diag::err_array_designator_negative)
+      << Value.toString(10) << Index->getSourceRange();
+
+  return false;
+}
+
+Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
+                                                        SourceLocation Loc,
+                                                        bool UsedColonSyntax,
+                                                        OwningExprResult Init) {
+  typedef DesignatedInitExpr::Designator ASTDesignator;
+
+  bool Invalid = false;
+  llvm::SmallVector<ASTDesignator, 32> Designators;
+  llvm::SmallVector<Expr *, 32> InitExpressions;
+
+  // Build designators and check array designator expressions.
+  for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) {
+    const Designator &D = Desig.getDesignator(Idx);
+    switch (D.getKind()) {
+    case Designator::FieldDesignator:
+      Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(), 
+                                          D.getFieldLoc()));
+      break;
+
+    case Designator::ArrayDesignator: {
+      Expr *Index = static_cast<Expr *>(D.getArrayIndex());
+      llvm::APSInt IndexValue;
+      if (CheckArrayDesignatorExpr(*this, Index, IndexValue))
+        Invalid = true;
+      else {
+        Designators.push_back(ASTDesignator(InitExpressions.size(),
+                                            D.getLBracketLoc(), 
+                                            D.getRBracketLoc()));
+        InitExpressions.push_back(Index);
+      }
+      break;
+    }
+
+    case Designator::ArrayRangeDesignator: {
+      Expr *StartIndex = static_cast<Expr *>(D.getArrayRangeStart());
+      Expr *EndIndex = static_cast<Expr *>(D.getArrayRangeEnd());
+      llvm::APSInt StartValue;
+      llvm::APSInt EndValue;
+      if (CheckArrayDesignatorExpr(*this, StartIndex, StartValue) ||
+          CheckArrayDesignatorExpr(*this, EndIndex, EndValue))
+        Invalid = true;
+      else if (EndValue < StartValue) {
+        Diag(D.getEllipsisLoc(), diag::err_array_designator_empty_range)
+          << StartValue.toString(10) << EndValue.toString(10) 
+          << StartIndex->getSourceRange() << EndIndex->getSourceRange();
+        Invalid = true;
+      } else {
+        Designators.push_back(ASTDesignator(InitExpressions.size(),
+                                            D.getLBracketLoc(), 
+                                            D.getEllipsisLoc(),
+                                            D.getRBracketLoc()));
+        InitExpressions.push_back(StartIndex);
+        InitExpressions.push_back(EndIndex);
+      }
+      break;
+    }
+    }
+  }
+
+  if (Invalid || Init.isInvalid())
+    return ExprError();
+
+  // Clear out the expressions within the designation.
+  Desig.ClearExprs(*this);
+
+  DesignatedInitExpr *DIE
+    = DesignatedInitExpr::Create(Context, &Designators[0], Designators.size(),
+                                 &InitExpressions[0], InitExpressions.size(),
+                                 Loc, UsedColonSyntax, 
+                                 static_cast<Expr *>(Init.release()));
+  return Owned(DIE);
+}
diff --git a/test/Sema/designated-initializers.c b/test/Sema/designated-initializers.c
new file mode 100644 (file)
index 0000000..5efb444
--- /dev/null
@@ -0,0 +1,78 @@
+// RUN: clang -fsyntax-only -verify %s
+
+int iarray[10] = {
+  [0] = 1,
+  [1 ... 5] = 2,
+  [ 6 ... 6 ] = 3,
+  [ 8 ... 7 ] = 4, // expected-error{{array designator range [8, 7] is empty}}
+  [10] = 5,
+  [-1] = 6 // expected-error{{array designator value '-1' is negative}}
+};
+
+int iarray2[10] = {
+  [10] = 1, // expected-error{{array designator index (10) exceeds array bounds (10)}}
+  [5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}}
+};
+
+struct point {
+  double x;
+  double y;
+};
+
+struct point p1 = { 
+  .y = 1.0, 
+  x: 2.0,
+  .a = 4.0, // expected-error{{field designator 'a' does not refer to any field in type 'struct point'}}
+
+  [1] = 1.0 // expected-error{{array designator cannot initialize non-array type}}
+};
+
+struct point array[10] = { 
+  [0].x = 1.0,
+  [1].y = 2.0,
+  [2].z = 3.0, // expected-error{{field designator 'z' does not refer to any field in type 'struct point'}}
+  [10].x = 2.0, // expected-error{{array designator index (10) exceeds array bounds (10)}}
+  [4 ... 5].y = 2.0,
+  [4 ... 6] = { .x = 3, .y = 4.0 },
+  .x = 5 // expected-error{{field designator cannot initialize a non-struct, non-union type}}
+};
+
+struct rect {
+  struct point top_left;
+  struct point bottom_right;
+};
+
+struct rect window = { .top_left.x = 1.0 };
+
+struct rect windows[] = {
+  [2].top_left = { 1.0, 2.0 },
+  [4].bottom_right = { .y = 1.0 },
+  { { .y = 7.0, .x = 8.0 }, { .x = 5.0 } },
+  [3] = { .top_left = { 1.1, 2.2 }, .bottom_right = { .y = 1.1 } }
+};
+
+int windows_size[((sizeof(windows) / sizeof(struct rect)) == 6)? 1 : -1];
+
+struct rect windows_bad[3] = {
+  [2].top_left = { { .x = 1.1 } }, // expected-error{{designator in initializer for scalar type}}
+  [1].top_left = { .x = 1.1 }
+};
+
+struct gui {
+  struct rect windows[10];
+};
+
+struct gui gui[] = {
+  [5].windows[3].top_left.x = { 7.0 } // expected-warning{{braces around scalar initializer}}
+};
+
+struct translator {
+  struct wonky { int * ptr; } wonky ;
+  struct rect window;
+  struct point offset;
+} tran = {
+  .window = { .top_left = { 1.0, 2.0 } },
+  { .x = 5.0, .y = 6.0 },
+  .wonky = { 0 }
+};
+