]> granicus.if.org Git - clang/commitdiff
Clean up designated initialization of unions, so that CodeGen doesn't
authorDouglas Gregor <dgregor@apple.com>
Thu, 29 Jan 2009 16:53:55 +0000 (16:53 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 29 Jan 2009 16:53:55 +0000 (16:53 +0000)
have to try to guess which member is being initialized.

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

include/clang/AST/Expr.h
lib/AST/Expr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprConstant.cpp
lib/Sema/SemaInit.cpp

index 54c764099921c16f81b063c4ca824ab7a0343a86..10b877ac891f3fb6b11129e818b25b67e6db821e 100644 (file)
@@ -1664,6 +1664,10 @@ class InitListExpr : public Expr {
   /// written in the source code.
   InitListExpr *SyntacticForm;
 
+  /// If this initializer list initializes a union, specifies which
+  /// field within the union will be initialized.
+  FieldDecl *UnionFieldInit;
+
 public:
   InitListExpr(SourceLocation lbraceloc, Expr **initexprs, unsigned numinits,
                SourceLocation rbraceloc);
@@ -1702,6 +1706,15 @@ public:
   /// accomodate the new entry.
   Expr *updateInit(unsigned Init, Expr *expr);
 
+  /// \brief If this initializes a union, specifies which field in the
+  /// union to initialize.
+  ///
+  /// Typically, this field is the first named field within the
+  /// union. However, a designated initializer can specify the
+  /// initialization of a different field within the union.
+  FieldDecl *getInitializedFieldInUnion() { return UnionFieldInit; }
+  void setInitializedFieldInUnion(FieldDecl *FD) { UnionFieldInit = FD; }
+
   // Explicit InitListExpr's originate from source code (and have valid source
   // locations). Implicit InitListExpr's are created by the semantic analyzer.
   bool isExplicit() {
index d96f734bf41970dbd0bd59f898fcc0f99d80928a..c1c8084cd59999b10635d902247253128d9c9a66 100644 (file)
@@ -223,7 +223,8 @@ InitListExpr::InitListExpr(SourceLocation lbraceloc,
                            Expr **initExprs, unsigned numInits,
                            SourceLocation rbraceloc)
   : Expr(InitListExprClass, QualType()),
-    LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0) {
+    LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), 
+    UnionFieldInit(0) {
 
   InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
 }
index 075a12c57e1b3bae9fbb9488f95b137a2ac36ab6..b487bacc711070169a89917935497ea31ecce1a9 100644 (file)
@@ -443,7 +443,38 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
   unsigned NumInitElements = E->getNumInits();
   RecordDecl *SD = E->getType()->getAsRecordType()->getDecl();
   unsigned CurInitVal = 0;
-  bool isUnion = E->getType()->isUnionType();
+
+  if (E->getType()->isUnionType()) {
+    // Only initialize one field of a union. The field itself is
+    // specified by the initializer list.
+    if (!E->getInitializedFieldInUnion()) {
+      // Empty union; we have nothing to do.
+      
+#ifndef NDEBUG
+      // Make sure that it's really an empty and not a failure of
+      // semantic analysis.
+      for (RecordDecl::field_iterator Field = SD->field_begin(),
+                                   FieldEnd = SD->field_end();
+           Field != FieldEnd; ++Field)
+        assert(Field->isUnnamedBitfield() && "Only unnamed bitfields allowed");
+#endif
+      return;
+    }
+
+    // FIXME: volatility
+    FieldDecl *Field = E->getInitializedFieldInUnion();
+    LValue FieldLoc = CGF.EmitLValueForField(DestPtr, Field, true, 0);
+
+    if (NumInitElements) {
+      // Store the initializer into the field
+      EmitInitializationToLValue(E->getInit(0), FieldLoc);
+    } else {
+      // Default-initialize to null
+      EmitNullInitializationToLValue(FieldLoc, Field->getType());
+    }
+
+    return;
+  }
   
   // Here we iterate over the fields; this makes it simpler to both
   // default-initialize fields and skip over unnamed fields.
@@ -457,29 +488,15 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
     if (Field->isUnnamedBitfield())
       continue;
 
-    // When we're coping with C99 designated initializers into a
-    // union, find the field that has the same type as the expression
-    // we're initializing the union with.
-    if (isUnion && CurInitVal < NumInitElements && 
-        (CGF.getContext().getCanonicalType(Field->getType()) != 
-           CGF.getContext().getCanonicalType(E->getInit(CurInitVal)->getType())))
-      continue;
-
     // FIXME: volatility
-    LValue FieldLoc = CGF.EmitLValueForField(DestPtr, *Field, isUnion,0);
+    LValue FieldLoc = CGF.EmitLValueForField(DestPtr, *Field, false, 0);
     if (CurInitVal < NumInitElements) {
       // Store the initializer into the field
-      // This will probably have to get a bit smarter when we support
-      // designators in initializers
       EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc);
     } else {
       // We're out of initalizers; default-initialize to null
       EmitNullInitializationToLValue(FieldLoc, Field->getType());
     }
-
-    // Unions only initialize one field.
-    if (isUnion)
-      break;
   }
 }
 
