From 87595e46ccd61c9b7c08074c2c64b66b5c0fc694 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 23 Jul 2009 23:32:59 +0000 Subject: [PATCH] Diagnose when base classes and members to be intialized with constructors don't have a matching constructor. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76913 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclCXX.h | 8 +++-- include/clang/Basic/DiagnosticSemaKinds.td | 3 ++ lib/AST/DeclCXX.cpp | 19 ++++++++---- lib/Sema/Sema.h | 5 ++++ lib/Sema/SemaDeclCXX.cpp | 35 +++++++++++++++++----- test/SemaCXX/constructor-initializer.cpp | 20 +++++++++++++ 6 files changed, 74 insertions(+), 16 deletions(-) diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 1d153eefd4..ed08a60a88 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -736,7 +736,7 @@ class CXXBaseOrMemberInitializer { Expr **Args; unsigned NumArgs; - /// CtorToCall - For a base or mamber needing a constructor for their + /// CtorToCall - For a base or member needing a constructor for their /// initialization, this is the constructor to call. CXXConstructorDecl *CtorToCall; @@ -923,8 +923,10 @@ public: } void setBaseOrMemberInitializers(ASTContext &C, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers); + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers, + llvm::SmallVectorImpl& Bases, + llvm::SmallVectorImpl&Members); /// isDefaultConstructor - Whether this constructor is a default /// constructor (C++ [class.ctor]p5), which can be used to diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a8c4de57ca..ead116d8da 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -346,6 +346,9 @@ def err_implicit_object_parameter_init : Error< "cannot initialize object parameter of type %0 with an expression " "of type %1">; +def err_missing_default_constructor : Error< + "default constructor for %1 is missing in initialization of " + "%select{base class|mamber}0">; def err_illegal_union_member : Error< "union member %0 has a non-trivial %select{constructor|" "copy constructor|copy assignment operator|destructor}1">; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 0f2230116c..7b5a29028c 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -564,9 +564,11 @@ CXXDestructorDecl::computeBaseOrMembersToDestroy(ASTContext &C) { void CXXConstructorDecl::setBaseOrMemberInitializers( - ASTContext &C, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers) { + ASTContext &C, + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers, + llvm::SmallVectorImpl& Bases, + llvm::SmallVectorImpl&Fields) { // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. CXXRecordDecl *ClassDecl = cast(getDeclContext()); @@ -594,7 +596,9 @@ CXXConstructorDecl::setBaseOrMemberInitializers( CXXRecordDecl *VBaseDecl = cast(VBase->getType()->getAsRecordType()->getDecl()); assert(VBaseDecl && "setBaseOrMemberInitializers - VBaseDecl null"); - // FIXME. Issue error if default ctor is missing. + if (!VBaseDecl->getDefaultConstructor(C) && + !VBase->getType()->isDependentType()) + Bases.push_back(VBase); CXXBaseOrMemberInitializer *Member = new (C) CXXBaseOrMemberInitializer(VBase->getType(), 0, 0, VBaseDecl->getDefaultConstructor(C), @@ -617,7 +621,9 @@ CXXConstructorDecl::setBaseOrMemberInitializers( CXXRecordDecl *BaseDecl = cast(Base->getType()->getAsRecordType()->getDecl()); assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null"); - // FIXME. Issue error if default ctor is missing. + if (!BaseDecl->getDefaultConstructor(C) && + !Base->getType()->isDependentType()) + Bases.push_back(Base); CXXBaseOrMemberInitializer *Member = new (C) CXXBaseOrMemberInitializer(Base->getType(), 0, 0, BaseDecl->getDefaultConstructor(C), @@ -643,7 +649,8 @@ CXXConstructorDecl::setBaseOrMemberInitializers( if (CXXRecordDecl *FieldClassDecl = dyn_cast(FieldType->getAsRecordType()->getDecl())) Ctor = FieldClassDecl->getDefaultConstructor(C); - // FIXME. Issue error if default ctor is missing. + if (!Ctor && !FieldType->isDependentType()) + Fields.push_back(*Field); CXXBaseOrMemberInitializer *Member = new (C) CXXBaseOrMemberInitializer((*Field), 0, 0, Ctor, diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index d66e642af3..5f50438445 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1482,6 +1482,11 @@ public: const FunctionProtoType *Proto, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc); + void BuildBaseOrMemberInitializers(ASTContext &C, + CXXConstructorDecl *Constructor, + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers + ); /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c12878c760..d5c8c3d3fc 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -810,6 +810,26 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, NumArgs, C, IdLoc); } +void +Sema::BuildBaseOrMemberInitializers(ASTContext &C, + CXXConstructorDecl *Constructor, + CXXBaseOrMemberInitializer **Initializers, + unsigned NumInitializers + ) { + llvm::SmallVectorBases; + llvm::SmallVectorMembers; + + Constructor->setBaseOrMemberInitializers(C, + Initializers, NumInitializers, + Bases, Members); + for (unsigned int i = 0; i < Bases.size(); i++) + Diag(Bases[i]->getSourceRange().getBegin(), + diag::err_missing_default_constructor) << 0 << Bases[i]->getType(); + for (unsigned int i = 0; i < Members.size(); i++) + Diag(Members[i]->getLocation(), diag::err_missing_default_constructor) + << 1 << Members[i]->getType(); +} + static void *GetKeyForTopLevelField(FieldDecl *Field) { // For anonymous unions, use the class declaration as the key. if (const RecordType *RT = Field->getType()->getAsRecordType()) { @@ -872,11 +892,11 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, << 0; err = true; } - if (!err) { - Constructor->setBaseOrMemberInitializers(Context, - reinterpret_cast(MemInits), - NumMemInits); - } + if (!err) + BuildBaseOrMemberInitializers(Context, Constructor, + reinterpret_cast(MemInits), + NumMemInits); + if (!err && (Diags.getDiagnosticLevel(diag::warn_base_initialized) != Diagnostic::Ignored || Diags.getDiagnosticLevel(diag::warn_field_initialized) @@ -960,8 +980,9 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) { if (CXXConstructorDecl *Constructor = dyn_cast(CDtorDecl.getAs())) - Constructor->setBaseOrMemberInitializers(Context, - (CXXBaseOrMemberInitializer **)0, 0); + BuildBaseOrMemberInitializers(Context, + Constructor, + (CXXBaseOrMemberInitializer **)0, 0); } namespace { diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp index 66a5f57e1c..71d38a1438 100644 --- a/test/SemaCXX/constructor-initializer.cpp +++ b/test/SemaCXX/constructor-initializer.cpp @@ -96,3 +96,23 @@ struct Current : Derived { INT::NonExisting() {} // expected-error {{expected a class or namespace}} \ // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}} }; + + // FIXME. This is bad message! +struct M { // expected-note {{candidate function}} \ + // expected-note {{candidate function}} + M(int i, int j); // expected-note {{candidate function}} \ + // // expected-note {{candidate function}} +}; + +struct N : M { + N() : M(1), // expected-error {{no matching constructor for initialization of 'M'}} + m1(100) { } // expected-error {{no matching constructor for initialization of 'm1'}} + M m1; +}; + +struct P : M { // expected-error {{default constructor for 'struct M' is missing in initialization of base class}} + P() { } + M m; // expected-error {{default constructor for 'struct M' is missing in initialization of mamber}} +}; + + -- 2.40.0