Skip to content

Commit f9c2177

Browse files
committed
Auto merge of #74877 - lcnr:min_const_generics, r=oli-obk
Implement the `min_const_generics` feature gate Implements both rust-lang/lang-team#37 and rust-lang/compiler-team#332. Adds the new feature gate `#![feature(min_const_generics)]`. This feature gate adds the following limitations to using const generics: - generic parameters must only be used in types if they are trivial. (either `N` or `{ N }`) - generic parameters must be either integers, `bool` or `char`. We do allow arbitrary expressions in associated consts though, meaning that the following is allowed, even if `<[u8; 0] as Foo>::ASSOC` is not const evaluatable. ```rust trait Foo { const ASSOC: usize; } impl<const N: usize> Foo for [u8; N] { const ASSOC: usize = 64 / N; } ``` r? @varkor cc @eddyb @withoutboats
2 parents f3a9de9 + 644c894 commit f9c2177

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+471
-101
lines changed

src/librustc_ast/ast.rs

+24
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,30 @@ impl Expr {
10521052
}
10531053
}
10541054

1055+
/// Is this expr either `N`, or `{ N }`.
1056+
///
1057+
/// If this is not the case, name resolution does not resolve `N` when using
1058+
/// `feature(min_const_generics)` as more complex expressions are not supported.
1059+
pub fn is_potential_trivial_const_param(&self) -> bool {
1060+
let this = if let ExprKind::Block(ref block, None) = self.kind {
1061+
if block.stmts.len() == 1 {
1062+
if let StmtKind::Expr(ref expr) = block.stmts[0].kind { expr } else { self }
1063+
} else {
1064+
self
1065+
}
1066+
} else {
1067+
self
1068+
};
1069+
1070+
if let ExprKind::Path(None, ref path) = this.kind {
1071+
if path.segments.len() == 1 && path.segments[0].args.is_none() {
1072+
return true;
1073+
}
1074+
}
1075+
1076+
false
1077+
}
1078+
10551079
pub fn to_bound(&self) -> Option<GenericBound> {
10561080
match &self.kind {
10571081
ExprKind::Path(None, path) => Some(GenericBound::Trait(

src/librustc_ast_passes/ast_validation.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,13 @@ fn validate_generic_param_order<'a>(
776776
span,
777777
&format!(
778778
"reorder the parameters: lifetimes, then types{}",
779-
if sess.features_untracked().const_generics { ", then consts" } else { "" },
779+
if sess.features_untracked().const_generics
780+
|| sess.features_untracked().min_const_generics
781+
{
782+
", then consts"
783+
} else {
784+
""
785+
},
780786
),
781787
ordered_params.clone(),
782788
Applicability::MachineApplicable,

src/librustc_ast_passes/feature_gate.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -526,12 +526,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
526526

527527
fn visit_generic_param(&mut self, param: &'a GenericParam) {
528528
if let GenericParamKind::Const { .. } = param.kind {
529-
gate_feature_post!(
529+
gate_feature_fn!(
530530
&self,
531-
const_generics,
531+
|x: &Features| x.const_generics || x.min_const_generics,
532532
param.ident.span,
533+
sym::min_const_generics,
533534
"const generics are unstable"
534-
)
535+
);
535536
}
536537
visit::walk_generic_param(self, param)
537538
}

src/librustc_feature/active.rs

+3
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,9 @@ declare_features! (
579579
/// Allows calling `transmute` in const fn
580580
(active, const_fn_transmute, "1.46.0", Some(53605), None),
581581

582+
/// The smallest useful subset of `const_generics`.
583+
(active, min_const_generics, "1.46.0", Some(74878), None),
584+
582585
// -------------------------------------------------------------------------
583586
// feature-group-end: actual feature gates
584587
// -------------------------------------------------------------------------

src/librustc_middle/ty/context.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1380,7 +1380,9 @@ impl<'tcx> TyCtxt<'tcx> {
13801380
/// we still evaluate them eagerly.
13811381
#[inline]
13821382
pub fn lazy_normalization(self) -> bool {
1383-
self.features().const_generics || self.features().lazy_normalization_consts
1383+
let features = self.features();
1384+
// Note: We do not enable lazy normalization for `features.min_const_generics`.
1385+
features.const_generics || features.lazy_normalization_consts
13841386
}
13851387

13861388
#[inline]

src/librustc_parse/parser/generics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl<'a> Parser<'a> {
5454
self.expect(&token::Colon)?;
5555
let ty = self.parse_ty()?;
5656

57-
self.sess.gated_spans.gate(sym::const_generics, const_span.to(self.prev_token.span));
57+
self.sess.gated_spans.gate(sym::min_const_generics, const_span.to(self.prev_token.span));
5858

5959
Ok(GenericParam {
6060
ident,

src/librustc_resolve/diagnostics.rs

+17
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,23 @@ impl<'a> Resolver<'a> {
466466
);
467467
err
468468
}
469+
ResolutionError::ParamInNonTrivialAnonConst(name) => {
470+
let mut err = self.session.struct_span_err(
471+
span,
472+
"generic parameters must not be used inside of non trivial constant values",
473+
);
474+
err.span_label(
475+
span,
476+
&format!(
477+
"non-trivial anonymous constants must not depend on the parameter `{}`",
478+
name
479+
),
480+
);
481+
err.help(
482+
&format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name)
483+
);
484+
err
485+
}
469486
ResolutionError::SelfInTyParamDefault => {
470487
let mut err = struct_span_err!(
471488
self.session,

src/librustc_resolve/late.rs

+27-13
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ crate enum RibKind<'a> {
111111
ItemRibKind(HasGenericParams),
112112

113113
/// We're in a constant item. Can't refer to dynamic stuff.
114-
ConstantItemRibKind,
114+
ConstantItemRibKind(bool),
115115

116116
/// We passed through a module.
117117
ModuleRibKind(Module<'a>),
@@ -137,7 +137,7 @@ impl RibKind<'_> {
137137
NormalRibKind
138138
| ClosureOrAsyncRibKind
139139
| FnItemRibKind
140-
| ConstantItemRibKind
140+
| ConstantItemRibKind(_)
141141
| ModuleRibKind(_)
142142
| MacroDefinition(_)
143143
| ConstParamTyRibKind => false,
@@ -426,7 +426,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
426426
}
427427
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
428428
debug!("visit_anon_const {:?}", constant);
429-
self.with_constant_rib(|this| {
429+
self.with_constant_rib(constant.value.is_potential_trivial_const_param(), |this| {
430430
visit::walk_anon_const(this, constant);
431431
});
432432
}
@@ -628,7 +628,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
628628
if !check_ns(TypeNS) && check_ns(ValueNS) {
629629
// This must be equivalent to `visit_anon_const`, but we cannot call it
630630
// directly due to visitor lifetimes so we have to copy-paste some code.
631-
self.with_constant_rib(|this| {
631+
self.with_constant_rib(true, |this| {
632632
this.smart_resolve_path(
633633
ty.id,
634634
qself.as_ref(),
@@ -829,7 +829,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
829829
| ClosureOrAsyncRibKind
830830
| FnItemRibKind
831831
| ItemRibKind(..)
832-
| ConstantItemRibKind
832+
| ConstantItemRibKind(_)
833833
| ModuleRibKind(..)
834834
| ForwardTyParamBanRibKind
835835
| ConstParamTyRibKind => {
@@ -948,7 +948,14 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
948948
// Only impose the restrictions of `ConstRibKind` for an
949949
// actual constant expression in a provided default.
950950
if let Some(expr) = default {
951-
this.with_constant_rib(|this| this.visit_expr(expr));
951+
// We allow arbitrary const expressions inside of associated consts,
952+
// even if they are potentially not const evaluatable.
953+
//
954+
// Type parameters can already be used and as associated consts are
955+
// not used as part of the type system, this is far less surprising.
956+
this.with_constant_rib(true, |this| {
957+
this.visit_expr(expr)
958+
});
952959
}
953960
}
954961
AssocItemKind::Fn(_, _, generics, _) => {
@@ -989,7 +996,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
989996
self.with_item_rib(HasGenericParams::No, |this| {
990997
this.visit_ty(ty);
991998
if let Some(expr) = expr {
992-
this.with_constant_rib(|this| this.visit_expr(expr));
999+
this.with_constant_rib(expr.is_potential_trivial_const_param(), |this| {
1000+
this.visit_expr(expr)
1001+
});
9931002
}
9941003
});
9951004
}
@@ -1086,11 +1095,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
10861095
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
10871096
}
10881097

1089-
fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
1098+
fn with_constant_rib(&mut self, trivial: bool, f: impl FnOnce(&mut Self)) {
10901099
debug!("with_constant_rib");
1091-
self.with_rib(ValueNS, ConstantItemRibKind, |this| {
1092-
this.with_rib(TypeNS, ConstantItemRibKind, |this| {
1093-
this.with_label_rib(ConstantItemRibKind, f);
1100+
self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| {
1101+
this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| {
1102+
this.with_label_rib(ConstantItemRibKind(trivial), f);
10941103
})
10951104
});
10961105
}
@@ -1220,7 +1229,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
12201229
for item in impl_items {
12211230
use crate::ResolutionError::*;
12221231
match &item.kind {
1223-
AssocItemKind::Const(..) => {
1232+
AssocItemKind::Const(_default, _ty, _expr) => {
12241233
debug!("resolve_implementation AssocItemKind::Const",);
12251234
// If this is a trait impl, ensure the const
12261235
// exists in trait
@@ -1231,7 +1240,12 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
12311240
|n, s| ConstNotMemberOfTrait(n, s),
12321241
);
12331242

1234-
this.with_constant_rib(|this| {
1243+
// We allow arbitrary const expressions inside of associated consts,
1244+
// even if they are potentially not const evaluatable.
1245+
//
1246+
// Type parameters can already be used and as associated consts are
1247+
// not used as part of the type system, this is far less surprising.
1248+
this.with_constant_rib(true, |this| {
12351249
visit::walk_assoc_item(this, item, AssocCtxt::Impl)
12361250
});
12371251
}

src/librustc_resolve/lib.rs

+29-3
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ enum ResolutionError<'a> {
218218
ParamInTyOfConstParam(Symbol),
219219
/// constant values inside of type parameter defaults must not depend on generic parameters.
220220
ParamInAnonConstInTyDefault(Symbol),
221+
/// generic parameters must not be used inside of non trivial constant values.
222+
///
223+
/// This error is only emitted when using `min_const_generics`.
224+
ParamInNonTrivialAnonConst(Symbol),
221225
/// Error E0735: type parameters with a default cannot use `Self`
222226
SelfInTyParamDefault,
223227
/// Error E0767: use of unreachable label
@@ -2507,7 +2511,7 @@ impl<'a> Resolver<'a> {
25072511
res_err = Some(CannotCaptureDynamicEnvironmentInFnItem);
25082512
}
25092513
}
2510-
ConstantItemRibKind => {
2514+
ConstantItemRibKind(_) => {
25112515
// Still doesn't deal with upvars
25122516
if record_used {
25132517
self.report_error(span, AttemptToUseNonConstantValueInConstant);
@@ -2546,7 +2550,18 @@ impl<'a> Resolver<'a> {
25462550
in_ty_param_default = true;
25472551
continue;
25482552
}
2549-
ConstantItemRibKind => {
2553+
ConstantItemRibKind(trivial) => {
2554+
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
2555+
if !trivial && self.session.features_untracked().min_const_generics {
2556+
if record_used {
2557+
self.report_error(
2558+
span,
2559+
ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
2560+
);
2561+
}
2562+
return Res::Err;
2563+
}
2564+
25502565
if in_ty_param_default {
25512566
if record_used {
25522567
self.report_error(
@@ -2612,7 +2627,18 @@ impl<'a> Resolver<'a> {
26122627
in_ty_param_default = true;
26132628
continue;
26142629
}
2615-
ConstantItemRibKind => {
2630+
ConstantItemRibKind(trivial) => {
2631+
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
2632+
if !trivial && self.session.features_untracked().min_const_generics {
2633+
if record_used {
2634+
self.report_error(
2635+
span,
2636+
ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
2637+
);
2638+
}
2639+
return Res::Err;
2640+
}
2641+
26162642
if in_ty_param_default {
26172643
if record_used {
26182644
self.report_error(

src/librustc_span/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ symbols! {
672672
min_align_of,
673673
min_align_of_val,
674674
min_const_fn,
675+
min_const_generics,
675676
min_const_unsafe_fn,
676677
min_specialization,
677678
minnumf32,

src/librustc_typeck/collect.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,9 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
12381238
// HACK(eddyb) this provides the correct generics when
12391239
// `feature(const_generics)` is enabled, so that const expressions
12401240
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
1241+
//
1242+
// Note that we do not supply the parent generics when using
1243+
// `feature(min_const_generics)`.
12411244
Some(parent_def_id.to_def_id())
12421245
} else {
12431246
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));

src/librustc_typeck/collect/type_of.rs

+31-13
Original file line numberDiff line numberDiff line change
@@ -326,21 +326,39 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
326326
GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
327327
GenericParamKind::Const { ty: ref hir_ty, .. } => {
328328
let ty = icx.to_ty(hir_ty);
329-
let err = match ty.peel_refs().kind {
330-
ty::FnPtr(_) => Some("function pointers"),
331-
ty::RawPtr(_) => Some("raw pointers"),
332-
_ => None,
329+
let err_ty_str;
330+
let err = if tcx.features().min_const_generics {
331+
match ty.kind {
332+
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
333+
ty::FnPtr(_) => Some("function pointers"),
334+
ty::RawPtr(_) => Some("raw pointers"),
335+
_ => {
336+
err_ty_str = format!("`{}`", ty);
337+
Some(err_ty_str.as_str())
338+
}
339+
}
340+
} else {
341+
match ty.peel_refs().kind {
342+
ty::FnPtr(_) => Some("function pointers"),
343+
ty::RawPtr(_) => Some("raw pointers"),
344+
_ => None,
345+
}
333346
};
334347
if let Some(unsupported_type) = err {
335-
tcx.sess
336-
.struct_span_err(
337-
hir_ty.span,
338-
&format!(
339-
"using {} as const generic parameters is forbidden",
340-
unsupported_type
341-
),
342-
)
343-
.emit();
348+
let mut err = tcx.sess.struct_span_err(
349+
hir_ty.span,
350+
&format!(
351+
"using {} as const generic parameters is forbidden",
352+
unsupported_type
353+
),
354+
);
355+
356+
if tcx.features().min_const_generics {
357+
err.note("the only supported types are integers, `bool` and `char`")
358+
.note("more complex types are supported with `#[feature(const_generics)]`").emit()
359+
} else {
360+
err.emit();
361+
}
344362
};
345363
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
346364
.is_some()

src/test/ui/const-generics/const-param-in-trait-ungated.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ error[E0658]: const generics are unstable
44
LL | trait Trait<const T: ()> {}
55
| ^
66
|
7-
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
8-
= help: add `#![feature(const_generics)]` to the crate attributes to enable
7+
= note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
8+
= help: add `#![feature(min_const_generics)]` to the crate attributes to enable
99

1010
error: aborting due to previous error
1111

src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ error[E0658]: const generics are unstable
1010
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
1111
| ^
1212
|
13-
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
14-
= help: add `#![feature(const_generics)]` to the crate attributes to enable
13+
= note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
14+
= help: add `#![feature(min_const_generics)]` to the crate attributes to enable
1515

1616
error: aborting due to 2 previous errors
1717

0 commit comments

Comments
 (0)