From: Derek Schuff Date: Tue, 10 May 2016 17:44:55 +0000 (+0000) Subject: Introduce CGCXXABI::canCallMismatchedFunctionType X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6d5ba2295fe4618f43fba20ca3c61e55ea838caa;p=clang Introduce CGCXXABI::canCallMismatchedFunctionType git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@269089 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 3f240b1802..8c0f6c2efd 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -106,6 +106,16 @@ public: virtual bool hasMostDerivedReturn(GlobalDecl GD) const { return false; } + /// Returns true if the target allows calling a function through a pointer + /// with a different signature than the actual function (or equivalently, + /// bitcasting a function or function pointer to a different function type). + /// In principle in the most general case this could depend on the target, the + /// calling convention, and the actual types of the arguments and return + /// value. Here it just means whether the signature mismatch could *ever* be + /// allowed; in other words, does the target do strict checking of signatures + /// for all calls. + virtual bool canCallMismatchedFunctionType() const { return true; } + /// If the C++ ABI requires the given type be returned in a particular way, /// this method sets RetAI and returns true. virtual bool classifyReturnType(CGFunctionInfo &FI) const = 0; diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 46d92ec46c..89d142e44b 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -88,11 +88,12 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D, // Special-case non-array C++ destructors, if they have the right signature. // Under some ABIs, destructors return this instead of void, and cannot be - // passed directly to __cxa_atexit. + // passed directly to __cxa_atexit if the target does not allow this mismatch. const CXXRecordDecl *Record = type->getAsCXXRecordDecl(); - bool CanRegisterDestructor = Record && - !CGM.getCXXABI().HasThisReturn(GlobalDecl( - Record->getDestructor(), Dtor_Complete)); + bool CanRegisterDestructor = + Record && (!CGM.getCXXABI().HasThisReturn( + GlobalDecl(Record->getDestructor(), Dtor_Complete)) || + CGM.getCXXABI().canCallMismatchedFunctionType()); // If __cxa_atexit is disabled via a flag, a different helper function is // generated elsewhere which uses atexit instead, and it takes the destructor // directly. diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 52e519f304..4da7b9498f 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -443,6 +443,7 @@ private: (isa(GD.getDecl()) && GD.getDtorType() != Dtor_Deleting); } + bool canCallMismatchedFunctionType() const override { return false; } }; } diff --git a/test/CodeGenCXX/runtimecc.cpp b/test/CodeGenCXX/runtimecc.cpp index 1aac5ffa71..ad6dc85c36 100644 --- a/test/CodeGenCXX/runtimecc.cpp +++ b/test/CodeGenCXX/runtimecc.cpp @@ -22,13 +22,8 @@ namespace test0 { A global; // CHECK-LABEL: define internal void @__cxx_global_var_init() // CHECK: call [[A]]* @_ZN5test01AC1Ev([[A]]* @_ZN5test06globalE) -// CHECK-NEXT: call i32 @__cxa_atexit(void (i8*)* @__cxx_global_array_dtor, i8* null, i8* @__dso_handle) [[NOUNWIND:#[0-9]+]] +// CHECK-NEXT: call i32 @__cxa_atexit(void (i8*)* bitcast ([[A]]* ([[A]]*)* @_ZN5test01AD1Ev to void (i8*)*), i8* bitcast ([[A]]* @_ZN5test06globalE to i8*), i8* @__dso_handle) [[NOUNWIND:#[0-9]+]] // CHECK-NEXT: ret void - -// CHECK-LABEL: define internal void @__cxx_global_array_dtor(i8*) -// CHECK: call [[A]]* @_ZN5test01AD1Ev([[A]]* @_ZN5test06globalE) -// CHECK-NEXT: ret void - } // CHECK: declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*) [[NOUNWIND]] diff --git a/test/CodeGenCXX/static-destructor.cpp b/test/CodeGenCXX/static-destructor.cpp index 1b6ca30556..24e31d3d86 100644 --- a/test/CodeGenCXX/static-destructor.cpp +++ b/test/CodeGenCXX/static-destructor.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -triple=x86_64-pc-linux -emit-llvm -o - | FileCheck --check-prefix=X86 %s // RUN: %clang_cc1 %s -triple=wasm32 -emit-llvm -o - | FileCheck --check-prefix=WASM %s -// RUN: %clang_cc1 %s -triple=armv7-apple-darwin9 -emit-llvm -o - | FileCheck --check-prefix=WASM %s +// RUN: %clang_cc1 %s -triple=armv7-apple-darwin9 -emit-llvm -o - | FileCheck --check-prefix=ARM %s // Test that destructors are not passed directly to __cxa_atexit when their // signatures do not match the type of its first argument. @@ -20,6 +20,12 @@ Foo global; // X86-NEXT: entry: // X86-NEXT: %0 = call i32 @__cxa_atexit(void (i8*)* bitcast (void (%class.Foo*)* @_ZN3FooD1Ev to void (i8*)*), i8* getelementptr inbounds (%class.Foo, %class.Foo* @global, i32 0, i32 0), i8* @__dso_handle) +// ARM destructors return this, but can be registered directly with __cxa_atexit +// because the calling conventions tolerate the mismatch. +// ARM: define internal void @__cxx_global_var_init() +// ARM-NEXT: entry: +// ARM-NEXT: %0 = call i32 @__cxa_atexit(void (i8*)* bitcast (%class.Foo* (%class.Foo*)* @_ZN3FooD1Ev to void (i8*)*), i8* getelementptr inbounds (%class.Foo, %class.Foo* @global, i32 0, i32 0), i8* @__dso_handle) + // Wasm destructors return this, and use a wrapper function, which is registered // with __cxa_atexit. // WASM: define internal void @__cxx_global_var_init()