Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a384039

Browse files
authoredMar 15, 2025
Rollup merge of #138283 - compiler-errors:enforce-const-param, r=BoxyUwU
Enforce type of const param correctly in MIR typeck Properly intercepts and then annotates the type for a `ConstKind::Param` in the MIR. This code should probably be cleaned up, it's kinda spaghetti, but no better structure really occurred to me when writing this case. We could probably gate this behind the feature gate or add a fast path when the args have no free regions if perf is bad. r? `@BoxyUwU`
2 parents adea7cb + 0160c60 commit a384039

File tree

6 files changed

+99
-0
lines changed

6 files changed

+99
-0
lines changed
 

‎compiler/rustc_borrowck/src/type_check/mod.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1773,6 +1773,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
17731773
{
17741774
span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr);
17751775
}
1776+
} else if let Const::Ty(_, ct) = constant.const_
1777+
&& let ty::ConstKind::Param(p) = ct.kind()
1778+
{
1779+
let body_def_id = self.universal_regions.defining_ty.def_id();
1780+
let const_param = tcx.generics_of(body_def_id).const_param(p, tcx);
1781+
self.ascribe_user_type(
1782+
constant.const_.ty(),
1783+
ty::UserType::new(ty::UserTypeKind::TypeOf(
1784+
const_param.def_id,
1785+
UserArgs {
1786+
args: self.universal_regions.defining_ty.args(),
1787+
user_self_ty: None,
1788+
},
1789+
)),
1790+
locations.span(self.body),
1791+
);
17761792
}
17771793

17781794
if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() {

‎compiler/rustc_borrowck/src/universal_regions.rs

+14
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,20 @@ impl<'tcx> DefiningTy<'tcx> {
184184
| DefiningTy::GlobalAsm(def_id) => def_id,
185185
}
186186
}
187+
188+
/// Returns the args of the `DefiningTy`. These are equivalent to the identity
189+
/// substs of the body, but replaced with region vids.
190+
pub(crate) fn args(&self) -> ty::GenericArgsRef<'tcx> {
191+
match *self {
192+
DefiningTy::Closure(_, args)
193+
| DefiningTy::Coroutine(_, args)
194+
| DefiningTy::CoroutineClosure(_, args)
195+
| DefiningTy::FnDef(_, args)
196+
| DefiningTy::Const(_, args)
197+
| DefiningTy::InlineConst(_, args) => args,
198+
DefiningTy::GlobalAsm(_) => ty::List::empty(),
199+
}
200+
}
187201
}
188202

189203
#[derive(Debug)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Ensure that we actually treat `N`'s type as `Invariant<'static>` in MIR typeck.
2+
3+
#![feature(adt_const_params)]
4+
5+
use std::marker::ConstParamTy;
6+
use std::ops::Deref;
7+
8+
#[derive(ConstParamTy, PartialEq, Eq)]
9+
struct Invariant<'a>(<&'a () as Deref>::Target);
10+
11+
fn test<'a, const N: Invariant<'static>>() {
12+
let x: Invariant<'a> = N;
13+
//~^ ERROR lifetime may not live long enough
14+
}
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/check-type-in-mir.rs:12:28
3+
|
4+
LL | fn test<'a, const N: Invariant<'static>>() {
5+
| -- lifetime `'a` defined here
6+
LL | let x: Invariant<'a> = N;
7+
| ^ assignment requires that `'a` must outlive `'static`
8+
|
9+
= note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant
10+
= note: the struct `Invariant<'a>` is invariant over the parameter `'a`
11+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
12+
13+
error: aborting due to 1 previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Ensure that we actually treat `N`'s type as `&'a u32` in MIR typeck.
2+
3+
#![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)]
4+
//~^ WARN the feature `unsized_const_params` is incomplete
5+
//~| WARN the feature `generic_const_parameter_types` is incomplete
6+
7+
fn foo<'a, const N: &'a u32>() {
8+
let b: &'static u32 = N;
9+
//~^ ERROR lifetime may not live long enough
10+
}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/check-type-in-mir.rs:3:12
3+
|
4+
LL | #![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
warning: the feature `generic_const_parameter_types` is incomplete and may not be safe to use and/or cause compiler crashes
11+
--> $DIR/check-type-in-mir.rs:3:52
12+
|
13+
LL | #![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)]
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
|
16+
= note: see issue #137626 <https://github.com/rust-lang/rust/issues/137626> for more information
17+
18+
error: lifetime may not live long enough
19+
--> $DIR/check-type-in-mir.rs:8:12
20+
|
21+
LL | fn foo<'a, const N: &'a u32>() {
22+
| -- lifetime `'a` defined here
23+
LL | let b: &'static u32 = N;
24+
| ^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
25+
26+
error: aborting due to 1 previous error; 2 warnings emitted
27+

0 commit comments

Comments
 (0)
Failed to load comments.