]> granicus.if.org Git - clang/commitdiff
Code generation support for C99 designated initializers.
authorDouglas Gregor <dgregor@apple.com>
Wed, 28 Jan 2009 21:54:33 +0000 (21:54 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 28 Jan 2009 21:54:33 +0000 (21:54 +0000)
The approach I've taken in this patch is relatively straightforward,
although the code itself is non-trivial. Essentially, as we process
an initializer list we build up a fully-explicit representation of the
initializer list, where each of the subobject initializations occurs
in order. Designators serve to "fill in" subobject initializations in
a non-linear way. The fully-explicit representation makes initializer
lists (both with and without designators) easy to grok for codegen and
later semantic analyses. We keep the syntactic form of the initializer
list linked into the AST for those clients interested in exactly what
the user wrote.

Known limitations:
  - Designating a member of a union that isn't the first member may
    result in bogus initialization (we warn about this)
  - GNU array-range designators are not supported (we warn about this)

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

17 files changed:
Driver/RewriteObjC.cpp
include/clang/AST/Decl.h
include/clang/AST/Expr.h
include/clang/AST/ExprCXX.h
include/clang/Basic/DiagnosticSemaKinds.def
lib/AST/Expr.cpp
lib/AST/StmtPrinter.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprConstant.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaInit.cpp
test/Sema/array-init.c
test/Sema/designated-initializers.c
test/Sema/vector-init.c

index 4524920f5a5afdcfdebaa4f65e37ebd10d8e2e7e..e2ddafe8d1925d12dea11e888705393a2e0a0a8a 100644 (file)
@@ -2310,7 +2310,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
         // (struct objc_super) { <exprs from above> }
         InitListExpr *ILE = new InitListExpr(SourceLocation(), 
                                              &InitExprs[0], InitExprs.size(), 
-                                             SourceLocation(), false);
+                                             SourceLocation());
         SuperRep = new CompoundLiteralExpr(SourceLocation(), superType, ILE,
                                            false);
         // struct objc_super *
@@ -2391,7 +2391,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
         // (struct objc_super) { <exprs from above> }
         InitListExpr *ILE = new InitListExpr(SourceLocation(), 
                                              &InitExprs[0], InitExprs.size(), 
-                                             SourceLocation(), false);
+                                             SourceLocation());
         SuperRep = new CompoundLiteralExpr(SourceLocation(), superType, ILE, false);
       }
       MsgExprs.push_back(SuperRep);
index 988a7419a59910d168d3d79bb19737a45d6d2a65..18d1c05467911d63eba429af4b39a3936e5fdca0 100644 (file)
@@ -678,6 +678,9 @@ public:
   /// isBitfield - Determines whether this field is a bitfield.
   bool isBitField() const { return BitWidth != NULL; }
 
+  /// @brief Determines whether this is an unnamed bitfield.
+  bool isUnnamedBitfield() const { return BitWidth != NULL && !getDeclName(); }
+
   /// isAnonymousStructOrUnion - Determines whether this field is a
   /// representative for an anonymous struct or union. Such fields are
   /// unnamed and are implicitly generated by the implementation to
index 5d768cd9dba319881cbf8bb18a89deb4f5cb1edf..861ac817ccac05e5a96c804acdb529ddbc6d7660 100644 (file)
@@ -185,6 +185,10 @@ public:
   /// initializer, which can be emitted at compile-time.
   bool isConstantInitializer(ASTContext &Ctx) const;
   
+  /// @brief Determines whether this expression (or any of its
+  /// subexpressions) has side effects.
+  bool hasSideEffects(ASTContext &Ctx) const;
+
   /// EvalResult is a struct with detailed info about an evaluated expression.
   struct EvalResult {
     /// Val - This is the scalar value the expression can be folded to.
@@ -1619,48 +1623,65 @@ public:
   static VAArgExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
 };
   
-/// InitListExpr - used for struct and array initializers, such as:
-///    struct foo x = { 1, { 2, 3 } };
+/// @brief Describes an C or C++ initializer list.
+///
+/// InitListExpr describes an initializer list, which can be used to
+/// initialize objects of different types, including
+/// struct/class/union types, arrays, and vectors. For example:
+///
+/// @code
+/// struct foo x = { 1, { 2, 3 } };
+/// @endcode
 ///
-/// Because C is somewhat loose with braces, the AST does not necessarily
-/// directly model the C source.  Instead, the semantic analyzer aims to make
-/// the InitListExprs match up with the type of the decl being initialized.  We
-/// have the following exceptions:
+/// Prior to semantic analysis, an initializer list will represent the
+/// initializer list as written by the user, but will have the
+/// placeholder type "void". This initializer list is called the
+/// syntactic form of the initializer, and may contain C99 designated
+/// initializers (represented as DesignatedInitExprs), initializations
+/// of subobject members without explicit braces, and so on. Clients
+/// interested in the original syntax of the initializer list should
+/// use the syntactic form of the initializer list.
 ///
-///  1. Elements at the end of the list may be dropped from the initializer.  
-///     These elements are defined to be initialized to zero.  For example:
-///         int x[20] = { 1 };
-///  2. Initializers may have excess initializers which are to be ignored by the
-///     compiler.  For example:
-///         int x[1] = { 1, 2 };
-///  3. Redundant InitListExprs may be present around scalar elements.  These
-///     always have a single element whose type is the same as the InitListExpr.
-///     this can only happen for Type::isScalarType() types.
-///         int x = { 1 };  int y[2] = { {1}, {2} };
+/// After semantic analysis, the initializer list will represent the
+/// semantic form of the initializer, where the initializations of all
+/// subobjects are made explicit with nested InitListExpr nodes and
+/// C99 designators have been eliminated by placing the designated
+/// initializations into the subobject they initialize. Additionally,
+/// any "holes" in the initialization, where no initializer has been
+/// specified for a particular subobject, will be replaced with
+/// implicitly-generated CXXZeroInitValueExpr expressions that
+/// value-initialize the subobjects. Note, however, that the
+/// initializer lists may still have fewer initializers than there are
+/// elements to initialize within the object.
 ///
+/// Given the semantic form of the initializer list, one can retrieve
+/// the original syntactic form of that initializer list (if it
+/// exists) using getSyntacticForm(). Since many initializer lists
+/// have the same syntactic and semantic forms, getSyntacticForm() may
+/// return NULL, indicating that the current initializer list also
+/// serves as its syntactic form.
 class InitListExpr : public Expr {
   std::vector<Stmt *> InitExprs;
   SourceLocation LBraceLoc, RBraceLoc;
   
-  /// HadDesignators - Return true if there were any designators in this
-  /// init list expr.  FIXME: this should be replaced by storing the designators
-  /// somehow and updating codegen.
-  bool HadDesignators;
+  /// Contains the initializer list that describes the syntactic form
+  /// written in the source code.
+  InitListExpr *SyntacticForm;
+
 public:
   InitListExpr(SourceLocation lbraceloc, Expr **initexprs, unsigned numinits,
-               SourceLocation rbraceloc, bool HadDesignators);
+               SourceLocation rbraceloc);
   
   unsigned getNumInits() const { return InitExprs.size(); }
