Skip to content

Commit 1ef6c37

Browse files
committed
Auto merge of #151431 - anforowicz:export-visibility, r=<try>
Add new unstable attribute: `#[export_visibility = ...]`. try-job: test-various try-job: x86_64-gnu-aux try-job: x86_64-gnu-llvm-21-3 try-job: x86_64-msvc-1 try-job: aarch64-apple try-job: x86_64-mingw-1
2 parents d2218f5 + a980a3a commit 1ef6c37

23 files changed

Lines changed: 482 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 RustcObjcClassParser;
157196

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

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ attribute_parsers!(
184184
Single<DeprecatedParser>,
185185
Single<DoNotRecommendParser>,
186186
Single<ExportNameParser>,
187+
Single<ExportVisibilityParser>,
187188
Single<IgnoreParser>,
188189
Single<InlineParser>,
189190
Single<InstructionSetParser>,

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_abi::{Align, ExternAbi};
22
use rustc_hir::attrs::{
3-
AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy,
3+
AttributeKind, EiiImplResolution, ExportVisibilityAttrValue, InlineAttr, Linkage, RtsanSetting,
4+
UsedBy,
45
};
56
use rustc_hir::def::DefKind;
67
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
@@ -70,6 +71,13 @@ fn process_builtin_attrs(
7071
match attr {
7172
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
7273
AttributeKind::ExportName { name, .. } => codegen_fn_attrs.symbol_name = Some(*name),
74+
AttributeKind::ExportVisibility { visibility, .. } => {
75+
codegen_fn_attrs.export_visibility = Some(match visibility {
76+
ExportVisibilityAttrValue::TargetDefault => {
77+
tcx.sess.default_visibility().into()
78+
}
79+
});
80+
}
7381
AttributeKind::Inline(inline, span) => {
7482
codegen_fn_attrs.inline = *inline;
7583
interesting_spans.inline = Some(*span);
@@ -533,6 +541,16 @@ fn handle_lang_items(
533541
}
534542
err.emit();
535543
}
544+
545+
if codegen_fn_attrs.export_visibility.is_some() {
546+
let span = find_attr!(attrs, ExportVisibility{span, ..} => *span).unwrap_or_default();
547+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
548+
tcx.dcx().emit_err(errors::ExportVisibilityWithRustcStdInternalSymbol { span });
549+
}
550+
if !codegen_fn_attrs.contains_extern_indicator() {
551+
tcx.dcx().emit_err(errors::ExportVisibilityWithoutNoMangleNorExportName { span });
552+
}
553+
}
536554
}
537555

538556
/// 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
@@ -1268,3 +1268,20 @@ pub(crate) struct LtoProcMacro;
12681268
#[diag("cannot prefer dynamic linking when performing LTO")]
12691269
#[note("only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO")]
12701270
pub(crate) struct DynamicLinkingWithLTO;
1271+
1272+
#[derive(Diagnostic)]
1273+
#[diag("`#[export_visibility = ...]` cannot be used on internal language items")]
1274+
pub(crate) struct ExportVisibilityWithRustcStdInternalSymbol {
1275+
#[primary_span]
1276+
pub span: Span,
1277+
}
1278+
1279+
#[derive(Diagnostic)]
1280+
#[diag(
1281+
"`#[export_visibility = ...]` will be ignored \
1282+
without `export_name`, `no_mangle`, or similar attribute"
1283+
)]
1284+
pub(crate) struct ExportVisibilityWithoutNoMangleNorExportName {
1285+
#[primary_span]
1286+
pub span: Span,
1287+
}

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
@@ -476,6 +476,8 @@ declare_features! (
476476
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
477477
/// Allows using `#[export_stable]` which indicates that an item is exportable.
478478
(incomplete, export_stable, "1.88.0", Some(139939)),
479+
/// Allows `#[export_visibility]` on definitions of statics and/or functions.
480+
(unstable, export_visibility, "CURRENT_RUSTC_VERSION", Some(151425)),
479481
/// Externally implementable items
480482
(unstable, extern_item_impls, "1.94.0", Some(125418)),
481483
/// Allows defining `extern type`s.

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,15 @@ impl Deprecation {
251251
}
252252
}
253253

254+
/// Pre-parsed value of `#[export_visibility = ...]` attribute.
255+
///
256+
/// In a future RFC we may consider adding support for `Hidden`, `Protected`, and/or
257+
/// `Interposable`.
258+
#[derive(Clone, Copy, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
259+
pub enum ExportVisibilityAttrValue {
260+
TargetDefault,
261+
}
262+
254263
/// There are three valid forms of the attribute:
255264
/// `#[used]`, which is equivalent to `#[used(linker)]` on targets that support it, but `#[used(compiler)]` if not.
256265
/// `#[used(compiler)]`
@@ -1045,6 +1054,12 @@ pub enum AttributeKind {
10451054
/// Represents `#[export_stable]`.
10461055
ExportStable,
10471056

1057+
/// Represents [`#[export_visibility = ...]`](https://github.com/rust-lang/rust/issues/151425)
1058+
ExportVisibility {
1059+
visibility: ExportVisibilityAttrValue,
1060+
span: Span,
1061+
},
1062+
10481063
/// Represents `#[feature(...)]`
10491064
Feature(ThinVec<Ident>, Span),
10501065

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

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

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)