about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-03-15 11:29:25 +0100
committerGitHub <noreply@github.com>2025-03-15 11:29:25 +0100
commita3840390538f2112ef0d3b7f4c5baee15d19c2da (patch)
treec07af41921dc0724f6509871f8684f6b2b7aaa9b
parentadea7cbc093434a527baa4c39df6a1f0c27341e6 (diff)
parent0160c60c7883910fbd9eb59dc2b7bad2b5a3e01a (diff)
downloadrust-a3840390538f2112ef0d3b7f4c5baee15d19c2da.tar.gz
rust-a3840390538f2112ef0d3b7f4c5baee15d19c2da.zip
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`
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs16
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs14
-rw-r--r--tests/ui/const-generics/adt_const_params/check-type-in-mir.rs16
-rw-r--r--tests/ui/const-generics/adt_const_params/check-type-in-mir.stderr14
-rw-r--r--tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs12
-rw-r--r--tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr27
6 files changed, 99 insertions, 0 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index d2eb7a52f78..d6a80e22602 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1773,6 +1773,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 {
                     span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr);
                 }
+            } else if let Const::Ty(_, ct) = constant.const_
+                && let ty::ConstKind::Param(p) = ct.kind()
+            {
+                let body_def_id = self.universal_regions.defining_ty.def_id();
+                let const_param = tcx.generics_of(body_def_id).const_param(p, tcx);
+                self.ascribe_user_type(
+                    constant.const_.ty(),
+                    ty::UserType::new(ty::UserTypeKind::TypeOf(
+                        const_param.def_id,
+                        UserArgs {
+                            args: self.universal_regions.defining_ty.args(),
+                            user_self_ty: None,
+                        },
+                    )),
+                    locations.span(self.body),
+                );
             }
 
             if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() {
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index cfac9b36832..994a5ad32b3 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -184,6 +184,20 @@ impl<'tcx> DefiningTy<'tcx> {
             | DefiningTy::GlobalAsm(def_id) => def_id,
         }
     }
+
+    /// Returns the args of the `DefiningTy`. These are equivalent to the identity
+    /// substs of the body, but replaced with region vids.
+    pub(crate) fn args(&self) -> ty::GenericArgsRef<'tcx> {
+        match *self {
+            DefiningTy::Closure(_, args)
+            | DefiningTy::Coroutine(_, args)
+            | DefiningTy::CoroutineClosure(_, args)
+            | DefiningTy::FnDef(_, args)
+            | DefiningTy::Const(_, args)
+            | DefiningTy::InlineConst(_, args) => args,
+            DefiningTy::GlobalAsm(_) => ty::List::empty(),
+        }
+    }
 }
 
 #[derive(Debug)]
diff --git a/tests/ui/const-generics/adt_const_params/check-type-in-mir.rs b/tests/ui/const-generics/adt_const_params/check-type-in-mir.rs
new file mode 100644
index 00000000000..bec485b001c
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/check-type-in-mir.rs
@@ -0,0 +1,16 @@
+// Ensure that we actually treat `N`'s type as `Invariant<'static>` in MIR typeck.
+
+#![feature(adt_const_params)]
+
+use std::marker::ConstParamTy;
+use std::ops::Deref;
+
+#[derive(ConstParamTy, PartialEq, Eq)]
+struct Invariant<'a>(<&'a () as Deref>::Target);
+
+fn test<'a, const N: Invariant<'static>>() {
+    let x: Invariant<'a> = N;
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/check-type-in-mir.stderr b/tests/ui/const-generics/adt_const_params/check-type-in-mir.stderr
new file mode 100644
index 00000000000..7e265f33f35
--- /dev/null
+++ b/tests/ui/const-generics/adt_const_params/check-type-in-mir.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+  --> $DIR/check-type-in-mir.rs:12:28
+   |
+LL | fn test<'a, const N: Invariant<'static>>() {
+   |         -- lifetime `'a` defined here
+LL |     let x: Invariant<'a> = N;
+   |                            ^ assignment requires that `'a` must outlive `'static`
+   |
+   = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant
+   = note: the struct `Invariant<'a>` is invariant over the parameter `'a`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs
new file mode 100644
index 00000000000..d3bc544ed6c
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.rs
@@ -0,0 +1,12 @@
+// Ensure that we actually treat `N`'s type as `&'a u32` in MIR typeck.
+
+#![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)]
+//~^ WARN the feature `unsized_const_params` is incomplete
+//~| WARN the feature `generic_const_parameter_types` is incomplete
+
+fn foo<'a, const N: &'a u32>() {
+    let b: &'static u32 = N;
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr
new file mode 100644
index 00000000000..3dc7ce438fa
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_parameter_types/check-type-in-mir.stderr
@@ -0,0 +1,27 @@
+warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/check-type-in-mir.rs:3:12
+   |
+LL | #![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: the feature `generic_const_parameter_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/check-type-in-mir.rs:3:52
+   |
+LL | #![feature(unsized_const_params, adt_const_params, generic_const_parameter_types)]
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #137626 <https://github.com/rust-lang/rust/issues/137626> for more information
+
+error: lifetime may not live long enough
+  --> $DIR/check-type-in-mir.rs:8:12
+   |
+LL | fn foo<'a, const N: &'a u32>() {
+   |        -- lifetime `'a` defined here
+LL |     let b: &'static u32 = N;
+   |            ^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: aborting due to 1 previous error; 2 warnings emitted
+