[cfe-commits] r106061 - in /cfe/trunk: include/clang/Basic/Builtins.def lib/CodeGen/CGBuiltin.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprCXX.cpp lib/CodeGen/CGObjCGNU.cpp lib/CodeGen/CGObjCMac.cpp lib/CodeGen/CGObjCRuntime.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/CodeGenCXX/implicit-copy-assign-operator.mm test/CodeGenCXX/implicit-copy-constructor.mm

Fariborz Jahanian fjahanian at apple.com
Tue Jun 15 15:44:06 PDT 2010


Author: fjahanian
Date: Tue Jun 15 17:44:06 2010
New Revision: 106061

URL: http://llvm.org/viewvc/llvm-project?rev=106061&view=rev
Log:
Patch adds support for copying of those
objective-c++ class objects which have GC'able objc object
pointers and need to use ObjC's objc_memmove_collectable
API (radar 8070772). 

Added:
    cfe/trunk/test/CodeGenCXX/implicit-copy-assign-operator.mm
    cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.mm
Modified:
    cfe/trunk/include/clang/Basic/Builtins.def
    cfe/trunk/lib/CodeGen/CGBuiltin.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
    cfe/trunk/lib/CodeGen/CGObjCMac.cpp
    cfe/trunk/lib/CodeGen/CGObjCRuntime.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Modified: cfe/trunk/include/clang/Basic/Builtins.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def?rev=106061&r1=106060&r2=106061&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Builtins.def (original)
+++ cfe/trunk/include/clang/Basic/Builtins.def Tue Jun 15 17:44:06 2010
@@ -540,6 +540,7 @@
 //   id objc_msgSend(id, SEL)
 // but we need new type letters for that.
 LIBBUILTIN(objc_msgSend, "v*.",   "f",     "objc/message.h")
+LIBBUILTIN(objc_memmove_collectable, "v*v*vC*z", "nF", "objc/objc-auto.h")
 
 // Builtin math library functions
 LIBBUILTIN(pow, "ddd", "fe", "math.h")

Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=106061&r1=106060&r2=106061&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Tue Jun 15 17:44:06 2010
@@ -14,6 +14,7 @@
 #include "TargetInfo.h"
 #include "CodeGenFunction.h"
 #include "CodeGenModule.h"
+#include "CGObjCRuntime.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/AST/APValue.h"
 #include "clang/AST/ASTContext.h"
@@ -483,6 +484,16 @@
                   llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0));
     return RValue::get(Address);
   }
+      
+  case Builtin::BIobjc_memmove_collectable: {
+    Value *Address = EmitScalarExpr(E->getArg(0));
+    Value *SrcAddr = EmitScalarExpr(E->getArg(1));
+    Value *SizeVal = EmitScalarExpr(E->getArg(2));
+    CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, 
+                                                  Address, SrcAddr, SizeVal);
+    return RValue::get(Address);
+  }
+      
   case Builtin::BImemmove:
   case Builtin::BI__builtin_memmove: {
     Value *Address = EmitScalarExpr(E->getArg(0));

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=106061&r1=106060&r2=106061&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Tue Jun 15 17:44:06 2010
@@ -177,11 +177,16 @@
 /// directly into the return value slot.  If GC does interfere, a final
 /// move will be performed.
 void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) {
-  if (!RequiresGCollection) return;
-
-  CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, DestPtr,
+  if (RequiresGCollection) {
+    std::pair<uint64_t, unsigned> TypeInfo = 
+      CGF.getContext().getTypeInfo(E->getType());
+    unsigned long size = TypeInfo.first/8;
+    const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
+    llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size);
+    CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, DestPtr,
                                                     Src.getAggregateAddr(),
-                                                    E->getType());
+                                                    SizeVal);
+  }
 }
 
 /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
@@ -198,9 +203,14 @@
   }
 
   if (RequiresGCollection) {
+    std::pair<uint64_t, unsigned> TypeInfo = 
+    CGF.getContext().getTypeInfo(E->getType());
+    unsigned long size = TypeInfo.first/8;
+    const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
+    llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size);
     CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF,
                                               DestPtr, Src.getAggregateAddr(),
-                                              E->getType());
+                                              SizeVal);
     return;
   }
   // If the result of the assignment is used, copy the LHS there also.
