@@ -18,7 +18,9 @@ use std::cell::Cell;
18
18
use std:: iter;
19
19
use std:: ops:: Bound ;
20
20
21
- use rustc_ast:: Recovered ;
21
+ use rustc_ast:: {
22
+ self as ast, Attribute , MetaItem , MetaItemKind , MetaItemLit , NestedMetaItem , Recovered ,
23
+ } ;
22
24
use rustc_data_structures:: captures:: Captures ;
23
25
use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
24
26
use rustc_data_structures:: unord:: UnordMap ;
@@ -33,15 +35,18 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
33
35
use rustc_infer:: traits:: ObligationCause ;
34
36
use rustc_middle:: hir:: nested_filter;
35
37
use rustc_middle:: query:: Providers ;
38
+ use rustc_middle:: ty:: trait_def:: GatedReceiver ;
36
39
use rustc_middle:: ty:: util:: { Discr , IntTypeExt } ;
37
40
use rustc_middle:: ty:: { self , AdtKind , Const , IsSuggestable , Ty , TyCtxt } ;
38
41
use rustc_middle:: { bug, span_bug} ;
42
+ use rustc_span:: edition:: Edition ;
39
43
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
40
44
use rustc_span:: { Span , DUMMY_SP } ;
41
45
use rustc_target:: spec:: abi;
42
46
use rustc_trait_selection:: error_reporting:: traits:: suggestions:: NextTypeParamName ;
43
47
use rustc_trait_selection:: infer:: InferCtxtExt ;
44
48
use rustc_trait_selection:: traits:: ObligationCtxt ;
49
+ use thin_vec:: ThinVec ;
45
50
use tracing:: { debug, instrument} ;
46
51
47
52
use crate :: check:: intrinsic:: intrinsic_operation_unsafety;
@@ -1205,6 +1210,60 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
1205
1210
tcx. mk_adt_def ( def_id. to_def_id ( ) , kind, variants, repr, is_anonymous)
1206
1211
}
1207
1212
1213
+ fn parse_rustc_skip_during_method_dispatch (
1214
+ dcx : DiagCtxtHandle < ' _ > ,
1215
+ attr : & Attribute ,
1216
+ ) -> Result < ( GatedReceiver , Edition ) , ErrorGuaranteed > {
1217
+ debug_assert ! ( attr. has_name( sym:: rustc_skip_during_method_dispatch) ) ;
1218
+ let mut receiver: Option < GatedReceiver > = None ;
1219
+ let mut before: Option < Edition > = None ;
1220
+ for arg in attr. meta_item_list ( ) . unwrap_or_default ( ) {
1221
+ let arg_span = arg. span ( ) ;
1222
+ if let NestedMetaItem :: MetaItem ( MetaItem {
1223
+ path : ast:: Path { segments, span : key_span, .. } ,
1224
+ kind : MetaItemKind :: NameValue ( MetaItemLit { symbol : value, span : value_span, .. } ) ,
1225
+ ..
1226
+ } ) = arg
1227
+ && let [ ast:: PathSegment { ident : key, .. } ] = segments. as_slice ( )
1228
+ {
1229
+ match key. as_str ( ) {
1230
+ "receiver" => {
1231
+ if receiver
1232
+ . replace ( value. as_str ( ) . parse ( ) . map_err ( |( ) | {
1233
+ dcx. span_err ( value_span, "Expected `array` or `boxed_slice`" )
1234
+ } ) ?)
1235
+ . is_some ( )
1236
+ {
1237
+ Err ( dcx. span_err ( arg_span, "`receiver` should be specified only once" ) ) ?
1238
+ }
1239
+ }
1240
+
1241
+ "before" => {
1242
+ if before
1243
+ . replace (
1244
+ value. as_str ( ) . parse ( ) . map_err ( |( ) | {
1245
+ dcx. span_err ( value_span, "Could not parse edition" )
1246
+ } ) ?,
1247
+ )
1248
+ . is_some ( )
1249
+ {
1250
+ Err ( dcx. span_err ( arg_span, "`before` should be specified only once" ) ) ?
1251
+ }
1252
+ }
1253
+ _ => Err ( dcx. span_err ( key_span, "Expected either `receiver` or `before`" ) ) ?,
1254
+ }
1255
+ } else {
1256
+ Err ( dcx
1257
+ . span_err ( arg_span, "Expected either `receiver = \" ...\" ` or `before = \" ...\" `" ) ) ?
1258
+ } ;
1259
+ }
1260
+
1261
+ Ok ( (
1262
+ receiver. ok_or_else ( || dcx. span_err ( attr. span , "Missing `receiver`" ) ) ?,
1263
+ before. ok_or_else ( || dcx. span_err ( attr. span , "Missing `before`" ) ) ?,
1264
+ ) )
1265
+ }
1266
+
1208
1267
fn trait_def ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> ty:: TraitDef {
1209
1268
let item = tcx. hir ( ) . expect_item ( def_id) ;
1210
1269
@@ -1234,20 +1293,19 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
1234
1293
let rustc_coinductive = tcx. has_attr ( def_id, sym:: rustc_coinductive) ;
1235
1294
let is_fundamental = tcx. has_attr ( def_id, sym:: fundamental) ;
1236
1295
1237
- // FIXME: We could probably do way better attribute validation here.
1238
- let mut skip_array_during_method_dispatch = false ;
1239
- let mut skip_boxed_slice_during_method_dispatch = false ;
1296
+ let mut skip_during_method_dispatch: ThinVec < ( GatedReceiver , Edition ) > = ThinVec :: new ( ) ;
1240
1297
for attr in tcx. get_attrs ( def_id, sym:: rustc_skip_during_method_dispatch) {
1241
- if let Some ( lst ) = attr . meta_item_list ( ) {
1242
- for item in lst {
1243
- if let Some ( ident ) = item . ident ( ) {
1244
- match ident . as_str ( ) {
1245
- "array" => skip_array_during_method_dispatch = true ,
1246
- "boxed_slice" => skip_boxed_slice_during_method_dispatch = true ,
1247
- _ => ( ) ,
1248
- }
1249
- }
1298
+ if let Ok ( parsed ) = parse_rustc_skip_during_method_dispatch ( tcx . dcx ( ) , attr ) {
1299
+ if skip_during_method_dispatch . iter ( ) . any ( |prev| prev . 0 == parsed . 0 ) {
1300
+ tcx . dcx ( ) . span_err (
1301
+ attr . span ,
1302
+ format ! (
1303
+ "Duplicate `#[rustc_skip_during_method_dispatch(receiver = \" {} \" )]`" ,
1304
+ parsed . 0
1305
+ ) ,
1306
+ ) ;
1250
1307
}
1308
+ skip_during_method_dispatch. push ( parsed) ;
1251
1309
}
1252
1310
}
1253
1311
@@ -1386,8 +1444,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
1386
1444
is_marker,
1387
1445
is_coinductive : rustc_coinductive || is_auto,
1388
1446
is_fundamental,
1389
- skip_array_during_method_dispatch,
1390
- skip_boxed_slice_during_method_dispatch,
1447
+ skip_during_method_dispatch,
1391
1448
specialization_kind,
1392
1449
must_implement_one_of,
1393
1450
implement_via_object,
0 commit comments