Skip to content

Commit e015bc7

Browse files
committed
Port #[rustc_skip_during_method_dispatch] to the new attribute system
1 parent f9c15f4 commit e015bc7

File tree

12 files changed

+210
-23
lines changed

12 files changed

+210
-23
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

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

233+
/// Represents `#[rustc_skip_during_method_dispatch]`.
234+
SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
235+
233236
/// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
234237
Stability {
235238
stability: Stability,

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub(crate) mod deprecation;
3333
pub(crate) mod inline;
3434
pub(crate) mod lint_helpers;
3535
pub(crate) mod repr;
36+
pub(crate) mod resolution;
3637
pub(crate) mod stability;
3738
pub(crate) mod transparency;
3839
pub(crate) mod util;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 Some(span) = match arg.args() {
37+
ArgParser::NoArgs => None,
38+
ArgParser::List(args) => Some(args.span),
39+
ArgParser::NameValue(args) => Some(args.eq_span.to(args.value_span)),
40+
} {
41+
cx.unexpected_literal(span);
42+
}
43+
let path = arg.path();
44+
let (key, skip): (Symbol, &mut bool) = match path.word_sym() {
45+
Some(key @ sym::array) => (key, &mut array),
46+
Some(key @ sym::boxed_slice) => (key, &mut boxed_slice),
47+
_ => {
48+
cx.expected_specific_argument(path.span(), vec!["array", "boxed_slice"]);
49+
continue;
50+
}
51+
};
52+
if mem::replace(skip, true) {
53+
cx.duplicate_key(arg.span(), key);
54+
}
55+
}
56+
Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span })
57+
}
58+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::attributes::deprecation::DeprecationParser;
2020
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
2121
use crate::attributes::lint_helpers::AsPtrParser;
2222
use crate::attributes::repr::ReprParser;
23+
use crate::attributes::resolution::SkipDuringMethodDispatchParser;
2324
use crate::attributes::stability::{
2425
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
2526
};
@@ -108,6 +109,7 @@ attribute_parsers!(
108109
Single<DeprecationParser>,
109110
Single<InlineParser>,
110111
Single<RustcForceInlineParser>,
112+
Single<SkipDuringMethodDispatchParser>,
111113
Single<TransparencyParser>,
112114
// tidy-alphabetical-end
113115
];
@@ -276,6 +278,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
276278
})
277279
}
278280

