diff options
| author | bors <bors@rust-lang.org> | 2017-08-27 12:53:48 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-08-27 12:53:48 +0000 |
| commit | eb8f2586ebd842dec49d3d7f50e49a985ab31493 (patch) | |
| tree | 226a99001cbff7d8aabda31213b640ba3a5f1b38 | |
| parent | 78e95bb7ac92f8f92654705a47cef652b6a0b259 (diff) | |
| parent | e13090e8b2f8adce9277f2ebfa37efa75c8837a8 (diff) | |
| download | rust-eb8f2586ebd842dec49d3d7f50e49a985ab31493.tar.gz rust-eb8f2586ebd842dec49d3d7f50e49a985ab31493.zip | |
Auto merge of #44060 - taleks:issue-43205, r=arielb1
Fixes issue #43205: ICE in Rvalue::Len evaluation. - fixes evaluation of array length for zero-sized type referenced by rvalue operand. - adds test to verify fix. *Cause of the issue*. Zero-sized aggregates are handled as operands, not lvalues. Therefore while visiting `Assign` statement by `LocalAnalyser`, `mark_as_lvalue()` is not called for related `Local`. This behaviour is controlled by `rvalue_creates_operand()` method. As result it causes error later, when rvalue operand is evaluated in `trans_rvalue_operand()` while handling `Rvalue::Len` case. Array length evaluation invokes `trans_lvalue()` which expects referenced `Local` to be value, not operand. *How it is fixed*. In certain cases result of `Rvalue::Len` can be evaluated without calling `trans_lvalue()`. Method `evaluate_array_len()` is introduced to handle length evaluation for zero-sized types referenced by Locals. *Some concerns*. - `trans_lvalue()` has two other entry points in `rvalue.rs`: it is invoked while handling `Rvalue::Ref` and `Rvalue::Discriminant`. There is a chance those may produce the same issue, but I've failed to write a specific test that leads to this. - `evaluate_array_len()` performs the same check (matches lvalue and `Local`), which is performed again in `trans_lvalue()`. Without changing `trans_lvalue()` signature to make it aware that caller deals with rvalue, it seems there is no cheap solution to avoid this check.
| -rw-r--r-- | src/librustc_trans/mir/rvalue.rs | 26 | ||||
| -rw-r--r-- | src/test/run-pass/issue-43205.rs | 14 |
2 files changed, 37 insertions, 3 deletions
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 8051e04060a..096f43e44ab 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -29,7 +29,7 @@ use type_of; use tvec; use value::Value; -use super::MirContext; +use super::{MirContext, LocalRef}; use super::constant::const_scalar_checked_binop; use super::operand::{OperandRef, OperandValue}; use super::lvalue::LvalueRef; @@ -381,9 +381,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::Rvalue::Len(ref lvalue) => { - let tr_lvalue = self.trans_lvalue(&bcx, lvalue); + let size = self.evaluate_array_len(&bcx, lvalue); let operand = OperandRef { - val: OperandValue::Immediate(tr_lvalue.len(bcx.ccx)), + val: OperandValue::Immediate(size), ty: bcx.tcx().types.usize, }; (bcx, operand) @@ -512,6 +512,26 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } } + fn evaluate_array_len(&mut self, + bcx: &Builder<'a, 'tcx>, + lvalue: &mir::Lvalue<'tcx>) -> ValueRef + { + // ZST are passed as operands and require special handling + // because trans_lvalue() panics if Local is operand. + if let mir::Lvalue::Local(index) = *lvalue { + if let LocalRef::Operand(Some(op)) = self.locals[index] { + if common::type_is_zero_size(bcx.ccx, op.ty) { + if let ty::TyArray(_, n) = op.ty.sty { + return common::C_uint(bcx.ccx, n); + } + } + } + } + // use common size calculation for non zero-sized types + let tr_value = self.trans_lvalue(&bcx, lvalue); + return tr_value.len(bcx.ccx); + } + pub fn trans_scalar_binop(&mut self, bcx: &Builder<'a, 'tcx>, op: mir::BinOp, diff --git a/src/test/run-pass/issue-43205.rs b/src/test/run-pass/issue-43205.rs new file mode 100644 index 00000000000..0e613ac0727 --- /dev/null +++ b/src/test/run-pass/issue-43205.rs @@ -0,0 +1,14 @@ +// Copyright 2016 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() { + &&[()][0]; + println!("{:?}", &[(),()][1]); +} |
