Skip to content

Commit 5afce2b

Browse files
Port #[no_mangle] to new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
1 parent 6d0c9e2 commit 5afce2b

File tree

18 files changed

+115
-69
lines changed

18 files changed

+115
-69
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ pub enum AttributeKind {
233233

234234
/// Represents `#[rustc_macro_transparency]`.
235235
MacroTransparency(Transparency),
236+
/// Represents `#[no_mangle]`
237+
NoMangle(Span),
236238
/// Represents `#[optimize(size|speed)]`
237239
Optimize(OptimizeAttr, Span),
238240
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,21 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
5656
Some(AttributeKind::Cold(cx.attr_span))
5757
}
5858
}
59+
60+
pub(crate) struct NoMangleParser;
61+
62+
impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
63+
const PATH: &[rustc_span::Symbol] = &[sym::no_mangle];
64+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
65+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
66+
const TEMPLATE: AttributeTemplate = template!(Word);
67+
68+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
69+
if !args.no_args() {
70+
cx.expected_no_args(args.span().unwrap_or(cx.attr_span));
71+
return None;
72+
};
73+
74+
Some(AttributeKind::NoMangle(cx.attr_span))
75+
}
76+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_session::Session;
1515
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
1616

1717
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
18-
use crate::attributes::codegen_attrs::{ColdParser, OptimizeParser};
18+
use crate::attributes::codegen_attrs::{ColdParser, NoMangleParser, OptimizeParser};
1919
use crate::attributes::confusables::ConfusablesParser;
2020
use crate::attributes::deprecation::DeprecationParser;
2121
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -110,6 +110,7 @@ attribute_parsers!(
110110
Single<ConstStabilityIndirectParser>,
111111
Single<DeprecationParser>,
112112
Single<InlineParser>,
113+
Single<NoMangleParser>,
113114
Single<OptimizeParser>,
114115
Single<RustcForceInlineParser>,
115116
Single<TransparencyParser>,

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple time
221221
222222
codegen_ssa_no_field = no field `{$name}`
223223
224+
codegen_ssa_no_mangle_nameless = `#[no_mangle]` cannot be used on {$definition} as it has no name
225+
224226
codegen_ssa_no_module_named =
225227
no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names}
226228

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use rustc_span::{Ident, Span, sym};
2323
use rustc_target::spec::SanitizerSet;
2424

2525
use crate::errors;
26+
use crate::errors::NoMangleNameless;
2627
use crate::target_features::{
2728
check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr,
2829
};
@@ -87,7 +88,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
8788
let mut link_ordinal_span = None;
8889
let mut no_sanitize_span = None;
8990
let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default();
90-
let mut no_mangle_span = None;
9191