-  bool hadDesignators() const { return HadDesignators; }
   
   const Expr* getInit(unsigned Init) const { 
     assert(Init < getNumInits() && "Initializer access out of range!");
-    return cast<Expr>(InitExprs[Init]);
+    return cast_or_null<Expr>(InitExprs[Init]);
   }
   
   Expr* getInit(unsigned Init) { 
     assert(Init < getNumInits() && "Initializer access out of range!");
-    return cast<Expr>(InitExprs[Init]);
+    return cast_or_null<Expr>(InitExprs[Init]);
   }
   
   void setInit(unsigned Init, Expr *expr) { 
@@ -1668,13 +1689,22 @@ public:
     InitExprs[Init] = expr;
   }
 
-  // Dynamic removal/addition (for constructing implicit InitExpr's).
-  void removeInit(unsigned Init) {
-    InitExprs.erase(InitExprs.begin()+Init);
-  }
-  void addInit(unsigned Init, Expr *expr) {
-    InitExprs.insert(InitExprs.begin()+Init, expr);
-  }
+  /// @brief Specify the number of initializers
+  ///
+  /// If there are more than @p NumInits initializers, the remaining
+  /// initializers will be destroyed. If there are fewer than @p
+  /// NumInits initializers, NULL expressions will be added for the
+  /// unknown initializers.
+  void resizeInits(ASTContext &Context, unsigned NumInits);
+
+  /// @brief Updates the initializer at index @p Init with the new
+  /// expression @p expr, and returns the old expression at that
+  /// location.
+  ///
+  /// When @p Init is out of range for this initializer list, the
+  /// initializer list will be extended with NULL expressions to
+  /// accomodate the new entry.
+  Expr *updateInit(unsigned Init, Expr *expr);
 
   // Explicit InitListExpr's originate from source code (and have valid source
   // locations). Implicit InitListExpr's are created by the semantic analyzer.
@@ -1682,6 +1712,13 @@ public:
     return LBraceLoc.isValid() && RBraceLoc.isValid();
   }
   
+  /// @brief Retrieve the initializer list that describes the
+  /// syntactic form of the initializer.
+  ///
+  /// 
+  InitListExpr *getSyntacticForm() const { return SyntacticForm; }
+  void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; }
+
   virtual SourceRange getSourceRange() const {
     return SourceRange(LBraceLoc, RBraceLoc);
   } 
@@ -1885,6 +1922,13 @@ public:
              "Only valid on an array-range designator");
       return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc);
     }
+
+    SourceLocation getStartLocation() const {
+      if (Kind == FieldDesignator)
+        return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc();
+      else
+        return getLBracketLoc();
+    }
   };
 
   static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators, 
index 669e790b3996d205c25830eba305bda033faaad4..4f48eb3716a920139cb752171c618b126bdcfcc1 100644 (file)
@@ -477,6 +477,12 @@ public:
   SourceLocation getTypeBeginLoc() const { return TyBeginLoc; }
   SourceLocation getRParenLoc() const { return RParenLoc; }
 
+  /// @brief Whether this initialization expression was
+  /// implicitly-generated.
+  bool isImplicit() const { 
+    return TyBeginLoc.isInvalid() && RParenLoc.isInvalid(); 
+  }
+
   virtual SourceRange getSourceRange() const {
     return SourceRange(TyBeginLoc, RParenLoc);
   }
index 2959f6186b748136001217c9400667a35823e96e..222e39911b812eec927509bdf80315643972c05a 100644 (file)
@@ -50,8 +50,20 @@ 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_field_designator_anon_class, ERROR,
+     "field designator %0 refers to a member of an anonymous %select{struct|class|union}1")
 DIAG(err_designator_for_scalar_init, ERROR,
      "designator in initializer for scalar type %0")
+DIAG(warn_subobject_initializer_overrides, WARNING,
+     "subobject initialization overrides initialization of other fields within its enclosing subobject")
+DIAG(warn_initializer_overrides, WARNING,
+     "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(warn_gnu_array_range_designator_unsupported, WARNING,
+     "GNU array-range designator extension is unsupported")
+DIAG(warn_designator_into_union_broken_init, WARNING,
+     "designated initialization of union member is broken")
 
 // Declarations.
 DIAG(ext_vla, EXTENSION,
index 8e43f99b67298dde0138dce845718a5c587a273a..ed73bfae27b29cd818fba02f97c025caf2e03a3c 100644 (file)
@@ -221,13 +221,31 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
 
 InitListExpr::InitListExpr(SourceLocation lbraceloc, 
                            Expr **initExprs, unsigned numInits,
-                           SourceLocation rbraceloc, bool hadDesignators)
+                           SourceLocation rbraceloc)
   : Expr(InitListExprClass, QualType()),
-    LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), HadDesignators(hadDesignators) {
+    LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0) {
 
   InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
 }
 
+void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) {
+  for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); Idx < LastIdx; ++Idx)
+    delete InitExprs[Idx];
+  InitExprs.resize(NumInits, 0);
+}
+
+Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) {
+  if (Init >= InitExprs.size()) {
+    InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0);
+    InitExprs.back() = expr;
+    return 0;
+  }
+  
+  Expr *Result = cast_or_null<Expr>(InitExprs[Init]);
+  InitExprs[Init] = expr;
+  return Result;
+}
+
 /// getFunctionType - Return the underlying function type for this block.
 ///
 const FunctionType *BlockExpr::getFunctionType() const {
@@ -740,6 +758,12 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
   return isEvaluatable(Ctx);
 }
 
+bool Expr::hasSideEffects(ASTContext &Ctx) const {
+  EvalResult Result;
+  Evaluate(Result, Ctx);
+  return Result.HasSideEffects;
+}
+
 /// isIntegerConstantExpr - this recursive routine will test if an expression is
 /// an integer constant expression. Note: With the introduction of VLA's in
 /// C99 the result of the sizeof operator is no longer always a constant
index 80de5b8ae4540df332f663bbb72cae99aeb31efd..7a558ab8dd7b8907b6167e07585de60baaf6d5da 100644 (file)
@@ -872,13 +872,38 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
   OS << "{ ";
   for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {
     if (i) OS << ", ";
-    PrintExpr(Node->getInit(i));
+    if (Node->getInit(i))
+      PrintExpr(Node->getInit(i));
+    else
+      OS << "0";
   }
   OS << " }";
 }
 
 void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
-  // FIXME!
+  for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(),
+                      DEnd = Node->designators_end();
+       D != DEnd; ++D) {
+    if (D->isFieldDesignator()) {
+      if (D->getDotLoc().isInvalid())
+        OS << D->getFieldName()->getName() << ":";
+      else
+        OS << "." << D->getFieldName()->getName();
+    } else {
+      OS << "[";
+      if (D->isArrayDesignator()) {
+        PrintExpr(Node->getArrayIndex(*D));
+      } else {
+        PrintExpr(Node->getArrayRangeStart(*D));
+        OS << " ... ";
+        PrintExpr(Node->getArrayRangeEnd(*D));        
+      }
+      OS << "]";
+    }
+  }
+
+  OS << " = ";
+  PrintExpr(Node->getInit());
 }
 
 void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
