Reland - [Clang] Add the ability to map DLL storage class to visibility

415f7ee883 had LIT test failures on any build where the clang executable
was not called "clang". I have adjusted the LIT CHECKs to remove the
binary name to fix this.

Original commit message:

For PlayStation we offer source code compatibility with
Microsoft's dllimport/export annotations; however, our file
format is based on ELF.

To support this we translate from DLL storage class to ELF
visibility at the end of codegen in Clang.

Other toolchains have used similar strategies (e.g. see the
documentation for this ARM toolchain:

https://developer.arm.com/documentation/dui0530/i/migrating-from-rvct-v3-1-to-rvct-v4-0/changes-to-symbol-visibility-between-rvct-v3-1-and-rvct-v4-0)

This patch adds the ability to perform this translation. Options
are provided to support customizing the mapping behaviour.

Differential Revision: https://reviews.llvm.org/D89970
This commit is contained in:
Ben Dunbobbin 2020-11-02 23:24:04 +00:00
parent 549eac9d87
commit ae9231ca2a
9 changed files with 420 additions and 3 deletions

View File

@ -307,6 +307,16 @@ ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility,
"default visibility for types [-ftype-visibility]")
LANGOPT(SetVisibilityForExternDecls, 1, 0,
"apply global symbol visibility to external declarations without an explicit visibility")
LANGOPT(VisibilityFromDLLStorageClass, 1, 0,
"set the visiblity of globals from their DLL storage class [-fvisibility-from-dllstorageclass]")
ENUM_LANGOPT(DLLExportVisibility, Visibility, 3, DefaultVisibility,
"visibility for functions and variables with dllexport annotations [-fvisibility-from-dllstorageclass]")
ENUM_LANGOPT(NoDLLStorageClassVisibility, Visibility, 3, HiddenVisibility,
"visibility for functions and variables without an explicit DLL storage class [-fvisibility-from-dllstorageclass]")
ENUM_LANGOPT(ExternDeclDLLImportVisibility, Visibility, 3, DefaultVisibility,
"visibility for external declarations with dllimport annotations [-fvisibility-from-dllstorageclass]")
ENUM_LANGOPT(ExternDeclNoDLLStorageClassVisibility, Visibility, 3, HiddenVisibility,
"visibility for external declarations without an explicit DLL storage class [-fvisibility-from-dllstorageclass]")
BENIGN_LANGOPT(SemanticInterposition , 1, 0, "semantic interposition")
BENIGN_LANGOPT(ExplicitNoSemanticInterposition, 1, 0, "explicitly no semantic interposition")
ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff,

View File

@ -1973,6 +1973,15 @@ def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group<clang_ignored_f_Gr
def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>,
HelpText<"Generate verbose assembly output">;
def dA : Flag<["-"], "dA">, Alias<fverbose_asm>;
defm visibility_from_dllstorageclass : OptInFFlag<"visibility-from-dllstorageclass", "Set the visiblity of symbols in the generated code from their DLL storage class">;
def fvisibility_dllexport_EQ : Joined<["-"], "fvisibility-dllexport=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"The visibility for dllexport defintions [-fvisibility-from-dllstorageclass]">, Values<"hidden,protected,default">;
def fvisibility_nodllstorageclass_EQ : Joined<["-"], "fvisibility-nodllstorageclass=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"The visibility for defintiions without an explicit DLL export class [-fvisibility-from-dllstorageclass]">, Values<"hidden,protected,default">;
def fvisibility_externs_dllimport_EQ : Joined<["-"], "fvisibility-externs-dllimport=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"The visibility for dllimport external declarations [-fvisibility-from-dllstorageclass]">, Values<"hidden,protected,default">;
def fvisibility_externs_nodllstorageclass_EQ : Joined<["-"], "fvisibility-externs-nodllstorageclass=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"The visibility for external declarations without an explicit DLL dllstorageclass [-fvisibility-from-dllstorageclass]">, Values<"hidden,protected,default">;
def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>,
HelpText<"Set the default symbol visibility for all global declarations">, Values<"hidden,default">;
def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>,

View File

