Replace -Z default-hidden-visibility with -Z default-visibility

MCP: https://github.com/rust-lang/compiler-team/issues/782

Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com>
This commit is contained in:
David Lattimore 2024-10-01 08:55:10 +10:00
parent fb4aebddd1
commit f48194ea55
14 changed files with 208 additions and 81 deletions

View File

@ -104,10 +104,17 @@ fn create_wrapper_function(
false,
);
if tcx.sess.default_hidden_visibility() {
#[cfg(feature = "master")]
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
#[cfg(feature = "master")]
match tcx.sess.default_visibility() {
rustc_target::spec::SymbolVisibility::Hidden => {
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden))
}
rustc_target::spec::SymbolVisibility::Protected => {
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Protected))
}
rustc_target::spec::SymbolVisibility::Interposable => {}
}
if tcx.sess.must_emit_unwind_tables() {
// TODO(antoyo): emit unwind tables.
}

View File

@ -77,18 +77,20 @@ pub(crate) unsafe fn codegen(
// __rust_alloc_error_handler_should_panic
let name = OomStrategy::SYMBOL;
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
if tcx.sess.default_hidden_visibility() {
llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
}
llvm::LLVMRustSetVisibility(
ll_g,
llvm::Visibility::from_generic(tcx.sess.default_visibility()),
);
let val = tcx.sess.opts.unstable_opts.oom.should_panic();
let llval = llvm::LLVMConstInt(i8, val as u64, False);
llvm::LLVMSetInitializer(ll_g, llval);
let name = NO_ALLOC_SHIM_IS_UNSTABLE;
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
if tcx.sess.default_hidden_visibility() {
llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
}
llvm::LLVMRustSetVisibility(
ll_g,
llvm::Visibility::from_generic(tcx.sess.default_visibility()),
);
let llval = llvm::LLVMConstInt(i8, 0, False);
llvm::LLVMSetInitializer(ll_g, llval);
}
@ -132,9 +134,11 @@ fn create_wrapper_function(
None
};
if tcx.sess.default_hidden_visibility() {
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
}
llvm::LLVMRustSetVisibility(
llfn,
llvm::Visibility::from_generic(tcx.sess.default_visibility()),
);
if tcx.sess.must_emit_unwind_tables() {
let uwtable =
attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind);

View File

@ -22,6 +22,7 @@ use tracing::debug;
use crate::abi::{FnAbi, FnAbiLlvmExt};
use crate::context::CodegenCx;
use crate::llvm::AttributePlace::Function;
use crate::llvm::Visibility;
use crate::type_::Type;
use crate::value::Value;
use crate::{attributes, llvm};
@ -84,11 +85,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
fn_type: &'ll Type,
) -> &'ll Value {
// Declare C ABI functions with the visibility used by C by default.
let visibility = if self.tcx.sess.default_hidden_visibility() {
llvm::Visibility::Hidden
} else {
llvm::Visibility::Default
};
let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type)
}
@ -107,11 +104,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
unnamed: llvm::UnnamedAddr,
fn_type: &'ll Type,
) -> &'ll Value {
let visibility = if self.tcx.sess.default_hidden_visibility() {
llvm::Visibility::Hidden
} else {
llvm::Visibility::Default
};
let visibility = Visibility::from_generic(self.tcx.sess.default_visibility());
declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type)
}

View File

