Skip to content

Commit 9e65da3

Browse files
committed
Add new unstable attribute: #[export_visibility = ...].
1 parent f889772 commit 9e65da3

23 files changed

Lines changed: 451 additions & 2 deletions

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
1+
use rustc_hir::attrs::{
2+
CoverageAttrKind, ExportVisibilityAttrValue, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy,
3+
};
24
use rustc_session::parse::feature_err;
35

46
use super::prelude::*;
@@ -153,6 +155,43 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
153155
}
154156
}
155157

158+
pub(crate) struct ExportVisibilityParser;
159+
160+
impl<S: Stage> SingleAttributeParser<S> for ExportVisibilityParser {
161+
const PATH: &[rustc_span::Symbol] = &[sym::export_visibility];
162+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
163+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
164+
const ALLOWED_TARGETS: AllowedTargets =
165+
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::Static)]);
166+
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "visibility");
167+
168+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
169+
let Some(nv) = args.name_value() else {
170+
cx.expected_name_value(cx.attr_span, None);
171+
return None;
172+
};
173+
let Some(sv) = nv.value_as_str() else {
174+
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
175+
return None;
176+
};
177+
178+
let str_to_visibility = [("target_default", ExportVisibilityAttrValue::TargetDefault)];
179+
for &(s, visibility) in str_to_visibility.iter() {
180+
if s == sv.as_str() {
181+
return Some(AttributeKind::ExportVisibility { visibility, span: cx.attr_span });
182+
}
183+
}
184+
185+
let allowed_str_values = str_to_visibility
186+
.into_iter()
187+
.map(|(s, _visibility)| s)
188+
.map(Symbol::intern)
189+
.collect::<Vec<_>>();
190+
cx.expected_specific_argument_strings(nv.value_span, &allowed_str_values);
191+
None
192+
}
193+
}
194+
156195
pub(crate) struct ObjcClassParser;
157196