@@ -1187,7 +1212,9 @@ void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
 //===----------------------------------------------------------------------===//
 
 void Stmt::dumpPretty() const {
-  printPretty(llvm::errs());
+  llvm::raw_ostream &OS = llvm::errs();
+  printPretty(OS);
+  OS.flush();
 }
 
 void Stmt::printPretty(llvm::raw_ostream &OS, PrinterHelper* Helper) const {
index 9181bf665450a999a26cfce26eb2d28ce83f73b2..2534a14cb6c59962f1fc3676cf345e2d491af2be 100644 (file)
@@ -71,7 +71,7 @@ public:
   void VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
     EmitAggLoadOfLValue(E);
   }
-
+  
   // Operators.
   //  case Expr::UnaryOperatorClass:
   //  case Expr::CastExprClass: 
@@ -303,11 +303,6 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
 }
 
 void AggExprEmitter::EmitNonConstInit(InitListExpr *E) {
-  if (E->hadDesignators()) {
-    CGF.ErrorUnsupported(E, "initializer list with designators");
-    return;
-  }
-  
   const llvm::PointerType *APType =
     cast<llvm::PointerType>(DestPtr->getType());
   const llvm::Type *DestType = APType->getElementType();
@@ -346,6 +341,8 @@ void AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
   // FIXME: Are initializers affected by volatile?
   if (E->getType()->isComplexType()) {
     CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
+  } else if (isa<CXXZeroInitValueExpr>(E)) {
+    EmitNullInitializationToLValue(LV, E->getType());
   } else if (CGF.hasAggregateLLVMType(E->getType())) {
     CGF.EmitAnyExpr(E, LV.getAddress(), false);
   } else {
@@ -380,11 +377,6 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) {
 }
 
 void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
-  if (E->hadDesignators()) {
-    CGF.ErrorUnsupported(E, "initializer list with designators");
-    return;
-  }
-
 #if 0
   // FIXME: Disabled while we figure out what to do about 
   // test/CodeGen/bitfield.c
@@ -426,7 +418,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
 
     uint64_t NumArrayElements = AType->getNumElements();
     QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
-    ElementType =CGF.getContext().getAsArrayType(ElementType)->getElementType();
+    ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
     
     unsigned CVRqualifier = ElementType.getCVRQualifiers();
 
@@ -479,7 +471,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
     }
 
     // Unions only initialize one field.
-    // (things can get weird with designators, but they aren't
+    // (FIXME: things can get weird with designators, but they aren't
     // supported yet.)
     if (isUnion)
       break;
index 32d126e5903e2869e8869dceae1db6937d07ac5a..3b6ebb4d56f3905d5bd93ba910ceee21e62aa9e2 100644 (file)
@@ -242,6 +242,8 @@ public:
     const llvm::Type *Ty = ConvertType(ILE->getType());
 
     // Find the field decl we're initializing, if any
+    // FIXME: C99 designated initializers won't always initialize the 
+    // first field
     int FieldNo = 0; // Field no in RecordDecl
     FieldDecl* curField = 0;
     for (RecordDecl::field_iterator Field = RD->field_begin(),
@@ -304,12 +306,6 @@ public:
       return llvm::Constant::getNullValue(RetTy);
     }
     
-    // FIXME: We don't codegen or sema designators yet.
-    if (ILE->hadDesignators()) {
-      CGM.ErrorUnsupported(ILE, "initializer list with designators");
-      return llvm::UndefValue::get(ConvertType(ILE->getType()));
-    }
-
     if (ILE->getType()->isArrayType())
       return EmitArrayInitialization(ILE);
 
index 33c5a6124bdcc5592ed29ba3dc3ee01d2fc4b84b..dd8b30041e707cea9291817d1ef4b889a993916b 100644 (file)
@@ -176,11 +176,6 @@ public:
     if (!VType) 
       return Visit(E->getInit(0));
     
-    if (E->hadDesignators()) {
-      CGF.ErrorUnsupported(E, "initializer list with designators");
-      return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
-    }
-    
     unsigned NumVectorElements = VType->getNumElements();
     const llvm::Type *ElementType = VType->getElementType();
 
index d017e6f9c7bc02fdf254d977bde2fac91e6ae68f..8cf10ff3e2a785f349c2c96b6b6d2a6fea24afdc 100644 (file)
@@ -28,6 +28,7 @@
 #include "llvm/ADT/OwningPtr.h"
 #include <string>
 #include <vector>
+#include <map>
 
 namespace llvm {
   class APSInt;
@@ -1835,38 +1836,67 @@ private:
 class InitListChecker {
   Sema *SemaRef;
   bool hadError;
+  std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic;
+  InitListExpr *FullyStructuredList;
   
   void CheckImplicitInitList(InitListExpr *ParentIList, QualType T, 
-                             unsigned &Index);
+                             unsigned &Index, InitListExpr *StructuredInitList,
+                             unsigned &StructuredInitIndex);
   void CheckExplicitInitList(InitListExpr *IList, QualType &T,
-                             unsigned &Index);
-
+                             unsigned &Index, InitListExpr *StructuredInitList,
+                             unsigned &StructuredInitIndex);
   void CheckListElementTypes(InitListExpr *IList, QualType &DeclType, 
                              bool SubobjectIsDesignatorContext, 
-                             unsigned &Index);
+                             unsigned &Index,
+                             InitListExpr *StructuredInitList,
+                             unsigned &StructuredInitIndex);
   void CheckSubElementType(InitListExpr *IList, QualType ElemType, 
-                           Expr *expr, unsigned &Index);
+                           Expr *expr, unsigned &Index,
+                           InitListExpr *StructuredInitList,
+                           unsigned &StructuredInitIndex);
   // FIXME: Does DeclType need to be a reference type?
   void CheckScalarType(InitListExpr *IList, QualType &DeclType, 
-                       Expr *expr, unsigned &Index);
-  void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index);
+                       Expr *expr, unsigned &Index,
+                       InitListExpr *StructuredInitList,
+                       unsigned &StructuredInitIndex);
+  void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index,
+                       InitListExpr *StructuredInitList,
+                       unsigned &StructuredInitIndex);
   void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, 
                              RecordDecl::field_iterator Field, 
-                             bool SubobjectIsDesignatorContext, unsigned &Index);
+                             bool SubobjectIsDesignatorContext, unsigned &Index,
+                             InitListExpr *StructuredInitList,
+                             unsigned &StructuredInitIndex);
   void CheckArrayType(InitListExpr *IList, QualType &DeclType, 
                       llvm::APSInt elementIndex, 
-                      bool SubobjectIsDesignatorContext, unsigned &Index);
+                      bool SubobjectIsDesignatorContext, unsigned &Index,
+                      InitListExpr *StructuredInitList,
+                      unsigned &StructuredInitIndex);
   bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE, 
                                   DesignatedInitExpr::designators_iterator D,
                                   QualType &CurrentObjectType, 
                                   RecordDecl::field_iterator *NextField,
                                   llvm::APSInt *NextElementIndex,
