Auto merge of #52400 - RalfJung:match, r=oli-obk

CTFE: use binary_op to compare integer with match disriminant

This is needed to unblock https://github.com/solson/miri/pull/401: There is code in the Windows initialization functions that uses `match` to test whether a pointer is NULL.

I will add a testcase in miri; I was not sure where to add a testcase in Rust itself.

r? @oli-obk
This commit is contained in:
bors 2018-07-15 21:35:22 +00:00
commit 31f1bc7b40
3 changed files with 61 additions and 4 deletions

View File

@ -1,10 +1,10 @@
use rustc::mir; use rustc::mir;
use rustc::ty::{self, Ty}; use rustc::ty::{self, Ty};
use rustc::ty::layout::LayoutOf; use rustc::ty::layout::{LayoutOf, Size};
use syntax::codemap::Span; use syntax::codemap::Span;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use rustc::mir::interpret::EvalResult; use rustc::mir::interpret::{EvalResult, Scalar};
use super::{EvalContext, Place, Machine, ValTy}; use super::{EvalContext, Place, Machine, ValTy};
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
@ -41,13 +41,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
let discr_prim = self.value_to_scalar(discr_val)?; let discr_prim = self.value_to_scalar(discr_val)?;
let discr_layout = self.layout_of(discr_val.ty).unwrap(); let discr_layout = self.layout_of(discr_val.ty).unwrap();
trace!("SwitchInt({:?}, {:#?})", discr_prim, discr_layout); trace!("SwitchInt({:?}, {:#?})", discr_prim, discr_layout);
let discr_prim = discr_prim.to_bits(discr_layout.size)?;
// Branch to the `otherwise` case by default, if no match is found. // Branch to the `otherwise` case by default, if no match is found.
let mut target_block = targets[targets.len() - 1]; let mut target_block = targets[targets.len() - 1];
for (index, &const_int) in values.iter().enumerate() { for (index, &const_int) in values.iter().enumerate() {
if discr_prim == const_int { // Compare using binary_op
let const_int = Scalar::Bits { bits: const_int, defined: 128 };
let res = self.binary_op(mir::BinOp::Eq,
discr_prim, discr_val.ty,
const_int, discr_val.ty
)?;
if res.0.to_bits(Size::from_bytes(1))? != 0 {
target_block = targets[index]; target_block = targets[index];
break; break;
} }

View File

@ -0,0 +1,22 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn main() {
// Make sure match uses the usual pointer comparison code path -- i.e., it should complain
// that pointer comparison is disallowed, not that parts of a pointer are accessed as raw
// bytes.
let _: [u8; 0] = [4; { //~ ERROR could not evaluate repeat length
match &1 as *const i32 as usize { //~ ERROR raw pointers cannot be cast to integers
0 => 42, //~ ERROR constant contains unimplemented expression type
//~^ NOTE "pointer arithmetic or comparison" needs an rfc before being allowed
n => n,
}
}];
}

View File

@ -0,0 +1,30 @@
error[E0018]: raw pointers cannot be cast to integers in constants
--> $DIR/match-test-ptr-null.rs:16:15
|
LL | match &1 as *const i32 as usize { //~ ERROR raw pointers cannot be cast to integers
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0019]: constant contains unimplemented expression type
--> $DIR/match-test-ptr-null.rs:17:13
|
LL | 0 => 42, //~ ERROR constant contains unimplemented expression type
| ^
error[E0080]: could not evaluate repeat length
--> $DIR/match-test-ptr-null.rs:15:26
|
LL | let _: [u8; 0] = [4; { //~ ERROR could not evaluate repeat length
| __________________________^
LL | | match &1 as *const i32 as usize { //~ ERROR raw pointers cannot be cast to integers
LL | | 0 => 42, //~ ERROR constant contains unimplemented expression type
| | - "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
LL | | //~^ NOTE "pointer arithmetic or comparison" needs an rfc before being allowed
LL | | n => n,
LL | | }
LL | | }];
| |_____^
error: aborting due to 3 previous errors
Some errors occurred: E0018, E0019, E0080.
For more information about an error, try `rustc --explain E0018`.