Skip to content

Commit

Permalink
Fixes issue rust-lang#43205: ICE in Rvalue::Len evaluation.
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
taleks committed Aug 23, 2017
1 parent a3f0ee9 commit e13090e
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 3 deletions.
26 changes: 23 additions & 3 deletions src/librustc_trans/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 14 additions & 0 deletions src/test/run-pass/issue-43205.rs
Original file line number Diff line number Diff line change
@@ -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]);
}

0 comments on commit e13090e

Please sign in to comment.