Skip to content

Commit b830801

Browse files
committed
Port #[rustc_skip_during_method_dispatch] to the new attribute system
1 parent 111e9bc commit b830801

File tree

16 files changed

+233
-33
lines changed

16 files changed

+233
-33
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ pub enum AttributeKind {
253253
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
254254
Repr(ThinVec<(ReprAttr, Span)>),
255255

256+
/// Represents `#[rustc_skip_during_method_dispatch]`.
257+
SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
258+
256259
/// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
257260
Stability {
258261
stability: Stability,

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,9 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
4848
const TEMPLATE: AttributeTemplate = template!(Word);
4949

5050
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
51-
if !args.no_args() {
52-
cx.expected_no_args(args.span().unwrap_or(cx.attr_span));
53-
return None;
54-
};
55-
51+
if let Err(span) = args.no_args() {
52+
cx.expected_no_args(span);
53+
}
5654
Some(AttributeKind::Cold(cx.attr_span))
5755
}
5856
}

compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
1414
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
1515
const TEMPLATE: AttributeTemplate = template!(Word);
1616

17-
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
18-
// FIXME: check that there's no args (this is currently checked elsewhere)
17+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
18+
if let Err(span) = args.no_args() {
19+
cx.expected_no_args(span);
20+
}
1921
Some(AttributeKind::AsPtr(cx.attr_span))
2022
}
2123
}

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub(crate) mod inline;
3535
pub(crate) mod lint_helpers;
3636
pub(crate) mod must_use;
3737
pub(crate) mod repr;
38+
pub(crate) mod resolution;
3839
pub(crate) mod semantics;
3940
pub(crate) mod stability;
4041
pub(crate) mod transparency;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use core::mem;
2+
3+
use rustc_attr_data_structures::AttributeKind;
4+
use rustc_feature::{AttributeTemplate, template};
5+
use rustc_span::{Symbol, sym};
6+
7+
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
8+
use crate::context::{AcceptContext, Stage};
9+
use crate::parser::ArgParser;
10+
11+
pub(crate) struct SkipDuringMethodDispatchParser;
12+
13+
impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
14+
const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch];
15+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
16+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
17+
18+
const TEMPLATE: AttributeTemplate = template!(List: "array, boxed_slice");
19+
20+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
21+
let mut array = false;
22+
let mut boxed_slice = false;
23+
let Some(args) = args.list() else {
24+
cx.expected_list(cx.attr_span);
25+
return None;
26+
};
27+
if args.is_empty() {
28+
cx.expected_at_least_one_argument(args.span);
29+
return None;
30+
}
31+
for arg in args.mixed() {
32+
let Some(arg) = arg.meta_item() else {
33+
cx.unexpected_literal(arg.span());
34+
continue;
35+
};
36+
if let Err(span) = arg.args().no_args() {
37+
cx.expected_no_args(span);
38+
}
39+
let path = arg.path();
40+
let (key, skip): (Symbol, &mut bool) = match path.word_sym() {
41+
Some(key @ sym::array) => (key, &mut array),
42+
Some(key @ sym::boxed_slice) => (key, &mut boxed_slice),
43+
_ => {
44+
cx.expected_specific_argument(path.span(), vec!["array", "boxed_slice"]);
45+
continue;
46+
}
47+
};
48+
if mem::replace(skip, true) {
49+
cx.duplicate_key(arg.span(), key);
50+
}
51+
}
52+
Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span })
53+
}
54+
}

compiler/rustc_attr_parsing/src/attributes/stability.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,10 @@ impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
139139
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
140140
const TEMPLATE: AttributeTemplate = template!(Word);
141141

142-
fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
142+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
143+
if let Err(span) = args.no_args() {
144+
cx.expected_no_args(span);
145+
}
143146
Some(AttributeKind::ConstStabilityIndirect)
144147
}
145148
}
@@ -361,7 +364,7 @@ pub(crate) fn parse_unstability<S: Stage>(
361364
};
362365
}
363366
Some(sym::soft) => {
364-
if !param.args().no_args() {
367+
if !param.args().is_no_args() {
365368
cx.emit_err(session_diagnostics::SoftNoArgs { span: param.span() });
366369
}
367370
is_soft = true;

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
2222
use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
2323
use crate::attributes::must_use::MustUseParser;
2424
use crate::attributes::repr::{AlignParser, ReprParser};
25+
use crate::attributes::resolution::SkipDuringMethodDispatchParser;
2526
use crate::attributes::semantics::MayDangleParser;
2627
use crate::attributes::stability::{
2728
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
@@ -117,6 +118,7 @@ attribute_parsers!(
117118
Single<OptimizeParser>,
118119
Single<PubTransparentParser>,
119120
Single<RustcForceInlineParser>,
121+
Single<SkipDuringMethodDispatchParser>,
120122
Single<TransparencyParser>,
121123
// tidy-alphabetical-end
122124
];
@@ -295,6 +297,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
295297
})
296298
}
297299

300+
pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
301+
self.emit_err(AttributeParseError {
302+
span,
303+
attr_span: self.attr_span,
304+
template: self.template.clone(),
305+
attribute: self.attr_path.clone(),
306+
reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
307+
})
308+
}
309+
298310
pub(crate) fn expected_specific_argument(
299311
&self,
300312
span: Span,

compiler/rustc_attr_parsing/src/parser.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,20 @@ impl<'a> ArgParser<'a> {
162162
}
163163

164164
/// Asserts that there are no arguments
165-
pub fn no_args(&self) -> bool {
165+
pub fn is_no_args(&self) -> bool {
166166
matches!(self, Self::NoArgs)
167167
}
168+
169+
/// Assert that there were no args.
170+
/// If there were, get a span to the arguments
171+
/// (to pass to [`AcceptContext::expected_no_args`](crate::context::AcceptContext::expected_no_args)).
172+
pub fn no_args(&self) -> Result<(), Span> {
173+
match self {
174+
Self::NoArgs => Ok(()),
175+
Self::List(args) => Err(args.span),
176+
Self::NameValue(args) => Err(args.eq_span.to(args.value_span)),
177+
}
178+
}
168179
}
169180

170181
/// Inside lists, values could be either literals, or more deeply nested meta items.

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ pub(crate) struct UnrecognizedReprHint {
485485
pub(crate) enum AttributeParseErrorReason {
486486
ExpectedNoArgs,
487487
ExpectedStringLiteral { byte_string: Option<Span> },
488+
ExpectedAtLeastOneArgument,
488489
ExpectedSingleArgument,
489490
ExpectedList,
490491
UnexpectedLiteral,
@@ -528,6 +529,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
528529
diag.span_label(self.span, "expected a single argument here");
529530
diag.code(E0805);
530531
}
532+
AttributeParseErrorReason::ExpectedAtLeastOneArgument => {
533+
diag.span_label(self.span, "expected at least 1 argument here");
534+
}
531535
AttributeParseErrorReason::ExpectedList => {
532536
diag.span_label(self.span, "expected this to be a list");
533537
}

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
10831083
"the `#[rustc_main]` attribute is used internally to specify test entry point function",
10841084
),
10851085
rustc_attr!(
1086-
rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing,
1086+
rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), ErrorFollowing,
10871087
EncodeCrossCrate::No,
10881088
"the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
10891089
from method dispatch when the receiver is of the following type, for compatibility in \

0 commit comments

Comments
 (0)