aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2013-02-19 01:57:35 +0000
committerJohn McCall <rjmccall@apple.com>2013-02-19 01:57:35 +0000
commita880b19aa6ef1dc95936f5de052be7a7d6ee6814 (patch)
tree5bfc6bbc9923a73e72a917920105bf1fb1f91df1
parent0b5a483c8f5d8563ebc6ad5e311f2fadb734058d (diff)
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
-rw-r--r--include/clang/Basic/LangOptions.def6
-rw-r--r--include/clang/Driver/CC1Options.td4
-rw-r--r--include/clang/Driver/Options.td6
-rw-r--r--lib/AST/Decl.cpp17
-rw-r--r--lib/Driver/Tools.cpp16
-rw-r--r--lib/Frontend/CompilerInvocation.cpp42
-rw-r--r--test/CodeGenCXX/visibility-ms-compat.cpp112
-rw-r--r--test/Driver/visibility.cpp34
8 files changed, 214 insertions, 23 deletions
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<f_Group>;
def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use .init_array instead of .ctors">;
def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>;
-def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>;
+def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>,
+ HelpText<"Set the default symbol visibility for all global declarations">;
def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>,
HelpText<"Give inline C++ member functions default visibility by default">,
Flags<[CC1Option]>;
+def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group<f_Group>,
+ HelpText<"Give global types 'default' visibility and global functions and "
+ "variables 'hidden' visibility by default">;
def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_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<TypeDecl>(D) || isa<ClassTemplateDecl>(D);
+ return isa<TypeDecl>(D) ||
+ isa<ClassTemplateDecl>(D) ||
+ isa<ObjCInterfaceDecl>(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 <class T> struct B {
+ static void foo() { bar(); }
+ static void bar();
+ };
+
+ template void B<A>::foo();
+ // CHECK: define weak_odr hidden void @_ZN5test31BINS_1AEE3fooEv()
+ // CHECK: declare void @_ZN5test31BINS_1AEE3barEv()
+
+ const std::type_info &ti = typeid(B<A>);
+ // CHECK-GLOBAL: @_ZTSN5test31BINS_1AEEE = linkonce_odr constant
+ // CHECK-GLOBAL: @_ZTIN5test31BINS_1AEEE = linkonce_odr unnamed_addr constant
+}
+
+namespace test4 {
+ struct A { int x; };
+ template <class T> struct DEFAULT B {
+ static void foo() { bar(); }
+ static void bar();
+ };
+
+ template void B<A>::foo();
+ // CHECK: define weak_odr void @_ZN5test41BINS_1AEE3fooEv()
+ // CHECK: declare void @_ZN5test41BINS_1AEE3barEv()
+
+ const std::type_info &ti = typeid(B<A>);
+ // CHECK-GLOBAL: @_ZTSN5test41BINS_1AEEE = linkonce_odr constant
+ // CHECK-GLOBAL: @_ZTIN5test41BINS_1AEEE = linkonce_odr unnamed_addr constant
+}
+
+namespace test5 {
+ struct A { int x; };
+ template <class T> struct HIDDEN B {
+ static void foo() { bar(); }
+ static void bar();
+ };
+
+ template void B<A>::foo();
+ // CHECK: define weak_odr hidden void @_ZN5test51BINS_1AEE3fooEv()
+ // CHECK: declare hidden void @_ZN5test51BINS_1AEE3barEv()
+
+ const std::type_info &ti = typeid(B<A>);
+ // 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"
+