Rollup merge of #91570 - nbdd0121:const_typeck, r=oli-obk

Evaluate inline const pat early and report error if too generic

Fix #90150

````@rustbot```` label: T-compiler F-inline_const
This commit is contained in:
Matthias Krüger 2021-12-08 16:08:08 +01:00 committed by GitHub
commit 67c58327fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 40 deletions

View File

@ -533,43 +533,64 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
}
}
/// Converts inline const patterns.
fn lower_inline_const(
&mut self,
anon_const: &'tcx hir::AnonConst,
id: hir::HirId,
span: Span,
) -> PatKind<'tcx> {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
// Evaluate early like we do in `lower_path`.
let value = value.eval(self.tcx, self.param_env);
match value.val {
ConstKind::Param(_) => {
self.errors.push(PatternError::ConstParamInPattern(span));
return PatKind::Wild;
}
ConstKind::Unevaluated(_) => {
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
return PatKind::Wild;
}
_ => (),
}
*self.const_to_pat(value, id, span, false).kind
}
/// Converts literals, paths and negation of literals to patterns.
/// The special case for negation exists to allow things like `-128_i8`
/// which would overflow if we tried to evaluate `128_i8` and then negate
/// afterwards.
fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
if let hir::ExprKind::Path(ref qpath) = expr.kind {
*self.lower_path(qpath, expr.hir_id, expr.span).kind
} else {
let (lit, neg) = match expr.kind {
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
if matches!(value.val, ConstKind::Param(_)) {
let span = self.tcx.hir().span(anon_const.hir_id);
self.errors.push(PatternError::ConstParamInPattern(span));
return PatKind::Wild;
}
return *self.const_to_pat(value, expr.hir_id, expr.span, false).kind;
}
hir::ExprKind::Lit(ref lit) => (lit, false),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
let lit = match expr.kind {
hir::ExprKind::Lit(ref lit) => lit,
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
};
(lit, true)
}
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
};
let lit_input =
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
match self.tcx.at(expr.span).lit_to_const(lit_input) {
Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind,
Err(LitToConstError::Reported) => PatKind::Wild,
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
let (lit, neg) = match expr.kind {
hir::ExprKind::Path(ref qpath) => {
return *self.lower_path(qpath, expr.hir_id, expr.span).kind;
}
hir::ExprKind::ConstBlock(ref anon_const) => {
return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
}
hir::ExprKind::Lit(ref lit) => (lit, false),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
let lit = match expr.kind {
hir::ExprKind::Lit(ref lit) => lit,
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
};
(lit, true)
}
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
};
let lit_input =
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
match self.tcx.at(expr.span).lit_to_const(lit_input) {
Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind,
Err(LitToConstError::Reported) => PatKind::Wild,
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
}
}
}

View File

@ -1,16 +1,31 @@
#![allow(incomplete_features)]
#![feature(inline_const_pat)]
#![feature(generic_const_exprs)]
// rust-lang/rust#82518: ICE with inline-const in match referencing const-generic parameter
fn foo<const V: usize>() {
match 0 {
const { V } => {},
//~^ ERROR const parameters cannot be referenced in patterns [E0158]
_ => {},
}
match 0 {
const { V } => {},
//~^ ERROR const parameters cannot be referenced in patterns [E0158]
_ => {},
}
}
const fn f(x: usize) -> usize {
x + 1
}
fn bar<const V: usize>() where [(); f(V)]: {
match 0 {
const { f(V) } => {},
//~^ ERROR constant pattern depends on a generic parameter
//~| ERROR constant pattern depends on a generic parameter
_ => {},
}
}
fn main() {
foo::<1>();
bar::<1>();
}

View File

@ -1,9 +1,21 @@
error[E0158]: const parameters cannot be referenced in patterns
--> $DIR/const-match-pat-generic.rs:8:11
--> $DIR/const-match-pat-generic.rs:9:9
|
LL | const { V } => {},
| ^^^^^
LL | const { V } => {},
| ^^^^^^^^^^^
error: aborting due to previous error
error: constant pattern depends on a generic parameter
--> $DIR/const-match-pat-generic.rs:21:9
|
LL | const { f(V) } => {},
| ^^^^^^^^^^^^^^
error: constant pattern depends on a generic parameter
--> $DIR/const-match-pat-generic.rs:21:9
|
LL | const { f(V) } => {},
| ^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0158`.