summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2013-12-10 08:25:00 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2013-12-10 08:25:00 +0000
commitab44d5badf576b5e823a6d78e5972f9ca6a99d68 (patch)
treeb35a52e3442bc48e623cc31728c86e303271f8d1 /clang/lib/Sema/SemaDecl.cpp
parent27964e663b3fced13dab38cb5af3d33823f340b6 (diff)
downloadbcm5719-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.cpp60
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)
OpenPOWER on IntegriCloud