@ -4,6 +4,7 @@
use std::marker::PhantomData;
use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
use rustc_target::spec::SymbolVisibility;
use super::RustString;
use super::debuginfo::{
@ -133,6 +134,16 @@ pub enum Visibility {
Protected = 2,
}
impl Visibility {
pub fn from_generic(visibility: SymbolVisibility) -> Self {
match visibility {
SymbolVisibility::Hidden => Visibility::Hidden,
SymbolVisibility::Protected => Visibility::Protected,
SymbolVisibility::Interposable => Visibility::Default,
}
}
}
/// LLVMUnnamedAddr
#[repr(C)]
pub enum UnnamedAddr {

View File

@ -770,7 +770,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(crate_attr, vec!["abc".to_string()]);
tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
tracked!(debug_info_for_profiling, true);
tracked!(default_hidden_visibility, Some(true));
tracked!(default_visibility, Some(rustc_target::spec::SymbolVisibility::Hidden));
tracked!(dep_info_omit_d_target, true);
tracked!(direct_access_external_data, Some(true));
tracked!(dual_proc_macros, true);

View File

@ -15,6 +15,7 @@ use rustc_query_system::ich::StableHashingContext;
use rustc_session::config::OptLevel;
use rustc_span::Span;
use rustc_span::symbol::Symbol;
use rustc_target::spec::SymbolVisibility;
use tracing::debug;
use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
@ -305,6 +306,16 @@ pub enum Visibility {
Protected,
}
impl From<SymbolVisibility> for Visibility {
fn from(value: SymbolVisibility) -> Self {
match value {
SymbolVisibility::Hidden => Visibility::Hidden,
SymbolVisibility::Protected => Visibility::Protected,
SymbolVisibility::Interposable => Visibility::Default,
}
}
}
impl<'tcx> CodegenUnit<'tcx> {
#[inline]
pub fn new(name: Symbol) -> CodegenUnit<'tcx> {

View File

@ -904,26 +904,22 @@ fn mono_item_visibility<'tcx>(
}
fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility {
if !tcx.sess.default_hidden_visibility() {
return Visibility::Default;
}
let export_level = if is_generic {
// Generic functions never have export-level C.
SymbolExportLevel::Rust
} else {
match tcx.reachable_non_generics(id.krate).get(&id) {
Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => SymbolExportLevel::C,
_ => SymbolExportLevel::Rust,
}
};
match export_level {
// C-export level items remain at `Default` to allow C code to
// access and interpose them.
SymbolExportLevel::C => Visibility::Default,
// Generic functions never have export-level C.
if is_generic {
return Visibility::Hidden;
}
// Things with export level C don't get instantiated in
// downstream crates.
if !id.is_local() {
return Visibility::Hidden;
}
// C-export level items remain at `Default`, all other internal
// items become `Hidden`.
match tcx.reachable_non_generics(id.krate).get(&id) {
Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default,
_ => Visibility::Hidden,
// For all other symbols, `default_visibility` determines which visibility to use.
SymbolExportLevel::Rust => tcx.sess.default_visibility().into(),
}
}

View File

@ -3008,7 +3008,8 @@ pub(crate) mod dep_tracking {
use rustc_span::edition::Edition;
use rustc_target::spec::{
CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, WasmCAbi,
RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTriple,
TlsModel, WasmCAbi,
};
use super::{
@ -3101,6 +3102,7 @@ pub(crate) mod dep_tracking {
StackProtector,
SwitchWithOptPath,
SymbolManglingVersion,
SymbolVisibility,
RemapPathScopeComponents,
SourceFileHashAlgorithm,
OutFileName,

View File

@ -13,8 +13,8 @@ use rustc_span::edition::Edition;
use rustc_span::{RealFileName, SourceFileHashAlgorithm};
use rustc_target::spec::{
CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
WasmCAbi,
RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility,
TargetTriple, TlsModel, WasmCAbi,
};
use crate::config::*;
@ -416,6 +416,8 @@ mod desc {
"one of: `disabled`, `trampolines`, or `aliases`";
pub(crate) const parse_symbol_mangling_version: &str =
"one of: `legacy`, `v0` (RFC 2603), or `hashed`";
pub(crate) const parse_opt_symbol_visibility: &str =
"one of: `hidden`, `protected`, or `interposable`";
pub(crate) const parse_src_file_hash: &str = "either `md5` or `sha1`";
pub(crate) const parse_relocation_model: &str =
"one of supported relocation models (`rustc --print relocation-models`)";
@ -922,6 +924,20 @@ mod parse {
true
}
pub(crate) fn parse_opt_symbol_visibility(
slot: &mut Option<SymbolVisibility>,
v: Option<&str>,
) -> bool {
if let Some(v) = v {
if let Ok(vis) = SymbolVisibility::from_str(v) {
*slot = Some(vis);
} else {
return false;
}
}
true
}
pub(crate) fn parse_optimization_fuel(
slot: &mut Option<(String, u64)>,
v: Option<&str>,
@ -1688,8 +1704,8 @@ options! {
"compress debug info sections (none, zlib, zstd, default: none)"),
deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
"deduplicate identical diagnostics (default: yes)"),
default_hidden_visibility: Option<bool> = (None, parse_opt_bool, [TRACKED],
"overrides the `default_hidden_visibility` setting of the target"),
default_visibility: Option<SymbolVisibility> = (None, parse_opt_symbol_visibility, [TRACKED],
"overrides the `default_visibility` setting of the target"),
dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
"in dep-info output, omit targets for tracking dependencies of the dep-info files \
themselves (default: no)"),

View File

@ -31,7 +31,8 @@ use rustc_span::{FileNameDisplayPreference, RealFileName, Span, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{
CodeModel, DebuginfoKind, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
SmallDataThresholdSupport, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, Target,
TargetTriple, TlsModel,
};
use crate::code_stats::CodeStats;
@ -617,12 +618,13 @@ impl Session {
}
}
/// Whether the default visibility of symbols should be "hidden" rather than "default".
pub fn default_hidden_visibility(&self) -> bool {
/// Returns the default symbol visibility.
pub fn default_visibility(&self) -> SymbolVisibility {
self.opts
.unstable_opts
.default_hidden_visibility
.unwrap_or(self.target.options.default_hidden_visibility)
.default_visibility
.or(self.target.options.default_visibility)
.unwrap_or(SymbolVisibility::Interposable)
}
}

View File

@ -830,6 +830,46 @@ impl RelroLevel {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum SymbolVisibility {
Hidden,
Protected,
Interposable,
}
impl SymbolVisibility {
pub fn desc(&self) -> &str {
match *self {
SymbolVisibility::Hidden => "hidden",
SymbolVisibility::Protected => "protected",
SymbolVisibility::Interposable => "interposable",
}
}
}
impl FromStr for SymbolVisibility {
type Err = ();
fn from_str(s: &str) -> Result<SymbolVisibility, ()> {
match s {
"hidden" => Ok(SymbolVisibility::Hidden),
"protected" => Ok(SymbolVisibility::Protected),
"interposable" => Ok(SymbolVisibility::Interposable),
_ => Err(()),
}
}
}
impl ToJson for SymbolVisibility {
fn to_json(&self) -> Json {
match *self {
SymbolVisibility::Hidden => "hidden".to_json(),
SymbolVisibility::Protected => "protected".to_json(),
SymbolVisibility::Interposable => "interposable".to_json(),
}
}
}
impl FromStr for RelroLevel {
type Err = ();
@ -2326,13 +2366,12 @@ pub struct TargetOptions {
/// for this target unconditionally.
pub no_builtins: bool,
/// The default visibility for symbols in this target should be "hidden"
/// rather than "default".
/// The default visibility for symbols in this target.
///
/// This value typically shouldn't be accessed directly, but through
/// the `rustc_session::Session::default_hidden_visibility` method, which
/// allows `rustc` users to override this setting using cmdline flags.
pub default_hidden_visibility: bool,
/// This value typically shouldn't be accessed directly, but through the
/// `rustc_session::Session::default_visibility` method, which allows `rustc` users to override
/// this setting using cmdline flags.
pub default_visibility: Option<SymbolVisibility>,
/// Whether a .debug_gdb_scripts section will be added to the output object file
pub emit_debug_gdb_scripts: bool,
@ -2623,7 +2662,7 @@ impl Default for TargetOptions {
requires_lto: false,
singlethread: false,
no_builtins: false,
default_hidden_visibility: false,
default_visibility: None,
emit_debug_gdb_scripts: true,
requires_uwtable: false,
default_uwtable: false,
@ -2963,6 +3002,18 @@ impl Target {
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, Option<SymbolVisibility>) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<SymbolVisibility>() {
Ok(level) => base.$key_name = Some(level),
_ => return Some(Err(format!("'{}' is not a valid value for \
symbol-visibility. Use 'hidden', 'protected, or 'interposable'.",
s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, DebuginfoKind) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
@ -3353,7 +3404,7 @@ impl Target {
key!(requires_lto, bool);
key!(singlethread, bool);
key!(no_builtins, bool);
key!(default_hidden_visibility, bool);
key!(default_visibility, Option<SymbolVisibility>)?;
key!(emit_debug_gdb_scripts, bool);
key!(requires_uwtable, bool);
key!(default_uwtable, bool);
@ -3633,7 +3684,7 @@ impl ToJson for Target {
target_option_val!(requires_lto);
target_option_val!(singlethread);
target_option_val!(no_builtins);
target_option_val!(default_hidden_visibility);
target_option_val!(default_visibility);
target_option_val!(emit_debug_gdb_scripts);
target_option_val!(requires_uwtable);
target_option_val!(default_uwtable);

View File

@ -1,12 +0,0 @@
# `default-hidden-visibility`
The tracking issue for this feature is: https://github.com/rust-lang/compiler-team/issues/656
------------------------
This flag can be used to override the target's
[`default_hidden_visibility`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html#structfield.default_hidden_visibility)
setting.
Using `-Zdefault_hidden_visibility=yes` is roughly equivalent to Clang's
[`-fvisibility=hidden`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fvisibility)
cmdline flag.

View File

@ -0,0 +1,44 @@
# `default-visibility`
The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/131090
------------------------
This flag can be used to override the target's
[`default_visibility`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html#structfield.default_visibility)
setting.
This option only affects building of shared objects and should have no effect on executables.
Visibility an be set to one of three options:
* protected
* hidden
* interposable
## Hidden visibility
Using `-Zdefault-visibility=hidden` is roughly equivalent to Clang's
[`-fvisibility=hidden`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fvisibility)
cmdline flag. Hidden symbols will not be exported from the created shared object, so cannot be
referenced from other shared objects or from executables.
## Protected visibility
Using `-Zdefault-visibility=protected` will cause rust-mangled symbols to be emitted with
"protected" visibility. This signals the compiler, the linker and the runtime linker that these
symbols cannot be overridden by the executable or by other shared objects earlier in the load order.
This will allow the compiler to emit direct references to symbols, which may improve performance. It
also removes the need for these symbols to be resolved when a shared object built with this option
is loaded.
Using protected visibility when linking with GNU ld prior to 2.40 will result in linker errors when
building for Linux. Other linkers such as LLD are not affected.
## Interposable
Using `-Zdefault-visibility=interposable` will cause symbols to be emitted with "default"
visibility. On platforms that support it, this makes it so that symbols can be interposed, which
means that they can be overridden by symbols with the same name from the executable or by other
shared objects earier in the load order.

View File

@ -1,11 +1,12 @@
// Verifies that `Session::default_hidden_visibility` is affected when using the related cmdline
// flag. This is a regression test for https://github.com/rust-lang/compiler-team/issues/656. See
// Verifies that `Session::default_visibility` is affected when using the related cmdline
// flag. This is a regression test for https://github.com/rust-lang/compiler-team/issues/782. See
// also https://github.com/rust-lang/rust/issues/73295 and
// https://github.com/rust-lang/rust/issues/37530.
//@ revisions:DEFAULT YES NO
//@[YES] compile-flags: -Zdefault-hidden-visibility=yes
//@[NO] compile-flags: -Zdefault-hidden-visibility=no
//@ revisions:DEFAULT HIDDEN PROTECTED INTERPOSABLE
//@[HIDDEN] compile-flags: -Zdefault-visibility=hidden
//@[PROTECTED] compile-flags: -Zdefault-visibility=protected
//@[INTERPOSABLE] compile-flags: -Zdefault-visibility=interposable
// The test scenario is specifically about visibility of symbols exported out of dynamically linked
// libraries.
@ -26,6 +27,7 @@ pub static tested_symbol: [u8; 6] = *b"foobar";
//
//@ only-x86_64-unknown-linux-gnu
// DEFAULT: @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = constant
// YES: @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = hidden constant
// NO: @{{.*}}default_hidden_visibility{{.*}}tested_symbol{{.*}} = constant
// HIDDEN: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = hidden constant
// PROTECTED: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = protected constant
// INTERPOSABLE: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant
// DEFAULT: @{{.*}}default_visibility{{.*}}tested_symbol{{.*}} = constant