From d6d37dee48cfc5bbcc998bd9d151e4fb3a9437e8 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 22 Dec 2009 00:05:34 +0000 Subject: [PATCH] When filling in value initializations within an initializer list, be sure to fill in the initialized member of a union when a member was explicitly designated. Fixes PR5843. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91858 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaInit.cpp | 151 ++++++++++++++++------------ test/Sema/designated-initializers.c | 17 ++++ 2 files changed, 103 insertions(+), 65 deletions(-) diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 466e6ccaf8..2a27466a55 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -345,6 +345,9 @@ class InitListChecker { int numArrayElements(QualType DeclType); int numStructUnionElements(QualType DeclType); + void FillInValueInitForField(unsigned Init, FieldDecl *Field, + const InitializedEntity &ParentEntity, + InitListExpr *ILE, bool &RequiresSecondPass); void FillInValueInitializations(const InitializedEntity &Entity, InitListExpr *ILE, bool &RequiresSecondPass); public: @@ -358,6 +361,68 @@ public: }; } // end anonymous namespace +void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, + const InitializedEntity &ParentEntity, + InitListExpr *ILE, + bool &RequiresSecondPass) { + SourceLocation Loc = ILE->getSourceRange().getBegin(); + unsigned NumInits = ILE->getNumInits(); + InitializedEntity MemberEntity + = InitializedEntity::InitializeMember(Field, &ParentEntity); + if (Init >= NumInits || !ILE->getInit(Init)) { + // FIXME: We probably don't need to handle references + // specially here, since value-initialization of references is + // handled in InitializationSequence. + if (Field->getType()->isReferenceType()) { + // C++ [dcl.init.aggr]p9: + // If an incomplete or empty initializer-list leaves a + // member of reference type uninitialized, the program is + // ill-formed. + SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized) + << Field->getType() + << ILE->getSyntacticForm()->getSourceRange(); + SemaRef.Diag(Field->getLocation(), + diag::note_uninit_reference_member); + hadError = true; + return; + } + + InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, + true); + InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, 0, 0); + if (!InitSeq) { + InitSeq.Diagnose(SemaRef, MemberEntity, Kind, 0, 0); + hadError = true; + return; + } + + Sema::OwningExprResult MemberInit + = InitSeq.Perform(SemaRef, MemberEntity, Kind, + Sema::MultiExprArg(SemaRef, 0, 0)); + if (MemberInit.isInvalid()) { + hadError = true; + return; + } + + if (hadError) { + // Do nothing + } else if (Init < NumInits) { + ILE->setInit(Init, MemberInit.takeAs()); + } else if (InitSeq.getKind() + == InitializationSequence::ConstructorInitialization) { + // Value-initialization requires a constructor call, so + // extend the initializer list to include the constructor + // call and make a note that we'll need to take another pass + // through the initializer list. + ILE->updateInit(Init, MemberInit.takeAs()); + RequiresSecondPass = true; + } + } else if (InitListExpr *InnerILE + = dyn_cast(ILE->getInit(Init))) + FillInValueInitializations(MemberEntity, InnerILE, + RequiresSecondPass); +} + /// Recursively replaces NULL values within the given initializer list /// with expressions that perform value-initialization of the /// appropriate type. @@ -372,76 +437,32 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, Loc = ILE->getSyntacticForm()->getSourceRange().getBegin(); if (const RecordType *RType = ILE->getType()->getAs()) { - 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 (hadError) - return; - - InitializedEntity MemberEntity - = InitializedEntity::InitializeMember(*Field, &Entity); - if (Init >= NumInits || !ILE->getInit(Init)) { - // FIXME: We probably don't need to handle references - // specially here, since value-initialization of references is - // handled in InitializationSequence. - if (Field->getType()->isReferenceType()) { - // C++ [dcl.init.aggr]p9: - // If an incomplete or empty initializer-list leaves a - // member of reference type uninitialized, the program is - // ill-formed. - SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized) - << Field->getType() - << ILE->getSyntacticForm()->getSourceRange(); - SemaRef.Diag(Field->getLocation(), - diag::note_uninit_reference_member); - hadError = true; - return; - } - - InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, - true); - InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, 0, 0); - if (!InitSeq) { - InitSeq.Diagnose(SemaRef, MemberEntity, Kind, 0, 0); - hadError = true; + if (RType->getDecl()->isUnion() && + ILE->getInitializedFieldInUnion()) + FillInValueInitForField(0, ILE->getInitializedFieldInUnion(), + Entity, ILE, RequiresSecondPass); + else { + unsigned Init = 0; + for (RecordDecl::field_iterator + Field = RType->getDecl()->field_begin(), + FieldEnd = RType->getDecl()->field_end(); + Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + + if (hadError) return; - } - Sema::OwningExprResult MemberInit - = InitSeq.Perform(SemaRef, MemberEntity, Kind, - Sema::MultiExprArg(SemaRef, 0, 0)); - if (MemberInit.isInvalid()) { - hadError = true; + FillInValueInitForField(Init, *Field, Entity, ILE, RequiresSecondPass); + if (hadError) return; - } - if (hadError) { - // Do nothing - } else if (Init < NumInits) { - ILE->setInit(Init, MemberInit.takeAs()); - } else if (InitSeq.getKind() - == InitializationSequence::ConstructorInitialization) { - // Value-initialization requires a constructor call, so - // extend the initializer list to include the constructor - // call and make a note that we'll need to take another pass - // through the initializer list. - ILE->updateInit(Init, MemberInit.takeAs()); - RequiresSecondPass = true; - } - } else if (InitListExpr *InnerILE - = dyn_cast(ILE->getInit(Init))) - FillInValueInitializations(MemberEntity, InnerILE, - RequiresSecondPass); - ++Init; + ++Init; - // Only look at the first initialization of a union. - if (RType->getDecl()->isUnion()) - break; + // Only look at the first initialization of a union. + if (RType->getDecl()->isUnion()) + break; + } } return; diff --git a/test/Sema/designated-initializers.c b/test/Sema/designated-initializers.c index 9e2dc88b9a..7e4ed6892a 100644 --- a/test/Sema/designated-initializers.c +++ b/test/Sema/designated-initializers.c @@ -231,4 +231,21 @@ int crazy_Y[] = { [ 0 ? crazy_x : 4] = 1 }; +// PR5843 +struct expr { + int nargs; + union { + unsigned long int num; + struct expr *args[3]; + } val; +}; +struct expr expr0 = { + .nargs = 2, + .val = { + .args = { + [0] = (struct expr *)0, + [1] = (struct expr *)0 + } + } +}; -- 2.40.0