9292
for attr in attrs.iter() {
9393
// In some cases, attribute are only valid on functions, but it's the `check_attr`
@@ -122,6 +122,25 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
122122
}
123123
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
124124
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
125+
AttributeKind::NoMangle(attr_span) => {
126+
if tcx.opt_item_name(did.to_def_id()).is_some() {
127+
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
128+
mixed_export_name_no_mangle_lint_state.track_no_mangle(
129+
*attr_span,
130+
tcx.local_def_id_to_hir_id(did),
131+
attr,
132+
);
133+
} else {
134+
tcx.dcx().emit_err(NoMangleNameless {
135+
span: *attr_span,
136+
definition: format!(
137+
"{} {}",
138+
tcx.def_descr_article(did.to_def_id()),
139+
tcx.def_descr(did.to_def_id())
140+
),
141+
});
142+
}
143+
}
125144
_ => {}
126145
}
127146
}
@@ -141,28 +160,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
141160
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
142161
}
143162
sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
144-
sym::no_mangle => {
145-
no_mangle_span = Some(attr.span());
146-
if tcx.opt_item_name(did.to_def_id()).is_some() {
147-
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
148-
mixed_export_name_no_mangle_lint_state.track_no_mangle(
149-
attr.span(),
150-
tcx.local_def_id_to_hir_id(did),
151-
attr,
152-
);
153-
} else {
154-
tcx.dcx()
155-
.struct_span_err(
156-
attr.span(),
157-
format!(
158-
"`#[no_mangle]` cannot be used on {} {} as it has no name",
159-
tcx.def_descr_article(did.to_def_id()),
160-
tcx.def_descr(did.to_def_id()),
161-
),
162-
)
163-
.emit();
164-
}
165-
}
166163
sym::rustc_std_internal_symbol => {
167164
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
168165
}
@@ -544,12 +541,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
544541
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
545542
&& codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
546543
{
544+
let no_mangle_span =
545+
find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span)
546+
.unwrap_or_default();
547547
let lang_item =
548548
lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name));
549549
let mut err = tcx
550550
.dcx()
551551
.struct_span_err(
552-
no_mangle_span.unwrap_or_default(),
552+
no_mangle_span,
553553
"`#[no_mangle]` cannot be used on internal language items",
554554
)
555555
.with_note("Rustc requires this item to have a specific mangled name.")

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,3 +1310,11 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_
13101310
diag
13111311
}
13121312
}
1313+
1314+
#[derive(Diagnostic)]
1315+
#[diag(codegen_ssa_no_mangle_nameless)]
1316+
pub(crate) struct NoMangleNameless {
1317+
#[primary_span]
1318+
pub span: Span,
1319+
pub definition: String,
1320+
}

