Rollup merge of #150704 - Kivooeo:const-ctor, r=BoxyUwU

MGCA: Const constructors support

part of https://github.com/rust-lang/rust/issues/132980

fixes rust-lang/rust#132985
fixes rust-lang/rust#136138
fixes rust-lang/rust#139596

r? BoxyUwU
This commit is contained in:
Matthias Krüger 2026-01-06 18:43:29 +01:00 committed by GitHub
commit 9c45483fe6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 254 additions and 55 deletions

View file

@ -1415,9 +1415,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let ct = self.check_param_uses_if_mcg(ct, span, false);
Ok(ct)
}
TypeRelativePath::Ctor { ctor_def_id, args } => {
return Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args)));
}
TypeRelativePath::Ctor { ctor_def_id, args } => match tcx.def_kind(ctor_def_id) {
DefKind::Ctor(_, CtorKind::Fn) => {
Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args)))
}
DefKind::Ctor(ctor_of, CtorKind::Const) => {
Ok(self.construct_const_ctor_value(ctor_def_id, ctor_of, args))
}
_ => unreachable!(),
},
// FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
// not just const ctors
TypeRelativePath::Variant { .. } => {
@ -1452,7 +1458,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// FIXME(mgca): do we want constructor resolutions to take priority over
// other possible resolutions?
if matches!(mode, LowerTypeRelativePathMode::Const)
&& let Some((CtorKind::Fn, ctor_def_id)) = variant_def.ctor
&& let Some((_, ctor_def_id)) = variant_def.ctor
{
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
let _ = self.prohibit_generic_args(
@ -2597,7 +2603,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
self.lower_const_param(def_id, hir_id)
}
Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => {
Res::Def(DefKind::Const, did) => {
assert_eq!(opt_self_ty, None);
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self
@ -2605,6 +2611,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let args = self.lower_generic_args_of_path_segment(span, did, segment);
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
}
Res::Def(DefKind::Ctor(ctor_of, CtorKind::Const), did) => {
assert_eq!(opt_self_ty, None);
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self
.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
let parent_did = tcx.parent(did);
let generics_did = match ctor_of {
CtorOf::Variant => tcx.parent(parent_did),
CtorOf::Struct => parent_did,
};
let args = self.lower_generic_args_of_path_segment(span, generics_did, segment);
self.construct_const_ctor_value(did, ctor_of, args)
}
Res::Def(DefKind::Ctor(_, CtorKind::Fn), did) => {
assert_eq!(opt_self_ty, None);
let [leading_segments @ .., segment] = path.segments else { bug!() };
@ -3174,4 +3195,31 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
Some(r)
}
fn construct_const_ctor_value(
&self,
ctor_def_id: DefId,
ctor_of: CtorOf,
args: GenericArgsRef<'tcx>,
) -> Const<'tcx> {
let tcx = self.tcx();
let parent_did = tcx.parent(ctor_def_id);
let adt_def = tcx.adt_def(match ctor_of {
CtorOf::Variant => tcx.parent(parent_did),
CtorOf::Struct => parent_did,
});
let variant_idx = adt_def.variant_index_with_id(parent_did);
let valtree = if adt_def.is_enum() {
let discr = ty::ValTree::from_scalar_int(tcx, variant_idx.as_u32().into());
ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, discr, tcx.types.u32)])
} else {
ty::ValTree::zst(tcx)
};
let adt_ty = Ty::new_adt(tcx, adt_def, args);
ty::Const::new_value(tcx, valtree, adt_ty)
}
}

View file

@ -1,17 +0,0 @@
//@ known-bug: #132985
//@ aux-build:aux132985.rs
#![allow(incomplete_features)]
#![feature(min_generic_const_args)]
#![feature(adt_const_params)]
extern crate aux132985;
use aux132985::Foo;
fn bar<const N: Foo>() {}
fn baz() {
bar::<{ Foo }>();
}
fn main() {}

View file

@ -1,7 +0,0 @@
//@ known-bug: #136138
#![feature(min_generic_const_args)]
struct U;
struct S<const N: U>()
where
S<{ U }>:;
fn main() {}

View file

@ -1,10 +0,0 @@
//@ known-bug: #139596
#![feature(min_generic_const_args)]
struct Colour;
struct Led<const C: Colour>;
fn main() {
Led::<{ Colour}>;
}

View file

@ -1,16 +0,0 @@
//@ known-bug: #132980
// Originally a rustdoc test. Should be moved back there with @has checks
// readded once fixed.
// Previous issue (before mgca): https://github.com/rust-lang/rust/issues/105952
#![crate_name = "foo"]
#![feature(min_generic_const_args)]
pub enum ParseMode {
Raw,
}
pub trait Parse {
#[type_const]
const PARSE_MODE: ParseMode;
}
pub trait RenderRaw {}
impl<T: Parse<PARSE_MODE = { ParseMode::Raw }>> RenderRaw for T {}

View file

@ -0,0 +1,20 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/105952>
#![crate_name = "foo"]
#![feature(min_generic_const_args, adt_const_params)]
#![expect(incomplete_features)]
use std::marker::ConstParamTy;
#[derive(PartialEq, Eq, ConstParamTy)]
pub enum ParseMode {
Raw,
}
pub trait Parse {
#[type_const]
const PARSE_MODE: ParseMode;
}
pub trait RenderRaw {}
//@ hasraw foo/trait.RenderRaw.html 'impl'
//@ hasraw foo/trait.RenderRaw.html 'ParseMode::Raw'
impl<T: Parse<PARSE_MODE = { ParseMode::Raw }>> RenderRaw for T {}

