Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

min_const_generics: allow ty param in repeat expr #78224

Merged
merged 2 commits into from
Oct 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion compiler/rustc_hir/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,10 @@ pub enum Res<Id = hir::HirId> {
/// ```rust
/// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] {} }
/// ```
/// 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<DefId> /* trait */, Option<(DefId, bool)> /* impl */),
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`

Expand Down
88 changes: 70 additions & 18 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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, _) => {
Expand Down Expand Up @@ -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)
});
}
Expand Down Expand Up @@ -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);
},
)
});
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
Expand Down
20 changes: 13 additions & 7 deletions src/test/ui/const-generics/issues/issue-62504.min.stderr
Original file line number Diff line number Diff line change
@@ -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<const X: usize> ArrayHolder<X> {
| ^^^^^^^^^^^^^^
= 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`.
4 changes: 2 additions & 2 deletions src/test/ui/const-generics/issues/issue-62504.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ struct ArrayHolder<const X: usize>([u32; X]);
impl<const X: usize> ArrayHolder<X> {
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
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/const-generics/issues/issue-67739.min.stderr
Original file line number Diff line number Diff line change
@@ -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::<Self::Associated>()];
| ^^^^^^^^^^^^^^^^ 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

3 changes: 1 addition & 2 deletions src/test/ui/const-generics/issues/issue-67739.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ pub trait Trait {

fn associated_size(&self) -> usize {
[0u8; mem::size_of::<Self::Associated>()];
//[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
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![feature(min_const_generics)]

use std::mem::size_of;

fn test<const N: usize>() {}

fn ok<const M: usize>() -> [u8; M] {
Expand All @@ -22,6 +24,24 @@ fn break3<const N: usize>() {
//~^ ERROR generic parameters may not be used in const operations
}

struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
//~^ ERROR generic parameters may not be used in const operations

struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
//~^ ERROR generic parameters may not be used in const operations

fn break_ty2<T>() {
let _: [u8; size_of::<*mut T>() + 1];
//~^ ERROR generic parameters may not be used in const operations
}

fn break_ty3<T>() {
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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,68 @@
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<const N: usize>([u8; { N + 1 }]);
| ^ cannot perform const operation using `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:12:40
--> $DIR/complex-expression.rs:14:40
|
LL | struct Break1<const N: usize>([u8; { { N } }]);
| ^ cannot perform const operation using `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`
|
= 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>(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>(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 <https://github.com/rust-lang/rust/issues/76200>

error: aborting due to 7 previous errors; 1 warning emitted

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// check-pass
#![feature(min_const_generics)]
#![allow(dead_code)]

fn foo<T>() {
[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>(T);

impl<T> Foo<T> {
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
}
}

struct Bar<const N: usize>;

impl<const N: usize> Bar<N> {
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
}
}

fn main() {}
Loading