-                                  unsigned &Index);
+                                  unsigned &Index,
+                                  InitListExpr *StructuredList,
+                                  unsigned &StructuredIndex);
+  InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
+                                           QualType CurrentObjectType,
+                                           InitListExpr *StructuredList,
+                                           unsigned StructuredIndex,
+                                           SourceRange InitRange);
+  void UpdateStructuredListElement(InitListExpr *StructuredInitList,
+                                   unsigned &StructuredInitIndex,
+                                   Expr *expr);
   int numArrayElements(QualType DeclType);
   int numStructUnionElements(QualType DeclType);
 public:
   InitListChecker(Sema *S, InitListExpr *IL, QualType &T);
   bool HadError() { return hadError; }
+
+  // @brief Retrieves the fully-structured initializer list used for
+  // semantic analysis and code generation.
+  InitListExpr *getFullyStructuredList() const { return FullyStructuredList; }
 };
 
 /// BlockSemaInfo - When a block is being parsed, this contains information
index cfbd288aaea9db4830a21be6a3e1f5d718939f7f..79efc7df9c0c13f77d27df273e682230e163a6d6 100644 (file)
@@ -1136,6 +1136,9 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
   }
 
   InitListChecker CheckInitList(this, InitList, DeclType);
+  if (!CheckInitList.HadError())
+    Init = CheckInitList.getFullyStructuredList();
+
   return CheckInitList.HadError();
 }
 
@@ -2209,6 +2212,12 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
     for (unsigned i = 0; i < numInits; i++) {
       // FIXME: Need to get the type of the declaration for C++,
       // because it could be a reference?
+
+      // Implicitly-generated value initializations are okay.
+      if (isa<CXXZeroInitValueExpr>(Exp->getInit(i)) &&
+          cast<CXXZeroInitValueExpr>(Exp->getInit(i))->isImplicit()) 
+        continue;
+
       if (CheckForConstantInitializer(Exp->getInit(i),
                                       Exp->getInit(i)->getType()))
         return true;
index 770404d82ac1fd5bfe7a5b1dcdb5a94cf972f376..064b8517f7c361271b4ddf3bcb53948896402dd7 100644 (file)
@@ -1985,7 +1985,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist,
   // CheckInitializer() - it requires knowledge of the object being intialized. 
 
   InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit, 
-                                    RBraceLoc, Designators.hasAnyDesignators());
+                                               RBraceLoc);
   E->setType(Context.VoidTy); // FIXME: just a place holder for now.
   return Owned(E);
 }
@@ -3988,8 +3988,7 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
   // Otherwise, create a compound literal expression as the base, and
   // iteratively process the offsetof designators.
   InitListExpr *IList =
-      new (Context) InitListExpr(SourceLocation(), 0, 0,
-                                 SourceLocation(), false);
+      new (Context) InitListExpr(SourceLocation(), 0, 0, SourceLocation());
   IList->setType(ArgTy);
   Expr *Res =
       new (Context) CompoundLiteralExpr(SourceLocation(), ArgTy, IList, false);
index 041e994bca8faae10636c530846808e3356d7ff7..511a394d8f268226cc781a0158bc9db055f45a8b 100644 (file)
 #include "clang/Parse/Designator.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/Basic/DiagnosticSema.h"
-#include <algorithm> // for std::count_if
-#include <functional> // for std::mem_fun
-
 using namespace clang;
 
+/// Recursively replaces NULL values within the given initializer list
+/// with expressions that perform value-initialization of the
+/// appropriate type.
+static void fillInValueInitializations(ASTContext &Context, InitListExpr *ILE) {
+  assert((ILE->getType() != Context.VoidTy) && "Should not have void type");
+  if (const RecordType *RType = ILE->getType()->getAsRecordType()) {
+    unsigned Init = 0, NumInits = ILE->getNumInits();
+    for (RecordDecl::field_iterator Field = RType->getDecl()->field_begin(),
+                                 FieldEnd = RType->getDecl()->field_end();
+         Field != FieldEnd; ++Field) {
+      if (Field->isUnnamedBitfield())
+        continue;
+
+      if (Init >= NumInits)
+        break;
+
+      // FIXME: Check for fields with reference type in C++?
+      if (!ILE->getInit(Init))
+        ILE->setInit(Init, 
+                     new (Context) CXXZeroInitValueExpr(Field->getType(), 
+                                                        SourceLocation(),
+                                                        SourceLocation()));
+      else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+        fillInValueInitializations(Context, InnerILE);
+      ++Init;
+    }
+
+    return;
+  } 
+
+  QualType ElementType;
+  
+  if (const ArrayType *AType = Context.getAsArrayType(ILE->getType()))
+    ElementType = AType->getElementType();
+  else if (const VectorType *VType = ILE->getType()->getAsVectorType())
+    ElementType = VType->getElementType();
+  else 
+    ElementType = ILE->getType();
+  
+  for (unsigned Init = 0, NumInits = ILE->getNumInits(); Init != NumInits; 
+       ++Init) {
+    if (!ILE->getInit(Init))
+      ILE->setInit(Init, new (Context) CXXZeroInitValueExpr(ElementType, 
+                                                            SourceLocation(),
+                                                            SourceLocation()));
+    else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+      fillInValueInitializations(Context, InnerILE);
+  }
+}
+
 InitListChecker::InitListChecker(Sema *S, InitListExpr *IL, QualType &T) {
   hadError = false;
   SemaRef = S;
 
   unsigned newIndex = 0;
+  unsigned newStructuredIndex = 0;
+  FullyStructuredList 
+    = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, SourceRange());
+  CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex);
 
-  CheckExplicitInitList(IL, T, newIndex);
+  if (!hadError) {
+    fillInValueInitializations(SemaRef->Context, FullyStructuredList);
+  }
 }
 
 int InitListChecker::numArrayElements(QualType DeclType) {
@@ -42,17 +96,22 @@ int InitListChecker::numArrayElements(QualType DeclType) {
 
 int InitListChecker::numStructUnionElements(QualType DeclType) {
   RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl();
-  const int InitializableMembers 
-    = std::count_if(structDecl->field_begin(), structDecl->field_end(),
-                    std::mem_fun(&FieldDecl::getDeclName));
+  int InitializableMembers = 0;
+  for (RecordDecl::field_iterator Field = structDecl->field_begin(),
+                               FieldEnd = structDecl->field_end();
+       Field != FieldEnd; ++Field) {
+    if ((*Field)->getIdentifier() || !(*Field)->isBitField())
+      ++InitializableMembers;
+  }
   if (structDecl->isUnion())
     return std::min(InitializableMembers, 1);
   return InitializableMembers - structDecl->hasFlexibleArrayMember();
 }
 
 void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, 
-                                            QualType T, unsigned &Index) {
-  llvm::SmallVector<Expr*, 4> InitExprs;
+                                            QualType T, unsigned &Index,
+                                            InitListExpr *StructuredList,
+                                            unsigned &StructuredIndex) {
   int maxElements = 0;
   
   if (T->isArrayType())
@@ -64,45 +123,39 @@ void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList,
   else
     assert(0 && "CheckImplicitInitList(): Illegal type");
 
+  // FIXME: Perhaps we should move this warning elsewhere?
   if (maxElements == 0) {
     SemaRef->Diag(ParentIList->getInit(Index)->getLocStart(),
                   diag::err_implicit_empty_initializer);
+    ++Index;
     hadError = true;
     return;
   }
 
-  // Check the element types *before* we create the implicit init list;
-  // otherwise, we might end up taking the wrong number of elements
-  unsigned NewIndex = Index;
-  CheckListElementTypes(ParentIList, T, false, NewIndex);
-
-  for (int i = 0; i < maxElements; ++i) {
-    // Don't attempt to go past the end of the init list
-    if (Index >= ParentIList->getNumInits())
-      break;
-    Expr* expr = ParentIList->getInit(Index);
-    
-    // Add the expr to the new implicit init list and remove if from the old.
-    InitExprs.push_back(expr);
-    ParentIList->removeInit(Index);
-  }
-  // Synthesize an "implicit" InitListExpr (marked by the invalid source locs).
-  InitListExpr *ILE = new InitListExpr(SourceLocation(), 
-                                       &InitExprs[0], InitExprs.size(), 
-                                       SourceLocation(),
-                                       ParentIList->hadDesignators());
-  ILE->setType(T);
-
-  // Modify the parent InitListExpr to point to the implicit InitListExpr.
-  ParentIList->addInit(Index, ILE);
+  // Build a structured initializer list corresponding to this subobject.
+  InitListExpr *StructuredSubobjectInitList
+    = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList, 
+                                 StructuredIndex, 
+                                 ParentIList->getInit(Index)->getSourceRange());
+  unsigned StructuredSubobjectInitIndex = 0;
+
+  // Check the element types and build the structural subobject.
+  CheckListElementTypes(ParentIList, T, false, Index,
+                        StructuredSubobjectInitList, 
+                        StructuredSubobjectInitIndex);
 }
 
 void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
