1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use rustc::hir;
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc_data_structures::indexed_vec::Idx;
use transform::{MirPass, MirSource};
pub struct Deaggregator;
impl MirPass for Deaggregator {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
mir: &mut Mir<'tcx>) {
let id = tcx.hir.as_local_node_id(source.def_id).unwrap();
match (tcx.hir.body_owner_kind(id), source.promoted) {
(_, Some(_)) |
(hir::BodyOwnerKind::Const, _) |
(hir::BodyOwnerKind::Static(_), _) => return,
(hir::BodyOwnerKind::Fn, _) => {
if tcx.is_const_fn(source.def_id) {
return
}
}
}
let (basic_blocks, local_decls) = mir.basic_blocks_and_local_decls_mut();
let local_decls = &*local_decls;
for bb in basic_blocks {
bb.expand_statements(|stmt| {
if let StatementKind::Assign(_, ref rhs) = stmt.kind {
if let Rvalue::Aggregate(ref kind, _) = *rhs {
if let AggregateKind::Array(_) = **kind {
return None;
}
} else {
return None;
}
} else {
return None;
}
let stmt = stmt.replace_nop();
let source_info = stmt.source_info;
let (mut lhs, kind, operands) = match stmt.kind {
StatementKind::Assign(lhs, Rvalue::Aggregate(kind, operands))
=> (lhs, kind, operands),
_ => bug!()
};
let mut set_discriminant = None;
let active_field_index = match *kind {
AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
if adt_def.is_enum() {
set_discriminant = Some(Statement {
kind: StatementKind::SetDiscriminant {
place: lhs.clone(),
variant_index,
},
source_info,
});
lhs = lhs.downcast(adt_def, variant_index);
}
active_field_index
}
_ => None
};
Some(operands.into_iter().enumerate().map(move |(i, op)| {
let lhs_field = if let AggregateKind::Array(_) = *kind {
let offset = i as u32;
assert_eq!(offset as usize, i);
lhs.clone().elem(ProjectionElem::ConstantIndex {
offset,
min_length: offset + 1,
from_end: false
})
} else {
let ty = op.ty(local_decls, tcx);
let field = Field::new(active_field_index.unwrap_or(i));
lhs.clone().field(field, ty)
};
Statement {
source_info,
kind: StatementKind::Assign(lhs_field, Rvalue::Use(op)),
}
}).chain(set_discriminant))
});
}
}
}