From 8179be4897db025dd7256bbee7c0d9e5794a2b34 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Tue, 10 May 2016 17:44:55 +0000 Subject: [PATCH] Introduce CGCXXABI::canCallMismatchedFunctionType llvm-svn: 269089 --- clang/lib/CodeGen/CGCXXABI.h | 10 ++++++++++ clang/lib/CodeGen/CGDeclCXX.cpp | 9 +++++---- clang/lib/CodeGen/ItaniumCXXABI.cpp | 1 + clang/test/CodeGenCXX/runtimecc.cpp | 7 +------ clang/test/CodeGenCXX/static-destructor.cpp | 8 +++++++- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 3f240b1802b8..8c0f6c2efd51 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/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/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 46d92ec46c4f..89d142e44b49 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/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/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 52e519f30441..4da7b9498f60 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/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/clang/test/CodeGenCXX/runtimecc.cpp b/clang/test/CodeGenCXX/runtimecc.cpp index 1aac5ffa7165..ad6dc85c360d 100644 --- a/clang/test/CodeGenCXX/runtimecc.cpp +++ b/clang/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/clang/test/CodeGenCXX/static-destructor.cpp b/clang/test/CodeGenCXX/static-destructor.cpp index 1b6ca305563c..24e31d3d8633 100644 --- a/clang/test/CodeGenCXX/static-destructor.cpp +++ b/clang/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()