-                                            unsigned &Index) {
+                                            unsigned &Index,
+                                            InitListExpr *StructuredList,
+                                            unsigned &StructuredIndex) {
   assert(IList->isExplicit() && "Illegal Implicit InitListExpr");
-
-  CheckListElementTypes(IList, T, true, Index);
+  SyntacticToSemantic[IList] = StructuredList;
+  StructuredList->setSyntacticForm(IList);
+  CheckListElementTypes(IList, T, true, Index, StructuredList, 
+                        StructuredIndex);
   IList->setType(T);
+  StructuredList->setType(T);
   if (hadError)
     return;
 
@@ -131,27 +184,31 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
 void InitListChecker::CheckListElementTypes(InitListExpr *IList,
                                             QualType &DeclType, 
                                             bool SubobjectIsDesignatorContext,
-                                            unsigned &Index) {
+                                            unsigned &Index,
+                                            InitListExpr *StructuredList,
+                                            unsigned &StructuredIndex) {
   if (DeclType->isScalarType()) {
-    CheckScalarType(IList, DeclType, 0, Index);
+    CheckScalarType(IList, DeclType, 0, Index, StructuredList, StructuredIndex);
   } else if (DeclType->isVectorType()) {
-    CheckVectorType(IList, DeclType, Index);
+    CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex);
   } else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
     if (DeclType->isStructureType() || DeclType->isUnionType()) {
       RecordDecl *RD = DeclType->getAsRecordType()->getDecl();
       CheckStructUnionTypes(IList, DeclType, RD->field_begin(), 
-                            SubobjectIsDesignatorContext, Index);
+                            SubobjectIsDesignatorContext, Index,
+                            StructuredList, StructuredIndex);
     } else if (DeclType->isArrayType()) {
       llvm::APSInt Zero(
                       SemaRef->Context.getTypeSize(SemaRef->Context.getSizeType()),
                       false);
-      CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index);
+      CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index,
+                     StructuredList, StructuredIndex);
     }
     else
-      assert(0 && "Aggregate that isn't a function or array?!");
+      assert(0 && "Aggregate that isn't a structure or array?!");
   } else if (DeclType->isVoidType() || DeclType->isFunctionType()) {
     // This type is invalid, issue a diagnostic.
-    Index++;
+    ++Index;
     SemaRef->Diag(IList->getLocStart(), diag::err_illegal_initializer_type)
       << DeclType;
     hadError = true;
@@ -165,31 +222,46 @@ void InitListChecker::CheckListElementTypes(InitListExpr *IList,
 void InitListChecker::CheckSubElementType(InitListExpr *IList,
                                           QualType ElemType, 
                                           Expr *expr,
-                                          unsigned &Index) {
+                                          unsigned &Index,
+                                          InitListExpr *StructuredList,
+                                          unsigned &StructuredIndex) {
   if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
     unsigned newIndex = 0;
-    CheckExplicitInitList(SubInitList, ElemType, newIndex);
-    Index++;
+    unsigned newStructuredIndex = 0;
+    InitListExpr *newStructuredList 
+      = getStructuredSubobjectInit(IList, Index, ElemType,
+                                   StructuredList, StructuredIndex,
+                                   SubInitList->getSourceRange());
+    CheckExplicitInitList(SubInitList, ElemType, newIndex, 
+                          newStructuredList, newStructuredIndex);
+    ++StructuredIndex;
+    ++Index;
   } else if (StringLiteral *lit =
              SemaRef->IsStringLiteralInit(expr, ElemType)) {
     SemaRef->CheckStringLiteralInit(lit, ElemType);
-    Index++;
+    UpdateStructuredListElement(StructuredList, StructuredIndex, lit);
+    ++Index;
   } else if (ElemType->isScalarType()) {
-    CheckScalarType(IList, ElemType, expr, Index);
+    CheckScalarType(IList, ElemType, expr, Index, StructuredList, 
+                    StructuredIndex);
   } else if (expr->getType()->getAsRecordType() &&
              SemaRef->Context.typesAreCompatible(
                expr->getType().getUnqualifiedType(),
                ElemType.getUnqualifiedType())) {
-    Index++;
+    UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+    ++Index;
     // FIXME: Add checking
   } else {
-    CheckImplicitInitList(IList, ElemType, Index);
-    Index++;
-  }
+    CheckImplicitInitList(IList, ElemType, Index, StructuredList, 
+                          StructuredIndex);
+    ++StructuredIndex;
+ }
 }
 
 void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
-                                      Expr *expr, unsigned &Index) {
+                                      Expr *expr, unsigned &Index,
+                                      InitListExpr *StructuredList,
+                                      unsigned &StructuredIndex) {
   if (Index < IList->getNumInits()) {
     if (!expr)
       expr = IList->getInit(Index);
@@ -199,6 +271,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
         << IList->getSourceRange();
       hadError = true;
       ++Index;
+      ++StructuredIndex;
       return;
     } else if (isa<DesignatedInitExpr>(expr)) {
       SemaRef->Diag(expr->getSourceRange().getBegin(), 
@@ -206,6 +279,7 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
         << DeclType << expr->getSourceRange();
       hadError = true;
       ++Index;
+      ++StructuredIndex;
       return;
     }
 
@@ -219,18 +293,27 @@ void InitListChecker::CheckScalarType(InitListExpr *IList, QualType &DeclType,
         DIE->setInit(expr);
       else
         IList->setInit(Index, expr);
+
     }
+    if (hadError)
+      ++StructuredIndex;
+    else
+      UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
     ++Index;
   } else {
     SemaRef->Diag(IList->getLocStart(), diag::err_empty_scalar_initializer)
       << IList->getSourceRange();
     hadError = true;
+    ++Index;
+    ++StructuredIndex;
     return;
   }
 }
 
 void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, 
