[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