Auto merge of #31326 - sdleffler:master, r=nikomatsakis

After the truly incredible and embarrassing mess I managed to make in my last pull request, this should be a bit less messy.

Fixes #31267 - with this change, the code mentioned in the issue compiles.

Found and fixed another issue as well - constants of zero-size types, when used in ExprRepeats inside associated constants, were causing the compiler to crash at the same place as #31267. An example of this:
```

struct Bar;

const BAZ: Bar = Bar;

struct Foo([Bar; 1]);

struct Biz;

impl Biz {
    const BAZ: Foo = Foo([BAZ; 1]);
}

fn main() {
    let foo = Biz::BAZ;
    println!("{:?}", foo);
}
```
However, I'm fairly certain that my fix for this is not as elegant as it could be. The problem seems to occur only with an associated constant of a tuple struct containing a fixed size array which is initialized using a repeat expression, and when the element to be repeated provided to the repeat expression is another constant which is of a zero-sized type. The fix works by looking for constants and associated constants which are zero-width and consequently contain no data, but for which rustc is still attempting to emit an LLVM value; it simply stops rustc from attempting to emit anything. By my logic, this should work fine since the only values that are emitted in this case (according to the comments) are for closures with side effects, and constants will never have side effects, so it's fine to simply get rid of them. It fixes the error and things compile fine with it, but I have a sneaking suspicion that it could be done in a far better manner.

r? @nikomatsakis
This commit is contained in:
bors 2016-02-04 06:07:26 +00:00
commit f511b21dba
3 changed files with 71 additions and 2 deletions

View File

@ -149,6 +149,21 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
},
}
}
// If we see a const here, that's because it evaluates to a type with zero size. We
// should be able to just discard it, since const expressions are guaranteed not to
// have side effects. This seems to be reached through tuple struct constructors being
// passed zero-size constants.
if let hir::ExprPath(..) = expr.node {
match bcx.def(expr.id) {
Def::Const(_) | Def::AssociatedConst(_) => {
assert!(type_is_zero_size(bcx.ccx(), bcx.tcx().node_id_to_type(expr.id)));
return bcx;
}
_ => {}
}
}
// Even if we don't have a value to emit, and the expression
// doesn't have any side-effects, we still have to translate the
// body of any closures.
@ -160,7 +175,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
match expr.node {
hir::ExprPath(..) => {
match bcx.def(expr.id) {
Def::Const(did) => {
Def::Const(did) | Def::AssociatedConst(did) => {
let empty_substs = bcx.tcx().mk_substs(Substs::trans_empty());
let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
empty_substs);
@ -896,7 +911,7 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let lval = Lvalue::new("expr::trans_def");
DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval)))
}
Def::Const(_) => {
Def::Const(_) | Def::AssociatedConst(_) => {
bcx.sess().span_bug(ref_expr.span,
"constant expression should not reach expr::trans_def")
}

View File

@ -0,0 +1,30 @@
// 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.
#![feature(associated_consts)]
#[derive(Clone, Copy, Debug)]
struct Bar;
const BAZ: Bar = Bar;
#[derive(Debug)]
struct Foo([Bar; 1]);
struct Biz;
impl Biz {
const BAZ: Foo = Foo([BAZ; 1]);
}
fn main() {
let foo = Biz::BAZ;
println!("{:?}", foo);
}

View File

@ -0,0 +1,24 @@
// 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.
// Regression test for issue #31267
#![feature(associated_consts)]
struct Foo;
impl Foo {
const FOO: [i32; 3] = [0; 3];
}
pub fn main() {
let foo = Foo::FOO;
assert_eq!(foo, [0i32, 0, 0]);
}