diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 6072c1c499d5..f698d146f1b0 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -117,6 +117,9 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { llvm::SmallVector ArgTys; + assert(!isa(MD) && "wrong method for contructors!"); + assert(!isa(MD) && "wrong method for destructors!"); + // Add the 'this' pointer unless this is a static method. if (MD->isInstance()) ArgTys.push_back(GetThisType(Context, MD->getParent())); diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index a5c16913078d..9a98281771fa 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -93,14 +93,9 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, return EmitCall(getContext().getPointerType(MD->getType()), Callee, ReturnValue, CE->arg_begin(), CE->arg_end()); } - - const FunctionProtoType *FPT = MD->getType()->getAs(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); + // Compute the object pointer. llvm::Value *This; - if (ME->isArrow()) This = EmitScalarExpr(ME->getBase()); else { @@ -108,7 +103,10 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, This = BaseLV.getAddress(); } - if (MD->isCopyAssignment() && MD->isTrivial()) { + if (MD->isTrivial()) { + if (isa(MD)) return RValue::get(0); + + assert(MD->isCopyAssignment() && "unknown trivial member function"); // We don't like to generate the trivial copy assignment operator when // it isn't necessary; just produce the proper effect here. llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); @@ -116,25 +114,34 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, return RValue::get(This); } + // Compute the function type we're calling. + const CGFunctionInfo &FInfo = + (isa(MD) + ? CGM.getTypes().getFunctionInfo(cast(MD), + Dtor_Complete) + : CGM.getTypes().getFunctionInfo(MD)); + + const FunctionProtoType *FPT = MD->getType()->getAs(); + const llvm::Type *Ty + = CGM.getTypes().GetFunctionType(FInfo, FPT->isVariadic()); + // C++ [class.virtual]p12: // Explicit qualification with the scope operator (5.1) suppresses the // virtual call mechanism. // // We also don't emit a virtual call if the base expression has a record type // because then we know what the type is. + bool UseVirtualCall = MD->isVirtual() && !ME->hasQualifier() + && !canDevirtualizeMemberFunctionCalls(ME->getBase()); + llvm::Value *Callee; - if (const CXXDestructorDecl *Destructor - = dyn_cast(MD)) { - if (Destructor->isTrivial()) - return RValue::get(0); - if (MD->isVirtual() && !ME->hasQualifier() && - !canDevirtualizeMemberFunctionCalls(ME->getBase())) { - Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty); + if (const CXXDestructorDecl *Dtor = dyn_cast(MD)) { + if (UseVirtualCall) { + Callee = BuildVirtualCall(Dtor, Dtor_Complete, This, Ty); } else { - Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty); + Callee = CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty); } - } else if (MD->isVirtual() && !ME->hasQualifier() && - !canDevirtualizeMemberFunctionCalls(ME->getBase())) { + } else if (UseVirtualCall) { Callee = BuildVirtualCall(MD, This, Ty); } else { Callee = CGM.GetAddrOfFunction(MD, Ty); @@ -853,7 +860,8 @@ static void EmitObjectDelete(CodeGenFunction &CGF, if (Dtor->isVirtual()) { const llvm::Type *Ty = - CGF.getTypes().GetFunctionType(CGF.getTypes().getFunctionInfo(Dtor), + CGF.getTypes().GetFunctionType(CGF.getTypes().getFunctionInfo(Dtor, + Dtor_Complete), /*isVariadic=*/false); llvm::Value *Callee diff --git a/clang/test/CodeGenCXX/arm.cpp b/clang/test/CodeGenCXX/arm.cpp index 05ed603acf66..44c0affa5a8f 100644 --- a/clang/test/CodeGenCXX/arm.cpp +++ b/clang/test/CodeGenCXX/arm.cpp @@ -237,6 +237,46 @@ namespace test4 { } } +// : don't crash +namespace test5 { + struct A { + ~A(); + }; + + // CHECK: define void @_ZN5test54testEPNS_1AE + void test(A *a) { + // CHECK: [[PTR:%.*]] = alloca [[A:%.*]]*, align 4 + // CHECK-NEXT: store [[A]]* {{.*}}, [[A]]** [[PTR]], align 4 + // CHECK-NEXT: [[TMP:%.*]] = load [[A]]** [[PTR]], align 4 + // CHECK-NEXT: call [[A]]* @_ZN5test51AD1Ev([[A]]* [[TMP]]) + // CHECK-NEXT: ret void + a->~A(); + } +} + +namespace test6 { + struct A { + virtual ~A(); + }; + + // CHECK: define void @_ZN5test64testEPNS_1AE + void test(A *a) { + // CHECK: [[AVAR:%.*]] = alloca [[A:%.*]]*, align 4 + // CHECK-NEXT: store [[A]]* {{.*}}, [[A]]** [[AVAR]], align 4 + // CHECK-NEXT: [[V:%.*]] = load [[A]]** [[AVAR]], align 4 + // CHECK-NEXT: [[ISNULL:%.*]] = icmp eq [[A]]* [[V]], null + // CHECK-NEXT: br i1 [[ISNULL]] + // CHECK: [[T0:%.*]] = bitcast [[A]]* [[V]] to [[A]]* ([[A]]*)*** + // CHECK-NEXT: [[T1:%.*]] = load [[A]]* ([[A]]*)*** [[T0]] + // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* ([[A]]*)** [[T1]], i64 1 + // CHECK-NEXT: [[T3:%.*]] = load [[A]]* ([[A]]*)** [[T2]] + // CHECK-NEXT: call [[A]]* [[T3]]([[A]]* [[V]]) + // CHECK-NEXT: br label + // CHECK: ret void + delete a; + } +} + // CHECK: define linkonce_odr [[C:%.*]]* @_ZTv0_n12_N5test21CD1Ev( // CHECK: call [[C]]* @_ZN5test21CD1Ev( // CHECK: ret [[C]]* undef