diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 33d5a86beb3b0..8bb215b6b2793 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1488,6 +1488,39 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id .then(|| WellFormedLoc::Ty(param.def_id.expect_local())), default, ); + } else { + // If we've got a generic const parameter we still want to check its + // type is correct in case both it and the param type are fully concrete. + let GenericArgKind::Const(ct) = default.unpack() else { + continue; + }; + + let ct_ty = match ct.kind() { + ty::ConstKind::Infer(_) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Bound(_, _) => unreachable!(), + ty::ConstKind::Error(_) | ty::ConstKind::Expr(_) => continue, + ty::ConstKind::Value(cv) => cv.ty, + ty::ConstKind::Unevaluated(uv) => { + infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) + } + ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(wfcx.param_env), + }; + + let param_ty = tcx.type_of(param.def_id).instantiate_identity(); + if !ct_ty.has_param() && !param_ty.has_param() { + let cause = traits::ObligationCause::new( + tcx.def_span(param.def_id), + wfcx.body_def_id, + ObligationCauseCode::WellFormed(None), + ); + wfcx.register_obligation(Obligation::new( + tcx, + cause, + wfcx.param_env, + ty::ClauseKind::ConstArgHasType(ct, param_ty), + )); + } } } } diff --git a/tests/ui/const-generics/defaults/concrete-const-param-type.rs b/tests/ui/const-generics/defaults/concrete-const-param-type.rs new file mode 100644 index 0000000000000..c411f81192bd6 --- /dev/null +++ b/tests/ui/const-generics/defaults/concrete-const-param-type.rs @@ -0,0 +1,13 @@ +#![feature(generic_const_parameter_types, unsized_const_params, adt_const_params)] +//~^ WARN the feature `generic_const_parameter_types` is incomplete +//~| WARN the feature `unsized_const_params` is incomplete +// Make sure that we test the const param type of default const parameters +// if both the type of the default and the type of the parameter are concrete. + +use std::marker::ConstParamTy_; + +struct Foo; //~ ERROR the constant `N` is not of type `u64` +struct Bar(T); // ok +struct Baz(T); // ok + +fn main() {} diff --git a/tests/ui/const-generics/defaults/concrete-const-param-type.stderr b/tests/ui/const-generics/defaults/concrete-const-param-type.stderr new file mode 100644 index 0000000000000..ad077f87e5dfb --- /dev/null +++ b/tests/ui/const-generics/defaults/concrete-const-param-type.stderr @@ -0,0 +1,25 @@ +warning: the feature `generic_const_parameter_types` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/concrete-const-param-type.rs:1:12 + | +LL | #![feature(generic_const_parameter_types, unsized_const_params, adt_const_params)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #137626 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/concrete-const-param-type.rs:1:43 + | +LL | #![feature(generic_const_parameter_types, unsized_const_params, adt_const_params)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #95174 for more information + +error: the constant `N` is not of type `u64` + --> $DIR/concrete-const-param-type.rs:9:26 + | +LL | struct Foo; + | ^^^^^^^^^^^^^^^^ expected `u64`, found `u32` + +error: aborting due to 1 previous error; 2 warnings emitted +