Skip to content

Commit a2f9dec

Browse files
committed
Parse #[rustc_abi(..)]
1 parent f889772 commit a2f9dec

File tree

10 files changed

+276
-124
lines changed

10 files changed

+276
-124
lines changed

compiler/rustc_attr_parsing/src/attributes/test_attrs.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_hir::attrs::RustcAbiAttrKind;
12
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
23

34
use super::prelude::*;
@@ -140,3 +141,52 @@ impl<S: Stage> SingleAttributeParser<S> for ReexportTestHarnessMainParser {
140141
Some(AttributeKind::ReexportTestHarnessMain(name))
141142
}
142143
}
144+
145+
pub(crate) struct RustcAbiParser;
146+
147+
impl<S: Stage> SingleAttributeParser<S> for RustcAbiParser {
148+
const PATH: &[Symbol] = &[sym::rustc_abi];
149+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
150+
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::debug, sym::assert_eq]);
151+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
152+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
153+
Allow(Target::TyAlias),
154+
Allow(Target::Fn),
155+
Allow(Target::ForeignFn),
156+
Allow(Target::Method(MethodKind::Inherent)),
157+
Allow(Target::Method(MethodKind::Trait { body: true })),
158+
Allow(Target::Method(MethodKind::Trait { body: false })),
159+
Allow(Target::Method(MethodKind::TraitImpl)),
160+
]);
161+
162+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
163+
let Some(args) = args.list() else {
164+
cx.expected_specific_argument_and_list(cx.attr_span, &[sym::assert_eq, sym::debug]);
165+
return None;
166+
};
167+
168+
let Some(arg) = args.single() else {
169+
cx.expected_single_argument(cx.attr_span);
170+
return None;
171+
};
172+
173+
let fail_incorrect_argument =
174+
|span| cx.expected_specific_argument(span, &[sym::assert_eq, sym::debug]);
175+
176+
let Some(arg) = arg.meta_item() else {
177+
fail_incorrect_argument(args.span);
178+
return None;
179+
};
180+
181+
let kind: RustcAbiAttrKind = match arg.path().word_sym() {
182+
Some(sym::assert_eq) => RustcAbiAttrKind::AssertEq,
183+
Some(sym::debug) => RustcAbiAttrKind::Debug,
184+
None | Some(_) => {
185+
fail_incorrect_argument(arg.span());
186+
return None;
187+
}
188+
};
189+
190+
Some(AttributeKind::RustcAbi { attr_span: cx.attr_span, kind })
191+
}
192+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ attribute_parsers!(
191191
Single<ProcMacroDeriveParser>,
192192
Single<RecursionLimitParser>,
193193
Single<ReexportTestHarnessMainParser>,
194+
Single<RustcAbiParser>,
194195
Single<RustcAllocatorZeroedVariantParser>,
195196
Single<RustcBuiltinMacroParser>,
196197
Single<RustcForceInlineParser>,

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,14 @@ pub enum CoverageAttrKind {
167167
Off,
168168
}
169169

170+
/// Successfully-parsed value of a `#[rustc_abi(..)]` attribute.
171+
#[derive(Copy, Debug, Eq, PartialEq, Encodable, Decodable, Clone)]
172+
#[derive(HashStable_Generic, PrintAttribute)]
173+
pub enum RustcAbiAttrKind {
174+
Debug,
175+
AssertEq,
176+
}
177+
170178
impl Deprecation {
171179
/// Whether an item marked with #[deprecated(since = "X")] is currently
172180
/// deprecated (i.e., whether X is not greater than the current rustc
@@ -1015,6 +1023,9 @@ pub enum AttributeKind {
10151023
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
10161024
Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span },
10171025

1026+
/// Represents `#[rustc_abi(..)]`
1027+
RustcAbi { attr_span: Span, kind: RustcAbiAttrKind },
1028+
10181029
/// Represents `#[rustc_allocator]`
10191030
RustcAllocator,
10201031

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ impl AttributeKind {
8989
RecursionLimit { .. } => No,
9090
ReexportTestHarnessMain(..) => No,
9191
Repr { .. } => No,
92+
RustcAbi { .. } => No,
9293
RustcAllocator => No,
9394
RustcAllocatorZeroed => No,
9495
RustcAllocatorZeroedVariant { .. } => Yes,

compiler/rustc_passes/src/abi_test.rs

Lines changed: 99 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
use rustc_hir::Attribute;
1+
use rustc_hir::attrs::{AttributeKind, RustcAbiAttrKind};
22
use rustc_hir::def::DefKind;
33
use rustc_hir::def_id::LocalDefId;
4+
use rustc_hir::find_attr;
45
use rustc_middle::span_bug;
56
use rustc_middle::ty::layout::{FnAbiError, LayoutError};
67
use rustc_middle::ty::{self, GenericArgs, Instance, Ty, TyCtxt};
8+
use rustc_span::Span;
79
use rustc_span::source_map::Spanned;
8-
use rustc_span::sym;
910
use rustc_target::callconv::FnAbi;
1011

1112
use super::layout_test::ensure_wf;
@@ -17,17 +18,19 @@ pub fn test_abi(tcx: TyCtxt<'_>) {
1718
return;
1819
}
1920
for id in tcx.hir_crate_items(()).definitions() {
20-
for attr in tcx.get_attrs(id, sym::rustc_abi) {
21-
match tcx.def_kind(id) {
22-
DefKind::Fn | DefKind::AssocFn => {
23-
dump_abi_of_fn_item(tcx, id, attr);
24-
}
25-
DefKind::TyAlias => {
26-
dump_abi_of_fn_type(tcx, id, attr);
27-
}
28-
_ => {
29-
tcx.dcx().emit_err(AbiInvalidAttribute { span: tcx.def_span(id) });
30-
}
21+
let Some((attr_span, attr_kind)) = find_attr!(tcx.get_all_attrs(id), AttributeKind::RustcAbi{ attr_span, kind } => (*attr_span, *kind))
22+
else {
23+
continue;
24+
};
25+
match tcx.def_kind(id) {
26+
DefKind::Fn | DefKind::AssocFn => {
27+
dump_abi_of_fn_item(tcx, id, attr_span, attr_kind);
28+
}
29+
DefKind::TyAlias => {
30+
dump_abi_of_fn_type(tcx, id, attr_span, attr_kind);
31+
}
32+
_ => {
33+
tcx.dcx().emit_err(AbiInvalidAttribute { span: tcx.def_span(id) });
3134
}
3235
}
3336
}
@@ -49,7 +52,12 @@ fn unwrap_fn_abi<'tcx>(
4952
}
5053
}
5154

52-
fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
55+
fn dump_abi_of_fn_item(
56+
tcx: TyCtxt<'_>,
57+
item_def_id: LocalDefId,
58+
attr_span: Span,
59+
attr_kind: RustcAbiAttrKind,
60+
) {
5361
let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id);
5462
let args = GenericArgs::identity_for_item(tcx, item_def_id);
5563
let instance = match Instance::try_resolve(tcx, typing_env, item_def_id.into(), args) {
@@ -75,22 +83,18 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
7583

7684
// Check out the `#[rustc_abi(..)]` attribute to tell what to dump.
7785
// The `..` are the names of fields to dump.
78-
let meta_items = attr.meta_item_list().unwrap_or_default();
79-
for meta_item in meta_items {
80-
match meta_item.name() {
81-
Some(sym::debug) => {
82-
let fn_name = tcx.item_name(item_def_id);
83-
tcx.dcx().emit_err(AbiOf {
84-
span: tcx.def_span(item_def_id),
85-
fn_name,
86-
// FIXME: using the `Debug` impl here isn't ideal.
87-
fn_abi: format!("{:#?}", abi),
88-
});
89-
}
90-
91-
_ => {
92-
tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() });
93-
}
86+
match attr_kind {
87+
RustcAbiAttrKind::Debug => {
88+
let fn_name = tcx.item_name(item_def_id);
89+
tcx.dcx().emit_err(AbiOf {
90+
span: tcx.def_span(item_def_id),
91+
fn_name,
92+
// FIXME: using the `Debug` impl here isn't ideal.
93+
fn_abi: format!("{:#?}", abi),
94+
});
95+
}
96+
_ => {
97+
tcx.dcx().emit_err(UnrecognizedArgument { span: attr_span });
9498
}
9599
}
96100
}
@@ -109,24 +113,29 @@ fn test_abi_eq<'tcx>(abi1: &'tcx FnAbi<'tcx, Ty<'tcx>>, abi2: &'tcx FnAbi<'tcx,
109113
&& abi1.args.iter().zip(abi2.args.iter()).all(|(arg1, arg2)| arg1.eq_abi(arg2))
110114
}
111115

112-
fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
116+
fn dump_abi_of_fn_type(
117+
tcx: TyCtxt<'_>,
118+
item_def_id: LocalDefId,
119+
attr_span: Span,
120+
attr_kind: RustcAbiAttrKind,
121+
) {
113122
let typing_env = ty::TypingEnv::post_analysis(tcx, item_def_id);
114123
let ty = tcx.type_of(item_def_id).instantiate_identity();
115124
let span = tcx.def_span(item_def_id);
116125
if !ensure_wf(tcx, typing_env, ty, item_def_id, span) {
117126
return;
118127
}
119-
let meta_items = attr.meta_item_list().unwrap_or_default();
120-
for meta_item in meta_items {
121-
match meta_item.name() {
122-
Some(sym::debug) => {
123-
let ty::FnPtr(sig_tys, hdr) = ty.kind() else {
124-
span_bug!(
125-
meta_item.span(),
126-
"`#[rustc_abi(debug)]` on a type alias requires function pointer type"
127-
);
128-
};
129-
let abi = unwrap_fn_abi(
128+
129+
match attr_kind {
130+
RustcAbiAttrKind::Debug => {
131+
let ty::FnPtr(sig_tys, hdr) = ty.kind() else {
132+
span_bug!(
133+
attr_span,
134+
"`#[rustc_abi(debug)]` on a type alias requires function pointer type"
135+
);
136+
};
137+
let abi =
138+
unwrap_fn_abi(
130139
tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((
131140
sig_tys.with(*hdr),
132141
/* extra_args */ ty::List::empty(),
@@ -135,61 +144,57 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
135144
item_def_id,
136145
);
137146

138-
let fn_name = tcx.item_name(item_def_id);
139-
tcx.dcx().emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) });
140-
}
141-
Some(sym::assert_eq) => {
142-
let ty::Tuple(fields) = ty.kind() else {
143-
span_bug!(
144-
meta_item.span(),
145-
"`#[rustc_abi(assert_eq)]` on a type alias requires pair type"
146-
);
147-
};
148-
let [field1, field2] = ***fields else {
149-
span_bug!(
150-
meta_item.span(),
151-
"`#[rustc_abi(assert_eq)]` on a type alias requires pair type"
152-
);
153-
};
154-
let ty::FnPtr(sig_tys1, hdr1) = field1.kind() else {
155-
span_bug!(
156-
meta_item.span(),
157-
"`#[rustc_abi(assert_eq)]` on a type alias requires pair of function pointer types"
158-
);
159-
};
160-
let abi1 = unwrap_fn_abi(
161-
tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((
162-
sig_tys1.with(*hdr1),
163-
/* extra_args */ ty::List::empty(),
164-
))),
165-
tcx,
166-
item_def_id,
147+
let fn_name = tcx.item_name(item_def_id);
148+
tcx.dcx().emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) });
149+
}
150+
RustcAbiAttrKind::AssertEq => {
151+
let ty::Tuple(fields) = ty.kind() else {
152+
span_bug!(
153+
attr_span,
154+
"`#[rustc_abi(assert_eq)]` on a type alias requires pair type"
167155
);
168-
let ty::FnPtr(sig_tys2, hdr2) = field2.kind() else {
169-
span_bug!(
170-
meta_item.span(),
171-
"`#[rustc_abi(assert_eq)]` on a type alias requires pair of function pointer types"
172-
);
173-
};
174-
let abi2 = unwrap_fn_abi(
175-
tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((
176-
sig_tys2.with(*hdr2),
177-
/* extra_args */ ty::List::empty(),
178-
))),
179-
tcx,
180-
item_def_id,
156+
};
157+
let [field1, field2] = ***fields else {
158+
span_bug!(
159+
attr_span,
160+
"`#[rustc_abi(assert_eq)]` on a type alias requires pair type"
161+
);
162+
};
163+
let ty::FnPtr(sig_tys1, hdr1) = field1.kind() else {
164+
span_bug!(
165+
attr_span,
166+
"`#[rustc_abi(assert_eq)]` on a type alias requires pair of function pointer types"
181167
);
168+
};
169+
let abi1 = unwrap_fn_abi(
170+
tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((
171+
sig_tys1.with(*hdr1),
172+
/* extra_args */ ty::List::empty(),
173+
))),
174+
tcx,
175+
item_def_id,
176+
);
177+
let ty::FnPtr(sig_tys2, hdr2) = field2.kind() else {
178+
span_bug!(
179+
attr_span,
180+
"`#[rustc_abi(assert_eq)]` on a type alias requires pair of function pointer types"
181+
);
182+
};
183+
let abi2 = unwrap_fn_abi(
184+
tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((
185+
sig_tys2.with(*hdr2),
186+
/* extra_args */ ty::List::empty(),
187+
))),
188+
tcx,
189+
item_def_id,
190+
);
182191

183-
if !test_abi_eq(abi1, abi2) {
184-
tcx.dcx().emit_err(AbiNe {
185-
span,
186-
left: format!("{:#?}", abi1),
187-
right: format!("{:#?}", abi2),
188-
});
189-
}
190-
}
191-
_ => {
192-
tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() });
192+
if !test_abi_eq(abi1, abi2) {
193+
tcx.dcx().emit_err(AbiNe {
194+
span,
195+
left: format!("{:#?}", abi1),
196+
right: format!("{:#?}", abi2),
197+
});
193198
}
194199
}
195200
}

compiler/rustc_passes/src/check_attr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
287287
| AttributeKind::ReexportTestHarnessMain(..)
288288
// handled below this loop and elsewhere
289289
| AttributeKind::Repr { .. }
290+
| AttributeKind::RustcAbi { .. }
290291
| AttributeKind::RustcAllocator
291292
| AttributeKind::RustcAllocatorZeroed
292293
| AttributeKind::RustcAllocatorZeroedVariant { .. }
@@ -392,7 +393,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
392393
| sym::rustc_conversion_suggestion
393394
| sym::rustc_deprecated_safe_2024
394395
| sym::rustc_test_marker
395-
| sym::rustc_abi
396396
| sym::rustc_layout
397397
| sym::rustc_proc_macro_decls
398398
| sym::rustc_never_type_options

0 commit comments

Comments
 (0)