Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -982,6 +982,8 @@ Flags<[CC1Option]>, HelpText<"Do not emit code to make initialization of local statics thread safe">; def fno_use_cxa_atexit : Flag<["-"], "fno-use-cxa-atexit">, Group, Flags<[CC1Option]>, HelpText<"Don't use __cxa_atexit for calling destructors">; +def fno_cxx_static_destructors : Flag<["-"], "fno-cxx-static-destructors">, Group, + Flags<[CC1Option]>, HelpText<"Don't register c++ exit time destructors">; def fno_use_init_array : Flag<["-"], "fno-use-init-array">, Group, Flags<[CC1Option]>, HelpText<"Don't use .init_array instead of .ctors">; def fno_unit_at_a_time : Flag<["-"], "fno-unit-at-a-time">, Group; Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -40,6 +40,7 @@ CODEGENOPT(CoverageNoFunctionNamesInData, 1, 0) ///< Do not include function names in GCDA files. CODEGENOPT(CoverageExitBlockBeforeBody, 1, 0) ///< Whether to emit the exit block before the body blocks in GCNO files. CODEGENOPT(CXAAtExit , 1, 1) ///< Use __cxa_atexit for calling destructors. +CODEGENOPT(CXXNoExitTimeDtor , 1, 0) ///< Do not register exit time destructors (skip calls to __cxa_atexit or atexit). CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker ///< aliases to base ctors when possible. CODEGENOPT(DataSections , 1, 0) ///< Set when -fdata-sections is enabled. Index: lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- lib/CodeGen/ItaniumCXXABI.cpp +++ lib/CodeGen/ItaniumCXXABI.cpp @@ -2132,6 +2132,10 @@ const VarDecl &D, llvm::Constant *dtor, llvm::Constant *addr) { + // Do not register global dtor at all + if (CGM.getCodeGenOpts().CXXNoExitTimeDtor) + return; + // Use __cxa_atexit if available. if (CGM.getCodeGenOpts().CXAAtExit) return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr, D.getTLSKind()); Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -5963,6 +5963,9 @@ CmdArgs.push_back("-fwhole-program-vtables"); } + if (Args.hasArg(options::OPT_fno_cxx_static_destructors)) + CmdArgs.push_back("-fno-cxx-static-destructors"); + // Finally add the compile command to the compilation. if (Args.hasArg(options::OPT__SLASH_fallback) && Output.getType() == types::TY_Object && Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -546,6 +546,7 @@ Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); + Opts.CXXNoExitTimeDtor = Args.hasArg(OPT_fno_cxx_static_destructors); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.CodeModel = getCodeModel(Args, Diags); Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass); Index: test/CodeGenCXX/static-destructor.cpp =================================================================== --- test/CodeGenCXX/static-destructor.cpp +++ test/CodeGenCXX/static-destructor.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -triple=x86_64-pc-linux -emit-llvm -o - | FileCheck --check-prefix=X86 %s +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -emit-llvm -fno-cxx-static-destructors -o - | FileCheck --check-prefix=X86-NOATEXIT %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=ARM %s @@ -19,6 +20,11 @@ // X86: define internal void @__cxx_global_var_init() // X86: 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) +// X86 destructors have void return, and are registered directly with __cxa_atexit. +// X86-NOATEXIT: define internal void @__cxx_global_var_init() +// X86-NOATEXIT-NOT: 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) +// X86-NOATEXIT-NOT: declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*) + // 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()