]> granicus.if.org Git - clang/commitdiff
Implement derived-to-base AST/code gen. There is a
authorFariborz Jahanian <fjahanian@apple.com>
Fri, 16 Oct 2009 19:20:59 +0000 (19:20 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Fri, 16 Oct 2009 19:20:59 +0000 (19:20 +0000)
FIXME in CGCXX.cpp that I would like Anders to
take a look at.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84265 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCXX.cpp
lib/Sema/Sema.h
lib/Sema/SemaExprCXX.cpp
test/CodeGenCXX/derived-to-base-conv.cpp [new file with mode: 0644]

index 3960cf51868f86dca9b1a559d06313c0555a9c69..44e5207e53d2b23e532d408b7178c0514b5ff4cb 100644 (file)
@@ -566,6 +566,10 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
       assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
              "EmitCXXConstructorCall - user declared copy constructor");
       const Expr *E = (*ArgBeg);
+      // FIXME. This may not be correct. But till now, we were skipping
+      // code gen of trivial copy constructors regardless of their arguments.
+      if (isa<CXXZeroInitValueExpr>(E))
+        return;
       QualType Ty = E->getType();
       llvm::Value *Src = EmitLValue(E).getAddress();
       EmitAggregateCopy(This, Src, Ty);
@@ -590,12 +594,15 @@ void
 CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
                                       const CXXConstructExpr *E) {
   assert(Dest && "Must have a destination!");
-
-  const CXXRecordDecl *RD =
-  cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
-  if (RD->hasTrivialConstructor())
+  const CXXConstructorDecl *CD = E->getConstructor();
+  // For a copy constructor, even if it is trivial, must fall thru so
+  // its argument is code-gen'ed.
+  if (!CD->isCopyConstructor(getContext())) {
+    const CXXRecordDecl *RD =
+      cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
+    if (RD->hasTrivialConstructor())
     return;
-
+  }
   // Code gen optimization to eliminate copy constructor and return
   // its first argument instead.
   if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
@@ -604,7 +611,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
     return;
   }
   // Call the constructor.
-  EmitCXXConstructorCall(E->getConstructor(), Ctor_Complete, Dest,
+  EmitCXXConstructorCall(CD, Ctor_Complete, Dest,
                          E->arg_begin(), E->arg_end());
 }
 
index 398b413e265ad1421226913e37bc3b86ff3df5b6..8ebe5ef6fc833aaf6aae99f2f4451bbd116294a6 100644 (file)
@@ -3552,6 +3552,10 @@ public:
   bool PerformImplicitConversion(Expr *&From, QualType ToType,
                                  const StandardConversionSequence& SCS,
                                  const char *Flavor);
+  
+  bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
+                                 const ImplicitConversionSequence& ICS,
+                                 const char *Flavor);
 
   /// the following "Check" methods will return a valid/converted QualType
   /// or a null QualType (indicating an error diagnostic was issued).
index 5f111c8a60e7a9c0892d6b43d94605c7c49762df..7fc27a44f7b69fb3417228178f5f239787a648ce 100644 (file)
@@ -1043,6 +1043,40 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
   return PerformImplicitConversion(From, ToType, ICS, Flavor);
 }
 
+/// BuildCXXDerivedToBaseExpr - This routine generates the suitable AST
+/// for the derived to base conversion of the expression 'From'. All
+/// necessary information is passed in ICS.
+bool 
+Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind,
+                                     const ImplicitConversionSequence& ICS,
+                                     const char *Flavor) {
+  QualType  BaseType = 
+    QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr);
+  // Must do additional defined to base conversion.
+  QualType  DerivedType = 
+    QualType::getFromOpaquePtr(ICS.UserDefined.After.FromTypePtr);
+
+  From = new (Context) ImplicitCastExpr(
+                                        DerivedType.getNonReferenceType(),
+                                        CastKind, 
+                                        From, 
+                                        DerivedType->isLValueReferenceType());
+  From = new (Context) ImplicitCastExpr(BaseType.getNonReferenceType(),
+                                        CastExpr::CK_DerivedToBase, From, 
+                                        BaseType->isLValueReferenceType());
+  ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+  OwningExprResult FromResult =
+  BuildCXXConstructExpr(
+                        ICS.UserDefined.After.CopyConstructor->getLocation(),
+                        BaseType,
+                        ICS.UserDefined.After.CopyConstructor,
+                        MultiExprArg(*this, (void **)&From, 1));
+  if (FromResult.isInvalid())
+    return true;
+  From = FromResult.takeAs<Expr>();
+  return false;
+}
+
 /// PerformImplicitConversion - Perform an implicit conversion of the
 /// expression From to the type ToType using the pre-computed implicit
 /// conversion sequence ICS. Returns true if there was an error, false
@@ -1095,13 +1129,19 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
 
       if (CastArg.isInvalid())
         return true;
+    
+      if (ICS.UserDefined.After.Second == ICK_Derived_To_Base &&
+          ICS.UserDefined.After.CopyConstructor) {
+        From = CastArg.takeAs<Expr>();
+        return BuildCXXDerivedToBaseExpr(From, CastKind, ICS, Flavor);
+      }
       
       From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(),
-                                            CastKind, CastArg.takeAs<Expr>(), 
+                                            CastKind, CastArg.takeAs<Expr>(),
                                             ToType->isLValueReferenceType());
       return false;
-    }
-
+  }
+      
   case ImplicitConversionSequence::EllipsisConversion:
     assert(false && "Cannot perform an ellipsis conversion");
     return false;
diff --git a/test/CodeGenCXX/derived-to-base-conv.cpp b/test/CodeGenCXX/derived-to-base-conv.cpp
new file mode 100644 (file)
index 0000000..218116e
--- /dev/null
@@ -0,0 +1,51 @@
+// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s &&
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s &&
+// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s &&
+// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s &&
+// RUN: true
+
+extern "C" int printf(...);
+
+struct A {
+ A (const A&) { printf("A::A(const A&)\n"); }
+ A() {};
+}; 
+
+struct B : public A {
+  B() {};
+}; 
+
+struct C : public B {
+  C() {};
+}; 
+
+struct X {
+       operator B&() {printf("X::operator B&()\n"); return b; }
+       operator C&() {printf("X::operator C&()\n"); return c; }
+       X (const X&) { printf("X::X(const X&)\n"); }
+       X () { printf("X::X()\n"); }
+       B b;
+       C c;
+};
+
+void f(A) {
+  printf("f(A)\n");
+}
+
+
+void func(X x) 
+{
+  f (x);
+}
+
+int main()
+{
+    X x;
+    func(x);
+}
+
+// CHECK-LP64: call     __ZN1XcvR1BEv
+// CHECK-LP64: call     __ZN1AC1ERKS_
+
+// CHECK-LP32: call     L__ZN1XcvR1BEv
+// CHECK-LP32: call     L__ZN1AC1ERKS_