@@ -1198,9 +1198,11 @@ fn super_predicates_that_define_assoc_type(
1198
1198
fn trait_def ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> ty:: TraitDef {
1199
1199
let item = tcx. hir ( ) . expect_item ( def_id. expect_local ( ) ) ;
1200
1200
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 , & [ ] [ ..] ) ,
1204
1206
_ => span_bug ! ( item. span, "trait_def_of_item invoked on non-trait" ) ,
1205
1207
} ;
1206
1208
@@ -1227,6 +1229,80 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
1227
1229
ty:: trait_def:: TraitSpecializationKind :: None
1228
1230
} ;
1229
1231
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
+
1230
1306
ty:: TraitDef :: new (
1231
1307
def_id,
1232
1308
unsafety,
@@ -1236,6 +1312,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
1236
1312
skip_array_during_method_dispatch,
1237
1313
spec_kind,
1238
1314
def_path_hash,
1315
+ must_implement_one_of,
1239
1316
)
1240
1317
}
1241
1318
0 commit comments