forked from OSchip/llvm-project
Keep track of whether a C++ class is an aggregate. Don't allow initialization of non-aggregates with initializer lists.
llvm-svn: 58757
This commit is contained in:
parent
6f5431543a
commit
cfd8ddc6de
|
@ -215,6 +215,9 @@ class CXXRecordDecl : public RecordDecl, public DeclContext {
|
|||
/// user-defined copy constructor.
|
||||
bool UserDeclaredCopyConstructor : 1;
|
||||
|
||||
/// Aggregate - True when this class is an aggregate.
|
||||
bool Aggregate : 1;
|
||||
|
||||
/// Bases - Base classes of this class.
|
||||
/// FIXME: This is wasted space for a union.
|
||||
CXXBaseSpecifier *Bases;
|
||||
|
@ -230,8 +233,8 @@ class CXXRecordDecl : public RecordDecl, public DeclContext {
|
|||
CXXRecordDecl(TagKind TK, DeclContext *DC,
|
||||
SourceLocation L, IdentifierInfo *Id)
|
||||
: RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord),
|
||||
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
|
||||
Bases(0), NumBases(0), Constructors(DC, Id) { }
|
||||
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
|
||||
Aggregate(true), Bases(0), NumBases(0), Constructors(DC, Id) { }
|
||||
|
||||
~CXXRecordDecl();
|
||||
|
||||
|
@ -300,6 +303,16 @@ public:
|
|||
return UserDeclaredCopyConstructor;
|
||||
}
|
||||
|
||||
/// isAggregate - Whether this class is an aggregate (C++
|
||||
/// [dcl.init.aggr]), which is a class with no user-declared
|
||||
/// constructors, no private or protected non-static data members,
|
||||
/// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1).
|
||||
bool isAggregate() const { return Aggregate; }
|
||||
|
||||
/// setAggregate - Set whether this class is an aggregate (C++
|
||||
/// [dcl.init.aggr]).
|
||||
void setAggregate(bool Agg) { Aggregate = Agg; }
|
||||
|
||||
/// viewInheritance - Renders and displays an inheritance diagram
|
||||
/// for this C++ class and all of its base classes (transitively) using
|
||||
/// GraphViz.
|
||||
|
|
|
@ -697,6 +697,8 @@ DIAG(err_reference_var_requires_init, ERROR,
|
|||
"declaration of reference variable '%0' requires an initializer")
|
||||
DIAG(err_const_var_requires_init, ERROR,
|
||||
"declaration of const variable '%0' requires an initializer")
|
||||
DIAG(err_init_non_aggr_init_list, ERROR,
|
||||
"initialization of non-aggregate type '%0' with an initializer list")
|
||||
|
||||
// Objective-C++
|
||||
DIAG(err_objc_decls_may_only_appear_in_global_scope, ERROR,
|
||||
|
|
|
@ -50,6 +50,11 @@ void CXXRecordDecl::Destroy(ASTContext &C) {
|
|||
void
|
||||
CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
||||
unsigned NumBases) {
|
||||
// C++ [dcl.init.aggr]p1:
|
||||
// An aggregate is an array or a class (clause 9) with [...]
|
||||
// no base classes [...].
|
||||
Aggregate = false;
|
||||
|
||||
if (this->Bases)
|
||||
delete [] this->Bases;
|
||||
|
||||
|
@ -78,6 +83,11 @@ CXXRecordDecl::addConstructor(ASTContext &Context,
|
|||
// Note that we have a user-declared constructor.
|
||||
UserDeclaredConstructor = true;
|
||||
|
||||
// C++ [dcl.init.aggr]p1:
|
||||
// An aggregate is an array or a class (clause 9) with no
|
||||
// user-declared constructors (12.1) [...].
|
||||
Aggregate = false;
|
||||
|
||||
// Note when we have a user-declared copy constructor, which will
|
||||
// suppress the implicit declaration of a copy constructor.
|
||||
if (ConDecl->isCopyConstructor(Context))
|
||||
|
@ -154,9 +164,8 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
|||
|
||||
bool CXXConstructorDecl::isDefaultConstructor() const {
|
||||
// C++ [class.ctor]p5:
|
||||
//
|
||||
// A default constructor for a class X is a constructor of class
|
||||
// X that can be called without an argument.
|
||||
// A default constructor for a class X is a constructor of class
|
||||
// X that can be called without an argument.
|
||||
return (getNumParams() == 0) ||
|
||||
(getNumParams() > 0 && getParamDecl(0)->getDefaultArg() != 0);
|
||||
}
|
||||
|
@ -165,10 +174,10 @@ bool
|
|||
CXXConstructorDecl::isCopyConstructor(ASTContext &Context,
|
||||
unsigned &TypeQuals) const {
|
||||
// C++ [class.copy]p2:
|
||||
// A non-template constructor for class X is a copy constructor
|
||||
// if its first parameter is of type X&, const X&, volatile X& or
|
||||
// const volatile X&, and either there are no other parameters
|
||||
// or else all other parameters have default arguments (8.3.6).
|
||||
// A non-template constructor for class X is a copy constructor
|
||||
// if its first parameter is of type X&, const X&, volatile X& or
|
||||
// const volatile X&, and either there are no other parameters
|
||||
// or else all other parameters have default arguments (8.3.6).
|
||||
if ((getNumParams() < 1) ||
|
||||
(getNumParams() > 1 && getParamDecl(1)->getDefaultArg() == 0))
|
||||
return false;
|
||||
|
|
|
@ -701,6 +701,23 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
|
|||
Init->getSourceRange());
|
||||
|
||||
return CheckSingleInitializer(Init, DeclType);
|
||||
} else if (getLangOptions().CPlusPlus) {
|
||||
// C++ [dcl.init]p14:
|
||||
// [...] If the class is an aggregate (8.5.1), and the initializer
|
||||
// is a brace-enclosed list, see 8.5.1.
|
||||
//
|
||||
// Note: 8.5.1 is handled below; here, we diagnose the case where
|
||||
// we have an initializer list and a destination type that is not
|
||||
// an aggregate.
|
||||
// FIXME: In C++0x, this is yet another form of initialization.
|
||||
if (const RecordType *ClassRec = DeclType->getAsRecordType()) {
|
||||
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
|
||||
if (!ClassDecl->isAggregate())
|
||||
return Diag(InitLoc,
|
||||
diag::err_init_non_aggr_init_list,
|
||||
DeclType.getAsString(),
|
||||
Init->getSourceRange());
|
||||
}
|
||||
}
|
||||
|
||||
InitListChecker CheckInitList(this, InitList, DeclType);
|
||||
|
|
|
@ -461,6 +461,15 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
|
|||
// member decls.
|
||||
CXXClassMemberWrapper(Member).setAccess(AS);
|
||||
|
||||
// C++ [dcl.init.aggr]p1:
|
||||
// An aggregate is an array or a class (clause 9) with [...] no
|
||||
// private or protected non-static data members (clause 11).
|
||||
if (isInstField && (AS == AS_private || AS == AS_protected))
|
||||
cast<CXXRecordDecl>(CurContext)->setAggregate(false);
|
||||
|
||||
// FIXME: If the member is a virtual function, mark it its class as
|
||||
// a non-aggregate.
|
||||
|
||||
if (BitWidth) {
|
||||
// C++ 9.6p2: Only when declaring an unnamed bit-field may the
|
||||
// constant-expression be a value equal to zero.
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
// RUN: clang -fsyntax-only -verify -std=c++98 %s
|
||||
|
||||
// Verify that we can't initialize non-aggregates with an initializer
|
||||
// list.
|
||||
struct NonAggr1 {
|
||||
NonAggr1(int) { }
|
||||
|
||||
int m;
|
||||
};
|
||||
|
||||
struct Base { };
|
||||
struct NonAggr2 : public Base {
|
||||
int m;
|
||||
};
|
||||
|
||||
class NonAggr3 {
|
||||
int m;
|
||||
};
|
||||
|
||||
// FIXME: virtual functions
|
||||
struct NonAggr4 {
|
||||
};
|
||||
|
||||
NonAggr1 na1 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr1' with an initializer list}}
|
||||
NonAggr2 na2 = { 17 }; // expected-error{{initialization of non-aggregate type 'struct NonAggr2' with an initializer list}}
|
||||
NonAggr3 na3 = { 17 }; // expected-error{{initialization of non-aggregate type 'class NonAggr3' with an initializer list}}
|
Loading…
Reference in New Issue