View file

@ -0,0 +1,19 @@
#![feature(min_generic_const_args, adt_const_params)]
#![expect(incomplete_features)]
use std::marker::ConstParamTy;
#[derive(ConstParamTy, PartialEq, Eq)]
struct U;
#[derive(ConstParamTy, PartialEq, Eq)]
//~^ ERROR overflow evaluating the requirement `S<U> well-formed`
//~| ERROR overflow evaluating the requirement `S<U> well-formed`
struct S<const N: U>()
where
S<{ U }>:;
//~^ ERROR overflow evaluating the requirement `S<U> well-formed`
//~| ERROR overflow evaluating the requirement `S<U> well-formed`
//~| ERROR overflow evaluating the requirement `S<U> well-formed`
fn main() {}

View file

@ -0,0 +1,80 @@
error[E0275]: overflow evaluating the requirement `S<U> well-formed`
--> $DIR/const-ctor-overflow-eval.rs:14:5
|
LL | S<{ U }>:;
| ^^^^^^^^
|
note: required by a bound in `S`
--> $DIR/const-ctor-overflow-eval.rs:14:5
|
LL | struct S<const N: U>()
| - required by a bound in this struct
LL | where
LL | S<{ U }>:;
| ^^^^^^^^ required by this bound in `S`
error[E0275]: overflow evaluating the requirement `S<U> well-formed`
--> $DIR/const-ctor-overflow-eval.rs:14:5
|
LL | S<{ U }>:;
| ^^^^^^^^
|
note: required by a bound in `S`
--> $DIR/const-ctor-overflow-eval.rs:14:5
|
LL | struct S<const N: U>()
| - required by a bound in this struct
LL | where
LL | S<{ U }>:;
| ^^^^^^^^ required by this bound in `S`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0275]: overflow evaluating the requirement `S<U> well-formed`
--> $DIR/const-ctor-overflow-eval.rs:14:5
|
LL | S<{ U }>:;
| ^^^^^^^^
|
note: required by a bound in `S`
--> $DIR/const-ctor-overflow-eval.rs:14:5
|
LL | struct S<const N: U>()
| - required by a bound in this struct
LL | where
LL | S<{ U }>:;
| ^^^^^^^^ required by this bound in `S`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0275]: overflow evaluating the requirement `S<U> well-formed`
--> $DIR/const-ctor-overflow-eval.rs:8:24
|
LL | #[derive(ConstParamTy, PartialEq, Eq)]
| ^^^^^^^^^
|
note: required by a bound in `S`
--> $DIR/const-ctor-overflow-eval.rs:14:5
|
LL | struct S<const N: U>()
| - required by a bound in this struct
LL | where
LL | S<{ U }>:;
| ^^^^^^^^ required by this bound in `S`
error[E0275]: overflow evaluating the requirement `S<U> well-formed`
--> $DIR/const-ctor-overflow-eval.rs:8:35
|
LL | #[derive(ConstParamTy, PartialEq, Eq)]
| ^^
|
note: required by a bound in `S`
--> $DIR/const-ctor-overflow-eval.rs:14:5
|
LL | struct S<const N: U>()
| - required by a bound in this struct
LL | where
LL | S<{ U }>:;
| ^^^^^^^^ required by this bound in `S`
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0275`.

View file

@ -0,0 +1,19 @@
// to ensure it does not ices like before
#![feature(min_generic_const_args, adt_const_params)]
#![expect(incomplete_features)]
use std::marker::ConstParamTy;
#[derive(ConstParamTy, PartialEq, Eq)]
enum Option<T> {
#[allow(dead_code)]
Some(T),
None,
}
fn pass_enum<const P: Option<u32>>() {}
fn main() {
pass_enum::<{ None }>();
//~^ ERROR missing generics for enum `std::option::Option`
}

View file

@ -0,0 +1,14 @@
error[E0107]: missing generics for enum `std::option::Option`
--> $DIR/const-ctor-with-error.rs:17:19
|
LL | pass_enum::<{ None }>();
| ^^^^ expected 1 generic argument
|
help: add missing generic argument
|
LL | pass_enum::<{ None<T> }>();
| +++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0107`.

View file

@ -0,0 +1,49 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/139596>
//! <https://github.com/rust-lang/rust/issues/136138>
//! <https://github.com/rust-lang/rust/issues/132985>
//@ check-pass
#![feature(
min_generic_const_args,
adt_const_params,
generic_const_parameter_types,
unsized_const_params
)]
#![expect(incomplete_features)]
use std::marker::{ConstParamTy, ConstParamTy_};
#[derive(ConstParamTy, PartialEq, Eq)]
struct Colour;
#[derive(ConstParamTy, PartialEq, Eq)]
enum A {
B,
}
#[derive(ConstParamTy, PartialEq, Eq)]
enum MyOption<T> {
#[allow(dead_code)]
Some(T),
None,
}
#[derive(ConstParamTy, PartialEq, Eq)]
struct Led<const C: Colour>;
#[derive(Eq, PartialEq, ConstParamTy)]
struct Foo<const N: usize>;
fn pass_enum<const P: MyOption<u32>>() {}
fn accepts_foo<const N: usize, const M: Foo<N>>() {}
fn accepts_bar<T: ConstParamTy_, const B: MyOption<T>>() {}
fn test<T: ConstParamTy_, const N: usize>() {
accepts_foo::<N, { Foo::<N> }>();
accepts_bar::<T, { MyOption::None::<T> }>();
}
fn main() {
Led::<{ Colour }>;
}