about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlexey Tarasov <tarasov@dodologics.com>2017-08-20 21:35:00 +1000
committerAlexey Tarasov <tarasov@dodologics.com>2017-08-23 23:10:03 +1000
commite13090e8b2f8adce9277f2ebfa37efa75c8837a8 (patch)
treef7cee317cf6ed47503d3ee921d0615cd977027cf
parenta3f0ee9a7b17d522bfc6385f841d040445730f28 (diff)
downloadrust-e13090e8b2f8adce9277f2ebfa37efa75c8837a8.tar.gz
rust-e13090e8b2f8adce9277f2ebfa37efa75c8837a8.zip
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.
-rw-r--r--src/librustc_trans/mir/rvalue.rs26
-rw-r--r--src/test/run-pass/issue-43205.rs14
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]);
+}