Index: docs/ClangCommandLineReference.rst =================================================================== --- docs/ClangCommandLineReference.rst +++ docs/ClangCommandLineReference.rst @@ -1217,6 +1217,8 @@ .. option:: -fcreate-profile +.. option:: -fcxx-dll, -fno-cxx-dll + .. option:: -fcxx-exceptions, -fno-cxx-exceptions Enable C++ exceptions Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -760,6 +760,10 @@ def fno_crash_diagnostics : Flag<["-"], "fno-crash-diagnostics">, Group, Flags<[NoArgumentUnused]>, HelpText<"Disable auto-generation of preprocessed source files and a script for reproduction during a clang crash">; def fcreate_profile : Flag<["-"], "fcreate-profile">, Group; +def fcxx_dll: Flag<["-"], "fcxx-dll">, Group, + HelpText<"Generate code for a C++ stdlib linked as a DLL">, Flags<[CC1Option]>; +def fno_cxx_dll: Flag<["-"], "fno-cxx-dll">, Group, + HelpText<"Don't generate code for a C++ stdlib linked as a DLL">, Flags<[CC1Option]>; def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group, HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>; def fcxx_modules : Flag <["-"], "fcxx-modules">, Group, Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -45,6 +45,7 @@ CODEGENOPT(CXAAtExit , 1, 1) ///< Use __cxa_atexit for calling destructors. CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker ///< aliases to base ctors when possible. +CODEGENOPT(CXXDll , 1, 0) ///< Set when -fcxx-dll is enabled. CODEGENOPT(DataSections , 1, 0) ///< Set when -fdata-sections is enabled. CODEGENOPT(UniqueSectionNames, 1, 1) ///< Set for -funique-section-names. CODEGENOPT(DisableFPElim , 1, 0) ///< Set when -fomit-frame-pointer is enabled. Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1308,8 +1308,10 @@ llvm::Function *InitFunc, InitSegAttr *ISA); // FIXME: Hardcoding priority here is gross. +public: void AddGlobalCtor(llvm::Function *Ctor, int Priority = 65535, llvm::Constant *AssociatedData = nullptr); +private: void AddGlobalDtor(llvm::Function *Dtor, int Priority = 65535); /// EmitCtorList - Generates a global array of functions and priorities using Index: lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- lib/CodeGen/ItaniumCXXABI.cpp +++ lib/CodeGen/ItaniumCXXABI.cpp @@ -2958,6 +2958,9 @@ llvm::Constant *VTable = CGM.getModule().getOrInsertGlobal(VTableName, CGM.Int8PtrTy); + llvm::GlobalValue *GV = dyn_cast(VTable); + if (GV && CGM.getCodeGenOpts().CXXDll) + GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); llvm::Type *PtrDiffTy = CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); @@ -3058,6 +3061,11 @@ // Add the vtable pointer. BuildVTablePointer(cast(Ty)); + bool DLLImport = CGM.getCodeGenOpts().CXXDll; + llvm::Constant *VTable = Fields.back(); + if (DLLImport) + Fields.back() = llvm::Constant::getNullValue(CGM.Int8PtrTy); + // And the name. llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage); llvm::Constant *TypeNameField; @@ -3171,7 +3179,7 @@ llvm::Module &M = CGM.getModule(); llvm::GlobalVariable *GV = new llvm::GlobalVariable(M, Init->getType(), - /*Constant=*/true, Linkage, Init, Name); + /*Constant=*/ !DLLImport, Linkage, Init, Name); // If there's already an old global variable, replace it with the new one. if (OldGV) { @@ -3185,6 +3193,31 @@ if (CGM.supportsCOMDAT() && GV->isWeakForLinker()) GV->setComdat(M.getOrInsertComdat(GV->getName())); + if (DLLImport) { + llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false); + SmallString<256> FnName; + { + llvm::raw_svector_ostream Out(FnName); + CGM.getCXXABI().getMangleContext().mangleDynamicInitializer( + NULL /* VarDecl */, Out); + } + llvm::Function *Fn = CGM.CreateGlobalInitOrDestructFunction( + FTy, FnName.str(), CGM.getTypes().arrangeNullaryFunction()); + + CodeGenFunction CGF(CGM); + CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, Fn, + CGM.getTypes().arrangeNullaryFunction(), FunctionArgList()); + llvm::Constant *Zero = llvm::Constant::getNullValue(CGM.Int32Ty); + llvm::Constant *Zeros[] = {Zero, Zero}; + llvm::Value *FieldPtr = llvm::ConstantExpr::getInBoundsGetElementPtr( + GV->getValueType(), GV, Zeros); + CGF.Builder.CreateDefaultAlignedStore( + llvm::ConstantExpr::getBitCast(VTable, CGM.Int8PtrTy), FieldPtr); + CGF.FinishFunction(); + // Run with priority 0, before any user defined ctors + CGM.AddGlobalCtor(Fn, 0); + } + // The Itanium ABI specifies that type_info objects must be globally // unique, with one exception: if the type is an incomplete class // type or a (possibly indirect) pointer to one. That exception Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -4276,6 +4276,10 @@ } } + // Link to the C++ standard library as a DLL. + if (Args.hasFlag(options::OPT_fcxx_dll, options::OPT_fno_cxx_dll, false)) + CmdArgs.push_back("-fcxx-dll"); + // C++ "sane" operator new. if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new)) Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -632,6 +632,7 @@ Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); + Opts.CXXDll = Args.hasFlag(OPT_fcxx_dll, OPT_fno_cxx_dll, false); Opts.CodeModel = getCodeModel(Args, Diags); Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass); Opts.DisableFPElim = Index: test/CodeGenCXX/rtti-mingw64.cpp =================================================================== --- test/CodeGenCXX/rtti-mingw64.cpp +++ test/CodeGenCXX/rtti-mingw64.cpp @@ -1,4 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-windows-gnu %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -fcxx-dll -fno-cxx-dll -triple x86_64-windows-gnu %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -fcxx-dll -triple x86_64-windows-gnu %s -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-DLL struct A { int a; }; struct B : virtual A { int b; }; B b; @@ -16,3 +18,23 @@ // CHECK-SAME: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), // This i64 is important, it should be an i64, not an i32. // CHECK-SAME: i64 -6141 }, comdat + + +// CHECK-DLL: @_ZTVN10__cxxabiv117__class_type_infoE = external dllimport global i8* + +// CHECK-DLL: @_ZTI1C = linkonce_odr global { i8*, i8* } +// The first field of the typeinfo, the vtable pointer, is initialized to null +// CHECK-DLL-SAME: i8* null, +// CHECK-DLL-SAME: i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1C, i32 0, i32 0) }, comdat +// CHECK-DLL: @_ZTI1B = linkonce_odr global { i8*, i8*, i32, i32, i8*, i64 } +// CHECK-DLL-SAME: i8* null, +// CHECK-DLL-SAME: i8* getelementptr inbounds ([3 x i8], [3 x i8]* @_ZTS1B, i32 0, i32 0), + +// CHECK-DLL: @llvm.global_ctors = appending global +// Check for high priority constructors (normal constructors run at priority 65535) +// CHECK-DLL-SAME: { i32 0, void ()* @__cxx_global_var_init.1, i8* null }, + +// CHECK-DLL: define internal void @__cxx_global_var_init.1() +// Check that the runtime constructor initializes the vtable pointer in the typeinfo. +// CHECK-DLL: store i8* bitcast (i8** getelementptr inbounds (i8*, i8** @_ZTVN10__cxxabiv117__class_type_infoE, i64 2) to i8*), +// CHECK-DLL-SAME: i8** getelementptr inbounds ({ i8*, i8* }, { i8*, i8* }* @_ZTI1C, i32 0, i32 0)