@@ -837,6 +847,30 @@
   if (SrcPtr->getType() != SBP)
     SrcPtr = Builder.CreateBitCast(SrcPtr, SBP, "tmp");
 
+  if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
+    RecordDecl *Record = RecordTy->getDecl();
+    if (Record->hasObjectMember()) {
+      unsigned long size = TypeInfo.first/8;
+      const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+      llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size);
+      CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, 
+                                                    SizeVal);
+      return;
+    }
+  } else if (getContext().getAsArrayType(Ty)) {
+    QualType BaseType = getContext().getBaseElementType(Ty);
+    if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
+      if (RecordTy->getDecl()->hasObjectMember()) {
+        unsigned long size = TypeInfo.first/8;
+        const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
+        llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size);
+        CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, 
+                                                      SizeVal);
+        return;
+      }
+    }
+  }
+  
   Builder.CreateCall5(CGM.getMemCpyFn(DestPtr->getType(), SrcPtr->getType(),
                                       IntPtr),
                       DestPtr, SrcPtr,

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=106061&r1=106060&r2=106061&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Tue Jun 15 17:44:06 2010
@@ -275,10 +275,7 @@
       
       llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
       QualType Ty = E->getType();
-      if (ClassDecl->hasObjectMember())
-        CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, This, Src, Ty);
-      else 
-        EmitAggregateCopy(This, Src, Ty);
+      EmitAggregateCopy(This, Src, Ty);
       return RValue::get(This);
     }
   }

Modified: cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCGNU.cpp?rev=106061&r1=106060&r2=106061&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCGNU.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Tue Jun 15 17:44:06 2010
@@ -197,7 +197,7 @@
   virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
                                         llvm::Value *DestPtr,
                                         llvm::Value *SrcPtr,
-                                        QualType Ty);
+                                        llvm::Value *Size);
   virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
                                       QualType ObjectTy,
                                       llvm::Value *BaseValue,
@@ -2174,17 +2174,12 @@
 void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
                                          llvm::Value *DestPtr,
                                          llvm::Value *SrcPtr,
-                                         QualType Ty) {
+                                         llvm::Value *Size) {
   CGBuilderTy B = CGF.Builder;
   DestPtr = EnforceType(B, DestPtr, IdTy);
   SrcPtr = EnforceType(B, SrcPtr, PtrToIdTy);
 
-  std::pair<uint64_t, unsigned> TypeInfo = CGM.getContext().getTypeInfo(Ty);
-  unsigned long size = TypeInfo.first/8;
-  // FIXME: size_t
-  llvm::Value *N = llvm::ConstantInt::get(LongTy, size);
-
-  B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, N);
+  B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, Size);
 }
 
 llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(

Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=106061&r1=106060&r2=106061&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Tue Jun 15 17:44:06 2010
@@ -1196,7 +1196,7 @@
                                         llvm::Value *src, llvm::Value *dest);
   virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
                                         llvm::Value *dest, llvm::Value *src,
-                                        QualType Ty);
+                                        llvm::Value *size);
 
   virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
                                       QualType ObjectTy,
@@ -1438,7 +1438,7 @@
                                         llvm::Value *src, llvm::Value *dest);
   virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
                                         llvm::Value *dest, llvm::Value *src,
-                                        QualType Ty);
+                                        llvm::Value *size);
   virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
                                       QualType ObjectTy,
                                       llvm::Value *BaseValue,
@@ -2938,15 +2938,11 @@
 void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
                                          llvm::Value *DestPtr,
                                          llvm::Value *SrcPtr,
-                                         QualType Ty) {
-  // Get size info for this aggregate.
-  std::pair<uint64_t, unsigned> TypeInfo = CGM.getContext().getTypeInfo(Ty);
-  unsigned long size = TypeInfo.first/8;
+                                         llvm::Value *size) {
   SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
   DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
-  llvm::Value *N = llvm::ConstantInt::get(ObjCTypes.LongTy, size);
   CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
-                          DestPtr, SrcPtr, N);
+                          DestPtr, SrcPtr, size);
   return;
 }
 
@@ -5476,15 +5472,11 @@
   CodeGen::CodeGenFunction &CGF,
   llvm::Value *DestPtr,
   llvm::Value *SrcPtr,