-                                      unsigned &Index) {
+                                      unsigned &Index,
+                                      InitListExpr *StructuredList,
+                                      unsigned &StructuredIndex) {
   if (Index < IList->getNumInits()) {
     const VectorType *VT = DeclType->getAsVectorType();
     int maxElements = VT->getNumElements();
@@ -240,7 +323,8 @@ 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, IList->getInit(Index), Index);
+      CheckSubElementType(IList, elementType, IList->getInit(Index), Index,
+                          StructuredList, StructuredIndex);
     }
   }
 }
@@ -248,12 +332,21 @@ void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType,
 void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, 
                                      llvm::APSInt elementIndex,
                                      bool SubobjectIsDesignatorContext, 
-                                     unsigned &Index) {
+                                     unsigned &Index,
+                                     InitListExpr *StructuredList,
+                                     unsigned &StructuredIndex) {
   // Check for the special-case of initializing an array with a string.
   if (Index < IList->getNumInits()) {
     if (StringLiteral *lit = 
         SemaRef->IsStringLiteralInit(IList->getInit(Index), DeclType)) {
       SemaRef->CheckStringLiteralInit(lit, DeclType);
+      // We place the string literal directly into the resulting
+      // initializer list. This is the only place where the structure
+      // of the structured initializer list doesn't match exactly,
+      // because doing so would involve allocating one character
+      // constant for each string.
+      UpdateStructuredListElement(StructuredList, StructuredIndex, lit);
+      StructuredList->resizeInits(SemaRef->Context, StructuredIndex);
       ++Index;
       return;
     }
@@ -267,11 +360,14 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
                   diag::err_variable_object_no_init)
       << VAT->getSizeExpr()->getSourceRange();
     hadError = true;
+    ++Index;
+    ++StructuredIndex;
     return;
   }
 
   // We might know the maximum number of elements in advance.
-  llvm::APSInt maxElements(elementIndex.getBitWidth(), elementIndex.isUnsigned());
+  llvm::APSInt maxElements(elementIndex.getBitWidth(),
+                           elementIndex.isUnsigned());
   bool maxElementsKnown = false;
   if (const ConstantArrayType *CAT =
         SemaRef->Context.getAsConstantArrayType(DeclType)) {
@@ -295,7 +391,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
       // Handle this designated initializer. elementIndex will be
       // updated to be the next array element we'll initialize.
       if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(), 
-                                     DeclType, 0, &elementIndex, Index)) {
+                                     DeclType, 0, &elementIndex, Index,
+                                     StructuredList, StructuredIndex)) {
         hadError = true;
         continue;
       }
@@ -320,7 +417,8 @@ void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType,
       break;
 
     // Check this element.
-    CheckSubElementType(IList, elementType, IList->getInit(Index), Index);
+    CheckSubElementType(IList, elementType, IList->getInit(Index), Index,
+                        StructuredList, StructuredIndex);
     ++elementIndex;
 
     // If the array is of incomplete type, keep track of the number of
@@ -348,7 +446,9 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
                                             QualType DeclType, 
                                             RecordDecl::field_iterator Field,
                                             bool SubobjectIsDesignatorContext, 
-                                            unsigned &Index) {
+                                            unsigned &Index,
+                                            InitListExpr *StructuredList,
+                                            unsigned &StructuredIndex) {
   RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl();
     
   // If the record is invalid, some of it's members are invalid. To avoid
@@ -376,7 +476,8 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
       // Handle this designated initializer. Field will be updated to
       // the next field that we'll be initializing.
       if (CheckDesignatedInitializer(IList, DIE, DIE->designators_begin(), 
-                                     DeclType, &Field, 0, Index))
+                                     DeclType, &Field, 0, Index,
+                                     StructuredList, StructuredIndex))
         hadError = true;
 
       continue;
@@ -391,13 +492,14 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
     if (Field->getType()->isIncompleteArrayType())
       break;
 
-    if (!Field->getIdentifier()) {
-      // Don't initialize unnamed fields, e.g. "int : 20;"
+    if (!Field->getIdentifier() && Field->isBitField()) {
+      // Don't initialize unnamed bitfields, e.g. "int : 20;"
       ++Field;
       continue;
     }
 
-    CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index);
+    CheckSubElementType(IList, Field->getType(), IList->getInit(Index), Index,
+                        StructuredList, StructuredIndex);
     if (DeclType->isUnionType()) // FIXME: designated initializers?
       break;
 
@@ -416,8 +518,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
 /// 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).
+/// @p NextField or @p NextElementIndex (whichever is appropriate).
 ///
 /// @param IList  The initializer list in which this designated
 /// initializer occurs.
@@ -439,6 +540,10 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
 /// @param Index  Index into @p IList where the designated initializer
 /// @p DIE occurs.
 ///
+/// @param StructuredList  The initializer list expression that
+/// describes all of the subobject initializers in the order they'll
+/// actually be initialized.
+///
 /// @returns true if there was an error, false otherwise.
 bool 
 InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
@@ -447,16 +552,30 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
                                       QualType &CurrentObjectType,
                                       RecordDecl::field_iterator *NextField,
                                       llvm::APSInt *NextElementIndex,
-                                      unsigned &Index) {
-  bool IsFirstDesignator = (D == DIE->designators_begin());
-
+                                      unsigned &Index,
+                                      InitListExpr *StructuredList,
+                                      unsigned &StructuredIndex) {
   if (D == DIE->designators_end()) {
     // Check the actual initialization for the designated object type.
     bool prevHadError = hadError;
-    CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index);
+    CheckSubElementType(IList, CurrentObjectType, DIE->getInit(), Index,
+                        StructuredList, StructuredIndex);
     return hadError && !prevHadError;
   }
 
+  bool IsFirstDesignator = (D == DIE->designators_begin());
+  assert((IsFirstDesignator || StructuredList) && 
+         "Need a non-designated initializer list to start from");
+
+  // Determine the structural initializer list that corresponds to the
+  // current subobject.
+  StructuredList = IsFirstDesignator? SyntacticToSemantic[IList]
+    : getStructuredSubobjectInit(IList, Index, CurrentObjectType, StructuredList,
+                                 StructuredIndex,
+                                 SourceRange(D->getStartLocation(),
+                                             DIE->getSourceRange().getEnd()));
+  assert(StructuredList && "Expected a structured initializer list");
+
   if (D->isFieldDesignator()) {
     // C99 6.7.8p7:
     //
@@ -478,56 +597,95 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
       return true;
     }
 
+    // Note: we perform a linear search of the fields here, despite
+    // the fact that we have a faster lookup method, because we always
+    // need to compute the field's index.
     IdentifierInfo *FieldName = D->getFieldName();
-    DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
-    FieldDecl *DesignatedField = 0;
-    if (Lookup.first == Lookup.second) {
-      // Lookup did not find anything with this name.
-      SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
-        << FieldName << CurrentObjectType;
-    } else if (isa<FieldDecl>(*Lookup.first)) {
-      // Name lookup found a field.
-      DesignatedField = 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);
+    unsigned FieldIndex = 0;
+    RecordDecl::field_iterator Field = RT->getDecl()->field_begin(),
+                            FieldEnd = RT->getDecl()->field_end();
+    for (; Field != FieldEnd; ++Field) {
+      if (Field->isUnnamedBitfield())
+        continue;
+
+      if (Field->getIdentifier() == FieldName)
+        break;
+
+      ++FieldIndex;
     }
 
