diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 04ebffbcba69d..f181da9aea6f9 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -359,16 +359,16 @@ BENIGN_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(VisibilityFromDLLStorageClass, 1, 0, + "override the visibility of globals based on their final DLL storage class [-fvisibility-from-dllstorageclass]") +BENIGN_ENUM_LANGOPT(DLLExportVisibility, VisibilityFromDLLStorageClassKinds, 3, VisibilityFromDLLStorageClassKinds::Default, + "how to adjust the visibility for functions and variables with dllexport annotations [-fvisibility-dllexport]") +BENIGN_ENUM_LANGOPT(NoDLLStorageClassVisibility, VisibilityFromDLLStorageClassKinds, 3, VisibilityFromDLLStorageClassKinds::Hidden, + "how to adjust the visibility for functions and variables without an explicit DLL storage class [-fvisibility-nodllstorageclass]") +BENIGN_ENUM_LANGOPT(ExternDeclDLLImportVisibility, VisibilityFromDLLStorageClassKinds, 3, VisibilityFromDLLStorageClassKinds::Default, + "how to adjust the visibility for external declarations with dllimport annotations [-fvisibility-externs-dllimport]") +BENIGN_ENUM_LANGOPT(ExternDeclNoDLLStorageClassVisibility, VisibilityFromDLLStorageClassKinds, 3, VisibilityFromDLLStorageClassKinds::Hidden, + "how to adjust the visibility for external declarations without an explicit DLL storage class [-fvisibility-externs-nodllstorageclass]") BENIGN_LANGOPT(SemanticInterposition , 1, 0, "semantic interposition") BENIGN_LANGOPT(HalfNoSemanticInterposition, 1, 0, "Like -fno-semantic-interposition but don't use local aliases") diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 9f986fce2d441..976a00d1a6fa5 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -381,6 +381,17 @@ class LangOptions : public LangOptionsBase { All, }; + enum class VisibilityFromDLLStorageClassKinds { + /// Keep the IR-gen assigned visibility. + Keep, + /// Override the IR-gen assigned visibility with default visibility. + Default, + /// Override the IR-gen assigned visibility with hidden visibility. + Hidden, + /// Override the IR-gen assigned visibility with protected visibility. + Protected, + }; + enum class StrictFlexArraysLevelKind { /// Any trailing array member is a FAM. Default = 0, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index d2e6c3ff721c2..f1687d823f6e0 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3862,27 +3862,32 @@ def dA : Flag<["-"], "dA">, Alias; defm visibility_from_dllstorageclass : BoolFOption<"visibility-from-dllstorageclass", LangOpts<"VisibilityFromDLLStorageClass">, DefaultFalse, PosFlag, + "Override the visibility of globals based on their final DLL storage class.">, NegFlag>; +class MarshallingInfoVisibilityFromDLLStorage + : MarshallingInfoEnum, + Values<"keep,hidden,protected,default">, + NormalizedValuesScope<"LangOptions::VisibilityFromDLLStorageClassKinds">, + NormalizedValues<["Keep", "Hidden", "Protected", "Default"]> {} def fvisibility_dllexport_EQ : Joined<["-"], "fvisibility-dllexport=">, Group, Visibility<[ClangOption, CC1Option]>, - HelpText<"The visibility for dllexport definitions [-fvisibility-from-dllstorageclass]">, - MarshallingInfoVisibility, "DefaultVisibility">, + HelpText<"The visibility for dllexport definitions. If Keep is specified the visibility is not adjusted [-fvisibility-from-dllstorageclass]">, + MarshallingInfoVisibilityFromDLLStorage, "Default">, ShouldParseIf; def fvisibility_nodllstorageclass_EQ : Joined<["-"], "fvisibility-nodllstorageclass=">, Group, Visibility<[ClangOption, CC1Option]>, - HelpText<"The visibility for definitions without an explicit DLL export class [-fvisibility-from-dllstorageclass]">, - MarshallingInfoVisibility, "HiddenVisibility">, + HelpText<"The visibility for definitions without an explicit DLL storage class. If Keep is specified the visibility is not adjusted [-fvisibility-from-dllstorageclass]">, + MarshallingInfoVisibilityFromDLLStorage, "Hidden">, ShouldParseIf; def fvisibility_externs_dllimport_EQ : Joined<["-"], "fvisibility-externs-dllimport=">, Group, Visibility<[ClangOption, CC1Option]>, - HelpText<"The visibility for dllimport external declarations [-fvisibility-from-dllstorageclass]">, - MarshallingInfoVisibility, "DefaultVisibility">, + HelpText<"The visibility for dllimport external declarations. If Keep is specified the visibility is not adjusted [-fvisibility-from-dllstorageclass]">, + MarshallingInfoVisibilityFromDLLStorage, "Default">, ShouldParseIf; def fvisibility_externs_nodllstorageclass_EQ : Joined<["-"], "fvisibility-externs-nodllstorageclass=">, Group, Visibility<[ClangOption, CC1Option]>, - HelpText<"The visibility for external declarations without an explicit DLL dllstorageclass [-fvisibility-from-dllstorageclass]">, - MarshallingInfoVisibility, "HiddenVisibility">, + HelpText<"The visibility for external declarations without an explicit DLL storage class. If Keep is specified the visibility is not adjusted [-fvisibility-from-dllstorageclass]">, + MarshallingInfoVisibilityFromDLLStorage, "Hidden">, ShouldParseIf; def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group, Visibility<[ClangOption, CC1Option]>, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 482c2108a988a..77c931842dd21 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -722,43 +722,70 @@ void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags, } } +static std::optional +getLLVMVisibility(clang::LangOptions::VisibilityFromDLLStorageClassKinds K) { + // Map to LLVM visibility. + switch (K) { + case clang::LangOptions::VisibilityFromDLLStorageClassKinds::Keep: + return std::nullopt; + case clang::LangOptions::VisibilityFromDLLStorageClassKinds::Default: + return llvm::GlobalValue::DefaultVisibility; + case clang::LangOptions::VisibilityFromDLLStorageClassKinds::Hidden: + return llvm::GlobalValue::HiddenVisibility; + case clang::LangOptions::VisibilityFromDLLStorageClassKinds::Protected: + return llvm::GlobalValue::ProtectedVisibility; + } + llvm_unreachable("unknown option value!"); +} + +void setLLVMVisibility(llvm::GlobalValue &GV, + std::optional V) { + if (!V) + return; + + // Reset DSO locality before setting the visibility. This removes + // any effects that visibility options and annotations may have + // had on the DSO locality. Setting the visibility will implicitly set + // appropriate globals to DSO Local; however, this will be pessimistic + // w.r.t. to the normal compiler IRGen. + GV.setDSOLocal(false); + GV.setVisibility(*V); +} + 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()); + std::optional DLLExportVisibility = + getLLVMVisibility(LO.getDLLExportVisibility()); + + std::optional + NoDLLStorageClassVisibility = + getLLVMVisibility(LO.getNoDLLStorageClassVisibility()); + + std::optional + ExternDeclDLLImportVisibility = + getLLVMVisibility(LO.getExternDeclDLLImportVisibility()); + + std::optional + ExternDeclNoDLLStorageClassVisibility = + getLLVMVisibility(LO.getExternDeclNoDLLStorageClassVisibility()); for (llvm::GlobalValue &GV : M.global_values()) { if (GV.hasAppendingLinkage() || GV.hasLocalLinkage()) continue; - // Reset DSO locality before setting the visibility. This removes - // any effects that visibility options and annotations may have - // had on the DSO locality. Setting the visibility will implicitly set - // appropriate globals to DSO Local; however, this will be pessimistic - // w.r.t. to the normal compiler IRGen. - GV.setDSOLocal(false); - - if (GV.isDeclarationForLinker()) { - GV.setVisibility(GV.getDLLStorageClass() == - llvm::GlobalValue::DLLImportStorageClass - ? ExternDeclDLLImportVisibility - : ExternDeclNoDLLStorageClassVisibility); - } else { - GV.setVisibility(GV.getDLLStorageClass() == - llvm::GlobalValue::DLLExportStorageClass - ? DLLExportVisibility - : NoDLLStorageClassVisibility); - } + if (GV.isDeclarationForLinker()) + setLLVMVisibility(GV, GV.getDLLStorageClass() == + llvm::GlobalValue::DLLImportStorageClass + ? ExternDeclDLLImportVisibility + : ExternDeclNoDLLStorageClassVisibility); + else + setLLVMVisibility(GV, GV.getDLLStorageClass() == + llvm::GlobalValue::DLLExportStorageClass + ? DLLExportVisibility + : NoDLLStorageClassVisibility); GV.setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); } diff --git a/clang/test/CodeGenCXX/visibility-dllstorageclass.cpp b/clang/test/CodeGenCXX/visibility-dllstorageclass.cpp index 6520e7039728e..a44ff1316d94c 100644 --- a/clang/test/CodeGenCXX/visibility-dllstorageclass.cpp +++ b/clang/test/CodeGenCXX/visibility-dllstorageclass.cpp @@ -1,7 +1,7 @@ // 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. +//// 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 \ @@ -32,12 +32,35 @@ // RUN: -x c++ %s -S -emit-llvm -o - | \ // RUN: FileCheck %s --check-prefixes=ALL_DEFAULT +// RUN: %clang_cc1 -triple x86_64-unknown-windows-itanium -fdeclspec \ +// RUN: -fvisibility=hidden \ +// RUN: -fapply-global-visibility-to-externs \ +// RUN: -fvisibility-from-dllstorageclass \ +// RUN: -fvisibility-dllexport=keep \ +// RUN: -fvisibility-nodllstorageclass=keep \ +// RUN: -fvisibility-externs-dllimport=keep \ +// RUN: -fvisibility-externs-nodllstorageclass=keep \ +// RUN: -x c++ %s -S -emit-llvm -o - | \ +// RUN: FileCheck %s --check-prefixes=ALL_KEEP + +//// Show that omitting -fvisibility-from-dllstorageclass causes the other options to be ignored. +// RUN: %clang_cc1 -triple x86_64-unknown-windows-itanium -fdeclspec \ +// RUN: -fvisibility=hidden \ +// RUN: -fapply-global-visibility-to-externs \ +// RUN: -fvisibility-dllexport=protected \ +// RUN: -fvisibility-nodllstorageclass=protected \ +// RUN: -fvisibility-externs-dllimport=protected \ +// RUN: -fvisibility-externs-nodllstorageclass=protected \ +// RUN: -x c++ %s -S -emit-llvm -o - | \ +// RUN: FileCheck %s --check-prefixes=ALL_KEEP + // Local static void l() {} void use_locals(){l();} // DEFAULTS-DAG: define internal void @_ZL1lv() // EXPLICIT-DAG: define internal void @_ZL1lv() // ALL_DEFAULT-DAG: define internal void @_ZL1lv() +// ALL_KEEP-DAG: define internal void @_ZL1lv() // Function void f() {} @@ -48,6 +71,8 @@ void __declspec(dllexport) exported_f() {} // EXPLICIT-DAG: define hidden void @_Z10exported_fv() // ALL_DEFAULT-DAG: define void @_Z1fv() // ALL_DEFAULT-DAG: define void @_Z10exported_fv() +// ALL_KEEP-DAG: define hidden void @_Z1fv() +// ALL_KEEP-DAG: define hidden void @_Z10exported_fv() // Variable int d = 123; @@ -58,6 +83,8 @@ __declspec(dllexport) int exported_d = 123; // EXPLICIT-DAG: @exported_d = hidden global // ALL_DEFAULT-DAG: @d = global // ALL_DEFAULT-DAG: @exported_d = global +// ALL_KEEP-DAG: @d = hidden global +// ALL_KEEP-DAG: @exported_d = hidden global // Alias extern "C" void aliased() {} @@ -69,6 +96,8 @@ void __declspec(dllexport) a_exported() __attribute__((alias("aliased"))); // EXPLICIT-DAG: @_Z10a_exportedv = hidden alias // ALL_DEFAULT-DAG: @_Z1av = alias // ALL_DEFAULT-DAG: @_Z10a_exportedv = alias +// ALL_KEEP-DAG: @_Z1av = hidden alias +// ALL_KEEP-DAG: @_Z10a_exportedv = dso_local alias // Declaration extern void e(); @@ -79,6 +108,8 @@ extern void __declspec(dllimport) imported_e(); // EXPLICIT-DAG: declare hidden void @_Z10imported_ev() // ALL_DEFAULT-DAG: declare void @_Z1ev() // ALL_DEFAULT-DAG: declare void @_Z10imported_ev() +// ALL_KEEP-DAG: declare hidden void @_Z1ev() +// ALL_KEEP-DAG: declare void @_Z10imported_ev() // Weak Declaration __attribute__((weak)) @@ -91,6 +122,8 @@ extern void __declspec(dllimport) imported_w(); // EXPLICIT-DAG: declare extern_weak hidden void @_Z10imported_wv() // ALL_DEFAULT-DAG: declare extern_weak void @_Z1wv() // ALL_DEFAULT-DAG: declare extern_weak void @_Z10imported_wv() +// ALL_KEEP-DAG: declare extern_weak hidden void @_Z1wv() +// ALL_KEEP-DAG: declare extern_weak void @_Z10imported_wv() void use_declarations(){e(); imported_e(); w(); imported_w();} @@ -101,11 +134,14 @@ struct __attribute__((type_visibility("protected"))) t { }; void t::foo() {} // DEFAULTS-DAG: @_ZTV1t = hidden unnamed_addr constant +// ALL_KEEP-DAG: @_ZTV1t = protected unnamed_addr constant int v __attribute__ ((__visibility__ ("protected"))) = 123; // DEFAULTS-DAG: @v = hidden global +// ALL_KEEP-DAG: @v = protected global #pragma GCC visibility push(protected) int p = 345; #pragma GCC visibility pop // DEFAULTS-DAG: @p = hidden global +// ALL_KEEP-DAG: @p = protected global diff --git a/clang/test/Driver/visibility-dllstorageclass.c b/clang/test/Driver/visibility-dllstorageclass.c index 1e495f694a5a5..65d13d348cc97 100644 --- a/clang/test/Driver/visibility-dllstorageclass.c +++ b/clang/test/Driver/visibility-dllstorageclass.c @@ -1,4 +1,4 @@ -// Check behaviour of -fvisibility-from-dllstorageclass options +//// Check behaviour of -fvisibility-from-dllstorageclass options // RUN: %clang -target x86_64-unknown-windows-itanium -fdeclspec \ // RUN: -Werror -S -### %s 2>&1 | \ @@ -85,3 +85,35 @@ // ALL-SAME: "-fvisibility-nodllstorageclass=protected" // ALL-SAME: "-fvisibility-externs-dllimport=hidden" // ALL-SAME: "-fvisibility-externs-nodllstorageclass=protected" + +//// Test that "keep" can be specified, which means that the visibility of +//// the matching globals will not be adjusted. + +// RUN: %clang -target x86_64-unknown-windows-itanium -fdeclspec \ +// RUN: -fvisibility-from-dllstorageclass \ +// RUN: -fvisibility-dllexport=keep \ +// RUN: -fvisibility-nodllstorageclass=keep \ +// RUN: -fvisibility-externs-dllimport=keep \ +// RUN: -fvisibility-externs-nodllstorageclass=keep \ +// RUN: -Werror -S -### %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=KEEP + +// KEEP: "-fvisibility-from-dllstorageclass" +// KEEP-SAME: "-fvisibility-dllexport=keep" +// KEEP-SAME: "-fvisibility-nodllstorageclass=keep" +// KEEP-SAME: "-fvisibility-externs-dllimport=keep" +// KEEP-SAME: "-fvisibility-externs-nodllstorageclass=keep" + +// RUN: %clang -target x86_64-unknown-windows-itanium -fdeclspec \ +// RUN: -fvisibility-from-dllstorageclass \ +// RUN: -fvisibility-dllexport=default \ +// RUN: -fvisibility-dllexport=keep \ +// RUN: -fvisibility-nodllstorageclass=default \ +// RUN: -fvisibility-nodllstorageclass=keep \ +// RUN: -fvisibility-externs-dllimport=default \ +// RUN: -fvisibility-externs-dllimport=keep \ +// RUN: -fvisibility-externs-nodllstorageclass=default \ +// RUN: -fvisibility-externs-nodllstorageclass=keep \ +// RUN: -Werror -S -### %s 2>&1 | \ +// RUN: FileCheck %s --check-prefixes=KEEP +