mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-27 23:22:58 +00:00
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.
This commit is contained in:
commit
eb8f2586eb
@ -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,
|
||||
|
14
src/test/run-pass/issue-43205.rs
Normal file
14
src/test/run-pass/issue-43205.rs
Normal file
@ -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]);
|
||||
}
|
Loading…
Reference in New Issue
Block a user