index b05048c946099dc0e2ec68bceaa3d33b156104f8..e523ab3acf2e119432d07ab294026fc45d3c0ad0 100644 (file)
@@ -241,32 +241,29 @@ public:
     RecordDecl *RD = ILE->getType()->getAsRecordType()->getDecl();
     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;
-    bool sawAnyFields = false;
-    for (RecordDecl::field_iterator Field = RD->field_begin(),
-                                 FieldEnd = RD->field_end();
-         Field != FieldEnd; ++Field) {
-      curField = *Field;
-      FieldNo++;
-
-      if (curField->isUnnamedBitfield())
-        continue;
-
-      // If we have an initializer, find the field whose type is the
-      // same as that initializer. This 
-      sawAnyFields = true;
-      if (ILE->getNumInits() > 0 &&
-          CGM.getContext().getCanonicalType(curField->getType()) ==
-            CGM.getContext().getCanonicalType(ILE->getInit(0)->getType()))
-        break;
-    }
+    // If this is an empty initializer list, we value-initialize the
+    // union.
+    if (ILE->getNumInits() == 0)
+      return llvm::Constant::getNullValue(Ty);
 
-    if (!curField || !curField->getIdentifier() || ILE->getNumInits() == 0)
+    FieldDecl* curField = ILE->getInitializedFieldInUnion();
+    if (!curField) {
+#ifndef NDEBUG
+#endif
+    }
+
+    if (!curField) {
+      // There's no field to initialize, so value-initialize the union.
+#ifndef NDEBUG
+      // Make sure that it's really an empty and not a failure of
+      // semantic analysis.
+      for (RecordDecl::field_iterator Field = RD->field_begin(),
+                                   FieldEnd = RD->field_end();
+           Field != FieldEnd; ++Field)
+        assert(Field->isUnnamedBitfield() && "Only unnamed bitfields allowed");
+#endif
       return llvm::Constant::getNullValue(Ty);
+    }
 
     if (curField->isBitField()) {
       // Create a dummy struct for bit-field insertion
index 5dc57751ffb3799e902d3710ba67adbe37b81ff3..527f965dc3f6118b58e9b88055e037c5c0cb06c9 100644 (file)
@@ -573,6 +573,11 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
                                      StructuredList, StructuredIndex))
         hadError = true;
 
+      // Abort early for unions: the designator handled the
+      // initialization of the appropriate field.
+      if (DeclType->isUnionType())
+        break;
+
       continue;
     }
 
@@ -585,7 +590,7 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
     if (Field->getType()->isIncompleteArrayType())
       break;
 
-    if (!Field->getIdentifier() && Field->isBitField()) {
+    if (Field->isUnnamedBitfield()) {
       // Don't initialize unnamed bitfields, e.g. "int : 20;"
       ++Field;
       continue;
@@ -593,8 +598,12 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList,
 
     CheckSubElementType(IList, Field->getType(), Index,
                         StructuredList, StructuredIndex);
-    if (DeclType->isUnionType())
+
+    if (DeclType->isUnionType()) {
+      // Initialize the first field within the union.
+      StructuredList->setInitializedFieldInUnion(*Field);
       break;
+    }
 
     ++Field;
   }
@@ -753,8 +762,10 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList,
 
     // All of the fields of a union are located at the same place in
     // the initializer list.
-    if (RT->getDecl()->isUnion())
+    if (RT->getDecl()->isUnion()) {
       FieldIndex = 0;
+      StructuredList->setInitializedFieldInUnion(*Field);
+    }
 
     // Update the designator with the field declaration.
     D->setField(*Field);