@ -401,6 +401,41 @@ void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags,
}
}
static void setVisibilityFromDLLStorageClass(const clang::LangOptions &LO,
llvm::Module &M) {
if (!LO.VisibilityFromDLLStorageClass)
return;
llvm::GlobalValue::VisibilityTypes DLLExportVisibility =
CodeGenModule::GetLLVMVisibility(LO.getDLLExportVisibility());
llvm::GlobalValue::VisibilityTypes NoDLLStorageClassVisibility =
CodeGenModule::GetLLVMVisibility(LO.getNoDLLStorageClassVisibility());
llvm::GlobalValue::VisibilityTypes ExternDeclDLLImportVisibility =
CodeGenModule::GetLLVMVisibility(LO.getExternDeclDLLImportVisibility());
llvm::GlobalValue::VisibilityTypes ExternDeclNoDLLStorageClassVisibility =
CodeGenModule::GetLLVMVisibility(
LO.getExternDeclNoDLLStorageClassVisibility());
for (llvm::GlobalValue &GV : M.global_values()) {
if (GV.hasAppendingLinkage() || GV.hasLocalLinkage())
return;
if (GV.isDeclarationForLinker()) {
GV.setVisibility(GV.getDLLStorageClass() ==
llvm::GlobalValue::DLLImportStorageClass
? ExternDeclDLLImportVisibility
: ExternDeclNoDLLStorageClassVisibility);
} else {
GV.setVisibility(GV.getDLLStorageClass() ==
llvm::GlobalValue::DLLExportStorageClass
? DLLExportVisibility
: NoDLLStorageClassVisibility);
}
GV.setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
}
}
void CodeGenModule::Release() {
EmitDeferred();
EmitVTablesOpportunistically();
@ -688,6 +723,12 @@ void CodeGenModule::Release() {
getTargetCodeGenInfo().emitTargetMetadata(*this, MangledDeclNames);
EmitBackendOptionsMetadata(getCodeGenOpts());
// Set visibility from DLL export class
// We do this at the end of LLVM IR generation; after any operation
// that might affect the DLL storage class or the visibility, and
// before anything that might act on these.
setVisibilityFromDLLStorageClass(LangOpts, getModule());
}
void CodeGenModule::EmitOpenCLMetadata() {

View File

@ -5317,6 +5317,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
if (!RawTriple.isPS4())
if (const Arg *A =
Args.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
options::OPT_fno_visibility_from_dllstorageclass)) {
if (A->getOption().matches(
options::OPT_fvisibility_from_dllstorageclass)) {
CmdArgs.push_back("-fvisibility-from-dllstorageclass");
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_dllexport_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_nodllstorageclass_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_externs_dllimport_EQ);
Args.AddLastArg(CmdArgs,
options::OPT_fvisibility_externs_nodllstorageclass_EQ);
}
}
if (const Arg *A = Args.getLastArg(options::OPT_mignore_xcoff_visibility)) {
if (Triple.isOSAIX())
CmdArgs.push_back("-mignore-xcoff-visibility");

View File

@ -239,9 +239,8 @@ SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const {
}
void toolchains::PS4CPU::addClangTargetOptions(
const ArgList &DriverArgs,
ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadingKind) const {
const ArgList &DriverArgs, ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadingKind) const {
// PS4 does not use init arrays.
if (DriverArgs.hasArg(options::OPT_fuse_init_array)) {
Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array);
@ -250,4 +249,36 @@ void toolchains::PS4CPU::addClangTargetOptions(
}
CC1Args.push_back("-fno-use-init-array");
const Arg *A =
DriverArgs.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
options::OPT_fno_visibility_from_dllstorageclass);
if (!A ||
A->getOption().matches(options::OPT_fvisibility_from_dllstorageclass)) {
CC1Args.push_back("-fvisibility-from-dllstorageclass");
if (DriverArgs.hasArg(options::OPT_fvisibility_dllexport_EQ))
DriverArgs.AddLastArg(CC1Args, options::OPT_fvisibility_dllexport_EQ);
else
CC1Args.push_back("-fvisibility-dllexport=protected");
if (DriverArgs.hasArg(options::OPT_fvisibility_nodllstorageclass_EQ))
DriverArgs.AddLastArg(CC1Args,
options::OPT_fvisibility_nodllstorageclass_EQ);
else
CC1Args.push_back("-fvisibility-nodllstorageclass=hidden");
if (DriverArgs.hasArg(options::OPT_fvisibility_externs_dllimport_EQ))
DriverArgs.AddLastArg(CC1Args,
options::OPT_fvisibility_externs_dllimport_EQ);
else
CC1Args.push_back("-fvisibility-externs-dllimport=default");
if (DriverArgs.hasArg(
options::OPT_fvisibility_externs_nodllstorageclass_EQ))
DriverArgs.AddLastArg(
CC1Args, options::OPT_fvisibility_externs_nodllstorageclass_EQ);
else
CC1Args.push_back("-fvisibility-externs-nodllstorageclass=default");
}
}

View File

