From 4a15a256626d3a9e017a18bb60bf98b1a6358bd5 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 22 Oct 2020 10:32:41 +0200 Subject: [PATCH 1/2] min_const_generics: allow ty param in repeat expr --- compiler/rustc_resolve/src/late.rs | 88 +++++++++++++++---- .../issues/issue-62504.min.stderr | 20 +++-- .../ui/const-generics/issues/issue-62504.rs | 4 +- .../issues/issue-67739.min.stderr | 8 +- .../ui/const-generics/issues/issue-67739.rs | 3 +- .../min_const_generics/complex-expression.rs | 20 +++++ .../complex-expression.stderr | 44 ++++++++-- .../const-evaluatable-unchecked.rs | 22 +++++ .../const-evaluatable-unchecked.stderr | 21 +++++ 9 files changed, 192 insertions(+), 38 deletions(-) create mode 100644 src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs create mode 100644 src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7517ab66170..d323aebe597 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -57,6 +57,12 @@ enum PatternSource { FnParam, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum IsRepeatExpr { + No, + Yes, +} + impl PatternSource { fn descr(self) -> &'static str { match self { @@ -437,10 +443,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.resolve_block(block); } fn visit_anon_const(&mut self, constant: &'ast AnonConst) { - debug!("visit_anon_const {:?}", constant); - self.with_constant_rib(constant.value.is_potential_trivial_const_param(), |this| { - visit::walk_anon_const(this, constant); - }); + // We deal with repeat expressions explicitly in `resolve_expr`. + self.resolve_anon_const(constant, IsRepeatExpr::No); } fn visit_expr(&mut self, expr: &'ast Expr) { self.resolve_expr(expr, None); @@ -647,7 +651,11 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { if !check_ns(TypeNS) && check_ns(ValueNS) { // This must be equivalent to `visit_anon_const`, but we cannot call it // directly due to visitor lifetimes so we have to copy-paste some code. - self.with_constant_rib(true, |this| { + // + // Note that we might not be inside of an repeat expression here, + // but considering that `IsRepeatExpr` is only relevant for + // non-trivial constants this is doesn't matter. + self.with_constant_rib(IsRepeatExpr::No, true, |this| { this.smart_resolve_path( ty.id, qself.as_ref(), @@ -980,9 +988,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // // Type parameters can already be used and as associated consts are // not used as part of the type system, this is far less surprising. - this.with_constant_rib(true, |this| { - this.visit_expr(expr) - }); + this.with_constant_rib( + IsRepeatExpr::No, + true, + |this| this.visit_expr(expr), + ); } } AssocItemKind::Fn(_, _, generics, _) => { @@ -1023,7 +1033,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_item_rib(HasGenericParams::No, |this| { this.visit_ty(ty); if let Some(expr) = expr { - this.with_constant_rib(expr.is_potential_trivial_const_param(), |this| { + // We already forbid generic params because of the above item rib, + // so it doesn't matter whether this is a trivial constant. + this.with_constant_rib(IsRepeatExpr::No, true, |this| { this.visit_expr(expr) }); } @@ -1122,12 +1134,29 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f)) } - fn with_constant_rib(&mut self, trivial: bool, f: impl FnOnce(&mut Self)) { - debug!("with_constant_rib"); - self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| { - this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| { - this.with_label_rib(ConstantItemRibKind(trivial), f); - }) + // HACK(min_const_generics,const_evaluatable_unchecked): We + // want to keep allowing `[0; std::mem::size_of::<*mut T>()]` + // with a future compat lint for now. We do this by adding an + // additional special case for repeat expressions. + // + // Note that we intentionally still forbid `[0; N + 1]` during + // name resolution so that we don't extend the future + // compat lint to new cases. + fn with_constant_rib( + &mut self, + is_repeat: IsRepeatExpr, + is_trivial: bool, + f: impl FnOnce(&mut Self), + ) { + debug!("with_constant_rib: is_repeat={:?} is_trivial={}", is_repeat, is_trivial); + self.with_rib(ValueNS, ConstantItemRibKind(is_trivial), |this| { + this.with_rib( + TypeNS, + ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial), + |this| { + this.with_label_rib(ConstantItemRibKind(is_trivial), f); + }, + ) }); } @@ -1272,9 +1301,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // // Type parameters can already be used and as associated consts are // not used as part of the type system, this is far less surprising. - this.with_constant_rib(true, |this| { - visit::walk_assoc_item(this, item, AssocCtxt::Impl) - }); + this.with_constant_rib( + IsRepeatExpr::No, + true, + |this| { + visit::walk_assoc_item( + this, + item, + AssocCtxt::Impl, + ) + }, + ); } AssocItemKind::Fn(_, _, generics, _) => { // We also need a new scope for the impl item type parameters. @@ -2199,6 +2236,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { debug!("(resolving block) leaving block"); } + fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatExpr) { + debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat); + self.with_constant_rib( + is_repeat, + constant.value.is_potential_trivial_const_param(), + |this| { + visit::walk_anon_const(this, constant); + }, + ); + } + fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) { // First, record candidate traits for this expression if it could // result in the invocation of a method call. @@ -2322,6 +2370,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::Async(..) | ExprKind::Closure(..) => { self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr)); } + ExprKind::Repeat(ref elem, ref ct) => { + self.visit_expr(elem); + self.resolve_anon_const(ct, IsRepeatExpr::Yes); + } _ => { visit::walk_expr(self, expr); } diff --git a/src/test/ui/const-generics/issues/issue-62504.min.stderr b/src/test/ui/const-generics/issues/issue-62504.min.stderr index 8f794312834..865eaf74932 100644 --- a/src/test/ui/const-generics/issues/issue-62504.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.min.stderr @@ -1,14 +1,20 @@ -error: generic `Self` types are currently not permitted in anonymous constants +error[E0308]: mismatched types + --> $DIR/issue-62504.rs:19:21 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE` + | + = note: expected array `[u32; X]` + found array `[u32; _]` + +error: constant expression depends on a generic parameter --> $DIR/issue-62504.rs:19:25 | LL | ArrayHolder([0; Self::SIZE]) | ^^^^^^^^^^ | -note: not a concrete type - --> $DIR/issue-62504.rs:17:22 - | -LL | impl ArrayHolder { - | ^^^^^^^^^^^^^^ + = note: this may fail depending on what value the parameter takes -error: aborting due to previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index 015f170f00d..5630962ff53 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -17,8 +17,8 @@ struct ArrayHolder([u32; X]); impl ArrayHolder { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) - //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic `Self` types are currently + //~^ ERROR constant expression depends on a generic parameter + //[min]~| ERROR mismatched types } } diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr index 35d97c46248..27a56b8eb02 100644 --- a/src/test/ui/const-generics/issues/issue-67739.min.stderr +++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters may not be used in const operations - --> $DIR/issue-67739.rs:12:30 +error: constant expression depends on a generic parameter + --> $DIR/issue-67739.rs:12:15 | LL | [0u8; mem::size_of::()]; - | ^^^^^^^^^^^^^^^^ cannot perform const operation using `Self` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: type parameters may not be used in const expressions + = note: this may fail depending on what value the parameter takes error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs index 21d13de22eb..0f5860f22fd 100644 --- a/src/test/ui/const-generics/issues/issue-67739.rs +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -10,8 +10,7 @@ pub trait Trait { fn associated_size(&self) -> usize { [0u8; mem::size_of::()]; - //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters may not be used in const operations + //~^ ERROR constant expression depends on a generic parameter 0 } } diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.rs b/src/test/ui/const-generics/min_const_generics/complex-expression.rs index 8257ffbf491..686ce98fcdf 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-expression.rs +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.rs @@ -1,5 +1,7 @@ #![feature(min_const_generics)] +use std::mem::size_of; + fn test() {} fn ok() -> [u8; M] { @@ -22,6 +24,24 @@ fn break3() { //~^ ERROR generic parameters may not be used in const operations } +struct BreakTy0(T, [u8; { size_of::<*mut T>() }]); +//~^ ERROR generic parameters may not be used in const operations + +struct BreakTy1(T, [u8; { { size_of::<*mut T>() } }]); +//~^ ERROR generic parameters may not be used in const operations + +fn break_ty2() { + let _: [u8; size_of::<*mut T>() + 1]; + //~^ ERROR generic parameters may not be used in const operations +} + +fn break_ty3() { + let _ = [0; size_of::<*mut T>() + 1]; + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out +} + + trait Foo { const ASSOC: usize; } diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr index 73768ac03a4..a8de987e167 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr @@ -1,5 +1,5 @@ error: generic parameters may not be used in const operations - --> $DIR/complex-expression.rs:9:38 + --> $DIR/complex-expression.rs:11:38 | LL | struct Break0([u8; { N + 1 }]); | ^ cannot perform const operation using `N` @@ -7,7 +7,7 @@ LL | struct Break0([u8; { N + 1 }]); = help: const parameters may only be used as standalone arguments, i.e. `N` error: generic parameters may not be used in const operations - --> $DIR/complex-expression.rs:12:40 + --> $DIR/complex-expression.rs:14:40 | LL | struct Break1([u8; { { N } }]); | ^ cannot perform const operation using `N` @@ -15,7 +15,7 @@ LL | struct Break1([u8; { { N } }]); = help: const parameters may only be used as standalone arguments, i.e. `N` error: generic parameters may not be used in const operations - --> $DIR/complex-expression.rs:16:17 + --> $DIR/complex-expression.rs:18:17 | LL | let _: [u8; N + 1]; | ^ cannot perform const operation using `N` @@ -23,12 +23,46 @@ LL | let _: [u8; N + 1]; = help: const parameters may only be used as standalone arguments, i.e. `N` error: generic parameters may not be used in const operations - --> $DIR/complex-expression.rs:21:17 + --> $DIR/complex-expression.rs:23:17 | LL | let _ = [0; N + 1]; | ^ cannot perform const operation using `N` | = help: const parameters may only be used as standalone arguments, i.e. `N` -error: aborting due to 4 previous errors +error: generic parameters may not be used in const operations + --> $DIR/complex-expression.rs:27:45 + | +LL | struct BreakTy0(T, [u8; { size_of::<*mut T>() }]); + | ^ cannot perform const operation using `T` + | + = note: type parameters may not be used in const expressions + +error: generic parameters may not be used in const operations + --> $DIR/complex-expression.rs:30:47 + | +LL | struct BreakTy1(T, [u8; { { size_of::<*mut T>() } }]); + | ^ cannot perform const operation using `T` + | + = note: type parameters may not be used in const expressions + +error: generic parameters may not be used in const operations + --> $DIR/complex-expression.rs:34:32 + | +LL | let _: [u8; size_of::<*mut T>() + 1]; + | ^ cannot perform const operation using `T` + | + = note: type parameters may not be used in const expressions + +warning: cannot use constants which depend on generic parameters in types + --> $DIR/complex-expression.rs:39:17 + | +LL | let _ = [0; size_of::<*mut T>() + 1]; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + +error: aborting due to 7 previous errors; 1 warning emitted diff --git a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs new file mode 100644 index 00000000000..4e99a098a34 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs @@ -0,0 +1,22 @@ +// check-pass +#![allow(dead_code)] + +fn foo() { + [0; std::mem::size_of::<*mut T>()]; + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out +} + +struct Foo(T); + +impl Foo { + const ASSOC: usize = 4; + + fn test() { + [0; Self::ASSOC]; + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr new file mode 100644 index 00000000000..f493f0da040 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr @@ -0,0 +1,21 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/const-evaluatable-unchecked.rs:5:9 + | +LL | [0; std::mem::size_of::<*mut T>()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + +warning: cannot use constants which depend on generic parameters in types + --> $DIR/const-evaluatable-unchecked.rs:16:13 + | +LL | [0; Self::ASSOC]; + | ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + +warning: 2 warnings emitted + From 83ecbb4a294abca245f8c515e298464e9425b9a2 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 23 Oct 2020 22:08:21 +0200 Subject: [PATCH 2/2] add tests for self with const params --- compiler/rustc_hir/src/def.rs | 4 +++- .../const-evaluatable-unchecked.rs | 15 ++++++++++++++- .../const-evaluatable-unchecked.stderr | 19 ++++++++++++++----- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 62b12542877..193247af584 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -206,8 +206,10 @@ pub enum Res { /// ```rust /// impl Foo { fn test() -> [u8; std::mem::size_of::()] {} } /// ``` + /// We do however allow `Self` in repeat expression even if it is generic to not break code + /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint. /// - /// FIXME(lazy_normalization_consts): Remove this bodge once this feature is stable. + /// FIXME(lazy_normalization_consts): Remove this bodge once that feature is stable. SelfTy(Option /* trait */, Option<(DefId, bool)> /* impl */), ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]` diff --git a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs index 4e99a098a34..dd82be33a8e 100644 --- a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs +++ b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.rs @@ -1,4 +1,5 @@ // check-pass +#![feature(min_const_generics)] #![allow(dead_code)] fn foo() { @@ -13,7 +14,19 @@ impl Foo { const ASSOC: usize = 4; fn test() { - [0; Self::ASSOC]; + let _ = [0; Self::ASSOC]; + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out + } +} + +struct Bar; + +impl Bar { + const ASSOC: usize = 4; + + fn test() { + let _ = [0; Self::ASSOC]; //~^ WARN cannot use constants which depend on generic parameters in types //~| WARN this was previously accepted by the compiler but is being phased out } diff --git a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr index f493f0da040..4d0cab012f9 100644 --- a/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr +++ b/src/test/ui/const-generics/min_const_generics/const-evaluatable-unchecked.stderr @@ -1,5 +1,5 @@ warning: cannot use constants which depend on generic parameters in types - --> $DIR/const-evaluatable-unchecked.rs:5:9 + --> $DIR/const-evaluatable-unchecked.rs:6:9 | LL | [0; std::mem::size_of::<*mut T>()]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,13 +9,22 @@ LL | [0; std::mem::size_of::<*mut T>()]; = note: for more information, see issue #76200 warning: cannot use constants which depend on generic parameters in types - --> $DIR/const-evaluatable-unchecked.rs:16:13 + --> $DIR/const-evaluatable-unchecked.rs:17:21 | -LL | [0; Self::ASSOC]; - | ^^^^^^^^^^^ +LL | let _ = [0; Self::ASSOC]; + | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #76200 -warning: 2 warnings emitted +warning: cannot use constants which depend on generic parameters in types + --> $DIR/const-evaluatable-unchecked.rs:29:21 + | +LL | let _ = [0; Self::ASSOC]; + | ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #76200 + +warning: 3 warnings emitted