@@ -6,9 +6,11 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
66use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
77use rustc_hir as hir;
88use rustc_hir:: def_id:: { DefId , LocalDefId } ;
9- use rustc_hir:: itemlikevisit:: ParItemLikeVisitor ;
9+ use rustc_hir:: intravisit as hir_visit;
10+ use rustc_hir:: intravisit:: Visitor ;
1011use rustc_hir:: lang_items;
1112use rustc_hir:: ItemKind ;
13+ use rustc_middle:: hir:: map as hir_map;
1214use rustc_middle:: ty:: subst:: { GenericArgKind , InternalSubsts , Subst } ;
1315use rustc_middle:: ty:: trait_def:: TraitSpecializationKind ;
1416use rustc_middle:: ty:: {
@@ -275,6 +277,95 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
275277 check_associated_item ( tcx, impl_item. hir_id , impl_item. span , method_sig) ;
276278}
277279
280+ fn check_param_wf ( tcx : TyCtxt < ' _ > , param : & hir:: GenericParam < ' _ > ) {
281+ match param. kind {
282+ // We currently only check wf of const params here.
283+ hir:: GenericParamKind :: Lifetime { .. } | hir:: GenericParamKind :: Type { .. } => ( ) ,
284+
285+ // Const parameters are well formed if their
286+ // type is structural match.
287+ hir:: GenericParamKind :: Const { ty : hir_ty } => {
288+ let ty = tcx. type_of ( tcx. hir ( ) . local_def_id ( param. hir_id ) ) ;
289+
290+ let err_ty_str;
291+ let err = if tcx. features ( ) . min_const_generics {
292+ match ty. kind {
293+ ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) | ty:: Error ( _) => None ,
294+ ty:: FnPtr ( _) => Some ( "function pointers" ) ,
295+ ty:: RawPtr ( _) => Some ( "raw pointers" ) ,
296+ _ => {
297+ err_ty_str = format ! ( "`{}`" , ty) ;
298+ Some ( err_ty_str. as_str ( ) )
299+ }
300+ }
301+ } else {
302+ match ty. peel_refs ( ) . kind {
303+ ty:: FnPtr ( _) => Some ( "function pointers" ) ,
304+ ty:: RawPtr ( _) => Some ( "raw pointers" ) ,
305+ _ => None ,
306+ }
307+ } ;
308+ if let Some ( unsupported_type) = err {
309+ let mut err = tcx. sess . struct_span_err (
310+ hir_ty. span ,
311+ & format ! ( "using {} as const generic parameters is forbidden" , unsupported_type) ,
312+ ) ;
313+
314+ if tcx. features ( ) . min_const_generics {
315+ err. note ( "the only supported types are integers, `bool` and `char`" )
316+ . note ( "more complex types are supported with `#[feature(const_generics)]`" )
317+ . emit ( )
318+ } else {
319+ err. emit ( ) ;
320+ }
321+ } ;
322+ if traits:: search_for_structural_match_violation ( param. hir_id , param. span , tcx, ty)
323+ . is_some ( )
324+ {
325+ // We use the same error code in both branches, because this is really the same
326+ // issue: we just special-case the message for type parameters to make it
327+ // clearer.
328+ if let ty:: Param ( _) = ty. peel_refs ( ) . kind {
329+ // Const parameters may not have type parameters as their types,
330+ // because we cannot be sure that the type parameter derives `PartialEq`
331+ // and `Eq` (just implementing them is not enough for `structural_match`).
332+ struct_span_err ! (
333+ tcx. sess,
334+ hir_ty. span,
335+ E0741 ,
336+ "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
337+ used as the type of a const parameter",
338+ ty,
339+ )
340+ . span_label (
341+ hir_ty. span ,
342+ format ! ( "`{}` may not derive both `PartialEq` and `Eq`" , ty) ,
343+ )
344+ . note (
345+ "it is not currently possible to use a type parameter as the type of a \
346+ const parameter",
347+ )
348+ . emit ( ) ;
349+ } else {
350+ struct_span_err ! (
351+ tcx. sess,
352+ hir_ty. span,
353+ E0741 ,
354+ "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
355+ the type of a const parameter",
356+ ty,
357+ )
358+ . span_label (
359+ hir_ty. span ,
360+ format ! ( "`{}` doesn't derive both `PartialEq` and `Eq`" , ty) ,
361+ )
362+ . emit ( ) ;
363+ }
364+ }
365+ }
366+ }
367+ }
368+
278369fn check_associated_item (
279370 tcx : TyCtxt < ' _ > ,
280371 item_id : hir:: HirId ,
@@ -1292,23 +1383,38 @@ impl CheckTypeWellFormedVisitor<'tcx> {
12921383 }
12931384}
12941385
1295- impl ParItemLikeVisitor < ' tcx > for CheckTypeWellFormedVisitor < ' tcx > {
1296- fn visit_item ( & self , i : & ' tcx hir:: Item < ' tcx > ) {
1386+ impl Visitor < ' tcx > for CheckTypeWellFormedVisitor < ' tcx > {
1387+ type Map = hir_map:: Map < ' tcx > ;
1388+
1389+ fn nested_visit_map ( & mut self ) -> hir_visit:: NestedVisitorMap < Self :: Map > {
1390+ hir_visit:: NestedVisitorMap :: OnlyBodies ( self . tcx . hir ( ) )
1391+ }
1392+
1393+ fn visit_item ( & mut self , i : & ' tcx hir:: Item < ' tcx > ) {
12971394 debug ! ( "visit_item: {:?}" , i) ;
12981395 let def_id = self . tcx . hir ( ) . local_def_id ( i. hir_id ) ;
12991396 self . tcx . ensure ( ) . check_item_well_formed ( def_id) ;
1397+ hir_visit:: walk_item ( self , i) ;
13001398 }
13011399
1302- fn visit_trait_item ( & self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
1400+ fn visit_trait_item ( & mut self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
13031401 debug ! ( "visit_trait_item: {:?}" , trait_item) ;
13041402 let def_id = self . tcx . hir ( ) . local_def_id ( trait_item. hir_id ) ;
13051403 self . tcx . ensure ( ) . check_trait_item_well_formed ( def_id) ;
1404+ hir_visit:: walk_trait_item ( self , trait_item) ;
13061405 }
13071406
1308- fn visit_impl_item ( & self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
1407+ fn visit_impl_item ( & mut self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
13091408 debug ! ( "visit_impl_item: {:?}" , impl_item) ;
13101409 let def_id = self . tcx . hir ( ) . local_def_id ( impl_item. hir_id ) ;
13111410 self . tcx . ensure ( ) . check_impl_item_well_formed ( def_id) ;
1411+ hir_visit:: walk_impl_item ( self , impl_item) ;
1412+ }
1413+
1414+ fn visit_generic_param ( & mut self , p : & ' tcx hir:: GenericParam < ' tcx > ) {
1415+ check_param_wf ( self . tcx , p) ;
1416+ // No need to walk further here, there is nothing interesting
1417+ // inside of generic params we don't already check in `check_param_wf`.
13121418 }
13131419}
13141420
0 commit comments