@ -2814,6 +2814,38 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fapply_global_visibility_to_externs))
Opts.SetVisibilityForExternDecls = 1;
if (Args.hasArg(OPT_fvisibility_from_dllstorageclass)) {
Opts.VisibilityFromDLLStorageClass = 1;
// Translate dllexport defintions to default visibility, by default.
if (Arg *O = Args.getLastArg(OPT_fvisibility_dllexport_EQ))
Opts.setDLLExportVisibility(parseVisibility(O, Args, Diags));
else
Opts.setDLLExportVisibility(DefaultVisibility);
// Translate defintions without an explict DLL storage class to hidden
// visibility, by default.
if (Arg *O = Args.getLastArg(OPT_fvisibility_nodllstorageclass_EQ))
Opts.setNoDLLStorageClassVisibility(parseVisibility(O, Args, Diags));
else
Opts.setNoDLLStorageClassVisibility(HiddenVisibility);
// Translate dllimport external declarations to default visibility, by
// default.
if (Arg *O = Args.getLastArg(OPT_fvisibility_externs_dllimport_EQ))
Opts.setExternDeclDLLImportVisibility(parseVisibility(O, Args, Diags));
else
Opts.setExternDeclDLLImportVisibility(DefaultVisibility);
// Translate external declarations without an explicit DLL storage class
// to hidden visibility, by default.
if (Arg *O = Args.getLastArg(OPT_fvisibility_externs_nodllstorageclass_EQ))
Opts.setExternDeclNoDLLStorageClassVisibility(
parseVisibility(O, Args, Diags));
else
Opts.setExternDeclNoDLLStorageClassVisibility(HiddenVisibility);
}
if (Args.hasArg(OPT_ftrapv)) {
Opts.setSignedOverflowBehavior(LangOptions::SOB_Trapping);
// Set the handler, if one is specified.

View File

@ -0,0 +1,70 @@
// REQUIRES: x86-registered-target
// Test that -fvisibility-from-dllstorageclass maps DLL storage class to visibility
// and that it overrides the effect of visibility options and annotations.
// RUN: %clang_cc1 -triple x86_64-unknown-windows-itanium -fdeclspec \
// RUN: -fvisibility hidden \
// RUN: -fvisibility-from-dllstorageclass \
// RUN: -x c++ %s -S -emit-llvm -o - | \
// RUN: FileCheck %s --check-prefixes=DEFAULT
// RUN: %clang_cc1 -triple x86_64-unknown-windows-itanium -fdeclspec \
// RUN: -fvisibility hidden \
// RUN: -fvisibility-from-dllstorageclass \
// RUN: -fvisibility-dllexport=hidden \
// RUN: -fvisibility-nodllstorageclass=protected \
// RUN: -fvisibility-externs-dllimport=hidden \
// RUN: -fvisibility-externs-nodllstorageclass=protected \
// RUN: -x c++ %s -S -emit-llvm -o - | \
// RUN: FileCheck %s --check-prefixes=EXPLICIT
// Function
void f() {}
void __declspec(dllexport) exported_f() {}
// DEFAULT-DAG: define hidden void @_Z1fv()
// DEFAULT-DAG: define dso_local void @_Z10exported_fv()
// EXPLICIT-DAG: define protected void @_Z1fv()
// EXPLICIT-DAG: define hidden void @_Z10exported_fv()
// Variable
int d = 123;
__declspec(dllexport) int exported_d = 123;
// DEFAULT-DAG: @d = hidden global
// DEFAULT-DAG: @exported_d = dso_local global
// EXPLICIT-DAG: @d = protected global
// EXPLICIT-DAG: @exported_d = hidden global
// Alias
extern "C" void aliased() {}
void a() __attribute__((alias("aliased")));
void __declspec(dllexport) a_exported() __attribute__((alias("aliased")));
// DEFAULT-DAG: @_Z1av = hidden alias
// DEFAULT-DAG: @_Z10a_exportedv = dso_local alias
// EXPLICIT-DAG: @_Z1av = protected alias
// EXPLICIT-DAG: @_Z10a_exportedv = hidden alias
// Declaration
extern void e();
extern void __declspec(dllimport) imported_e();
void use_declarations(){e(); imported_e();}
// DEFAULT-DAG: declare hidden void @_Z1ev()
// DEFAULT-DAG: declare void @_Z10imported_ev()
// EXPLICIT-DAG: declare protected void @_Z1ev()
// EXPLICIT-DAG: declare hidden void @_Z10imported_ev()
// Show that -fvisibility-from-dllstorageclass overrides the effect of visibility annotations.
struct __attribute__((type_visibility("protected"))) t {
virtual void foo();
};
void t::foo() {}
// DEFAULT-DAG: @_ZTV1t = hidden unnamed_addr constant
int v __attribute__ ((__visibility__ ("protected"))) = 123;
// DEFAULT-DAG: @v = hidden global
#pragma GCC visibility push(protected)
int p = 345;
#pragma GCC visibility pop
// DEFAULT-DAG: @p = hidden global

View File

@ -0,0 +1,122 @@
// Check behaviour of -fvisibility-from-dllstorageclass options for PS4
// RUN: %clang -### -target x86_64-scei-ps4 %s -Werror -o - 2>&1 | \
// RUN: FileCheck %s -check-prefixes=DEFAULTS,DEFAULTS1 \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass
// RUN: %clang -### -target x86_64-scei-ps4 \
// RUN: -fno-visibility-from-dllstorageclass \
// RUN: -fvisibility-from-dllstorageclass \
// RUN: -Werror \
// RUN: %s -o - 2>&1 | \
// RUN: FileCheck %s -check-prefixes=DEFAULTS,DEFAULTS2 \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass
// DEFAULTS: "-fvisibility-from-dllstorageclass"
// DEFAULTS-SAME: "-fvisibility-dllexport=protected"
// DEFAULTS-SAME: "-fvisibility-nodllstorageclass=hidden"
// DEFAULTS-SAME: "-fvisibility-externs-dllimport=default"
// DEFAULTS-SAME: "-fvisibility-externs-nodllstorageclass=default"
// RUN: %clang -### -target x86_64-scei-ps4 \
// RUN: -fvisibility-from-dllstorageclass \
// RUN: -fvisibility-dllexport=hidden \
// RUN: -fvisibility-nodllstorageclass=protected \
// RUN: -fvisibility-externs-dllimport=hidden \
// RUN: -fvisibility-externs-nodllstorageclass=protected \
// RUN: -fno-visibility-from-dllstorageclass \
// RUN: %s -o - 2>&1 | \
// RUN: FileCheck %s -check-prefix=UNUSED \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass \
// RUN: --implicit-check-not=warning:
// UNUSED: warning: argument unused during compilation: '-fvisibility-dllexport=hidden'
// UNUSED-NEXT: warning: argument unused during compilation: '-fvisibility-nodllstorageclass=protected'
// UNUSED-NEXT: warning: argument unused during compilation: '-fvisibility-externs-dllimport=hidden'
// UNUSED-NEXT: warning: argument unused during compilation: '-fvisibility-externs-nodllstorageclass=protected'
// RUN: %clang -### -target x86_64-scei-ps4 \
// RUN: -fvisibility-nodllstorageclass=protected \
// RUN: -fvisibility-externs-dllimport=hidden \
// RUN: -Werror \
// RUN: %s -o - 2>&1 | \
// RUN: FileCheck %s -check-prefix=SOME \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass
// RUN: %clang -### -target x86_64-scei-ps4 \
// RUN: -fvisibility-from-dllstorageclass \
// RUN: -fvisibility-nodllstorageclass=protected \
// RUN: -fvisibility-externs-dllimport=hidden \
// RUN: -Werror \
// RUN: %s -o - 2>&1 | \
// RUN: FileCheck %s -check-prefix=SOME \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass
// SOME: "-fvisibility-from-dllstorageclass"
// SOME-SAME: "-fvisibility-dllexport=protected"
// SOME-SAME: "-fvisibility-nodllstorageclass=protected"
// SOME-SAME: "-fvisibility-externs-dllimport=hidden"
// SOME-SAME: "-fvisibility-externs-nodllstorageclass=default"
// RUN: %clang -### -target x86_64-scei-ps4 \
// RUN: -fvisibility-dllexport=default \
// RUN: -fvisibility-dllexport=hidden \
// RUN: -fvisibility-nodllstorageclass=default \
// RUN: -fvisibility-nodllstorageclass=protected \
// RUN: -fvisibility-externs-dllimport=default \
// RUN: -fvisibility-externs-dllimport=hidden \
// RUN: -fvisibility-externs-nodllstorageclass=default \
// RUN: -fvisibility-externs-nodllstorageclass=protected \
// RUN: -Werror \
// RUN: %s -o - 2>&1 | \
// RUN: FileCheck %s -check-prefix=ALL \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass
// RUN: %clang -### -target x86_64-scei-ps4 \
// RUN: -fvisibility-from-dllstorageclass \
// RUN: -fvisibility-dllexport=default \
// RUN: -fvisibility-dllexport=hidden \
// RUN: -fvisibility-nodllstorageclass=default \
// RUN: -fvisibility-nodllstorageclass=protected \
// RUN: -fvisibility-externs-dllimport=default \
// RUN: -fvisibility-externs-dllimport=hidden \
// RUN: -fvisibility-externs-nodllstorageclass=default \
// RUN: -fvisibility-externs-nodllstorageclass=protected \
// RUN: -Werror \
// RUN: %s -o - 2>&1 | \
// RUN: FileCheck %s -check-prefix=ALL \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass
// ALL: "-fvisibility-from-dllstorageclass"
// ALL-SAME: "-fvisibility-dllexport=hidden"
// ALL-SAME: "-fvisibility-nodllstorageclass=protected"
// ALL-SAME: "-fvisibility-externs-dllimport=hidden"
// ALL-SAME: "-fvisibility-externs-nodllstorageclass=protected"

View File

@ -0,0 +1,87 @@
// Check behaviour of -fvisibility-from-dllstorageclass options
// RUN: %clang -target x86_64-unknown-windows-itanium -fdeclspec \
// RUN: -Werror -S -### %s 2>&1 | \
// RUN: FileCheck %s \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass
// RUN: %clang -target x86_64-unknown-windows-itanium -fdeclspec \
// RUN: -fvisibility-from-dllstorageclass \
// RUN: -fno-visibility-from-dllstorageclass \
// RUN: -Werror -S -### %s 2>&1 | \
// RUN: FileCheck %s \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass
// RUN: %clang -target x86_64-unknown-windows-itanium -fdeclspec \
// RUN: -fno-visibility-from-dllstorageclass \
// RUN: -fvisibility-from-dllstorageclass \
// RUN: -Werror -S -### %s 2>&1 | \
// RUN: FileCheck %s --check-prefix=SET \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass
// RUN: %clang -target x86_64-unknown-windows-itanium -fdeclspec \
// RUN: -fvisibility-dllexport=hidden \
// RUN: -fvisibility-nodllstorageclass=protected \
// RUN: -fvisibility-externs-dllimport=hidden \
// RUN: -fvisibility-externs-nodllstorageclass=protected \
// RUN: -S -### %s 2>&1 | \
// RUN: FileCheck %s --check-prefixes=UNUSED \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass \
// RUN: --implicit-check-not=error: \
// RUN: --implicit-check-not=warning:
// RUN: %clang -target x86_64-unknown-windows-itanium -fdeclspec \
// RUN: -fno-visibility-from-dllstorageclass \
// RUN: -fvisibility-dllexport=hidden \
// RUN: -fvisibility-nodllstorageclass=protected \
// RUN: -fvisibility-externs-dllimport=hidden \
// RUN: -fvisibility-externs-nodllstorageclass=protected \
// RUN: -S -### %s 2>&1 | \
// RUN: FileCheck %s --check-prefixes=UNUSED \
// RUN: --implicit-check-not=-fvisibility-from-dllstorageclass \
// RUN: --implicit-check-not=-fvisibility-dllexport \
// RUN: --implicit-check-not=-fvisibility-nodllstorageclass \
// RUN: --implicit-check-not=-fvisibility-externs-dllimport \
// RUN: --implicit-check-not=-fvisibility-externs-nodllstorageclass \
// RUN: --implicit-check-not=error: \
// RUN: --implicit-check-not=warning:
// UNUSED: warning: argument unused during compilation: '-fvisibility-dllexport=hidden'
// UNUSED-NEXT: warning: argument unused during compilation: '-fvisibility-nodllstorageclass=protected'
// UNUSED-NEXT: warning: argument unused during compilation: '-fvisibility-externs-dllimport=hidden'
// UNUSED-NEXT: warning: argument unused during compilation: '-fvisibility-externs-nodllstorageclass=protected'
// RUN: %clang -target x86_64-unknown-windows-itanium -fdeclspec \
// RUN: -fvisibility-from-dllstorageclass \
// RUN: -fvisibility-dllexport=default \
// RUN: -fvisibility-dllexport=hidden \
// RUN: -fvisibility-nodllstorageclass=default \
// RUN: -fvisibility-nodllstorageclass=protected \
// RUN: -fvisibility-externs-dllimport=default \
// RUN: -fvisibility-externs-dllimport=hidden \
// RUN: -fvisibility-externs-nodllstorageclass=default \
// RUN: -fvisibility-externs-nodllstorageclass=protected \
// RUN: -Werror -S -### %s 2>&1 | \
// RUN: FileCheck %s --check-prefixes=SET,ALL
// SET: "-fvisibility-from-dllstorageclass"
// ALL-SAME: "-fvisibility-dllexport=hidden"
// ALL-SAME: "-fvisibility-nodllstorageclass=protected"
// ALL-SAME: "-fvisibility-externs-dllimport=hidden"
// ALL-SAME: "-fvisibility-externs-nodllstorageclass=protected"