From: Douglas Gregor Date: Thu, 29 Jan 2009 16:53:55 +0000 (+0000) Subject: Clean up designated initialization of unions, so that CodeGen doesn't X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0bb76897bedb8b747efc6523efb432fc24966118;p=clang Clean up designated initialization of unions, so that CodeGen doesn't 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 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 54c7640999..10b877ac89 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -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() { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index d96f734bf4..c1c8084cd5 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -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); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 075a12c57e..b487bacc71 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -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; } } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index b05048c946..e523ab3acf 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -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 diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 5dc57751ff..527f965dc3 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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);