158197
impl<S: Stage> SingleAttributeParser<S> for ObjcClassParser {

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ attribute_parsers!(
171171
Single<DoNotRecommendParser>,
172172
Single<DummyParser>,
173173
Single<ExportNameParser>,
174+
Single<ExportVisibilityParser>,
174175
Single<IgnoreParser>,
175176
Single<InlineParser>,
176177
Single<InstructionSetParser>,

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use rustc_abi::{Align, ExternAbi};
44
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
55
use rustc_ast::{LitKind, MetaItem, MetaItemInner};
66
use rustc_hir::attrs::{
7-
AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy,
7+
AttributeKind, EiiImplResolution, ExportVisibilityAttrValue, InlineAttr, Linkage, RtsanSetting,
8+
UsedBy,
89
};
910
use rustc_hir::def::DefKind;
1011
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
@@ -75,6 +76,13 @@ fn process_builtin_attrs(
7576
match attr {
7677
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
7778
AttributeKind::ExportName { name, .. } => codegen_fn_attrs.symbol_name = Some(*name),
79+
AttributeKind::ExportVisibility { visibility, .. } => {
80+
codegen_fn_attrs.export_visibility = Some(match visibility {
81+
ExportVisibilityAttrValue::TargetDefault => {
82+
tcx.sess.default_visibility().into()
83+
}
84+
});
85+
}
7886
AttributeKind::Inline(inline, span) => {
7987
codegen_fn_attrs.inline = *inline;
8088
interesting_spans.inline = Some(*span);
@@ -542,6 +550,17 @@ fn handle_lang_items(
542550
}
543551
err.emit();
544552
}
553+
554+
if codegen_fn_attrs.export_visibility.is_some() {
555+
let span = find_attr!(attrs, AttributeKind::ExportVisibility{span, ..} => *span)
556+
.unwrap_or_default();
557+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
558+
tcx.dcx().emit_err(errors::ExportVisibilityWithRustcStdInternalSymbol { span });
559+
}
560+
if !codegen_fn_attrs.contains_extern_indicator() {
561+
tcx.dcx().emit_err(errors::ExportVisibilityWithoutNoMangleNorExportName { span });
562+
}
563+
}
545564
}
546565

547566
/// Generate the [`CodegenFnAttrs`] for an item (identified by the [`LocalDefId`]).

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,3 +1299,20 @@ pub(crate) struct LtoProcMacro;
12991299
#[diag("cannot prefer dynamic linking when performing LTO")]
13001300
#[note("only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO")]
13011301
pub(crate) struct DynamicLinkingWithLTO;
1302+
1303+
#[derive(Diagnostic)]
1304+
#[diag("`#[export_visibility = ...]` cannot be used on internal language items")]
1305+
pub(crate) struct ExportVisibilityWithRustcStdInternalSymbol {
1306+
#[primary_span]
1307+
pub span: Span,
1308+
}
1309+
1310+
#[derive(Diagnostic)]
1311+
#[diag(
1312+
"`#[export_visibility = ...]` will be ignored \
1313+
without `export_name`, `no_mangle`, or similar attribute"
1314+
)]
1315+
pub(crate) struct ExportVisibilityWithoutNoMangleNorExportName {
1316+
#[primary_span]
1317+
pub span: Span,
1318+
}

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
649649
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"),
650650
FutureWarnPreceding, EncodeCrossCrate::No
651651
),
652+
gated!(export_visibility, Normal, template!(NameValueStr: "visibility"), ErrorPreceding, EncodeCrossCrate::No, experimental!(export_visibility)),
652653
ungated!(
653654
unsafe(Edition2024) link_section, Normal,
654655
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"),

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,8 @@ declare_features! (
478478
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
479479
/// Allows using `#[export_stable]` which indicates that an item is exportable.
480480
(incomplete, export_stable, "1.88.0", Some(139939)),
481+
/// Allows `#[export_visibility]` on definitions of statics and/or functions.
482+
(unstable, export_visibility, "CURRENT_RUSTC_VERSION", Some(151425)),
481483
/// Externally implementable items
482484
(unstable, extern_item_impls, "1.94.0", Some(125418)),
483485
/// Allows defining `extern type`s.

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,15 @@ impl Deprecation {
187187
}
188188
}
189189

190+
/// Pre-parsed value of `#[export_visibility = ...]` attribute.
191+
///
192+
/// In a future RFC we may consider adding support for `Hidden`, `Protected`, and/or
193+
/// `Interposable`.
194+
#[derive(Clone, Copy, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
195+
pub enum ExportVisibilityAttrValue {
196+
TargetDefault,
197+
}
198+
190199
/// There are three valid forms of the attribute:
191200
/// `#[used]`, which is equivalent to `#[used(linker)]` on targets that support it, but `#[used(compiler)]` if not.
192201
/// `#[used(compiler)]`
@@ -872,6 +881,9 @@ pub enum AttributeKind {
872881
/// Represents `#[export_stable]`.
873882
ExportStable,
874883

884+
/// Represents [`#[export_visibility = ...]`](https://github.com/rust-lang/rust/issues/151425)
885+
ExportVisibility { visibility: ExportVisibilityAttrValue, span: Span },
886+
875887
/// Represents `#[ffi_const]`.
876888
FfiConst(Span),
877889

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ impl AttributeKind {
4444
EiiImpls(..) => No,
4545
ExportName { .. } => Yes,
4646
ExportStable => No,
47+
ExportVisibility { .. } => Yes,
4748
FfiConst(..) => No,
4849
FfiPure(..) => No,
4950
Fundamental { .. } => Yes,

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ pub struct CodegenFnAttrs {
7979
/// be set when `link_name` is set. This is for foreign items with the
8080
/// "raw-dylib" kind.
8181
pub link_ordinal: Option<u16>,
82+
/// The `#[export_visibility = "..."]` attribute, with values interpreted
83+
/// as follows:
84+
/// * `None` - use the "inherent" visibility (either based on the target platform, or provided via
85+
/// `-Zdefault-visibility=...` command-line flag)
86+
/// * `Some(...)` - use the item/symbol-specific visibility
87+
pub export_visibility: Option<Visibility>,
8288
/// The `#[target_feature(enable = "...")]` attribute and the enabled
8389
/// features (only enabled features are supported right now).
8490
/// Implied target features have already been applied.
@@ -224,6 +230,7 @@ impl CodegenFnAttrs {
224230
optimize: OptimizeAttr::Default,
225231
symbol_name: None,
226232
link_ordinal: None,
233+
export_visibility: None,
227234
target_features: vec![],
228235
foreign_item_symbol_aliases: vec![],
229236
safe_target_features: false,

compiler/rustc_monomorphize/src/partitioning.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,11 @@ fn mono_item_visibility<'tcx>(
931931
}
932932

933933
fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility {
934+
// If present, then symbol-specific `#[export_visibility = ...]` "wins".
935+
if let Some(visibility) = tcx.codegen_fn_attrs(id).export_visibility {
936+
return visibility;
937+
}
938+
934939
// Fast-path to avoid expensive query call below
935940
if tcx.sess.default_visibility() == SymbolVisibility::Interposable {
936941
return Visibility::Default;

0 commit comments

Comments
 (0)