@@ -1198,9 +1198,11 @@ fn super_predicates_that_define_assoc_type(
11981198fn trait_def ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> ty:: TraitDef {
11991199 let item = tcx. hir ( ) . expect_item ( def_id. expect_local ( ) ) ;
12001200
1201- let ( is_auto, unsafety) = match item. kind {
1202- hir:: ItemKind :: Trait ( is_auto, unsafety, ..) => ( is_auto == hir:: IsAuto :: Yes , unsafety) ,
1203- hir:: ItemKind :: TraitAlias ( ..) => ( false , hir:: Unsafety :: Normal ) ,
1201+ let ( is_auto, unsafety, items) = match item. kind {
1202+ hir:: ItemKind :: Trait ( is_auto, unsafety, .., items) => {
1203+ ( is_auto == hir:: IsAuto :: Yes , unsafety, items)
1204+ }
1205+ hir:: ItemKind :: TraitAlias ( ..) => ( false , hir:: Unsafety :: Normal , & [ ] [ ..] ) ,
12041206 _ => span_bug ! ( item. span, "trait_def_of_item invoked on non-trait" ) ,
12051207 } ;
12061208
@@ -1227,6 +1229,80 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
12271229 ty:: trait_def:: TraitSpecializationKind :: None
12281230 } ;
12291231 let def_path_hash = tcx. def_path_hash ( def_id) ;
1232+
1233+ let must_implement_one_of = tcx
1234+ . get_attrs ( def_id)
1235+ . iter ( )
1236+ . find ( |attr| attr. has_name ( sym:: rustc_must_implement_one_of) )
1237+ // Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
1238+ // and that they are all identifiers
1239+ . and_then ( |attr| match attr. meta_item_list ( ) {
1240+ Some ( items) if items. len ( ) < 2 => {
1241+ tcx. sess
1242+ . struct_span_err (
1243+ attr. span ,
1244+ "the `#[rustc_must_implement_one_of]` attribute must be \
1245+ used with at least 2 args",
1246+ )
1247+ . emit ( ) ;
1248+
1249+ None
1250+ }
1251+ Some ( items) => items
1252+ . into_iter ( )
1253+ . map ( |item| item. ident ( ) . ok_or ( item. span ( ) ) )
1254+ . collect :: < Result < Box < [ _ ] > , _ > > ( )
1255+ . map_err ( |span| {
1256+ tcx. sess . struct_span_err ( span, "must be an identifier of a method" ) . emit ( ) ;
1257+ } )
1258+ . ok ( )
1259+ . zip ( Some ( attr. span ) ) ,
1260+ // Error is reported by `rustc_attr!`
1261+ None => None ,
1262+ } )
1263+ // Check that all arguments of `#[rustc_must_implement_one_of]` reference
1264+ // methods in the trait with default implementations
1265+ . and_then ( |( list, attr_span) | {
1266+ let errors = list. iter ( ) . filter_map ( |ident| {
1267+ let item = items. iter ( ) . find ( |item| item. ident == * ident) ;
1268+
1269+ match item {
1270+ Some ( item) if matches ! ( item. kind, hir:: AssocItemKind :: Fn { .. } ) => {
1271+ if !item. defaultness . has_value ( ) {
1272+ tcx. sess
1273+ . struct_span_err (
1274+ item. span ,
1275+ "This method doesn't have a default implementation" ,
1276+ )
1277+ . span_note ( attr_span, "required by this annotation" )
1278+ . emit ( ) ;
1279+
1280+ return Some ( ( ) ) ;
1281+ }
1282+
1283+ return None ;
1284+ }
1285+ Some ( item) => tcx
1286+ . sess
1287+ . struct_span_err ( item. span , "Not a method" )
1288+ . span_note ( attr_span, "required by this annotation" )
1289+ . note (
1290+ "All `#[rustc_must_implement_one_of]` arguments \
1291+ must be method identifiers",
1292+ )
1293+ . emit ( ) ,
1294+ None => tcx
1295+ . sess
1296+ . struct_span_err ( ident. span , "Method not found in this trait" )
1297+ . emit ( ) ,
1298+ }
1299+
1300+ Some ( ( ) )
1301+ } ) ;
1302+
1303+ ( errors. count ( ) == 0 ) . then_some ( list)
1304+ } ) ;
1305+
12301306 ty:: TraitDef :: new (
12311307 def_id,
12321308 unsafety,
@@ -1236,6 +1312,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
12361312 skip_array_during_method_dispatch,
12371313 spec_kind,
12381314 def_path_hash,
1315+ must_implement_one_of,
12391316 )
12401317}
12411318
0 commit comments