@@ -6,9 +6,12 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
6
6
use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
7
7
use rustc_hir as hir;
8
8
use rustc_hir:: def_id:: { DefId , LocalDefId } ;
9
+ use rustc_hir:: intravisit as hir_visit;
10
+ use rustc_hir:: intravisit:: Visitor ;
9
11
use rustc_hir:: itemlikevisit:: ParItemLikeVisitor ;
10
12
use rustc_hir:: lang_items;
11
13
use rustc_hir:: ItemKind ;
14
+ use rustc_middle:: hir:: map as hir_map;
12
15
use rustc_middle:: ty:: subst:: { GenericArgKind , InternalSubsts , Subst } ;
13
16
use rustc_middle:: ty:: trait_def:: TraitSpecializationKind ;
14
17
use rustc_middle:: ty:: {
@@ -275,6 +278,107 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
275
278
check_associated_item ( tcx, impl_item. hir_id , impl_item. span , method_sig) ;
276
279
}
277
280
281
+ fn check_param_wf ( tcx : TyCtxt < ' _ > , param : & hir:: GenericParam < ' _ > ) {
282
+ match param. kind {
283
+ // We currently only check wf of const params here.
284
+ hir:: GenericParamKind :: Lifetime { .. } | hir:: GenericParamKind :: Type { .. } => ( ) ,
285
+
286
+ // Const parameters are well formed if their
287
+ // type is structural match.
288
+ hir:: GenericParamKind :: Const { ty : hir_ty } => {
289
+ let ty = tcx. type_of ( tcx. hir ( ) . local_def_id ( param. hir_id ) ) ;
290
+
291
+ let err_ty_str;
292
+ let mut is_ptr = true ;
293
+ let err = if tcx. features ( ) . min_const_generics {
294
+ match ty. kind {
295
+ ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) | ty:: Error ( _) => None ,
296
+ ty:: FnPtr ( _) => Some ( "function pointers" ) ,
297
+ ty:: RawPtr ( _) => Some ( "raw pointers" ) ,
298
+ _ => {
299
+ is_ptr = false ;
300
+ err_ty_str = format ! ( "`{}`" , ty) ;
301
+ Some ( err_ty_str. as_str ( ) )
302
+ }
303
+ }
304
+ } else {
305
+ match ty. peel_refs ( ) . kind {
306
+ ty:: FnPtr ( _) => Some ( "function pointers" ) ,
307
+ ty:: RawPtr ( _) => Some ( "raw pointers" ) ,
308
+ _ => None ,
309
+ }
310
+ } ;
311
+ if let Some ( unsupported_type) = err {
312
+ if is_ptr {
313
+ tcx. sess . span_err (
314
+ hir_ty. span ,
315
+ & format ! (
316
+ "using {} as const generic parameters is forbidden" ,
317
+ unsupported_type
318
+ ) ,
319
+ )
320
+ } else {
321
+ tcx. sess
322
+ . struct_span_err (
323
+ hir_ty. span ,
324
+ & format ! (
325
+ "{} is forbidden as the type of a const generic parameter" ,
326
+ unsupported_type
327
+ ) ,
328
+ )
329
+ . note ( "the only supported types are integers, `bool` and `char`" )
330
+ . note ( "more complex types are supported with `#[feature(const_generics)]`" )
331
+ . emit ( )
332
+ }
333
+ } ;
334
+
335
+ if traits:: search_for_structural_match_violation ( param. hir_id , param. span , tcx, ty)
336
+ . is_some ( )
337
+ {
338
+ // We use the same error code in both branches, because this is really the same
339
+ // issue: we just special-case the message for type parameters to make it
340
+ // clearer.
341
+ if let ty:: Param ( _) = ty. peel_refs ( ) . kind {
342
+ // Const parameters may not have type parameters as their types,
343
+ // because we cannot be sure that the type parameter derives `PartialEq`
344
+ // and `Eq` (just implementing them is not enough for `structural_match`).
345
+ struct_span_err ! (
346
+ tcx. sess,
347
+ hir_ty. span,
348
+ E0741 ,
349
+ "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
350
+ used as the type of a const parameter",
351
+ ty,
352
+ )
353
+ . span_label (
354
+ hir_ty. span ,
355
+ format ! ( "`{}` may not derive both `PartialEq` and `Eq`" , ty) ,
356
+ )
357
+ . note (
358
+ "it is not currently possible to use a type parameter as the type of a \
359
+ const parameter",
360
+ )
361
+ . emit ( ) ;
362
+ } else {
363
+ struct_span_err ! (
364
+ tcx. sess,
365
+ hir_ty. span,
366
+ E0741 ,
367
+ "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
368
+ the type of a const parameter",
369
+ ty,
370
+ )
371
+ . span_label (
372
+ hir_ty. span ,
373
+ format ! ( "`{}` doesn't derive both `PartialEq` and `Eq`" , ty) ,
374
+ )
375
+ . emit ( ) ;
376
+ }
377
+ }
378
+ }
379
+ }
380
+ }
381
+
278
382
fn check_associated_item (
279
383
tcx : TyCtxt < ' _ > ,
280
384
item_id : hir:: HirId ,
@@ -1282,6 +1386,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) {
1282
1386
fcx. select_all_obligations_or_error ( ) ;
1283
1387
}
1284
1388
1389
+ #[ derive( Clone , Copy ) ]
1285
1390
pub struct CheckTypeWellFormedVisitor < ' tcx > {
1286
1391
tcx : TyCtxt < ' tcx > ,
1287
1392
}
@@ -1294,21 +1399,49 @@ impl CheckTypeWellFormedVisitor<'tcx> {
1294
1399
1295
1400
impl ParItemLikeVisitor < ' tcx > for CheckTypeWellFormedVisitor < ' tcx > {
1296
1401
fn visit_item ( & self , i : & ' tcx hir:: Item < ' tcx > ) {
1402
+ Visitor :: visit_item ( & mut self . clone ( ) , i) ;
1403
+ }
1404
+
1405
+ fn visit_trait_item ( & self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
1406
+ Visitor :: visit_trait_item ( & mut self . clone ( ) , trait_item) ;
1407
+ }
1408
+
1409
+ fn visit_impl_item ( & self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
1410
+ Visitor :: visit_impl_item ( & mut self . clone ( ) , impl_item) ;
1411
+ }
1412
+ }
1413
+
1414
+ impl Visitor < ' tcx > for CheckTypeWellFormedVisitor < ' tcx > {
1415
+ type Map = hir_map:: Map < ' tcx > ;
1416
+
1417
+ fn nested_visit_map ( & mut self ) -> hir_visit:: NestedVisitorMap < Self :: Map > {
1418
+ hir_visit:: NestedVisitorMap :: OnlyBodies ( self . tcx . hir ( ) )
1419
+ }
1420
+
1421
+ fn visit_item ( & mut self , i : & ' tcx hir:: Item < ' tcx > ) {
1297
1422
debug ! ( "visit_item: {:?}" , i) ;
1298
1423
let def_id = self . tcx . hir ( ) . local_def_id ( i. hir_id ) ;
1299
1424
self . tcx . ensure ( ) . check_item_well_formed ( def_id) ;
1425
+ hir_visit:: walk_item ( self , i) ;
1300
1426
}
1301
1427
1302
- fn visit_trait_item ( & self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
1428
+ fn visit_trait_item ( & mut self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
1303
1429
debug ! ( "visit_trait_item: {:?}" , trait_item) ;
1304
1430
let def_id = self . tcx . hir ( ) . local_def_id ( trait_item. hir_id ) ;
1305
1431
self . tcx . ensure ( ) . check_trait_item_well_formed ( def_id) ;
1432
+ hir_visit:: walk_trait_item ( self , trait_item) ;
1306
1433
}
1307
1434
1308
- fn visit_impl_item ( & self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
1435
+ fn visit_impl_item ( & mut self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
1309
1436
debug ! ( "visit_impl_item: {:?}" , impl_item) ;
1310
1437
let def_id = self . tcx . hir ( ) . local_def_id ( impl_item. hir_id ) ;
1311
1438
self . tcx . ensure ( ) . check_impl_item_well_formed ( def_id) ;
1439
+ hir_visit:: walk_impl_item ( self , impl_item) ;
1440
+ }
1441
+
1442
+ fn visit_generic_param ( & mut self , p : & ' tcx hir:: GenericParam < ' tcx > ) {
1443
+ check_param_wf ( self . tcx , p) ;
1444
+ hir_visit:: walk_generic_param ( self , p) ;
1312
1445
}
1313
1446
}
1314
1447
0 commit comments