[cfe-commits] r58622 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/overload-call-copycon.cpp
Douglas Gregor
doug.gregor at gmail.com
Mon Nov 3 09:51:50 PST 2008
Author: dgregor
Date: Mon Nov 3 11:51:48 2008
New Revision: 58622
URL: http://llvm.org/viewvc/llvm-project?rev=58622&view=rev
Log:
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).
Added:
cfe/trunk/test/SemaCXX/overload-call-copycon.cpp (with props)
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=58622&r1=58621&r2=58622&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Nov 3 11:51:48 2008
@@ -281,6 +281,10 @@
/// the constructors of this class.
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.
void addConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl);
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=58622&r1=58621&r2=58622&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Nov 3 11:51:48 2008
@@ -59,6 +59,18 @@
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
CXXRecordDecl::addConstructor(ASTContext &Context,
CXXConstructorDecl *ConDecl) {
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=58622&r1=58621&r2=58622&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Nov 3 11:51:48 2008
@@ -799,6 +799,8 @@
Declarator &D, ExprTy *BitfieldWidth,
ExprTy *Init, DeclTy *LastInGroup);
+ void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
+
virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
DeclTy *TagDecl,
SourceLocation LBrac,
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=58622&r1=58621&r2=58622&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Nov 3 11:51:48 2008
@@ -552,9 +552,115 @@
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) {
CXXRecordDecl *Rec = cast<CXXRecordDecl>(static_cast<Decl *>(D));
FieldCollector->FinishClass();
+ AddImplicitlyDeclaredMembersToClass(Rec);
PopDeclContext();
// Everything, including inline method definitions, have been parsed.
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=58622&r1=58621&r2=58622&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Nov 3 11:51:48 2008
@@ -982,6 +982,13 @@
ImpCastExprToType(From, FromType);
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:
assert(false && "Improper second standard conversion");
break;
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=58622&r1=58621&r2=58622&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Nov 3 11:51:48 2008
@@ -350,24 +350,34 @@
ImplicitConversionSequence ICS;
if (IsStandardConversion(From, ToType, ICS.Standard))
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
- else if (IsUserDefinedConversion(From, ToType, ICS.UserDefined))
+ else if (IsUserDefinedConversion(From, ToType, ICS.UserDefined)) {
ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
- else {
- // FIXME: This is a hack to allow a class type S to implicitly
- // convert to another class type S, at least until we have proper
- // support for implicitly-declared copy constructors.
- QualType FromType = Context.getCanonicalType(From->getType());
- ToType = Context.getCanonicalType(ToType);
- if (FromType.getUnqualifiedType() == ToType.getUnqualifiedType()) {
- ICS.Standard.setAsIdentityConversion();
- ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr();
- ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr();
- ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
- return ICS;
+ // C++ [over.ics.user]p4:
+ // A conversion of an expression of class type to the same class
+ // type is given Exact Match rank, and a conversion of an
+ // expression of class type to a base class of that type is
+ // given Conversion rank, in spite of the fact that a copy
+ // constructor (i.e., a user-defined conversion function) is
+ // called for those cases.
+ if (CXXConstructorDecl *Constructor
+ = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
+ if (Constructor->isCopyConstructor(Context)) {
+ // FIXME: This is a temporary hack to give copy-constructor
+ // 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;
- }
return ICS;
}
Added: cfe/trunk/test/SemaCXX/overload-call-copycon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call-copycon.cpp?rev=58622&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call-copycon.cpp (added)
+++ cfe/trunk/test/SemaCXX/overload-call-copycon.cpp Mon Nov 3 11:51:48 2008
@@ -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);
+}
Propchange: cfe/trunk/test/SemaCXX/overload-call-copycon.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/SemaCXX/overload-call-copycon.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/SemaCXX/overload-call-copycon.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the cfe-commits
mailing list