From a880b19aa6ef1dc95936f5de052be7a7d6ee6814 Mon Sep 17 00:00:00 2001 From: John McCall Date: Tue, 19 Feb 2013 01:57:35 +0000 Subject: [PATCH] Add support for -fvisibility-ms-compat. We treat this as an alternative to -fvisibility= which changes the default value visibility to "hidden" and the default type visibility to "default". Expose a -cc1 option for changing the default type visibility, repurposing -fvisibility as the default value visibility option (also setting type visibility from it in the absence of a specific option). rdar://13079314 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175480 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/LangOptions.def | 6 +- include/clang/Driver/CC1Options.td | 4 +- include/clang/Driver/Options.td | 6 +- lib/AST/Decl.cpp | 17 +++- lib/Driver/Tools.cpp | 16 +++- lib/Frontend/CompilerInvocation.cpp | 42 ++++++--- test/CodeGenCXX/visibility-ms-compat.cpp | 112 +++++++++++++++++++++++ test/Driver/visibility.cpp | 34 +++++++ 8 files changed, 214 insertions(+), 23 deletions(-) create mode 100644 test/CodeGenCXX/visibility-ms-compat.cpp create mode 100644 test/Driver/visibility.cpp diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def index 60a7e83137..a7c753ed24 100644 --- a/include/clang/Basic/LangOptions.def +++ b/include/clang/Basic/LangOptions.def @@ -147,8 +147,10 @@ BENIGN_LANGOPT(DelayedTemplateParsing , 1, 0, "delayed template parsing") LANGOPT(BlocksRuntimeOptional , 1, 0, "optional blocks runtime") ENUM_LANGOPT(GC, GCMode, 2, NonGC, "Objective-C Garbage Collection mode") -ENUM_LANGOPT(VisibilityMode, Visibility, 3, DefaultVisibility, - "symbol visibility") +ENUM_LANGOPT(ValueVisibilityMode, Visibility, 3, DefaultVisibility, + "value symbol visibility") +ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility, + "type symbol visibility") ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff, "stack protector mode") ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined, diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index b84f96bbe6..3c5e75ffb9 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -415,7 +415,9 @@ def stack_protector : Separate<["-"], "stack-protector">, def stack_protector_buffer_size : Separate<["-"], "stack-protector-buffer-size">, HelpText<"Lower bound for a buffer to be considered for stack protection">; def fvisibility : Separate<["-"], "fvisibility">, - HelpText<"Default symbol visibility">; + HelpText<"Default type and symbol visibility">; +def ftype_visibility : Separate<["-"], "ftype-visibility">, + HelpText<"Default type visibility">; def ftemplate_depth : Separate<["-"], "ftemplate-depth">, HelpText<"Maximum depth of recursive template instantiation">; def fconstexpr_depth : Separate<["-"], "fconstexpr-depth">, diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 5fd2fffde9..cafd7d7517 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -723,10 +723,14 @@ def fuse_cxa_atexit : Flag<["-"], "fuse-cxa-atexit">, Group; def fuse_init_array : Flag<["-"], "fuse-init-array">, Group, Flags<[CC1Option]>, HelpText<"Use .init_array instead of .ctors">; def fverbose_asm : Flag<["-"], "fverbose-asm">, Group; -def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group; +def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group, + HelpText<"Set the default symbol visibility for all global declarations">; def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group, HelpText<"Give inline C++ member functions default visibility by default">, Flags<[CC1Option]>; +def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group, + HelpText<"Give global types 'default' visibility and global functions and " + "variables 'hidden' visibility by default">; def fwrapv : Flag<["-"], "fwrapv">, Group, Flags<[CC1Option]>, HelpText<"Treat signed integer overflow as two's complement">; def fwritable_strings : Flag<["-"], "fwritable-strings">, Group, Flags<[CC1Option]>, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 0183c0b59e..6e93dd6415 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -80,7 +80,9 @@ typedef NamedDecl::LinkageInfo LinkageInfo; /// Is the given declaration a "type" or a "value" for the purposes of /// visibility computation? static bool usesTypeVisibility(const NamedDecl *D) { - return isa(D) || isa(D); + return isa(D) || + isa(D) || + isa(D); } /// Return the explicit visibility of the given declaration. @@ -440,10 +442,15 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // Add in global settings if the above didn't give us direct visibility. if (!LV.visibilityExplicit()) { - // FIXME: type visibility - LV.mergeVisibility(Context.getLangOpts().getVisibilityMode(), - /*explicit*/ false); - + // Use global type/value visibility as appropriate. + Visibility globalVisibility; + if (computation == LVForValue) { + globalVisibility = Context.getLangOpts().getValueVisibilityMode(); + } else { + assert(computation == LVForType); + globalVisibility = Context.getLangOpts().getTypeVisibilityMode(); + } + LV.mergeVisibility(globalVisibility, /*explicit*/ false); // If we're paying attention to global visibility, apply // -finline-visibility-hidden if this is an inline method. diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index f5ea38bec4..5b3b65428d 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -2523,9 +2523,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Twine(N))); } - if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) { - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back(A->getValue()); + // -fvisibility= and -fvisibility-ms-compat are of a piece. + if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ, + options::OPT_fvisibility_ms_compat)) { + if (A->getOption().matches(options::OPT_fvisibility_EQ)) { + CmdArgs.push_back("-fvisibility"); + CmdArgs.push_back(A->getValue()); + } else { + assert(A->getOption().matches(options::OPT_fvisibility_ms_compat)); + CmdArgs.push_back("-fvisibility"); + CmdArgs.push_back("hidden"); + CmdArgs.push_back("-ftype-visibility"); + CmdArgs.push_back("default"); + } } Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index f4bf4b7756..05e079470a 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1001,6 +1001,24 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.DollarIdents = !Opts.AsmPreprocessor; } +/// Attempt to parse a visibility value out of the given argument. +static Visibility parseVisibility(Arg *arg, ArgList &args, + DiagnosticsEngine &diags) { + StringRef value = arg->getValue(); + if (value == "default") { + return DefaultVisibility; + } else if (value == "hidden") { + return HiddenVisibility; + } else if (value == "protected") { + // FIXME: diagnose if target does not support protected visibility + return ProtectedVisibility; + } + + diags.Report(diag::err_drv_invalid_value) + << arg->getAsString(args) << value; + return DefaultVisibility; +} + static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { // FIXME: Cleanup per-file based stuff. @@ -1132,17 +1150,19 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fdelayed_template_parsing)) Opts.DelayedTemplateParsing = 1; - StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); - if (Vis == "default") - Opts.setVisibilityMode(DefaultVisibility); - else if (Vis == "hidden") - Opts.setVisibilityMode(HiddenVisibility); - else if (Vis == "protected") - // FIXME: diagnose if target does not support protected visibility - Opts.setVisibilityMode(ProtectedVisibility); - else - Diags.Report(diag::err_drv_invalid_value) - << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; + // The value-visibility mode defaults to "default". + if (Arg *visOpt = Args.getLastArg(OPT_fvisibility)) { + Opts.setValueVisibilityMode(parseVisibility(visOpt, Args, Diags)); + } else { + Opts.setValueVisibilityMode(DefaultVisibility); + } + + // The type-visibility mode defaults to the value-visibility mode. + if (Arg *typeVisOpt = Args.getLastArg(OPT_ftype_visibility)) { + Opts.setTypeVisibilityMode(parseVisibility(typeVisOpt, Args, Diags)); + } else { + Opts.setTypeVisibilityMode(Opts.getValueVisibilityMode()); + } if (Args.hasArg(OPT_fvisibility_inlines_hidden)) Opts.InlineVisibilityHidden = 1; diff --git a/test/CodeGenCXX/visibility-ms-compat.cpp b/test/CodeGenCXX/visibility-ms-compat.cpp new file mode 100644 index 0000000000..58a8fed62e --- /dev/null +++ b/test/CodeGenCXX/visibility-ms-compat.cpp @@ -0,0 +1,112 @@ +// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -fvisibility hidden -ftype-visibility default -emit-llvm -o %t +// RUN: FileCheck %s < %t +// RUN: FileCheck -check-prefix=CHECK-GLOBAL %s < %t + +// The two visibility options above are how we translate +// -fvisibility-ms-compat in the driver. + +// rdar://13079314 + +#define HIDDEN __attribute__((visibility("hidden"))) +#define PROTECTED __attribute__((visibility("protected"))) +#define DEFAULT __attribute__((visibility("default"))) + +namespace std { + class type_info; +}; + +namespace test0 { + struct A { + static void foo(); + static void bar(); + }; + + void A::foo() { bar(); } + // CHECK: define hidden void @_ZN5test01A3fooEv() + // CHECK: declare void @_ZN5test01A3barEv() + + const std::type_info &ti = typeid(A); + // CHECK-GLOBAL: @_ZTSN5test01AE = linkonce_odr constant + // CHECK-GLOBAL: @_ZTIN5test01AE = linkonce_odr unnamed_addr constant + // CHECK-GLOBAL: @_ZN5test02tiE = hidden constant +} + +namespace test1 { + struct HIDDEN A { + static void foo(); + static void bar(); + }; + + void A::foo() { bar(); } + // CHECK: define hidden void @_ZN5test11A3fooEv() + // CHECK: declare hidden void @_ZN5test11A3barEv() + + const std::type_info &ti = typeid(A); + // CHECK-GLOBAL: @_ZTSN5test11AE = linkonce_odr hidden constant + // CHECK-GLOBAL: @_ZTIN5test11AE = linkonce_odr hidden unnamed_addr constant + // CHECK-GLOBAL: @_ZN5test12tiE = hidden constant +} + +namespace test2 { + struct DEFAULT A { + static void foo(); + static void bar(); + }; + + void A::foo() { bar(); } + // CHECK: define void @_ZN5test21A3fooEv() + // CHECK: declare void @_ZN5test21A3barEv() + + const std::type_info &ti = typeid(A); + // CHECK-GLOBAL: @_ZTSN5test21AE = linkonce_odr constant + // CHECK-GLOBAL: @_ZTIN5test21AE = linkonce_odr unnamed_addr constant + // CHECK-GLOBAL: @_ZN5test22tiE = hidden constant +} + +namespace test3 { + struct A { int x; }; + template struct B { + static void foo() { bar(); } + static void bar(); + }; + + template void B::foo(); + // CHECK: define weak_odr hidden void @_ZN5test31BINS_1AEE3fooEv() + // CHECK: declare void @_ZN5test31BINS_1AEE3barEv() + + const std::type_info &ti = typeid(B); + // CHECK-GLOBAL: @_ZTSN5test31BINS_1AEEE = linkonce_odr constant + // CHECK-GLOBAL: @_ZTIN5test31BINS_1AEEE = linkonce_odr unnamed_addr constant +} + +namespace test4 { + struct A { int x; }; + template struct DEFAULT B { + static void foo() { bar(); } + static void bar(); + }; + + template void B::foo(); + // CHECK: define weak_odr void @_ZN5test41BINS_1AEE3fooEv() + // CHECK: declare void @_ZN5test41BINS_1AEE3barEv() + + const std::type_info &ti = typeid(B); + // CHECK-GLOBAL: @_ZTSN5test41BINS_1AEEE = linkonce_odr constant + // CHECK-GLOBAL: @_ZTIN5test41BINS_1AEEE = linkonce_odr unnamed_addr constant +} + +namespace test5 { + struct A { int x; }; + template struct HIDDEN B { + static void foo() { bar(); } + static void bar(); + }; + + template void B::foo(); + // CHECK: define weak_odr hidden void @_ZN5test51BINS_1AEE3fooEv() + // CHECK: declare hidden void @_ZN5test51BINS_1AEE3barEv() + + const std::type_info &ti = typeid(B); + // CHECK-GLOBAL: @_ZTSN5test51BINS_1AEEE = linkonce_odr hidden constant + // CHECK-GLOBAL: @_ZTIN5test51BINS_1AEEE = linkonce_odr hidden unnamed_addr constant +} diff --git a/test/Driver/visibility.cpp b/test/Driver/visibility.cpp new file mode 100644 index 0000000000..cdbef97aad --- /dev/null +++ b/test/Driver/visibility.cpp @@ -0,0 +1,34 @@ +// RUN: %clang -### -S -fvisibility=hidden -fvisibility=default %s 2> %t.log +// RUN: FileCheck -check-prefix=CHECK-1 %s < %t.log +// CHECK-NOT: "-ftype-visibility" +// CHECK-1: "-fvisibility" "default" +// CHECK-NOT: "-ftype-visibility" + +// RUN: %clang -### -S -fvisibility=default -fvisibility=hidden %s 2> %t.log +// RUN: FileCheck -check-prefix=CHECK-2 %s < %t.log +// CHECK-NOT: "-ftype-visibility" +// CHECK-2: "-fvisibility" "hidden" +// CHECK-NOT: "-ftype-visibility" + +// RUN: %clang -### -S -fvisibility-ms-compat -fvisibility=hidden %s 2> %t.log +// RUN: FileCheck -check-prefix=CHECK-3 %s < %t.log +// CHECK-NOT: "-ftype-visibility" +// CHECK-3: "-fvisibility" "hidden" +// CHECK-NOT: "-ftype-visibility" + +// RUN: %clang -### -S -fvisibility-ms-compat -fvisibility=default %s 2> %t.log +// RUN: FileCheck -check-prefix=CHECK-4 %s < %t.log +// CHECK-NOT: "-ftype-visibility" +// CHECK-4: "-fvisibility" "default" +// CHECK-NOT: "-ftype-visibility" + +// RUN: %clang -### -S -fvisibility=hidden -fvisibility-ms-compat %s 2> %t.log +// RUN: FileCheck -check-prefix=CHECK-5 %s < %t.log +// CHECK-5: "-fvisibility" "hidden" +// CHECK-5: "-ftype-visibility" "default" + +// RUN: %clang -### -S -fvisibility=default -fvisibility-ms-compat %s 2> %t.log +// RUN: FileCheck -check-prefix=CHECK-6 %s < %t.log +// CHECK-6: "-fvisibility" "hidden" +// CHECK-6: "-ftype-visibility" "default" + -- 2.40.0