-  QualType Ty) {
-  // Get size info for this aggregate.
-  std::pair<uint64_t, unsigned> TypeInfo = CGM.getContext().getTypeInfo(Ty);
-  unsigned long size = TypeInfo.first/8;
+  llvm::Value *Size) {
   SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
   DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
-  llvm::Value *N = llvm::ConstantInt::get(ObjCTypes.LongTy, size);
   CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
-                          DestPtr, SrcPtr, N);
+                          DestPtr, SrcPtr, Size);
   return;
 }
 

Modified: cfe/trunk/lib/CodeGen/CGObjCRuntime.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCRuntime.h?rev=106061&r1=106060&r2=106061&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCRuntime.h (original)
+++ cfe/trunk/lib/CodeGen/CGObjCRuntime.h Tue Jun 15 17:44:06 2010
@@ -208,7 +208,7 @@
   virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
                                         llvm::Value *DestPtr,
                                         llvm::Value *SrcPtr,
-                                        QualType Ty) = 0;
+                                        llvm::Value *Size) = 0;
 };
 
 /// Creates an instance of an Objective-C runtime class.

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=106061&r1=106060&r2=106061&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jun 15 17:44:06 2010
@@ -6232,6 +6232,12 @@
                (FD->getType()->isObjCObjectPointerType() ||
                 FD->getType().isObjCGCStrong()))
       Record->setHasObjectMember(true);
+    else if (Context.getAsArrayType(FD->getType())) {
+      QualType BaseType = Context.getBaseElementType(FD->getType());
+      if (Record && BaseType->isRecordType() && 
+          BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
+        Record->setHasObjectMember(true);
+    }
     // Keep track of the number of named members.
     if (FD->getIdentifier())
       ++NumNamedMembers;

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=106061&r1=106060&r2=106061&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Jun 15 17:44:06 2010
@@ -4557,6 +4557,8 @@
   
   // \brief Reference to the __builtin_memcpy function.
   Expr *BuiltinMemCpyRef = 0;
+  // \brief Reference to the objc_memmove_collectable function.
+  Expr *CollectableMemCpyRef = 0;
   
   // Assign non-static members.
   for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
@@ -4633,9 +4635,34 @@
       // Take the address of the field references for "from" and "to".
       From = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(From));
       To = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(To));
-      
+          
+      bool NeedsCollectableMemCpy = 
+          (BaseType->isRecordType() && 
+           BaseType->getAs<RecordType>()->getDecl()->hasObjectMember());
+          
+      if (NeedsCollectableMemCpy) {
+        if (!CollectableMemCpyRef) {
+          // Create a reference to the objc_memmove_collectable function.
+          LookupResult R(*this, &Context.Idents.get("objc_memmove_collectable"), 
+                         Loc, LookupOrdinaryName);
+          LookupName(R, TUScope, true);
+        
+          FunctionDecl *CollectableMemCpy = R.getAsSingle<FunctionDecl>();
+          if (!CollectableMemCpy) {
+            // Something went horribly wrong earlier, and we will have 
+            // complained about it.
+            Invalid = true;
+            continue;
+          }
+        
+          CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, 
+                                                  CollectableMemCpy->getType(),
+                                                  Loc, 0).takeAs<Expr>();
+          assert(CollectableMemCpyRef && "Builtin reference cannot fail");
+        }
+      }
       // Create a reference to the __builtin_memcpy builtin function.
