Patch for implementation of C++'s object model. This is

work in progress.

llvm-svn: 73782
This commit is contained in:
Fariborz Jahanian 2009-06-19 19:55:27 +00:00
parent 2028e25325
commit 423a81f259
7 changed files with 192 additions and 5 deletions

View File

@ -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.

View File

@ -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">;

View File

@ -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<CXXConstructorDecl>(*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);

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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<CXXRecordDecl>(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<CXXRecordDecl>(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<CXXRecordDecl>(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;
}

View File

@ -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}}