diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-12-10 08:25:00 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-12-10 08:25:00 +0000 |
commit | ab44d5badf576b5e823a6d78e5972f9ca6a99d68 (patch) | |
tree | b35a52e3442bc48e623cc31728c86e303271f8d1 /clang/lib/Sema/SemaDecl.cpp | |
parent | 27964e663b3fced13dab38cb5af3d33823f340b6 (diff) | |
download | bcm5719-llvm-ab44d5badf576b5e823a6d78e5972f9ca6a99d68.tar.gz bcm5719-llvm-ab44d5badf576b5e823a6d78e5972f9ca6a99d68.zip |
Implement DR1460: fix handling of default initializers in unions; don't allow
more than one such initializer in a union, make mem-initializers override
default initializers for other union members, handle anonymous unions with
anonymous struct members better. Fix a couple of semi-related bugs exposed by
the tests for same.
llvm-svn: 196892
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 60 |
1 files changed, 51 insertions, 9 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 10137a1095e..cd28c228c06 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3547,6 +3547,39 @@ StorageClassSpecToVarDeclStorageClass(const DeclSpec &DS) { llvm_unreachable("unknown storage class specifier"); } +static SourceLocation findDefaultInitializer(const CXXRecordDecl *Record) { + assert(Record->hasInClassInitializer()); + + for (DeclContext::decl_iterator I = Record->decls_begin(), + E = Record->decls_end(); + I != E; ++I) { + FieldDecl *FD = dyn_cast<FieldDecl>(*I); + if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(*I)) + FD = IFD->getAnonField(); + if (FD && FD->hasInClassInitializer()) + return FD->getLocation(); + } + + llvm_unreachable("couldn't find in-class initializer"); +} + +static void checkDuplicateDefaultInit(Sema &S, CXXRecordDecl *Parent, + SourceLocation DefaultInitLoc) { + if (!Parent->isUnion() || !Parent->hasInClassInitializer()) + return; + + S.Diag(DefaultInitLoc, diag::err_multiple_mem_union_initialization); + S.Diag(findDefaultInitializer(Parent), diag::note_previous_initializer) << 0; +} + +static void checkDuplicateDefaultInit(Sema &S, CXXRecordDecl *Parent, + CXXRecordDecl *AnonUnion) { + if (!Parent->isUnion() || !Parent->hasInClassInitializer()) + return; + + checkDuplicateDefaultInit(S, Parent, findDefaultInitializer(AnonUnion)); +} + /// BuildAnonymousStructOrUnion - Handle the declaration of an /// anonymous structure or union. Anonymous unions are a C++ feature /// (C++ [class.union]) and a C11 feature; anonymous structures @@ -3704,6 +3737,14 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, } } } + + // C++11 [class.union]p8 (DR1460): + // At most one variant member of a union may have a + // brace-or-equal-initializer. + if (cast<CXXRecordDecl>(Record)->hasInClassInitializer() && + Owner->isRecord()) + checkDuplicateDefaultInit(*this, cast<CXXRecordDecl>(Owner), + cast<CXXRecordDecl>(Record)); } if (!Record->isUnion() && !Owner->isRecord()) { @@ -3756,11 +3797,14 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, } Anon->setImplicit(); + // Mark this as an anonymous struct/union type. + Record->setAnonymousStructOrUnion(true); + // Add the anonymous struct/union object to the current // context. We'll be referencing this object when we refer to one of // its members. Owner->addDecl(Anon); - + // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. @@ -3771,14 +3815,6 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Chain, false)) Invalid = true; - // Mark this as an anonymous struct/union type. Note that we do not - // do this until after we have already checked and injected the - // members of this anonymous struct/union type, because otherwise - // the members could be injected twice: once by DeclContext when it - // builds its lookup table, and once by - // InjectAnonymousStructOrUnionMembers. - Record->setAnonymousStructOrUnion(true); - if (Invalid) Anon->setInvalidDecl(); @@ -11516,6 +11552,12 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } } + // C++11 [class.union]p8 (DR1460): + // At most one variant member of a union may have a + // brace-or-equal-initializer. + if (InitStyle != ICIS_NoInit) + checkDuplicateDefaultInit(*this, cast<CXXRecordDecl>(Record), Loc); + FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo, BitWidth, Mutable, InitStyle); if (InvalidDecl) |