-    if (!DesignatedField) {
+    if (Field == FieldEnd) {
+      // We did not find the field we're looking for. Produce a
+      // suitable diagnostic and return a failure.
+      DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
+      if (Lookup.first == Lookup.second) {
+        // Name lookup didn't find anything.
+        SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
+          << FieldName << CurrentObjectType;
+      } 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);
+      }
+
+      ++Index;
+      return true;
+    } else if (cast<RecordDecl>((*Field)->getDeclContext())
+                 ->isAnonymousStructOrUnion()) {
+      SemaRef->Diag(D->getFieldLoc(), diag::err_field_designator_anon_class)
+        << FieldName
+        << (cast<RecordDecl>((*Field)->getDeclContext())->isUnion()? 2 : 
+            (int)SemaRef->getLangOptions().CPlusPlus);
+      SemaRef->Diag((*Field)->getLocation(), diag::note_field_designator_found);
       ++Index;
       return true;
     }
-        
+
+    // All of the fields of a union are located at the same place in
+    // the initializer list.
+    // FIXME: Need to tell CodeGen which type to initialize to. ImplicitCastExpr?
+    if (RT->getDecl()->isUnion() && FieldIndex != 0) {
+      SemaRef->Diag(D->getStartLocation(), 
+                    diag::warn_designator_into_union_broken_init)
+        << SourceRange(D->getStartLocation(), DIE->getSourceRange().getEnd());
+      FieldIndex = 0;
+    }
+
     // Update the designator with the field declaration.
-    D->setField(DesignatedField);
+    D->setField(*Field);
       
+    // Make sure that our non-designated initializer list has space
+    // for a subobject corresponding to this field.
+    if (FieldIndex >= StructuredList->getNumInits())
+      StructuredList->resizeInits(SemaRef->Context, FieldIndex + 1);
+
     // Recurse to check later designated subobjects.
-    QualType FieldType = DesignatedField->getType();
-    if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index))
+    QualType FieldType = (*Field)->getType();
+    unsigned newStructuredIndex = FieldIndex;
+    if (CheckDesignatedInitializer(IList, DIE, ++D, FieldType, 0, 0, Index,
+                                   StructuredList, newStructuredIndex))
       return true;
 
     // Find the position of the next field to be initialized in this
     // subobject.
-    RecordDecl::field_iterator Field(DeclContext::decl_iterator(DesignatedField),
-                                     RT->getDecl()->decls_end());
     ++Field;
+    ++FieldIndex;
 
     // If this the first designator, our caller will continue checking
     // the rest of this struct/class/union subobject.
     if (IsFirstDesignator) {
       if (NextField)
         *NextField = Field;
+      StructuredIndex = FieldIndex;
       return false;
     }
 
     // Check the remaining fields within this class/struct/union subobject.
     bool prevHadError = hadError;
-    CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index);
+    CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index,
+                          StructuredList, FieldIndex);
     return hadError && !prevHadError;
   }
 
@@ -561,6 +719,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
   else {
     assert(D->isArrayRangeDesignator() && "Need array-range designator");
     IndexExpr = DIE->getArrayRangeEnd(*D);
+    SemaRef->Diag(D->getEllipsisLoc(), 
+                  diag::warn_gnu_array_range_designator_unsupported)
+      << SourceRange(D->getLBracketLoc(), D->getRBracketLoc());
   }
 
   bool ConstExpr 
@@ -581,28 +742,115 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
     }
   }
   
+  // Make sure that our non-designated initializer list has space
+  // for a subobject corresponding to this array element.
+  unsigned ElementIndex = DesignatedIndex.getZExtValue();
+  if (ElementIndex >= StructuredList->getNumInits())
+    StructuredList->resizeInits(SemaRef->Context, ElementIndex + 1);
+
   // Recurse to check later designated subobjects.
   QualType ElementType = AT->getElementType();
-  if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index))
+  if (CheckDesignatedInitializer(IList, DIE, ++D, ElementType, 0, 0, Index,
+                                 StructuredList, ElementIndex))
     return true;
 
   // Move to the next index in the array that we'll be initializing.
   ++DesignatedIndex;
+  ElementIndex = DesignatedIndex.getZExtValue();
 
   // If this the first designator, our caller will continue checking
   // the rest of this array subobject.
   if (IsFirstDesignator) {
     if (NextElementIndex)
       *NextElementIndex = DesignatedIndex;
+    StructuredIndex = ElementIndex;
     return false;
   }
     
   // Check the remaining elements within this array subobject.
   bool prevHadError = hadError;
-  CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index);
+  CheckArrayType(IList, CurrentObjectType, DesignatedIndex, true, Index,
+                 StructuredList, ElementIndex);
   return hadError && !prevHadError;  
 }
 
+// Get the structured initializer list for a subobject of type
+// @p CurrentObjectType.
+InitListExpr *
+InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
+                                            QualType CurrentObjectType,
+                                            InitListExpr *StructuredList,
+                                            unsigned StructuredIndex,
+                                            SourceRange InitRange) {
+  Expr *ExistingInit = 0;
+  if (!StructuredList)
+    ExistingInit = SyntacticToSemantic[IList];
+  else if (StructuredIndex < StructuredList->getNumInits())
+    ExistingInit = StructuredList->getInit(StructuredIndex);
+  
+  if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
+    return Result;
+
+  if (ExistingInit) {
+    // We are creating an initializer list that initializes the
+    // subobjects of the current object, but there was already an
+    // initialization that completely initialized the current
+    // subobject, e.g., by a compound literal:
+    // 
+    // struct X { int a, b; };
+    // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
+    // 
+    // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
+    // designated initializer re-initializes the whole
+    // subobject [0], overwriting previous initializers.
+    SemaRef->Diag(InitRange.getBegin(), diag::warn_subobject_initializer_overrides)
+      << InitRange;
+    SemaRef->Diag(ExistingInit->getSourceRange().getBegin(), 
+                  diag::note_previous_initializer)
+      << ExistingInit->hasSideEffects(SemaRef->Context)
+      << ExistingInit->getSourceRange();
+  }
+
+  InitListExpr *Result 
+    = new (SemaRef->Context) InitListExpr(SourceLocation(), 0, 0, 
+                                          SourceLocation());
+  Result->setType(CurrentObjectType);
+
+  // Link this new initializer list into the structured initializer
+  // lists.
+  if (StructuredList)
+    StructuredList->updateInit(StructuredIndex, Result);
+  else {
+    Result->setSyntacticForm(IList);
+    SyntacticToSemantic[IList] = Result;
+  }
+
+  return Result;
+}
+
+/// Update the initializer at index @p StructuredIndex within the
+/// structured initializer list to the value @p expr.
+void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
+                                                  unsigned &StructuredIndex,
+                                                  Expr *expr) {
+  // No structured initializer list to update
+  if (!StructuredList)
+    return;
+
+  if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) {
+    // This initializer overwrites a previous initializer. Warn.
+    SemaRef->Diag(expr->getSourceRange().getBegin(), 
+                  diag::warn_initializer_overrides)
+      << expr->getSourceRange();
+    SemaRef->Diag(PrevInit->getSourceRange().getBegin(), 
+                  diag::note_previous_initializer)
+      << (int)PrevInit->hasSideEffects(SemaRef->Context)
+      << PrevInit->getSourceRange();
+  }
+  
+  ++StructuredIndex;
+}
+
 /// 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
