From: Fariborz Jahanian Date: Fri, 19 Jun 2009 19:55:27 +0000 (+0000) Subject: Patch for implementation of C++'s object model. This is X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f8dcb866d344aa9355595e14c429852830b63095;p=clang Patch for implementation of C++'s object model. This is work in progress. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73782 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 1dd2bceb43..1216eb09ee 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -439,6 +439,9 @@ public: TemplateOrInstantiation = Template; } + /// getDefaultConstructor - Returns the default constructor for this class + CXXConstructorDecl *getDefaultConstructor(ASTContext &Context); + /// getDestructor - Returns the destructor decl for this class. const CXXDestructorDecl *getDestructor(ASTContext &Context); @@ -638,6 +641,10 @@ class CXXConstructorDecl : public CXXMethodDecl { /// explicitly defaulted (i.e., defined with " = default") will have /// @c !Implicit && ImplicitlyDefined. bool ImplicitlyDefined : 1; + + /// ImplicitMustBeDefined - Implicit constructor was used to create an + /// object of its class type. It must be defined. + bool ImplicitMustBeDefined : 1; /// FIXME: Add support for base and member initializers. @@ -645,7 +652,8 @@ class CXXConstructorDecl : public CXXMethodDecl { DeclarationName N, QualType T, bool isExplicit, bool isInline, bool isImplicitlyDeclared) : CXXMethodDecl(CXXConstructor, RD, L, N, T, false, isInline), - Explicit(isExplicit), ImplicitlyDefined(false) { + Explicit(isExplicit), ImplicitlyDefined(false), + ImplicitMustBeDefined(false) { setImplicit(isImplicitlyDeclared); } @@ -676,6 +684,17 @@ public: ImplicitlyDefined = ID; } + /// isImplicitMustBeDefined - Whether a definition must be synthesized for + /// the implicit constructor. + bool isImplicitMustBeDefined() const { + return isImplicit() && ImplicitMustBeDefined; + } + + /// setImplicitMustBeDefined - constructor must be implicitly defined. + void setImplicitMustBeDefined() { + ImplicitMustBeDefined = true; + } + /// isDefaultConstructor - Whether this constructor is a default /// constructor (C++ [class.ctor]p5), which can be used to /// default-initialize a class of this type. diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 9f554495b6..5b324d87c0 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -573,6 +573,14 @@ def err_param_default_argument_references_this : Error< def err_param_default_argument_nonfunc : Error< "default arguments can only be specified for parameters in a function " "declaration">; +def err_defining_default_ctor : Error< + "cannot define the default constructor for %0, because %1 does not " + "have any default constructor">; +def not_previous_class_decl : Note< + "class %0 declared here">; +def err_unintialized_member : Error< + "cannot define the default constructor for %0, because of " + "unintialized %select{reference|const}1 member">; def err_use_of_default_argument_to_function_declared_later : Error< "use of default argument to function %0 that is declared later in class %1">; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index f299ed1023..2fa5ed7919 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -184,10 +184,28 @@ void CXXRecordDecl::addConversionFunction(ASTContext &Context, Conversions.addOverload(ConvDecl); } + +CXXConstructorDecl * +CXXRecordDecl::getDefaultConstructor(ASTContext &Context) { + QualType ClassType = Context.getTypeDeclType(this); + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType.getUnqualifiedType())); + + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = lookup(Context, ConstructorName); + Con != ConEnd; ++Con) { + CXXConstructorDecl *Constructor = cast(*Con); + if (Constructor->isDefaultConstructor()) + return Constructor; + } + return 0; +} + const CXXDestructorDecl * CXXRecordDecl::getDestructor(ASTContext &Context) { QualType ClassType = Context.getTypeDeclType(this); - + DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index cd18b969a4..bb9fa4b798 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1533,6 +1533,11 @@ public: CXXConstructorDecl *Constructor, QualType DeclInitType, Expr **Exprs, unsigned NumExprs); + + /// DefineImplicitDefaultConstructor - Checks for feasibilityt of + /// defining this constructor as the default constructor. + void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor); /// MaybeBindToTemporary - If the passed in expression has a record type with /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 9e31bae79d..c4d1fe9983 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2732,8 +2732,12 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) { IK_Default); if (!Constructor) Var->setInvalidDecl(); - else if (!RD->hasTrivialConstructor()) - InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0); + else { + if (!RD->hasTrivialConstructor()) + InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0); + // Check for valid construction. + DefineImplicitDefaultConstructor(Var->getLocation(), Constructor); + } } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a37929cb67..fd1cc0406f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1793,7 +1793,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, return DeclPtrTy(); } - NamespaceAliasDecl *AliasDecl = + NamespaceAliasDecl *AliasDecl = NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc, Alias, SS.getRange(), (NestedNameSpecifier *)SS.getScopeRep(), @@ -1803,6 +1803,80 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, return DeclPtrTy::make(AliasDecl); } +void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor) { + if (!Constructor->isDefaultConstructor() || + !Constructor->isImplicit() || Constructor->isImplicitMustBeDefined()) + return; + + CXXRecordDecl *ClassDecl + = cast(Constructor->getDeclContext()); + assert(ClassDecl && "InitializeVarWithConstructor - invalid constructor"); + // Before the implicitly-declared default constructor for a class is + // implicitly defined, all the implicitly-declared default constructors + // for its base class and its non-static data members shall have been + // implicitly defined. + bool err = false; + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + CXXRecordDecl *BaseClassDecl + = cast(Base->getType()->getAsRecordType()->getDecl()); + if (!BaseClassDecl->hasTrivialConstructor()) { + if (CXXConstructorDecl *BaseCtor = + BaseClassDecl->getDefaultConstructor(Context)) { + if (BaseCtor->isImplicit()) + BaseCtor->setImplicitMustBeDefined(); + } + else { + Diag(CurrentLocation, diag::err_defining_default_ctor) + << ClassDecl->getNameAsCString() << BaseClassDecl->getNameAsCString(); + Diag(BaseClassDecl->getLocation(), diag::not_previous_class_decl) + << BaseClassDecl->getNameAsCString(); + err = true; + } + } + } + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context); + Field != ClassDecl->field_end(Context); + ++Field) { + QualType FieldType = Context.getCanonicalType((*Field)->getType()); + if (const ArrayType *Array = Context.getAsArrayType(FieldType)) + FieldType = Array->getElementType(); + if (const RecordType *FieldClassType = FieldType->getAsRecordType()) { + CXXRecordDecl *FieldClassDecl + = cast(FieldClassType->getDecl()); + if (!FieldClassDecl->hasTrivialConstructor()) + if (CXXConstructorDecl *FieldCtor = + FieldClassDecl->getDefaultConstructor(Context)) { + if (FieldCtor->isImplicit()) + FieldCtor->setImplicitMustBeDefined(); + } + else { + Diag(CurrentLocation, diag::err_defining_default_ctor) + << ClassDecl->getNameAsCString() << + FieldClassDecl->getNameAsCString(); + Diag(FieldClassDecl->getLocation(), diag::not_previous_class_decl) + << FieldClassDecl->getNameAsCString(); + err = true; + } + } + else if (FieldType->isReferenceType()) { + Diag(CurrentLocation, diag::err_unintialized_member) + << ClassDecl->getNameAsCString() << 0; + Diag((*Field)->getLocation(), diag::note_declared_at); + err = true; + } + else if (FieldType.isConstQualified()) { + Diag(CurrentLocation, diag::err_unintialized_member) + << ClassDecl->getNameAsCString() << 1; + Diag((*Field)->getLocation(), diag::note_declared_at); + err = true; + } + } + if (!err) + Constructor->setImplicitMustBeDefined(); +} + void Sema::InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, QualType DeclInitType, @@ -1878,6 +1952,9 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, VDecl->setCXXDirectInitializer(true); InitializeVarWithConstructor(VDecl, Constructor, DeclInitType, (Expr**)Exprs.release(), NumExprs); + // An implicitly-declared default constructor for a class is implicitly + // defined when it is used to creat an object of its class type. + DefineImplicitDefaultConstructor(VDecl->getLocation(), Constructor); } return; } diff --git a/test/SemaCXX/default-contructor-initializers.cpp b/test/SemaCXX/default-contructor-initializers.cpp new file mode 100644 index 0000000000..c21a0210e1 --- /dev/null +++ b/test/SemaCXX/default-contructor-initializers.cpp @@ -0,0 +1,56 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct X1 { // has no implicit default constructor + X1(int); +}; + +struct X2 : X1 { // expected-note {{class X2 declared here}} \ + // expected-note {{class X2 declared here}} + X2(int); +}; + +struct X3 : public X2 { +}; +X3 x3; // expected-error {{cannot define the default constructor for X3, because X2 does not have any default constructor}} + + +struct X4 { + X2 x2; + X2 & rx2; // expected-note {{declared at}} +}; + +X4 x4; // expected-error {{cannot define the default constructor for X4, because X2 does not have any default constructor}} \ + // expected-error {{cannot define the default constructor for X4, because of unintialized reference member}} + + +struct Y1 { // has no implicit default constructor + Y1(int); +}; + +struct Y2 : Y1 { + Y2(int); + Y2(); +}; + +struct Y3 : public Y2 { +}; +Y3 y3; + +struct Y4 { + Y2 y2; +}; + +Y4 y4; + +// More tests + + +struct Z1 { + int& z; // expected-note {{declared at}} + const int c1; // expected-note {{declared at}} + volatile int v1; +}; + +Z1 z1; // expected-error {{cannot define the default constructor for Z1, because of unintialized const member}} \ + // expected-error {{cannot define the default constructor for Z1, because of unintialized reference member}} +