forked from OSchip/llvm-project
"This patch implements the restrictions on union members detailed in
[class.union]p1", from John McCall! llvm-svn: 76766
This commit is contained in:
parent
f03c9bec63
commit
8a27391190
|
@ -673,6 +673,7 @@ private:
|
|||
bool HasInheritedPrototype : 1;
|
||||
bool HasWrittenPrototype : 1;
|
||||
bool IsDeleted : 1;
|
||||
bool IsTrivial : 1; // sunk from CXXMethodDecl
|
||||
|
||||
// Move to DeclGroup when it is implemented.
|
||||
SourceLocation TypeSpecStartLoc;
|
||||
|
@ -712,8 +713,8 @@ protected:
|
|||
ParamInfo(0), Body(),
|
||||
SClass(S), IsInline(isInline), C99InlineDefinition(false),
|
||||
IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
|
||||
HasWrittenPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL),
|
||||
EndRangeLoc(L), TemplateOrSpecialization() {}
|
||||
HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
|
||||
TypeSpecStartLoc(TSSL), EndRangeLoc(L), TemplateOrSpecialization() {}
|
||||
|
||||
virtual ~FunctionDecl() {}
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
@ -782,6 +783,13 @@ public:
|
|||
bool isPure() const { return IsPure; }
|
||||
void setPure(bool P = true) { IsPure = P; }
|
||||
|
||||
/// Whether this function is "trivial" in some specialized C++ senses.
|
||||
/// Can only be true for default constructors, copy constructors,
|
||||
/// copy assignment operators, and destructors. Not meaningful until
|
||||
/// the class has been fully built by Sema.
|
||||
bool isTrivial() const { return IsTrivial; }
|
||||
void setTrivial(bool IT) { IsTrivial = IT; }
|
||||
|
||||
/// \brief Whether this function has a prototype, either because one
|
||||
/// was explicitly written or because it was "inherited" by merging
|
||||
/// a declaration without a prototype with a declaration that has a
|
||||
|
|
|
@ -297,12 +297,51 @@ class CXXRecordDecl : public RecordDecl {
|
|||
/// pure virtual function, (that can come from a base class).
|
||||
bool Abstract : 1;
|
||||
|
||||
/// HasTrivialConstructor - True when this class has a trivial constructor
|
||||
/// HasTrivialConstructor - True when this class has a trivial constructor.
|
||||
///
|
||||
/// C++ [class.ctor]p5. A constructor is trivial if it is an
|
||||
/// implicitly-declared default constructor and if:
|
||||
/// * its class has no virtual functions and no virtual base classes, and
|
||||
/// * all the direct base classes of its class have trivial constructors, and
|
||||
/// * for all the nonstatic data members of its class that are of class type
|
||||
/// (or array thereof), each such class has a trivial constructor.
|
||||
bool HasTrivialConstructor : 1;
|
||||
|
||||
/// HasTrivialDestructor - True when this class has a trivial destructor
|
||||
bool HasTrivialDestructor : 1;
|
||||
/// HasTrivialCopyConstructor - True when this class has a trivial copy
|
||||
/// constructor.
|
||||
///
|
||||
/// C++ [class.copy]p6. A copy constructor for class X is trivial
|
||||
/// if it is implicitly declared and if
|
||||
/// * class X has no virtual functions and no virtual base classes, and
|
||||
/// * each direct base class of X has a trivial copy constructor, and
|
||||
/// * for all the nonstatic data members of X that are of class type (or
|
||||
/// array thereof), each such class type has a trivial copy constructor;
|
||||
/// otherwise the copy constructor is non-trivial.
|
||||
bool HasTrivialCopyConstructor : 1;
|
||||
|
||||
/// HasTrivialCopyAssignment - True when this class has a trivial copy
|
||||
/// assignment operator.
|
||||
///
|
||||
/// C++ [class.copy]p11. A copy assignment operator for class X is
|
||||
/// trivial if it is implicitly declared and if
|
||||
/// * class X has no virtual functions and no virtual base classes, and
|
||||
/// * each direct base class of X has a trivial copy assignment operator, and
|
||||
/// * for all the nonstatic data members of X that are of class type (or
|
||||
/// array thereof), each such class type has a trivial copy assignment
|
||||
/// operator;
|
||||
/// otherwise the copy assignment operator is non-trivial.
|
||||
bool HasTrivialCopyAssignment : 1;
|
||||
|
||||
/// HasTrivialDestructor - True when this class has a trivial destructor.
|
||||
///
|
||||
/// C++ [class.dtor]p3. A destructor is trivial if it is an
|
||||
/// implicitly-declared destructor and if:
|
||||
/// * all of the direct base classes of its class have trivial destructors
|
||||
/// and
|
||||
/// * for all of the non-static data members of its class that are of class
|
||||
/// type (or array thereof), each such class has a trivial destructor.
|
||||
bool HasTrivialDestructor : 1;
|
||||
|
||||
/// Bases - Base classes of this class.
|
||||
/// FIXME: This is wasted space for a union.
|
||||
CXXBaseSpecifier *Bases;
|
||||
|
@ -342,11 +381,11 @@ protected:
|
|||
|
||||
public:
|
||||
/// base_class_iterator - Iterator that traverses the base classes
|
||||
/// of a clas.
|
||||
/// of a class.
|
||||
typedef CXXBaseSpecifier* base_class_iterator;
|
||||
|
||||
/// base_class_const_iterator - Iterator that traverses the base
|
||||
/// classes of a clas.
|
||||
/// classes of a class.
|
||||
typedef const CXXBaseSpecifier* base_class_const_iterator;
|
||||
|
||||
static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
|
@ -379,6 +418,28 @@ public:
|
|||
base_class_iterator vbases_end() { return VBases + NumVBases; }
|
||||
base_class_const_iterator vbases_end() const { return VBases + NumVBases; }
|
||||
|
||||
/// Iterator access to method members. The method iterator visits
|
||||
/// all method members of the class, including non-instance methods,
|
||||
/// special methods, etc.
|
||||
typedef specific_decl_iterator<CXXMethodDecl> method_iterator;
|
||||
|
||||
method_iterator method_begin() const {
|
||||
return method_iterator(decls_begin());
|
||||
}
|
||||
method_iterator method_end() const {
|
||||
return method_iterator(decls_end());
|
||||
}
|
||||
|
||||
/// Iterator access to constructor members.
|
||||
typedef specific_decl_iterator<CXXConstructorDecl> ctor_iterator;
|
||||
|
||||
ctor_iterator ctor_begin() const {
|
||||
return ctor_iterator(decls_begin());
|
||||
}
|
||||
ctor_iterator ctor_end() const {
|
||||
return ctor_iterator(decls_end());
|
||||
}
|
||||
|
||||
/// hasConstCopyConstructor - Determines whether this class has a
|
||||
/// copy constructor that accepts a const-qualified argument.
|
||||
bool hasConstCopyConstructor(ASTContext &Context) const;
|
||||
|
@ -487,6 +548,22 @@ public:
|
|||
// (C++ [class.ctor]p5)
|
||||
void setHasTrivialConstructor(bool TC) { HasTrivialConstructor = TC; }
|
||||
|
||||
// hasTrivialCopyConstructor - Whether this class has a trivial copy
|
||||
// constructor (C++ [class.copy]p6)
|
||||
bool hasTrivialCopyConstructor() const { return HasTrivialCopyConstructor; }
|
||||
|
||||
// setHasTrivialCopyConstructor - Set whether this class has a trivial
|
||||
// copy constructor (C++ [class.copy]p6)
|
||||
void setHasTrivialCopyConstructor(bool TC) { HasTrivialCopyConstructor = TC; }
|
||||
|
||||
// hasTrivialCopyAssignment - Whether this class has a trivial copy
|
||||
// assignment operator (C++ [class.copy]p11)
|
||||
bool hasTrivialCopyAssignment() const { return HasTrivialCopyAssignment; }
|
||||
|
||||
// setHasTrivialCopyAssignment - Set whether this class has a
|
||||
// trivial copy assignment operator (C++ [class.copy]p11)
|
||||
void setHasTrivialCopyAssignment(bool TC) { HasTrivialCopyAssignment = TC; }
|
||||
|
||||
// hasTrivialDestructor - Whether this class has a trivial destructor
|
||||
// (C++ [class.dtor]p3)
|
||||
bool hasTrivialDestructor() const { return HasTrivialDestructor; }
|
||||
|
|
|
@ -339,6 +339,18 @@ def err_implicit_object_parameter_init : Error<
|
|||
"cannot initialize object parameter of type %0 with an expression "
|
||||
"of type %1">;
|
||||
|
||||
def err_illegal_union_member : Error<
|
||||
"union member %0 has a non-trivial %select{constructor|"
|
||||
"copy constructor|copy assignment operator|destructor}1">;
|
||||
def note_nontrivial_has_virtual : Note<
|
||||
"because type %0 has a virtual %select{member function|base class}1">;
|
||||
def note_nontrivial_has_nontrivial : Note<
|
||||
"because type %0 has a %select{member|base class}1 with a non-trivial "
|
||||
"%select{constructor|copy constructor|copy assignment operator|destructor}2">;
|
||||
def note_nontrivial_user_defined : Note<
|
||||
"because type %0 has a user-declared %select{constructor|copy constructor|"
|
||||
"copy assignment operator|destructor}1">;
|
||||
|
||||
def err_different_return_type_for_overriding_virtual_function : Error<
|
||||
"virtual function %0 has a different return type (%1) than the "
|
||||
"function it overrides (which has return type %2)">;
|
||||
|
|
|
@ -30,7 +30,8 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
|
|||
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
|
||||
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
|
||||
Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false),
|
||||
HasTrivialConstructor(true), HasTrivialDestructor(true),
|
||||
HasTrivialConstructor(true), HasTrivialCopyConstructor(true),
|
||||
HasTrivialCopyAssignment(true), HasTrivialDestructor(true),
|
||||
Bases(0), NumBases(0), VBases(0), NumVBases(0),
|
||||
Conversions(DC, DeclarationName()),
|
||||
TemplateOrInstantiation() { }
|
||||
|
@ -123,7 +124,7 @@ CXXRecordDecl::setBases(ASTContext &C,
|
|||
}
|
||||
if (vbaseCount > 0) {
|
||||
// build AST for inhireted, direct or indirect, virtual bases.
|
||||
this->VBases = new(C) CXXBaseSpecifier [vbaseCount];
|
||||
this->VBases = new (C) CXXBaseSpecifier [vbaseCount];
|
||||
this->NumVBases = vbaseCount;
|
||||
for (int i = 0; i < vbaseCount; i++) {
|
||||
QualType QT = UniqueVbases[i]->getType();
|
||||
|
@ -225,12 +226,19 @@ CXXRecordDecl::addedConstructor(ASTContext &Context,
|
|||
// C++ [class.ctor]p5:
|
||||
// A constructor is trivial if it is an implicitly-declared default
|
||||
// constructor.
|
||||
// FIXME: C++0x: don't do this for "= default" default constructors.
|
||||
HasTrivialConstructor = false;
|
||||
|
||||
// Note when we have a user-declared copy constructor, which will
|
||||
// suppress the implicit declaration of a copy constructor.
|
||||
if (ConDecl->isCopyConstructor(Context))
|
||||
if (ConDecl->isCopyConstructor(Context)) {
|
||||
UserDeclaredCopyConstructor = true;
|
||||
|
||||
// C++ [class.copy]p6:
|
||||
// A copy constructor is trivial if it is implicitly declared.
|
||||
// FIXME: C++0x: don't do this for "= default" copy constructors.
|
||||
HasTrivialCopyConstructor = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
|
||||
|
@ -254,6 +262,11 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
|
|||
// Suppress the implicit declaration of a copy constructor.
|
||||
UserDeclaredCopyAssignment = true;
|
||||
|
||||
// C++ [class.copy]p11:
|
||||
// A copy assignment operator is trivial if it is implicitly declared.
|
||||
// FIXME: C++0x: don't do this for "= default" copy operators.
|
||||
HasTrivialCopyAssignment = false;
|
||||
|
||||
// C++ [class]p4:
|
||||
// A POD-struct is an aggregate class that [...] has no user-defined copy
|
||||
// assignment operator [...].
|
||||
|
|
|
@ -541,6 +541,14 @@ public:
|
|||
SourceLocation TSSL,
|
||||
AccessSpecifier AS, NamedDecl *PrevDecl,
|
||||
Declarator *D = 0);
|
||||
|
||||
enum CXXSpecialMember {
|
||||
CXXDefaultConstructor = 0,
|
||||
CXXCopyConstructor = 1,
|
||||
CXXCopyAssignment = 2,
|
||||
CXXDestructor = 3
|
||||
};
|
||||
void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
|
||||
|
||||
virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
|
||||
DeclPtrTy IntfDecl,
|
||||
|
|
|
@ -2265,6 +2265,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
CurClass->setPOD(false);
|
||||
CurClass->setPolymorphic(true);
|
||||
CurClass->setHasTrivialConstructor(false);
|
||||
CurClass->setHasTrivialCopyConstructor(false);
|
||||
CurClass->setHasTrivialCopyAssignment(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2505,6 +2507,7 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
|
|||
|
||||
// C++ [class.dtor]p3: A destructor is trivial if it is an implicitly-
|
||||
// declared destructor.
|
||||
// FIXME: C++0x: don't do this for "= default" destructors
|
||||
Record->setHasTrivialDestructor(false);
|
||||
} else if (CXXConversionDecl *Conversion
|
||||
= dyn_cast<CXXConversionDecl>(NewFD))
|
||||
|
@ -4085,6 +4088,57 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
|
|||
NewFD->setInvalidDecl();
|
||||
}
|
||||
|
||||
if (getLangOptions().CPlusPlus) {
|
||||
QualType EltTy = T;
|
||||
while (const ArrayType *AT = Context.getAsArrayType(EltTy))
|
||||
EltTy = AT->getElementType();
|
||||
|
||||
if (const RecordType *RT = EltTy->getAsRecordType()) {
|
||||
CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
|
||||
|
||||
if (!RDecl->hasTrivialConstructor())
|
||||
cast<CXXRecordDecl>(Record)->setHasTrivialConstructor(false);
|
||||
if (!RDecl->hasTrivialCopyConstructor())
|
||||
cast<CXXRecordDecl>(Record)->setHasTrivialCopyConstructor(false);
|
||||
if (!RDecl->hasTrivialCopyAssignment())
|
||||
cast<CXXRecordDecl>(Record)->setHasTrivialCopyAssignment(false);
|
||||
if (!RDecl->hasTrivialDestructor())
|
||||
cast<CXXRecordDecl>(Record)->setHasTrivialDestructor(false);
|
||||
|
||||
// C++ 9.5p1: An object of a class with a non-trivial
|
||||
// constructor, a non-trivial copy constructor, a non-trivial
|
||||
// destructor, or a non-trivial copy assignment operator
|
||||
// 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.
|
||||
|
||||
const CXXSpecialMember invalid = (CXXSpecialMember) -1;
|
||||
|
||||
CXXSpecialMember member;
|
||||
if (!RDecl->hasTrivialCopyConstructor())
|
||||
member = CXXCopyConstructor;
|
||||
else if (!RDecl->hasTrivialConstructor())
|
||||
member = CXXDefaultConstructor;
|
||||
else if (!RDecl->hasTrivialCopyAssignment())
|
||||
member = CXXCopyAssignment;
|
||||
else if (!RDecl->hasTrivialDestructor())
|
||||
member = CXXDestructor;
|
||||
else
|
||||
member = invalid;
|
||||
|
||||
if (member != invalid) {
|
||||
Diag(Loc, diag::err_illegal_union_member) << Name << member;
|
||||
DiagnoseNontrivial(RT, member);
|
||||
NewFD->setInvalidDecl();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getLangOptions().CPlusPlus && !T->isPODType())
|
||||
cast<CXXRecordDecl>(Record)->setPOD(false);
|
||||
|
||||
|
@ -4113,6 +4167,133 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
|
|||
return NewFD;
|
||||
}
|
||||
|
||||
/// DiagnoseNontrivial - Given that a class has a non-trivial
|
||||
/// special member, figure out why.
|
||||
void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
|
||||
QualType QT(T, 0U);
|
||||
CXXRecordDecl* RD = cast<CXXRecordDecl>(T->getDecl());
|
||||
|
||||
// Check whether the member was user-declared.
|
||||
switch (member) {
|
||||
case CXXDefaultConstructor:
|
||||
if (RD->hasUserDeclaredConstructor()) {
|
||||
typedef CXXRecordDecl::ctor_iterator ctor_iter;
|
||||
for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce; ++ci)
|
||||
if (!ci->isImplicitlyDefined(Context)) {
|
||||
SourceLocation CtorLoc = ci->getLocation();
|
||||
Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(0 && "found no user-declared constructors");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case CXXCopyConstructor:
|
||||
if (RD->hasUserDeclaredCopyConstructor()) {
|
||||
SourceLocation CtorLoc =
|
||||
RD->getCopyConstructor(Context, 0)->getLocation();
|
||||
Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case CXXCopyAssignment:
|
||||
if (RD->hasUserDeclaredCopyAssignment()) {
|
||||
// FIXME: this should use the location of the copy
|
||||
// assignment, not the type.
|
||||
SourceLocation TyLoc = RD->getSourceRange().getBegin();
|
||||
Diag(TyLoc, diag::note_nontrivial_user_defined) << QT << member;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case CXXDestructor:
|
||||
if (RD->hasUserDeclaredDestructor()) {
|
||||
SourceLocation DtorLoc = RD->getDestructor(Context)->getLocation();
|
||||
Diag(DtorLoc, diag::note_nontrivial_user_defined) << QT << member;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
typedef CXXRecordDecl::base_class_iterator base_iter;
|
||||
|
||||
// Virtual bases and members inhibit trivial copying/construction,
|
||||
// but not trivial destruction.
|
||||
if (member != CXXDestructor) {
|
||||
// Check for virtual bases. vbases includes indirect virtual bases,
|
||||
// so we just iterate through the direct bases.
|
||||
for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi)
|
||||
if (bi->isVirtual()) {
|
||||
SourceLocation BaseLoc = bi->getSourceRange().getBegin();
|
||||
Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for virtual methods.
|
||||
typedef CXXRecordDecl::method_iterator meth_iter;
|
||||
for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
|
||||
++mi) {
|
||||
if (mi->isVirtual()) {
|
||||
SourceLocation MLoc = mi->getSourceRange().getBegin();
|
||||
Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool (CXXRecordDecl::*hasTrivial)() const;
|
||||
switch (member) {
|
||||
case CXXDefaultConstructor:
|
||||
hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break;
|
||||
case CXXCopyConstructor:
|
||||
hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
|
||||
case CXXCopyAssignment:
|
||||
hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break;
|
||||
case CXXDestructor:
|
||||
hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break;
|
||||
default:
|
||||
assert(0 && "unexpected special member"); return;
|
||||
}
|
||||
|
||||
// Check for nontrivial bases (and recurse).
|
||||
for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) {
|
||||
const RecordType *BaseRT = bi->getType()->getAsRecordType();
|
||||
assert(BaseRT);
|
||||
CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl());
|
||||
if (!(BaseRecTy->*hasTrivial)()) {
|
||||
SourceLocation BaseLoc = bi->getSourceRange().getBegin();
|
||||
Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member;
|
||||
DiagnoseNontrivial(BaseRT, member);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for nontrivial members (and recurse).
|
||||
typedef RecordDecl::field_iterator field_iter;
|
||||
for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
|
||||
++fi) {
|
||||
QualType EltTy = (*fi)->getType();
|
||||
while (const ArrayType *AT = Context.getAsArrayType(EltTy))
|
||||
EltTy = AT->getElementType();
|
||||
|
||||
if (const RecordType *EltRT = EltTy->getAsRecordType()) {
|
||||
CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
|
||||
|
||||
if (!(EltRD->*hasTrivial)()) {
|
||||
SourceLocation FLoc = (*fi)->getLocation();
|
||||
Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
|
||||
DiagnoseNontrivial(EltRT, member);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(0 && "found no explanation for non-trivial member");
|
||||
}
|
||||
|
||||
/// TranslateIvarVisibility - Translate visibility from a token ID to an
|
||||
/// AST enum value.
|
||||
static ObjCIvarDecl::AccessControl
|
||||
|
|
|
@ -400,19 +400,40 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
|
|||
// C++ [class.ctor]p5:
|
||||
// A constructor is trivial if its class has no virtual base classes.
|
||||
Class->setHasTrivialConstructor(false);
|
||||
|
||||
// C++ [class.copy]p6:
|
||||
// A copy constructor is trivial if its class has no virtual base classes.
|
||||
Class->setHasTrivialCopyConstructor(false);
|
||||
|
||||
// C++ [class.copy]p11:
|
||||
// A copy assignment operator is trivial if its class has no virtual
|
||||
// base classes.
|
||||
Class->setHasTrivialCopyAssignment(false);
|
||||
} else {
|
||||
// C++ [class.ctor]p5:
|
||||
// A constructor is trivial if all the direct base classes of its
|
||||
// class have trivial constructors.
|
||||
Class->setHasTrivialConstructor(cast<CXXRecordDecl>(BaseDecl)->
|
||||
hasTrivialConstructor());
|
||||
if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialConstructor())
|
||||
Class->setHasTrivialConstructor(false);
|
||||
|
||||
// C++ [class.copy]p6:
|
||||
// A copy constructor is trivial if all the direct base classes of its
|
||||
// class have trivial copy constructors.
|
||||
if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyConstructor())
|
||||
Class->setHasTrivialCopyConstructor(false);
|
||||
|
||||
// C++ [class.copy]p11:
|
||||
// A copy assignment operator is trivial if all the direct base classes
|
||||
// of its class have trivial copy assignment operators.
|
||||
if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyAssignment())
|
||||
Class->setHasTrivialCopyAssignment(false);
|
||||
}
|
||||
|
||||
// C++ [class.ctor]p3:
|
||||
// A destructor is trivial if all the direct base classes of its class
|
||||
// have trivial destructors.
|
||||
Class->setHasTrivialDestructor(cast<CXXRecordDecl>(BaseDecl)->
|
||||
hasTrivialDestructor());
|
||||
if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialDestructor())
|
||||
Class->setHasTrivialDestructor(false);
|
||||
|
||||
// Create the base specifier.
|
||||
// FIXME: Allocate via ASTContext?
|
||||
|
@ -1154,30 +1175,6 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
|
|||
if (RD->isAbstract())
|
||||
AbstractClassUsageDiagnoser(*this, RD);
|
||||
|
||||
if (RD->hasTrivialConstructor() || RD->hasTrivialDestructor()) {
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
// All the nonstatic data members must have trivial constructors.
|
||||
QualType FTy = i->getType();
|
||||
while (const ArrayType *AT = Context.getAsArrayType(FTy))
|
||||
FTy = AT->getElementType();
|
||||
|
||||
if (const RecordType *RT = FTy->getAsRecordType()) {
|
||||
CXXRecordDecl *FieldRD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
|
||||
if (!FieldRD->hasTrivialConstructor())
|
||||
RD->setHasTrivialConstructor(false);
|
||||
if (!FieldRD->hasTrivialDestructor())
|
||||
RD->setHasTrivialDestructor(false);
|
||||
|
||||
// If RD has neither a trivial constructor nor a trivial destructor
|
||||
// we don't need to continue checking.
|
||||
if (!RD->hasTrivialConstructor() && !RD->hasTrivialDestructor())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!RD->isDependentType())
|
||||
AddImplicitlyDeclaredMembersToClass(RD);
|
||||
}
|
||||
|
@ -1213,6 +1210,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
/*isImplicitlyDeclared=*/true);
|
||||
DefaultCon->setAccess(AS_public);
|
||||
DefaultCon->setImplicit();
|
||||
DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
|
||||
ClassDecl->addDecl(DefaultCon);
|
||||
}
|
||||
|
||||
|
@ -1283,6 +1281,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
/*isImplicitlyDeclared=*/true);
|
||||
CopyConstructor->setAccess(AS_public);
|
||||
CopyConstructor->setImplicit();
|
||||
CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
|
||||
|
||||
// Add the parameter to the constructor.
|
||||
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
|
||||
|
@ -1359,6 +1358,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
/*isStatic=*/false, /*isInline=*/true);
|
||||
CopyAssignment->setAccess(AS_public);
|
||||
CopyAssignment->setImplicit();
|
||||
CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
|
||||
|
||||
// Add the parameter to the operator.
|
||||
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
|
||||
|
@ -1388,6 +1388,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
|||
/*isImplicitlyDeclared=*/true);
|
||||
Destructor->setAccess(AS_public);
|
||||
Destructor->setImplicit();
|
||||
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
|
||||
ClassDecl->addDecl(Destructor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
void abort();
|
||||
|
||||
class Okay {
|
||||
int a_;
|
||||
};
|
||||
|
||||
class Virtual {
|
||||
virtual void foo() { abort(); } // expected-note 3 {{because type 'class Virtual' has a virtual member function}}
|
||||
};
|
||||
|
||||
class VirtualBase : virtual Okay { // expected-note 3 {{because type 'class VirtualBase' has a virtual base class}}
|
||||
};
|
||||
|
||||
class Ctor {
|
||||
Ctor() { abort(); } // expected-note 3 {{because type 'class Ctor' has a user-declared constructor}}
|
||||
};
|
||||
|
||||
class CopyCtor {
|
||||
CopyCtor(CopyCtor &cc) { abort(); } // expected-note 3 {{because type 'class CopyCtor' has a user-declared copy constructor}}
|
||||
};
|
||||
|
||||
// FIXME: this should eventually trigger on the operator's declaration line
|
||||
class CopyAssign { // expected-note 3 {{because type 'class CopyAssign' has a user-declared copy assignment operator}}
|
||||
CopyAssign& operator=(CopyAssign& CA) { abort(); }
|
||||
};
|
||||
|
||||
class Dtor {
|
||||
~Dtor() { abort(); } // expected-note 3 {{because type 'class Dtor' has a user-declared destructor}}
|
||||
};
|
||||
|
||||
union U1 {
|
||||
Virtual v; // expected-error {{union member 'v' has a non-trivial copy constructor}}
|
||||
VirtualBase vbase; // expected-error {{union member 'vbase' has a non-trivial copy constructor}}
|
||||
Ctor ctor; // expected-error {{union member 'ctor' has a non-trivial constructor}}
|
||||
CopyCtor copyctor; // expected-error {{union member 'copyctor' has a non-trivial copy constructor}}
|
||||
CopyAssign copyassign; // expected-error {{union member 'copyassign' has a non-trivial copy assignment operator}}
|
||||
Dtor dtor; // expected-error {{union member 'dtor' has a non-trivial destructor}}
|
||||
Okay okay;
|
||||
};
|
||||
|
||||
union U2 {
|
||||
struct {
|
||||
Virtual v; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial copy constructor}}
|
||||
} m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
|
||||
struct {
|
||||
VirtualBase vbase; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial copy constructor}}
|
||||
} m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
|
||||
struct {
|
||||
Ctor ctor; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial constructor}}
|
||||
} m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
|
||||
struct {
|
||||
CopyCtor copyctor; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial copy constructor}}
|
||||
} m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
|
||||
struct {
|
||||
CopyAssign copyassign; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial copy assignment operator}}
|
||||
} m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
|
||||
struct {
|
||||
Dtor dtor; // expected-note {{because type 'struct U2::<anonymous>' has a member with a non-trivial destructor}}
|
||||
} m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
|
||||
struct {
|
||||
Okay okay;
|
||||
} m7;
|
||||
};
|
||||
|
||||
union U3 {
|
||||
struct s1 : Virtual { // expected-note {{because type 'struct U3::s1' has a base class with a non-trivial copy constructor}}
|
||||
} m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
|
||||
struct s2 : VirtualBase { // expected-note {{because type 'struct U3::s2' has a base class with a non-trivial copy constructor}}
|
||||
} m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
|
||||
struct s3 : Ctor { // expected-note {{because type 'struct U3::s3' has a base class with a non-trivial constructor}}
|
||||
} m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
|
||||
struct s4 : CopyCtor { // expected-note {{because type 'struct U3::s4' has a base class with a non-trivial copy constructor}}
|
||||
} m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
|
||||
struct s5 : CopyAssign { // expected-note {{because type 'struct U3::s5' has a base class with a non-trivial copy assignment operator}}
|
||||
} m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
|
||||
struct s6 : Dtor { // expected-note {{because type 'struct U3::s6' has a base class with a non-trivial destructor}}
|
||||
} m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
|
||||
struct s7 : Okay {
|
||||
} m7;
|
||||
};
|
||||
|
||||
template <class A, class B> struct Either {
|
||||
bool tag;
|
||||
union {
|
||||
A a;
|
||||
B b;
|
||||
};
|
||||
|
||||
Either(A& a) : tag(true), a(a) {}
|
||||
Either(B& b) : tag(false), b(b) {}
|
||||
};
|
||||
|
||||
/* FIXME: this should work, but crashes in template code.
|
||||
void fred() {
|
||||
Either<int,Virtual> virt(0);
|
||||
Either<int,VirtualBase> vbase(0);
|
||||
Either<int,Ctor> ctor(0);
|
||||
Either<int,CopyCtor> copyctor(0);
|
||||
Either<int,CopyAssign> copyassign(0);
|
||||
Either<int,Dtor> dtor(0);
|
||||
Either<int,Okay> okay(0);
|
||||
}
|
||||
*/
|
Loading…
Reference in New Issue