@@ -24,6 +24,9 @@ use rustc_span::symbol::{sym, Ident, Symbol};
2424use rustc_span:: { Span , DUMMY_SP } ;
2525use rustc_target:: spec:: abi:: Abi ;
2626use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt ;
27+ use rustc_trait_selection:: traits:: misc:: {
28+ type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError ,
29+ } ;
2730use rustc_trait_selection:: traits:: outlives_bounds:: InferCtxtExt as _;
2831use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
2932use rustc_trait_selection:: traits:: {
@@ -865,43 +868,65 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
865868 ) ;
866869 } ) ;
867870 } else {
868- let err_ty_str;
869- let mut is_ptr = true ;
870-
871- let err = match ty. kind ( ) {
871+ let diag = match ty. kind ( ) {
872872 ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) | ty:: Error ( _) => None ,
873- ty:: FnPtr ( _) => Some ( "function pointers" ) ,
874- ty:: RawPtr ( _) => Some ( "raw pointers" ) ,
875- _ => {
876- is_ptr = false ;
877- err_ty_str = format ! ( "`{ty}`" ) ;
878- Some ( err_ty_str. as_str ( ) )
879- }
873+ ty:: FnPtr ( _) => Some ( tcx. sess . struct_span_err (
874+ hir_ty. span ,
875+ "using function pointers as const generic parameters is forbidden" ,
876+ ) ) ,
877+ ty:: RawPtr ( _) => Some ( tcx. sess . struct_span_err (
878+ hir_ty. span ,
879+ "using raw pointers as const generic parameters is forbidden" ,
880+ ) ) ,
881+ _ => Some ( tcx. sess . struct_span_err (
882+ hir_ty. span ,
883+ format ! ( "`{}` is forbidden as the type of a const generic parameter" , ty) ,
884+ ) ) ,
880885 } ;
881886
882- if let Some ( unsupported_type) = err {
883- if is_ptr {
884- tcx. sess . span_err (
885- hir_ty. span ,
886- format ! (
887- "using {unsupported_type} as const generic parameters is forbidden" ,
888- ) ,
889- ) ;
890- } else {
891- let mut err = tcx. sess . struct_span_err (
892- hir_ty. span ,
893- format ! (
894- "{unsupported_type} is forbidden as the type of a const generic parameter" ,
895- ) ,
896- ) ;
897- err. note ( "the only supported types are integers, `bool` and `char`" ) ;
898- if tcx. sess . is_nightly_build ( ) {
899- err. help (
900- "more complex types are supported with `#![feature(adt_const_params)]`" ,
901- ) ;
887+ if let Some ( mut diag) = diag {
888+ diag. note ( "the only supported types are integers, `bool` and `char`" ) ;
889+
890+ let cause = ObligationCause :: misc ( hir_ty. span , param. def_id ) ;
891+ let may_suggest_feature = match type_allowed_to_implement_const_param_ty (
892+ tcx,
893+ tcx. param_env ( param. def_id ) ,
894+ ty,
895+ cause,
896+ ) {
897+ // Can never implement `ConstParamTy`, don't suggest anything.
898+ Err ( ConstParamTyImplementationError :: NotAnAdtOrBuiltinAllowed ) => false ,
899+ // May be able to implement `ConstParamTy`. Only emit the feature help
900+ // if the type is local, since the user may be able to fix the local type.
901+ Err ( ConstParamTyImplementationError :: InfrigingFields ( ..) ) => {
902+ fn ty_is_local ( ty : Ty < ' _ > ) -> bool {
903+ match ty. kind ( ) {
904+ ty:: Adt ( adt_def, ..) => adt_def. did ( ) . is_local ( ) ,
905+ // Arrays and slices use the inner type's `ConstParamTy`.
906+ ty:: Array ( ty, ..) => ty_is_local ( * ty) ,
907+ ty:: Slice ( ty) => ty_is_local ( * ty) ,
908+ // `&` references use the inner type's `ConstParamTy`.
909+ // `&mut` are not supported.
910+ ty:: Ref ( _, ty, ast:: Mutability :: Not ) => ty_is_local ( * ty) ,
911+ // Say that a tuple is local if any of its components are local.
912+ // This is not strictly correct, but it's likely that the user can fix the local component.
913+ ty:: Tuple ( tys) => tys. iter ( ) . any ( |ty| ty_is_local ( ty) ) ,
914+ _ => false ,
915+ }
916+ }
917+
918+ ty_is_local ( ty)
902919 }
903- err. emit ( ) ;
920+ // Implments `ConstParamTy`, suggest adding the feature to enable.
921+ Ok ( ..) => true ,
922+ } ;
923+ if may_suggest_feature && tcx. sess . is_nightly_build ( ) {
924+ diag. help (
925+ "add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types" ,
926+ ) ;
904927 }
928+
929+ diag. emit ( ) ;
905930 }
906931 }
907932 }
0 commit comments