From e13090e8b2f8adce9277f2ebfa37efa75c8837a8 Mon Sep 17 00:00:00 2001 From: Alexey Tarasov Date: Sun, 20 Aug 2017 21:35:00 +1000 Subject: [PATCH] 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. --- src/librustc_trans/mir/rvalue.rs | 26 +++++++++++++++++++++++--- src/test/run-pass/issue-43205.rs | 14 ++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/issue-43205.rs 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + &&[()][0]; + println!("{:?}", &[(),()][1]); +}