From dd7744d01e513e941f47893b16dfebae2c1c9911 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 16 Aug 2010 17:27:08 +0000 Subject: [PATCH] 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 --- include/clang/Basic/DiagnosticSemaKinds.td | 6 +-- include/clang/Sema/Sema.h | 1 + lib/Sema/SemaDecl.cpp | 63 ++++++++++++++-------- test/SemaCXX/anonymous-struct.cpp | 11 ++++ 4 files changed, 57 insertions(+), 24 deletions(-) create mode 100644 test/SemaCXX/anonymous-struct.cpp diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1d85979621..52c81c1676 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -633,9 +633,9 @@ def err_missing_default_ctor : Error< "%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 a57a5a78c7..f815430ed5 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1019,6 +1019,7 @@ public: 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 3271997e0e..cc6e2fa350 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1855,6 +1855,9 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, << (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(*Mem) && (*Mem)->getDeclContext() != Record) { @@ -6044,27 +6047,8 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // 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 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, 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()) { + CXXRecordDecl* RDecl = cast(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 0000000000..dfa284ae8b --- /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}} + }; +}; -- 2.40.0