diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 17 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 2 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 9 | ||||
-rw-r--r-- | test/SemaCXX/aggregate-initialization.cpp | 26 |
6 files changed, 85 insertions, 9 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 3d0c805a3a..9d0065e4fb 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -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. diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 30238f6d6f..c4c3d0c986 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -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, diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index f49b207b0c..cf59d1af36 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5dc571c0ee..c8c253a3fb 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b95ebf0bad..53051ff57f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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. diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp new file mode 100644 index 0000000000..855bc27616 --- /dev/null +++ b/test/SemaCXX/aggregate-initialization.cpp @@ -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}} |