Skip to content

Commit

Permalink
Rollup merge of rust-lang#91570 - nbdd0121:const_typeck, r=oli-obk
Browse files Browse the repository at this point in the history
Evaluate inline const pat early and report error if too generic

Fix rust-lang#90150

``@rustbot`` label: T-compiler F-inline_const
  • Loading branch information
matthiaskrgr authored Dec 8, 2021
2 parents 4da7fcc + 2a95958 commit 2429f11
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 40 deletions.
83 changes: 52 additions & 31 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,43 +533,64 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
}

/// 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"),
}
}
}
Expand Down
25 changes: 20 additions & 5 deletions src/test/ui/inline-const/const-match-pat-generic.rs
Original file line number Diff line number Diff line change
@@ -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>();
}
20 changes: 16 additions & 4 deletions src/test/ui/inline-const/const-match-pat-generic.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 2429f11

Please sign in to comment.