Skip to content

Commit abb61d9

Browse files
committed
Extend the nullable pointer optimization to captured vars of closures
1 parent d8b64c7 commit abb61d9

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

src/librustc_trans/trans/adt.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,22 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>,
440440
None
441441
},
442442

443+
// Perhaps one of the upvars of this struct is non-zero
444+
// Let's recurse and find out!
445+
ty::ty_closure(def_id, substs) => {
446+
let typer = NormalizingClosureTyper::new(tcx);
447+
let upvars = typer.closure_upvars(def_id, substs).unwrap();
448+
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
449+
450+
for (j, &ty) in upvar_types.iter().enumerate() {
451+
if let Some(mut fpath) = find_discr_field_candidate(tcx, ty, path.clone()) {
452+
fpath.push(j);
453+
return Some(fpath);
454+
}
455+
}
456+
None
457+
},
458+
443459
// Can we use one of the fields in this tuple?
444460
ty::ty_tup(ref tys) => {
445461
for (j, &ty) in tys.iter().enumerate() {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2015 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+
12+
use std::mem;
13+
14+
pub fn main() {
15+
// By Ref Capture
16+
let a = 10i32;
17+
let b = Some(|| println!("{}", a));
18+
// When we capture by reference we can use any of the
19+
// captures as the discriminant since they're all
20+
// behind a pointer.
21+
assert_eq!(mem::size_of_val(&b), mem::size_of::<usize>());
22+
23+
// By Value Capture
24+
let a = Box::new(12i32);
25+
let b = Some(move || println!("{}", a));
26+
// We captured `a` by value and since it's a `Box` we can use it
27+
// as the discriminant.
28+
assert_eq!(mem::size_of_val(&b), mem::size_of::<Box<i32>>());
29+
30+
// By Value Capture - Transitive case
31+
let a = "Hello".to_string(); // String -> Vec -> Unique -> NonZero
32+
let b = Some(move || println!("{}", a));
33+
// We captured `a` by value and since down the chain it contains
34+
// a `NonZero` field, we can use it as the discriminant.
35+
assert_eq!(mem::size_of_val(&b), mem::size_of::<String>());
36+
37+
// By Value - No Optimization
38+
let a = 14i32;
39+
let b = Some(move || println!("{}", a));
40+
// We captured `a` by value but we can't use it as the discriminant
41+
// thus we end up with an extra field for the discriminant
42+
assert_eq!(mem::size_of_val(&b), mem::size_of::<(i32, i32)>());
43+
}

0 commit comments

Comments
 (0)