@@ -18,7 +18,9 @@ use std::cell::Cell;
1818use std:: iter;
1919use std:: ops:: Bound ;
2020
21- use rustc_ast:: Recovered ;
21+ use rustc_ast:: {
22+ self as ast, Attribute , MetaItem , MetaItemKind , MetaItemLit , NestedMetaItem , Recovered ,
23+ } ;
2224use rustc_data_structures:: captures:: Captures ;
2325use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
2426use rustc_data_structures:: unord:: UnordMap ;
@@ -33,15 +35,18 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
3335use rustc_infer:: traits:: ObligationCause ;
3436use rustc_middle:: hir:: nested_filter;
3537use rustc_middle:: query:: Providers ;
38+ use rustc_middle:: ty:: trait_def:: GatedReceiver ;
3639use rustc_middle:: ty:: util:: { Discr , IntTypeExt } ;
3740use rustc_middle:: ty:: { self , AdtKind , Const , IsSuggestable , Ty , TyCtxt } ;
3841use rustc_middle:: { bug, span_bug} ;
42+ use rustc_span:: edition:: Edition ;
3943use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
4044use rustc_span:: { Span , DUMMY_SP } ;
4145use rustc_target:: spec:: abi;
4246use rustc_trait_selection:: error_reporting:: traits:: suggestions:: NextTypeParamName ;
4347use rustc_trait_selection:: infer:: InferCtxtExt ;
4448use rustc_trait_selection:: traits:: ObligationCtxt ;
49+ use thin_vec:: ThinVec ;
4550use tracing:: { debug, instrument} ;
4651
4752use crate :: check:: intrinsic:: intrinsic_operation_unsafety;
@@ -1205,6 +1210,60 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
12051210 tcx. mk_adt_def ( def_id. to_def_id ( ) , kind, variants, repr, is_anonymous)
12061211}
12071212
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+
12081267fn trait_def ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> ty:: TraitDef {
12091268 let item = tcx. hir ( ) . expect_item ( def_id) ;
12101269
@@ -1234,20 +1293,19 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
12341293 let rustc_coinductive = tcx. has_attr ( def_id, sym:: rustc_coinductive) ;
12351294 let is_fundamental = tcx. has_attr ( def_id, sym:: fundamental) ;
12361295
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 ( ) ;
12401297 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+ ) ;
12501307 }
1308+ skip_during_method_dispatch. push ( parsed) ;
12511309 }
12521310 }
12531311
@@ -1386,8 +1444,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
13861444 is_marker,
13871445 is_coinductive : rustc_coinductive || is_auto,
13881446 is_fundamental,
1389- skip_array_during_method_dispatch,
1390- skip_boxed_slice_during_method_dispatch,
1447+ skip_during_method_dispatch,
13911448 specialization_kind,
13921449 must_implement_one_of,
13931450 implement_via_object,
0 commit comments