Skip to content

Commit f511b21

Browse files
committed
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
2 parents 1096e7a + fb00e60 commit f511b21

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

src/librustc_trans/trans/expr.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,21 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
149149
},
150150
}
151151
}
152+
153+
// If we see a const here, that's because it evaluates to a type with zero size. We
154+
// should be able to just discard it, since const expressions are guaranteed not to
155+
// have side effects. This seems to be reached through tuple struct constructors being
156+
// passed zero-size constants.
157+
if let hir::ExprPath(..) = expr.node {
158+
match bcx.def(expr.id) {
159+
Def::Const(_) | Def::AssociatedConst(_) => {
160+
assert!(type_is_zero_size(bcx.ccx(), bcx.tcx().node_id_to_type(expr.id)));
161+
return bcx;
162+
}
163+
_ => {}
164+
}
165+
}
166+
152167
// Even if we don't have a value to emit, and the expression
153168
// doesn't have any side-effects, we still have to translate the
154169
// body of any closures.
@@ -160,7 +175,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
160175
match expr.node {
161176
hir::ExprPath(..) => {
162177
match bcx.def(expr.id) {
163-
Def::Const(did) => {
178+
Def::Const(did) | Def::AssociatedConst(did) => {
164179
let empty_substs = bcx.tcx().mk_substs(Substs::trans_empty());
165180
let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
166181
empty_substs);
@@ -896,7 +911,7 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
896911
let lval = Lvalue::new("expr::trans_def");
897912
DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval)))
898913
}
899-
Def::Const(_) => {
914+
Def::Const(_) | Def::AssociatedConst(_) => {
900915
bcx.sess().span_bug(ref_expr.span,
901916
"constant expression should not reach expr::trans_def")
902917
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(associated_consts)]
12+
13+
#[derive(Clone, Copy, Debug)]
14+
struct Bar;
15+
16+
const BAZ: Bar = Bar;
17+
18+
#[derive(Debug)]
19+
struct Foo([Bar; 1]);
20+
21+
struct Biz;
22+
23+
impl Biz {
24+
const BAZ: Foo = Foo([BAZ; 1]);
25+
}
26+
27+
fn main() {
28+
let foo = Biz::BAZ;
29+
println!("{:?}", foo);
30+
}

src/test/run-pass/issue-31267.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Regression test for issue #31267
12+
13+
#![feature(associated_consts)]
14+
15+
struct Foo;
16+
17+
impl Foo {
18+
const FOO: [i32; 3] = [0; 3];
19+
}
20+
21+
pub fn main() {
22+
let foo = Foo::FOO;
23+
assert_eq!(foo, [0i32, 0, 0]);
24+
}

0 commit comments

Comments
 (0)