-      if (!BuiltinMemCpyRef) {
+      else if (!BuiltinMemCpyRef) {
         LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc,
                        LookupOrdinaryName);
         LookupName(R, TUScope, true);
@@ -4661,10 +4688,12 @@
       llvm::SmallVector<SourceLocation, 4> Commas; // FIXME: Silly
       Commas.push_back(Loc);
       Commas.push_back(Loc);
-      OwningExprResult Call = ActOnCallExpr(/*Scope=*/0, 
-                                            Owned(BuiltinMemCpyRef->Retain()),
-                                            Loc, move_arg(CallArgs), 
-                                            Commas.data(), Loc);
+      OwningExprResult Call = ActOnCallExpr(/*Scope=*/0,
+                                  NeedsCollectableMemCpy ?
+                                    Owned(CollectableMemCpyRef->Retain()) :
+                                    Owned(BuiltinMemCpyRef->Retain()),
+                                  Loc, move_arg(CallArgs), 
+                                  Commas.data(), Loc);
       assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
       Statements.push_back(Call.takeAs<Expr>());
       continue;

Added: cfe/trunk/test/CodeGenCXX/implicit-copy-assign-operator.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/implicit-copy-assign-operator.mm?rev=106061&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/implicit-copy-assign-operator.mm (added)
+++ cfe/trunk/test/CodeGenCXX/implicit-copy-assign-operator.mm Tue Jun 15 17:44:06 2010
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -fobjc-gc -emit-llvm -triple x86_64-apple-darwin10.0.0 -o - %s | FileCheck %s
+struct A { 
+  A &operator=(const A&);
+  A &operator=(A&);
+};
+
+struct B {
+  B &operator=(B&);
+};
+
+struct C {
+  virtual C& operator=(const C&);
+};
+
+struct POD {
+  id myobjc;
+  int array[3][4];
+};
+
+struct CopyByValue {
+  CopyByValue(const CopyByValue&);
+  CopyByValue &operator=(CopyByValue);
+};
+
+struct D : A, B, virtual C { 
+  int scalar;
+  int scalar_array[2][3];
+  B class_member;
+  C class_member_array[2][3];
+  POD pod_array[2][3];
+
+  union {
+    int x;
+    float f[3];
+  };
+
+  CopyByValue by_value;
+};
+
+void test_D(D d1, D d2) {
+  d1 = d2;
+}
+
+// CHECK: define linkonce_odr %struct.D* @_ZN1DaSERS_
+// CHECK: {{call.*_ZN1AaSERS_}}
+// CHECK: {{call.*_ZN1BaSERS_}}
+// CHECK: {{call.*_ZN1CaSERKS_}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}}
+// CHECK: {{call.*_ZN1BaSERS_}}
+// CHECK: br
+// CHECK: {{call.*_ZN1CaSERKS_}}
+// CHECK: {{call.*@objc_memmove_collectable}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}}
+// CHECK: call void @_ZN11CopyByValueC1ERKS_
+// CHECK: {{call.*_ZN11CopyByValueaSES_}}
+// CHECK: ret
+

Added: cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.mm?rev=106061&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.mm (added)
+++ cfe/trunk/test/CodeGenCXX/implicit-copy-constructor.mm Tue Jun 15 17:44:06 2010
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+struct A { 
+  A();
+  A(const A&);
+  A(A&);
+  ~A();
+};
+
+struct B {
+  B();
+  B(B&);
+};
+
+struct C {
+  C() {}
+  C(C& other, A a = A());
+  int i, j;
+};
+
+struct POD {
+  id myobjc;
+  int array[3][4];
+};
+
+struct D : A, B, virtual C { 
+  D();
+  int scalar;
+  int scalar_array[2][3];
+  B class_member;
+  C class_member_array[2][3];
+  POD pod_array[2][3];
+
+  union {
+    int x;
+    float f[3];
+  };
+};
+
+void f(D d) {
+  D d2(d);
+}
+
+// CHECK: define linkonce_odr void @_ZN1DC1ERS_
+// CHECK: call void @_ZN1AC1Ev
+// CHECK: call void @_ZN1CC2ERS_1A
+// CHECK: call void @_ZN1AD1Ev
+// CHECK: call void @_ZN1AC2ERS_
+// CHECK: call void @_ZN1BC2ERS_
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}}
+// CHECK: call void @_ZN1BC1ERS_
+// CHECK: br
+// CHECK: {{icmp ult.*, 2}}
+// CHECK: {{icmp ult.*, 3}}
+// CHECK: call void @_ZN1AC1Ev
+// CHECK: call void @_ZN1CC1ERS_1A
+// CHECK: call void @_ZN1AD1Ev
+// CHECK: {{call.*@objc_memmove_collectable}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}}
+// CHECK: ret void
+
+
+template<class T> struct X0 { void f0(T * ) { } };
+template <class > struct X1 { X1( X1& , int = 0 ) { } };
+struct X2 { X1<int> result; };
+void test_X2()
+{
+  typedef X2 impl;
+  typedef X0<impl> pimpl;
+  impl* i;
+  pimpl pdata;
+  pdata.f0( new impl(*i));
+}





More information about the cfe-commits mailing list