281+
pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed {
282+
self.emit_err(AttributeParseError {
283+
span,
284+
attr_span: self.attr_span,
285+
template: self.template.clone(),
286+
attribute: self.attr_path.clone(),
287+
reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument,
288+
})
289+
}
290+
279291
pub(crate) fn expected_specific_argument(
280292
&self,
281293
span: Span,

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ pub(crate) struct UnrecognizedReprHint {
467467

468468
pub(crate) enum AttributeParseErrorReason {
469469
ExpectedStringLiteral { byte_string: Option<Span> },
470+
ExpectedAtLeastOneArgument,
470471
ExpectedSingleArgument,
471472
ExpectedList,
472473
UnexpectedLiteral,
@@ -510,6 +511,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
510511
diag.span_label(self.span, "expected a single argument here");
511512
diag.code(E0805);
512513
}
514+
AttributeParseErrorReason::ExpectedAtLeastOneArgument => {
515+
diag.span_label(self.span, "expected at least 1 argument here");
516+
}
513517
AttributeParseErrorReason::ExpectedList => {
514518
diag.span_label(self.span, "expected this to be a list");
515519
}

compiler/rustc_feature/src/builtin_attrs.rs

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

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use std::ops::Bound;
2121

2222
use rustc_abi::ExternAbi;
2323
use rustc_ast::Recovered;
24+
use rustc_attr_data_structures::{AttributeKind, find_attr};
2425
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
2526
use rustc_data_structures::unord::UnordMap;
2627
use rustc_errors::{
@@ -1093,22 +1094,11 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
10931094
let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
10941095
let is_fundamental = tcx.has_attr(def_id, sym::fundamental);
10951096

1096-
// FIXME: We could probably do way better attribute validation here.
1097-
let mut skip_array_during_method_dispatch = false;
1098-
let mut skip_boxed_slice_during_method_dispatch = false;
1099-
for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) {
1100-
if let Some(lst) = attr.meta_item_list() {
1101-
for item in lst {
1102-
if let Some(ident) = item.ident() {
1103-
match ident.as_str() {
1104-
"array" => skip_array_during_method_dispatch = true,
1105-
"boxed_slice" => skip_boxed_slice_during_method_dispatch = true,
1106-
_ => (),
1107-
}
1108-
}
1109-
}
1110-
}
1111-
}
1097+
let [skip_array_during_method_dispatch, skip_boxed_slice_during_method_dispatch] = find_attr!(
1098+
tcx.get_all_attrs(def_id),
1099+
AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span:_ } => [*array, *boxed_slice]
1100+
)
1101+
.unwrap_or([false; 2]);
11121102

11131103
let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
11141104
ty::trait_def::TraitSpecializationKind::Marker

compiler/rustc_parse/src/validate_attr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ fn emit_malformed_attribute(
290290
| sym::rustc_confusables
291291
| sym::repr
292292
| sym::deprecated
293+
| sym::rustc_skip_during_method_dispatch
293294
) {
294295
return;
295296
}

compiler/rustc_passes/src/check_attr.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
117117
let attrs = self.tcx.hir_attrs(hir_id);
118118
for attr in attrs {
119119
match attr {
120+
Attribute::Parsed(AttributeKind::SkipDuringMethodDispatch {
121+
span: attr_span,
122+
..
123+
}) => {
124+
self.check_must_be_applied_to_trait(*attr_span, span, target);
125+
}
120126
Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => {
121127
self.check_confusables(*first_span, target);
122128
}
@@ -224,7 +230,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
224230
| [sym::rustc_must_implement_one_of, ..]
225231
| [sym::rustc_deny_explicit_impl, ..]
226232
| [sym::rustc_do_not_implement_via_object, ..]
227-
| [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
233+
| [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target),
228234
[sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
229235
[sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
230236
[sym::must_use, ..] => self.check_must_use(hir_id, attr, target),
@@ -1887,14 +1893,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
18871893
}
18881894

18891895
/// Checks if the attribute is applied to a trait.
1890-
fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) {
1896+
fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, target: Target) {
18911897
match target {
18921898
Target::Trait => {}
18931899
_ => {
1894-
self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
1895-
attr_span: attr.span(),
1896-
defn_span: span,
1897-
});
1900+
self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span });
18981901
}
18991902
}
19001903
}

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,7 @@ symbols! {
578578
box_new,
579579
box_patterns,
580580
box_syntax,
581+
boxed_slice,
581582
bpf_target_feature,
582583
braced_empty_structs,
583584
branch,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#![feature(rustc_attrs)]
2+
3+
#[rustc_skip_during_method_dispatch]
4+
//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input [E0539]
5+
trait NotAList {}
6+
7+
#[rustc_skip_during_method_dispatch = "array"]
8+
//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input [E0539]
9+
trait AlsoNotAList {}
10+
11+
#[rustc_skip_during_method_dispatch()]
12+
//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input
13+
trait Argless {}
14+
15+
#[rustc_skip_during_method_dispatch(array, boxed_slice, array)]
16+
//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input
17+
trait Duplicate {}
18+
19+
#[rustc_skip_during_method_dispatch(slice)]
20+
//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input
21+
trait Unexpected {}
22+
23+
#[rustc_skip_during_method_dispatch(array = true)]
24+
//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input
25+
trait KeyValue {}
26+
27+
#[rustc_skip_during_method_dispatch("array")]
28+
//~^ ERROR: malformed `rustc_skip_during_method_dispatch` attribute input
29+
trait String {}
30+
31+
#[rustc_skip_during_method_dispatch(array, boxed_slice)]
32+
trait OK {}
33+
34+
#[rustc_skip_during_method_dispatch(array)]
35+
//~^ ERROR: attribute should be applied to a trait
36+
impl OK for () {}
37+
38+
fn main() {}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input
2+
--> $DIR/rustc_skip_during_method_dispatch.rs:3:1
3+
|
4+
LL | #[rustc_skip_during_method_dispatch]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| expected this to be a list
8+
| help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
9+
10+
error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input
11+
--> $DIR/rustc_skip_during_method_dispatch.rs:7:1
12+
|
13+
LL | #[rustc_skip_during_method_dispatch = "array"]
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
| |
16+
| expected this to be a list
17+
| help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
18+
19+
error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input
20+
--> $DIR/rustc_skip_during_method_dispatch.rs:11:1
21+
|
22+
LL | #[rustc_skip_during_method_dispatch()]
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--^
24+
| | |
25+
| | expected at least 1 argument here
26+
| help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
27+
28+
error[E0538]: malformed `rustc_skip_during_method_dispatch` attribute input
29+
--> $DIR/rustc_skip_during_method_dispatch.rs:15:1
30+
|
31+
LL | #[rustc_skip_during_method_dispatch(array, boxed_slice, array)]
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^
33+
| | |
34+
| | found `array` used as a key more than once
35+
| help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
36+
37+
error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input
38+
--> $DIR/rustc_skip_during_method_dispatch.rs:19:1
39+
|
40+
LL | #[rustc_skip_during_method_dispatch(slice)]
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^
42+
| | |
43+
| | valid arguments are `array` or `boxed_slice`
44+
| help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
45+
46+
error[E0565]: malformed `rustc_skip_during_method_dispatch` attribute input
47+
--> $DIR/rustc_skip_during_method_dispatch.rs:23:1
48+
|
49+
LL | #[rustc_skip_during_method_dispatch(array = true)]
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^
51+
| | |
52+
| | didn't expect a literal here
53+
| help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
54+
55+
error[E0565]: malformed `rustc_skip_during_method_dispatch` attribute input
56+
--> $DIR/rustc_skip_during_method_dispatch.rs:27:1
57+
|
58+
LL | #[rustc_skip_during_method_dispatch("array")]
59+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^
60+
| | |
61+
| | didn't expect a literal here
62+
| help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]`
63+
64+
error: attribute should be applied to a trait
65+
--> $DIR/rustc_skip_during_method_dispatch.rs:34:1
66+
|
67+
LL | #[rustc_skip_during_method_dispatch(array)]
68+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
69+
LL |
70+
LL | impl OK for () {}
71+
| ----------------- not a trait
72+
73+
error: aborting due to 8 previous errors
74+
75+
Some errors have detailed explanations: E0538, E0539, E0565.
76+
For more information about an error, try `rustc --explain E0538`.

0 commit comments

Comments
 (0)