Emit diagnostic error when the field of an anonymous struct is non trivial.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111158 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 1d85979..52c81c1 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -633,9 +633,9 @@
"%select{|implicit default }0constructor for %1 must explicitly initialize "
"the %select{base class|member}2 %3 which does not have a default "
"constructor">;
-def err_illegal_union_member : Error<
- "union member %0 has a non-trivial %select{constructor|"
- "copy constructor|copy assignment operator|destructor}1">;
+def err_illegal_union_or_anon_struct_member : Error<
+ "%select{anonymous struct|union}0 member %1 has a non-trivial "
+ "%select{constructor|copy constructor|copy assignment operator|destructor}2">;
def note_nontrivial_has_virtual : Note<
"because type %0 has a virtual %select{member function|base class}1">;
def note_nontrivial_has_nontrivial : Note<
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index a57a5a7..f815430 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1019,6 +1019,7 @@
CXXCopyAssignment = 2,
CXXDestructor = 3
};
+ bool CheckNontrivialField(FieldDecl *FD);
void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 3271997..cc6e2fa 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1855,6 +1855,9 @@
<< (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected);
Invalid = true;
}
+
+ if (CheckNontrivialField(FD))
+ Invalid = true;
} else if ((*Mem)->isImplicit()) {
// Any implicit members are fine.
} else if (isa<TagDecl>(*Mem) && (*Mem)->getDeclContext() != Record) {
@@ -6044,27 +6047,8 @@
// cannot be a member of a union, nor can an array of such
// objects.
// TODO: C++0x alters this restriction significantly.
- if (Record->isUnion()) {
- // We check for copy constructors before constructors
- // because otherwise we'll never get complaints about
- // copy constructors.
-
- CXXSpecialMember member = CXXInvalid;
- if (!RDecl->hasTrivialCopyConstructor())
- member = CXXCopyConstructor;
- else if (!RDecl->hasTrivialConstructor())
- member = CXXConstructor;
- else if (!RDecl->hasTrivialCopyAssignment())
- member = CXXCopyAssignment;
- else if (!RDecl->hasTrivialDestructor())
- member = CXXDestructor;
-
- if (member != CXXInvalid) {
- Diag(Loc, diag::err_illegal_union_member) << Name << member;
- DiagnoseNontrivial(RT, member);
- NewFD->setInvalidDecl();
- }
- }
+ if (Record->isUnion() && CheckNontrivialField(NewFD))
+ NewFD->setInvalidDecl();
}
}
}
@@ -6094,6 +6078,43 @@
return NewFD;
}
+bool Sema::CheckNontrivialField(FieldDecl *FD) {
+ assert(FD);
+ assert(getLangOptions().CPlusPlus && "valid check only for C++");
+
+ if (FD->isInvalidDecl())
+ return true;
+
+ QualType EltTy = Context.getBaseElementType(FD->getType());
+ if (const RecordType *RT = EltTy->getAs<RecordType>()) {
+ CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (RDecl->getDefinition()) {
+ // We check for copy constructors before constructors
+ // because otherwise we'll never get complaints about
+ // copy constructors.
+
+ CXXSpecialMember member = CXXInvalid;
+ if (!RDecl->hasTrivialCopyConstructor())
+ member = CXXCopyConstructor;
+ else if (!RDecl->hasTrivialConstructor())
+ member = CXXConstructor;
+ else if (!RDecl->hasTrivialCopyAssignment())
+ member = CXXCopyAssignment;
+ else if (!RDecl->hasTrivialDestructor())
+ member = CXXDestructor;
+
+ if (member != CXXInvalid) {
+ Diag(FD->getLocation(), diag::err_illegal_union_or_anon_struct_member)
+ << (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
+ DiagnoseNontrivial(RT, member);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
/// DiagnoseNontrivial - Given that a class has a non-trivial
/// special member, figure out why.
void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
diff --git a/test/SemaCXX/anonymous-struct.cpp b/test/SemaCXX/anonymous-struct.cpp
new file mode 100644
index 0000000..dfa284a
--- /dev/null
+++ b/test/SemaCXX/anonymous-struct.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct S {
+ S(); // expected-note {{because type 'S' has a user-declared constructor}}
+};
+
+struct E {
+ struct {
+ S x; // expected-error {{anonymous struct member 'x' has a non-trivial constructor}}
+ };
+};