Index: clang/include/clang/Basic/LangOptions.h =================================================================== --- clang/include/clang/Basic/LangOptions.h +++ clang/include/clang/Basic/LangOptions.h @@ -206,6 +206,10 @@ /// input is a header file (i.e. -x c-header). bool IsHeaderFile = false; + /// If set, dllexported classes dllexport their inline methods. + bool DllexportInlines = true; + + LangOptions(); // Define accessors/mutators for language options of enumeration type. Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -114,6 +114,7 @@ LANGOPT(GNUKeywords , 1, 1, "GNU keywords") BENIGN_LANGOPT(ImplicitInt, 1, !C99 && !CPlusPlus, "C89 implicit 'int'") LANGOPT(Digraphs , 1, 0, "digraphs") +LANGOPT(DllexportInlines , 1, 1, "If dllexport a class should dllexport inline methods in the Microsoft ABI") BENIGN_LANGOPT(HexFloats , 1, C99, "C99 hexadecimal float constants") LANGOPT(CXXOperatorNames , 1, 0, "C++ operator name keywords") LANGOPT(AppleKext , 1, 0, "Apple kext support") Index: clang/include/clang/Driver/CC1Options.td =================================================================== --- clang/include/clang/Driver/CC1Options.td +++ clang/include/clang/Driver/CC1Options.td @@ -165,6 +165,7 @@ HelpText<"Make assembler warnings fatal">; def mrelax_relocations : Flag<["--"], "mrelax-relocations">, HelpText<"Use relaxable elf relocations">; +def ms_no_dllexport_inline : Flag<["-"], "ms-no-dllexport-inline">; def msave_temp_labels : Flag<["-"], "msave-temp-labels">, HelpText<"Save temporary labels in the symbol table. " "Note this may change .s semantics and shouldn't generally be used " Index: clang/include/clang/Driver/CLCompatOptions.td =================================================================== --- clang/include/clang/Driver/CLCompatOptions.td +++ clang/include/clang/Driver/CLCompatOptions.td @@ -301,6 +301,8 @@ MetaVarName<"">; def _SLASH_Y_ : CLFlag<"Y-">, HelpText<"Disable precompiled headers, overrides /Yc and /Yu">; +def _SLASH_Zc_dllexportInlines : CLFlag<"Zc:dllexportInlines">; +def _SLASH_Zc_dllexportInlines_ : CLFlag<"Zc:dllexportInlines-">; def _SLASH_Fp : CLJoined<"Fp">, HelpText<"Set pch filename (with /Yc and /Yu)">, MetaVarName<"">; Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -5153,6 +5153,12 @@ if (VolatileOptionID == options::OPT__SLASH_volatile_ms) CmdArgs.push_back("-fms-volatile"); + // FIXME: what about the non-cl driver + if (Args.hasFlag(options::OPT__SLASH_Zc_dllexportInlines_, + options::OPT__SLASH_Zc_dllexportInlines, + false)) + CmdArgs.push_back("-ms-no-dllexport-inline"); + Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg); Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb); if (MostGeneralArg && BestCaseArg) Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -2125,6 +2125,9 @@ } } + if (Args.getLastArg(OPT_ms_no_dllexport_inline)) + Opts.DllexportInlines = false; + if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { StringRef Name = A->getValue(); if (Name == "full" || Name == "branch") { Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -5527,6 +5527,10 @@ if (!MD) continue; + // XXX: need to skip inlines here + // or not needed because they no longer get dllexport attribs. hmm, best place here + // or checkClassLevelDLLAttribute? + if (Member->getAttr()) { if (MD->isUserProvided()) { // Instantiate non-default class member functions ... @@ -5546,6 +5550,7 @@ // defaulted methods, and the copy and move assignment operators. The // latter are exported even if they are trivial, because the address of // an operator can be taken and should compare equal across libraries. + // XXX not with that flag i guess DiagnosticErrorTrap Trap(S.Diags); S.MarkFunctionReferenced(Class->getLocation(), MD); if (Trap.hasErrorOccurred()) { @@ -5691,6 +5696,14 @@ !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) continue; + // XXX: check inline funs with static vars + // XXX: explicit instantiation declarations give me trouble + if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + !getLangOpts().DllexportInlines && + Class->getTemplateSpecializationKind() != TSK_ExplicitInstantiationDeclaration && + Class->getTemplateSpecializationKind() != TSK_ExplicitInstantiationDefinition) + continue; + // MSVC versions before 2015 don't export the move assignment operators // and move constructor, so don't attempt to import/export them if // we have a definition.