mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 19:24:21 +00:00
Add implicitly-declared default and copy constructors to C++ classes,
when appropriate. Conversions for class types now make use of copy constructors. I've replaced the egregious hack allowing class-to-class conversions with a slightly less egregious hack calling these conversions standard conversions (for overloading reasons). llvm-svn: 58622
This commit is contained in:
parent
d395a1722d
commit
0537942f3c
@ -281,6 +281,10 @@ public:
|
|||||||
/// the constructors of this class.
|
/// the constructors of this class.
|
||||||
const OverloadedFunctionDecl *getConstructors() const { return &Constructors; }
|
const OverloadedFunctionDecl *getConstructors() const { return &Constructors; }
|
||||||
|
|
||||||
|
/// hasConstCopyConstructor - Determines whether this class has a
|
||||||
|
/// copy constructor that accepts a const-qualified argument.
|
||||||
|
bool hasConstCopyConstructor(ASTContext &Context) const;
|
||||||
|
|
||||||
/// addConstructor - Add another constructor to the list of constructors.
|
/// addConstructor - Add another constructor to the list of constructors.
|
||||||
void addConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl);
|
void addConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl);
|
||||||
|
|
||||||
|
@ -59,6 +59,18 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
|||||||
this->Bases[i] = *Bases[i];
|
this->Bases[i] = *Bases[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
|
||||||
|
for (OverloadedFunctionDecl::function_const_iterator Con
|
||||||
|
= Constructors.function_begin();
|
||||||
|
Con != Constructors.function_end(); ++Con) {
|
||||||
|
unsigned TypeQuals;
|
||||||
|
if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, TypeQuals) &&
|
||||||
|
(TypeQuals & QualType::Const != 0))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXXRecordDecl::addConstructor(ASTContext &Context,
|
CXXRecordDecl::addConstructor(ASTContext &Context,
|
||||||
CXXConstructorDecl *ConDecl) {
|
CXXConstructorDecl *ConDecl) {
|
||||||
|
@ -799,6 +799,8 @@ public:
|
|||||||
Declarator &D, ExprTy *BitfieldWidth,
|
Declarator &D, ExprTy *BitfieldWidth,
|
||||||
ExprTy *Init, DeclTy *LastInGroup);
|
ExprTy *Init, DeclTy *LastInGroup);
|
||||||
|
|
||||||
|
void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
|
||||||
|
|
||||||
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
|
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
|
||||||
DeclTy *TagDecl,
|
DeclTy *TagDecl,
|
||||||
SourceLocation LBrac,
|
SourceLocation LBrac,
|
||||||
|
@ -552,9 +552,115 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
|
|||||||
FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
|
FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
|
||||||
|
/// special functions, such as the default constructor, copy
|
||||||
|
/// constructor, or destructor, to the given C++ class (C++
|
||||||
|
/// [special]p1). This routine can only be executed just before the
|
||||||
|
/// definition of the class is complete.
|
||||||
|
void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
|
||||||
|
if (!ClassDecl->hasUserDeclaredConstructor()) {
|
||||||
|
// C++ [class.ctor]p5:
|
||||||
|
// A default constructor for a class X is a constructor of class X
|
||||||
|
// that can be called without an argument. If there is no
|
||||||
|
// user-declared constructor for class X, a default constructor is
|
||||||
|
// implicitly declared. An implicitly-declared default constructor
|
||||||
|
// is an inline public member of its class.
|
||||||
|
CXXConstructorDecl *DefaultCon =
|
||||||
|
CXXConstructorDecl::Create(Context, ClassDecl,
|
||||||
|
ClassDecl->getLocation(),
|
||||||
|
ClassDecl->getIdentifier(),
|
||||||
|
Context.getFunctionType(Context.VoidTy,
|
||||||
|
0, 0, false, 0),
|
||||||
|
/*isExplicit=*/false,
|
||||||
|
/*isInline=*/true,
|
||||||
|
/*isImplicitlyDeclared=*/true);
|
||||||
|
DefaultCon->setAccess(AS_public);
|
||||||
|
ClassDecl->addConstructor(Context, DefaultCon);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
|
||||||
|
// C++ [class.copy]p4:
|
||||||
|
// If the class definition does not explicitly declare a copy
|
||||||
|
// constructor, one is declared implicitly.
|
||||||
|
|
||||||
|
// C++ [class.copy]p5:
|
||||||
|
// The implicitly-declared copy constructor for a class X will
|
||||||
|
// have the form
|
||||||
|
//
|
||||||
|
// X::X(const X&)
|
||||||
|
//
|
||||||
|
// if
|
||||||
|
bool HasConstCopyConstructor = true;
|
||||||
|
|
||||||
|
// -- each direct or virtual base class B of X has a copy
|
||||||
|
// constructor whose first parameter is of type const B& or
|
||||||
|
// const volatile B&, and
|
||||||
|
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
|
||||||
|
HasConstCopyConstructor && Base != ClassDecl->bases_end(); ++Base) {
|
||||||
|
const CXXRecordDecl *BaseClassDecl
|
||||||
|
= cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl());
|
||||||
|
HasConstCopyConstructor
|
||||||
|
= BaseClassDecl->hasConstCopyConstructor(Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- for all the nonstatic data members of X that are of a
|
||||||
|
// class type M (or array thereof), each such class type
|
||||||
|
// has a copy constructor whose first parameter is of type
|
||||||
|
// const M& or const volatile M&.
|
||||||
|
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin();
|
||||||
|
HasConstCopyConstructor && Field != ClassDecl->field_end(); ++Field) {
|
||||||
|
QualType FieldType = (*Field)->getType();
|
||||||
|
if (const ArrayType *Array = Context.getAsArrayType(FieldType))
|
||||||
|
FieldType = Array->getElementType();
|
||||||
|
if (const RecordType *FieldClassType = FieldType->getAsRecordType()) {
|
||||||
|
const CXXRecordDecl *FieldClassDecl
|
||||||
|
= cast<CXXRecordDecl>(FieldClassType->getDecl());
|
||||||
|
HasConstCopyConstructor
|
||||||
|
= FieldClassDecl->hasConstCopyConstructor(Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, the implicitly declared copy constructor will have
|
||||||
|
// the form
|
||||||
|
//
|
||||||
|
// X::X(X&)
|
||||||
|
QualType ArgType = Context.getTypeDeclType(ClassDecl);
|
||||||
|
if (HasConstCopyConstructor)
|
||||||
|
ArgType = ArgType.withConst();
|
||||||
|
ArgType = Context.getReferenceType(ArgType);
|
||||||
|
|
||||||
|
// An implicitly-declared copy constructor is an inline public
|
||||||
|
// member of its class.
|
||||||
|
CXXConstructorDecl *CopyConstructor
|
||||||
|
= CXXConstructorDecl::Create(Context, ClassDecl,
|
||||||
|
ClassDecl->getLocation(),
|
||||||
|
ClassDecl->getIdentifier(),
|
||||||
|
Context.getFunctionType(Context.VoidTy,
|
||||||
|
&ArgType, 1,
|
||||||
|
false, 0),
|
||||||
|
/*isExplicit=*/false,
|
||||||
|
/*isInline=*/true,
|
||||||
|
/*isImplicitlyDeclared=*/true);
|
||||||
|
CopyConstructor->setAccess(AS_public);
|
||||||
|
|
||||||
|
// Add the parameter to the constructor.
|
||||||
|
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
|
||||||
|
ClassDecl->getLocation(),
|
||||||
|
/*IdentifierInfo=*/0,
|
||||||
|
ArgType, VarDecl::None, 0, 0);
|
||||||
|
CopyConstructor->setParams(&FromParam, 1);
|
||||||
|
|
||||||
|
ClassDecl->addConstructor(Context, CopyConstructor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Implicit destructor
|
||||||
|
// FIXME: Implicit copy assignment operator
|
||||||
|
}
|
||||||
|
|
||||||
void Sema::ActOnFinishCXXClassDef(DeclTy *D) {
|
void Sema::ActOnFinishCXXClassDef(DeclTy *D) {
|
||||||
CXXRecordDecl *Rec = cast<CXXRecordDecl>(static_cast<Decl *>(D));
|
CXXRecordDecl *Rec = cast<CXXRecordDecl>(static_cast<Decl *>(D));
|
||||||
FieldCollector->FinishClass();
|
FieldCollector->FinishClass();
|
||||||
|
AddImplicitlyDeclaredMembersToClass(Rec);
|
||||||
PopDeclContext();
|
PopDeclContext();
|
||||||
|
|
||||||
// Everything, including inline method definitions, have been parsed.
|
// Everything, including inline method definitions, have been parsed.
|
||||||
|
@ -982,6 +982,13 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
|
|||||||
ImpCastExprToType(From, FromType);
|
ImpCastExprToType(From, FromType);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ICK_Derived_To_Base:
|
||||||
|
// FIXME: This should never happen. It's a consequence of
|
||||||
|
// pretending that a user-defined conversion via copy constructor
|
||||||
|
// is actually a standard conversion.
|
||||||
|
ImpCastExprToType(From, ToType);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false && "Improper second standard conversion");
|
assert(false && "Improper second standard conversion");
|
||||||
break;
|
break;
|
||||||
|
@ -350,24 +350,34 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType)
|
|||||||
ImplicitConversionSequence ICS;
|
ImplicitConversionSequence ICS;
|
||||||
if (IsStandardConversion(From, ToType, ICS.Standard))
|
if (IsStandardConversion(From, ToType, ICS.Standard))
|
||||||
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
|
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
|
||||||
else if (IsUserDefinedConversion(From, ToType, ICS.UserDefined))
|
else if (IsUserDefinedConversion(From, ToType, ICS.UserDefined)) {
|
||||||
ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
|
ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
|
||||||
else {
|
// C++ [over.ics.user]p4:
|
||||||
// FIXME: This is a hack to allow a class type S to implicitly
|
// A conversion of an expression of class type to the same class
|
||||||
// convert to another class type S, at least until we have proper
|
// type is given Exact Match rank, and a conversion of an
|
||||||
// support for implicitly-declared copy constructors.
|
// expression of class type to a base class of that type is
|
||||||
QualType FromType = Context.getCanonicalType(From->getType());
|
// given Conversion rank, in spite of the fact that a copy
|
||||||
ToType = Context.getCanonicalType(ToType);
|
// constructor (i.e., a user-defined conversion function) is
|
||||||
if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType()) {
|
// called for those cases.
|
||||||
ICS.Standard.setAsIdentityConversion();
|
if (CXXConstructorDecl *Constructor
|
||||||
ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr();
|
= dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
|
||||||
ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr();
|
if (Constructor->isCopyConstructor(Context)) {
|
||||||
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
|
// FIXME: This is a temporary hack to give copy-constructor
|
||||||
return ICS;
|
// calls the appropriate rank (Exact Match or Conversion) by
|
||||||
|
// making them into standard conversions. To really fix this, we
|
||||||
|
// need to tweak the rank-checking logic to deal with ranking
|
||||||
|
// different kinds of user conversions.
|
||||||
|
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
|
||||||
|
ICS.Standard.setAsIdentityConversion();
|
||||||
|
ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr();
|
||||||
|
ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr();
|
||||||
|
if (IsDerivedFrom(From->getType().getUnqualifiedType(),
|
||||||
|
ToType.getUnqualifiedType()))
|
||||||
|
ICS.Standard.Second = ICK_Derived_To_Base;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
|
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
|
||||||
}
|
|
||||||
|
|
||||||
return ICS;
|
return ICS;
|
||||||
}
|
}
|
||||||
|
38
clang/test/SemaCXX/overload-call-copycon.cpp
Normal file
38
clang/test/SemaCXX/overload-call-copycon.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// RUN: clang -fsyntax-only %s
|
||||||
|
class X { };
|
||||||
|
|
||||||
|
int& copycon(X x);
|
||||||
|
float& copycon(...);
|
||||||
|
|
||||||
|
void test_copycon(X x, X const xc, X volatile xv) {
|
||||||
|
int& i1 = copycon(x);
|
||||||
|
int& i2 = copycon(xc);
|
||||||
|
float& f1 = copycon(xv);
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public:
|
||||||
|
A(A&);
|
||||||
|
};
|
||||||
|
|
||||||
|
class B : public A { };
|
||||||
|
|
||||||
|
short& copycon2(A a);
|
||||||
|
int& copycon2(B b);
|
||||||
|
float& copycon2(...);
|
||||||
|
|
||||||
|
void test_copycon2(A a, const A ac, B b, B const bc, B volatile bv) {
|
||||||
|
int& i1 = copycon2(b);
|
||||||
|
float& f1 = copycon2(bc);
|
||||||
|
float& f2 = copycon2(bv);
|
||||||
|
short& s1 = copycon2(a);
|
||||||
|
float& f3 = copycon2(ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
int& copycon3(A a);
|
||||||
|
float& copycon3(...);
|
||||||
|
|
||||||
|
void test_copycon3(B b, const B bc) {
|
||||||
|
int& i1 = copycon3(b);
|
||||||
|
float& f1 = copycon3(bc);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user