index 9d2a942410aecc43a0d9b9d27f5b5bd824dc9666..3d2cf6912744ddf0f0ea537d8036c2e6c00d1b58 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: clang -fsyntax-only -verify -pedantic %s
+// RUN: clang -fsyntax-only -pedantic -verify %s
 
 extern int foof() = 1; // expected-error{{illegal initializer (only variables can be initialized)}}
 
@@ -101,6 +101,7 @@ void legal() {
     { 2, 3 },
     { 4, 5, 6 }
   };
+  int q_sizecheck[(sizeof(q) / sizeof(short [3][2])) == 3? 1 : -1];
 }
 
 unsigned char asso_values[] = { 34 };
@@ -134,15 +135,19 @@ typedef int AryT[];
 void testTypedef()
 {
   AryT a = { 1, 2 }, b = { 3, 4, 5 };
+  int a_sizecheck[(sizeof(a) / sizeof(int)) == 2? 1 : -1];
+  int b_sizecheck[(sizeof(b) / sizeof(int)) == 3? 1 : -1];
 }
 
 static char const xx[] = "test";
+int xx_sizecheck[(sizeof(xx) / sizeof(char)) == 5? 1 : -1];
 static char const yy[5] = "test";
 static char const zz[3] = "test"; // expected-warning{{initializer-string for char array is too long}}
 
 void charArrays()
 {
        static char const test[] = "test";
+        int test_sizecheck[(sizeof(test) / sizeof(char)) == 5? 1 : -1];
        static char const test2[] = { "weird stuff" };
        static char const test3[] = { "test", "excess stuff" }; // expected-error{{excess elements in char array initializer}}
 
@@ -171,6 +176,7 @@ void variableArrayInit() {
 float r1[10] = {{7}}; //expected-warning{{braces around scalar initializer}}
 float r2[] = {{8}}; //expected-warning{{braces around scalar initializer}}
 char r3[][5] = {1,2,3,4,5,6};
+int r3_sizecheck[(sizeof(r3) / sizeof(char[5])) == 2? 1 : -1];
 char r3_2[sizeof r3 == 10 ? 1 : -1];
 float r4[1][2] = {1,{2},3,4}; //expected-warning{{braces around scalar initializer}} expected-warning{{excess elements in array initializer}}
 char r5[][5] = {"aa", "bbb", "ccccc"};
@@ -195,7 +201,7 @@ int bar (void) {
   return z.z; 
 } 
 struct s3 {void (*a)(void);} t5 = {autoStructTest};
-// GCC extension; flexible array init. Once this is implemented, the warning should be removed.
+// 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-warning{{excess elements in array initializer}}
 union {char a; int b;} t7[] = {1, 2, 3};
@@ -238,3 +244,21 @@ struct soft_segment_descriptor gdt_segs[] = {
 
 static void sppp_ipv6cp_up();
 const struct {} ipcp = { sppp_ipv6cp_up }; //expected-warning{{empty struct extension}} expected-warning{{excess elements in array initializer}}
+
+struct _Matrix { union { float m[4][4]; }; }; //expected-warning{{anonymous unions are a GNU extension in C}}
+typedef struct _Matrix Matrix;
+void test_matrix() {
+  const Matrix mat1 = {
+    { { 1.0f, 2.0f, 3.0f, 4.0f,
+        5.0f, 6.0f, 7.0f, 8.0f,
+        9.0f, 10.0f, 11.0f, 12.0f,
+        13.0f, 14.0f, 15.0f, 16.0f } }
+  };
+
+  const Matrix mat2 = {
+    1.0f, 2.0f, 3.0f, 4.0f,
+    5.0f, 6.0f, 7.0f, 8.0f,
+    9.0f, 10.0f, 11.0f, 12.0f,
+    13.0f, 14.0f, 15.0f, 16.0f 
+  };
+}
index fd4873193cfd366a79d9237af6594895db48172d..c9a0aa7f05bd2ae850ed144fa0061845014dae2b 100644 (file)
@@ -18,7 +18,8 @@ int iarray2[10] = {
 };
 
 int iarray3[10] = {
-  [5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}}
+  [5 ... 12] = 2 // expected-error{{array designator index (12) exceeds array bounds (10)}}\
+                // expected-warning{{GNU array-range designator extension is unsupported}}
 };
 
 struct point {
@@ -44,8 +45,8 @@ struct point array[10] = {
 
 struct point array2[10] = {
   [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 }
+  [4 ... 5].y = 2.0, // expected-warning{{GNU array-range designator extension is unsupported}}
+  [4 ... 6] = { .x = 3, .y = 4.0 } // expected-warning{{GNU array-range designator extension is unsupported}}
 };
 
 struct point array3[10] = {
@@ -116,4 +117,25 @@ struct disklabel_ops disklabel64_ops = {
 // PR clang/3378
 int bitwidth[] = { [(long long int)1] = 5, [(short int)2] = 2 };
 int a[]= { [sizeof(int)] = 0 };
-int a2[]= { [0 ... sizeof(int)] = 0 };
+int a2[]= { [0 ... sizeof(int)] = 0 }; // expected-warning{{GNU array-range designator extension is unsupported}}
+
+// Test warnings about initializers overriding previous initializers
+struct X {
+  int a, b, c;
+};
+
+int counter = 0;
+int get8() { ++counter; return 8; }
+
+void test() {
+  struct X xs[] = { 
+    [0] = (struct X){1, 2}, // expected-note{{previous initialization is here}}
+    [0].c = 3,  // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
+    (struct X) {4, 5, 6}, // expected-note{{previous initialization is here}}
+    [1].b = get8(), // expected-warning{{subobject initialization overrides initialization of other fields within its enclosing subobject}}
+    [0].b = 8
+  };
+}
+
+// FIXME: we need to 
+union { char c; long l; } u1 = { .l = 0xFFFF }; // expected-warning{{designated initialization of union member is broken}}
index 1e2ba012c8f2bb9160d058918bb3a943139994a3..6913082228cace5331df63b25c17087124b58542 100644 (file)
@@ -1,5 +1,15 @@
-// RUN: clang %s -verify -fsyntax-only
+// RUN: clang %s -fsyntax-only -verify
 
 typedef __attribute__(( ext_vector_type(4) ))  float float4;
+//typedef float float4 __attribute__((vector_size(16)));
 
 float4 foo = (float4){ 1.0, 2.0, 3.0, 4.0 };
+
+float4 array[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
+int array_sizecheck[(sizeof(array) / sizeof(float4)) == 3? 1 : -1];
+
+float4 array2[2] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 
+                     9.0 }; // expected-warning {{excess elements in array initializer}}
+
+float4 array3[2] = { {1.0, 2.0, 3.0}, 5.0, 6.0, 7.0, 8.0,
+                     9.0 }; // expected-warning {{excess elements in array initializer}}