compiler/rustc_lint/src/builtin.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
2121
use rustc_ast::visit::{FnCtxt, FnKind};
2222
use rustc_ast::{self as ast, *};
2323
use rustc_ast_pretty::pprust::expr_to_string;
24+
use rustc_attr_data_structures::{AttributeKind, find_attr};
2425
use rustc_errors::{Applicability, LintDiagnostic};
2526
use rustc_feature::GateIssue;
2627
use rustc_hir as hir;
@@ -954,7 +955,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN
954955
impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
955956
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
956957
let attrs = cx.tcx.hir_attrs(it.hir_id());
957-
let check_no_mangle_on_generic_fn = |attr: &hir::Attribute,
958+
let check_no_mangle_on_generic_fn = |attr_span: Span,
958959
impl_generics: Option<&hir::Generics<'_>>,
959960
generics: &hir::Generics<'_>,
960961
span| {
@@ -967,7 +968,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
967968
cx.emit_span_lint(
968969
NO_MANGLE_GENERIC_ITEMS,
969970
span,
970-
BuiltinNoMangleGeneric { suggestion: attr.span() },
971+
BuiltinNoMangleGeneric { suggestion: attr_span },
971972
);
972973
break;
973974
}
@@ -976,14 +977,15 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
976977
};
977978
match it.kind {
978979
hir::ItemKind::Fn { generics, .. } => {
979-
if let Some(attr) = attr::find_by_name(attrs, sym::export_name)
980-
.or_else(|| attr::find_by_name(attrs, sym::no_mangle))
980+
if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name)
981+
.map(|at| at.span())
982+
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
981983
{
982-
check_no_mangle_on_generic_fn(attr, None, generics, it.span);
984+
check_no_mangle_on_generic_fn(attr_span, None, generics, it.span);
983985
}
984986
}
985987
hir::ItemKind::Const(..) => {
986-
if attr::contains_name(attrs, sym::no_mangle) {
988+
if find_attr!(attrs, AttributeKind::NoMangle(..)) {
987989
// account for "pub const" (#45562)
988990
let start = cx
989991
.tcx
@@ -1008,11 +1010,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
10081010
for it in *items {
10091011
if let hir::AssocItemKind::Fn { .. } = it.kind {
10101012
let attrs = cx.tcx.hir_attrs(it.id.hir_id());
1011-
if let Some(attr) = attr::find_by_name(attrs, sym::export_name)
1012-
.or_else(|| attr::find_by_name(attrs, sym::no_mangle))
1013+
if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name)
1014+
.map(|at| at.span())
1015+
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
10131016
{
10141017
check_no_mangle_on_generic_fn(
1015-
attr,
1018+
attr_span,
10161019
Some(generics),
10171020
cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(),
10181021
it.span,

compiler/rustc_lint/src/nonstandard_style.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_abi::ExternAbi;
2-
use rustc_attr_data_structures::{AttributeKind, ReprAttr};
2+
use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr};
33
use rustc_attr_parsing::AttributeParser;
44
use rustc_hir::def::{DefKind, Res};
55
use rustc_hir::intravisit::FnKind;
@@ -396,7 +396,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
396396
match &fk {
397397
FnKind::Method(ident, sig, ..) => match method_context(cx, id) {
398398
MethodLateContext::PlainImpl => {
399-
if sig.header.abi != ExternAbi::Rust && cx.tcx.has_attr(id, sym::no_mangle) {
399+
if sig.header.abi != ExternAbi::Rust
400+
&& find_attr!(cx.tcx.get_all_attrs(id), AttributeKind::NoMangle(..))
401+
{
400402
return;
401403
}
402404
self.check_snake_case(cx, "method", ident);
@@ -408,7 +410,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
408410
},
409411
FnKind::ItemFn(ident, _, header) => {
410412
// Skip foreign-ABI #[no_mangle] functions (Issue #31924)
411-
if header.abi != ExternAbi::Rust && cx.tcx.has_attr(id, sym::no_mangle) {
413+
if header.abi != ExternAbi::Rust
414+
&& find_attr!(cx.tcx.get_all_attrs(id), AttributeKind::NoMangle(..))
415+
{
412416
return;
413417
}
414418
self.check_snake_case(cx, "function", ident);
@@ -514,7 +518,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
514518
let attrs = cx.tcx.hir_attrs(it.hir_id());
515519
match it.kind {
516520
hir::ItemKind::Static(_, ident, ..)
517-
if !ast::attr::contains_name(attrs, sym::no_mangle) =>
521+
if !find_attr!(attrs, AttributeKind::NoMangle(..)) =>
518522
{
519523
NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident);
520524
}

compiler/rustc_passes/src/check_attr.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
163163
Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
164164
self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target)
165165
}
166+
Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => {
167+
self.check_no_mangle(hir_id, *attr_span, span, target)
168+
}
166169
Attribute::Unparsed(_) => {
167170
match attr.path().as_slice() {
168171
[sym::diagnostic, sym::do_not_recommend, ..] => {
@@ -250,7 +253,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
250253
[sym::link, ..] => self.check_link(hir_id, attr, span, target),
251254
[sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target),
252255
[sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
253-
[sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target),
254256
[sym::macro_use, ..] | [sym::macro_escape, ..] => {
255257
self.check_macro_use(hir_id, attr, target)
256258
}
@@ -688,6 +690,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
688690
AttributeKind::Deprecation { .. }
689691
| AttributeKind::Repr { .. }
690692
| AttributeKind::Align { .. }
693+
| AttributeKind::NoMangle(..)
691694
| AttributeKind::Cold(..),
692695
) => {
693696
continue;
@@ -1936,7 +1939,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
19361939
}
19371940

19381941
/// Checks if `#[no_mangle]` is applied to a function or static.
1939-
fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1942+
fn check_no_mangle(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
19401943
match target {
19411944
Target::Static | Target::Fn => {}
19421945
Target::Method(..) if self.is_impl_item(hir_id) => {}
@@ -1945,7 +1948,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
19451948
// erroneously allowed it and some crates used it accidentally, to be compatible
19461949
// with crates depending on them, we can't throw an error here.
19471950
Target::Field | Target::Arm | Target::MacroDef => {
1948-
self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_mangle");
1951+
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "no_mangle");
19491952
}
19501953
// FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error
19511954
// The error should specify that the item that is wrong is specifically a *foreign* fn/static
@@ -1959,8 +1962,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
19591962
self.tcx.emit_node_span_lint(
19601963
UNUSED_ATTRIBUTES,
19611964
hir_id,
1962-
attr.span(),
1963-
errors::NoMangleForeign { span, attr_span: attr.span(), foreign_item_kind },
1965+
attr_span,
1966+
errors::NoMangleForeign { span, attr_span, foreign_item_kind },
19641967
);
19651968
}
19661969
_ => {
@@ -1969,7 +1972,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
19691972
self.tcx.emit_node_span_lint(
19701973
UNUSED_ATTRIBUTES,
19711974
hir_id,
1972-
attr.span(),
1975+
attr_span,
19731976
errors::NoMangle { span },
19741977
);
19751978
}

src/librustdoc/clean/types.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,6 @@ impl Item {
749749
pub(crate) fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String> {
750750
const ALLOWED_ATTRIBUTES: &[Symbol] =
751751
&[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
752-
753752
self.attrs
754753
.other_attrs
755754
.iter()
@@ -767,7 +766,9 @@ impl Item {
767766
s
768767
}),
769768
}
770-
} else if attr.has_any_name(ALLOWED_ATTRIBUTES) {
769+
} else if attr.has_any_name(ALLOWED_ATTRIBUTES)
770+
|| matches!(attr, hir::Attribute::Parsed(AttributeKind::NoMangle(..)))
771+
{
771772
Some(
772773
rustc_hir_pretty::attribute_to_string(&tcx, attr)
773774
.replace("\\\n", "")

src/rustdoc-json-types/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
3737
// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
3838
// are deliberately not in a doc comment, because they need not be in public docs.)
3939
//
40-
// Latest feature: improve handling of generic args
41-
pub const FORMAT_VERSION: u32 = 51;
40+
// Latest feature: Pretty printing of no_mangle attributes changed
41+
pub const FORMAT_VERSION: u32 = 52;
4242

4343
/// The root of the emitted JSON blob.
4444
///

src/tools/clippy/clippy_lints/src/functions/must_use.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use clippy_utils::ty::is_must_use_ty;
1515
use clippy_utils::visitors::for_each_expr_without_closures;
1616
use clippy_utils::{return_ty, trait_ref_of_method};
1717
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
18+
use rustc_attr_data_structures::{AttributeKind, find_attr};
1819

1920
use core::ops::ControlFlow;
2021

@@ -33,7 +34,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
3334
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
3435
if let Some(attr) = attr {
3536
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
36-
} else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
37+
} else if is_public && !is_proc_macro(attrs) && !find_attr!(attrs, AttributeKind::NoMangle(..)) {
3738
check_must_use_candidate(
3839
cx,
3940
sig.decl,

src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use rustc_hir::{Item, ItemKind};
66
use rustc_lint::{LateContext, LateLintPass};
77
use rustc_session::declare_lint_pass;
88
use rustc_span::{BytePos, Pos};
9+
use rustc_attr_data_structures::AttributeKind;
10+
use rustc_hir::Attribute;
911

1012
declare_clippy_lint! {
1113
/// ### What it does
@@ -44,8 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
4446
let mut app = Applicability::MaybeIncorrect;
4547
let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(ident.span.lo()), "..", &mut app);
4648
for attr in attrs {
47-
if let Some(ident) = attr.ident()
48-
&& ident.name == rustc_span::sym::no_mangle
49+
if let Attribute::Parsed(AttributeKind::NoMangle(attr_span)) = attr
4950
&& fn_sig.header.abi == ExternAbi::Rust
5051
&& let Some((fn_attrs, _)) = fn_snippet.rsplit_once("fn")
5152
&& !fn_attrs.contains("extern")
@@ -54,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
5455
.span
5556
.with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len()))
5657
.shrink_to_lo();
57-
let attr_snippet = snippet(cx, attr.span(), "..");
58+
let attr_snippet = snippet(cx, *attr_span, "..");
5859

5960
span_lint_and_then(
6061
cx,

0 commit comments

Comments
 (0)