Skip to content

Commit da03a98

Browse files
Use loop instead of visitor to check for invalid projections
1 parent e0fdf7c commit da03a98

File tree

1 file changed

+38
-58
lines changed

1 file changed

+38
-58
lines changed

src/librustc_codegen_ssa/mir/analyze.rs

Lines changed: 38 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use rustc_target::abi::LayoutOf;
1616
pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
1717
fx: &FunctionCx<'a, 'tcx, Bx>,
1818
) -> BitSet<mir::Local> {
19+
trace!("non_ssa_locals({:?})", fx.instance.def_id());
20+
1921
let mir = fx.mir;
2022
let mut analyzer = LocalAnalyzer::new(fx);
2123

@@ -40,21 +42,13 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
4042
analyzer.non_ssa_locals
4143
}
4244

43-
#[derive(Default, PartialEq, Eq)]
44-
struct PlaceInfo {
45-
has_disqualifying_projection: bool,
46-
has_deref_projection: bool,
47-
}
48-
4945
struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
5046
fx: &'mir FunctionCx<'a, 'tcx, Bx>,
5147
dominators: Dominators<mir::BasicBlock>,
5248
non_ssa_locals: BitSet<mir::Local>,
5349

5450
/// The location of the first visited direct assignment to each local.
5551
first_assignment: IndexVec<mir::Local, Option<Location>>,
56-
57-
place_info: PlaceInfo,
5852
}
5953

6054
impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
@@ -65,7 +59,6 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
6559
dominators,
6660
non_ssa_locals: BitSet::new_empty(fx.mir.local_decls.len()),
6761
first_assignment: IndexVec::from_elem(None, &fx.mir.local_decls),
68-
place_info: PlaceInfo::default(),
6962
};
7063

7164
// Arguments get assigned to by means of the function being called
@@ -146,7 +139,12 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
146139
self.super_terminator(terminator, location);
147140
}
148141

149-
fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
142+
fn visit_place(
143+
&mut self,
144+
place: &mir::Place<'tcx>,
145+
mut context: PlaceContext,
146+
location: Location,
147+
) {
150148
debug!("visit_place(place={:?}, context={:?})", place, context);
151149

152150
// Except for `VarDebugInfo`, non-uses do not force locals onto the stack.
@@ -158,7 +156,8 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
158156

159157
let mir::Place { local, projection } = *place;
160158

161-
// Reads from ZSTs do not require memory accesses.
159+
// Reads from ZSTs do not require memory accesses and do not count when determining what
160+
// needs to live on the stack.
162161
if is_consume(context) {
163162
let ty = place.ty(self.fx.mir, self.fx.cx.tcx()).ty;
164163
let ty = self.fx.monomorphize(&ty);
@@ -168,24 +167,40 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
168167
}
169168
}
170169

171-
assert!(self.place_info == PlaceInfo::default(), "`visit_place` should not recurse");
172-
self.visit_projection(local, projection, context, location);
170+
let mut has_disqualifying_projection = false;
173171

174-
let PlaceInfo { has_disqualifying_projection, has_deref_projection } =
175-
std::mem::take(&mut self.place_info);
172+
let mut projection: &[_] = projection.as_ref();
173+
while let [ref proj_base @ .., elem] = *projection {
174+
projection = proj_base;
175+
self.super_projection_elem(local, proj_base, elem, context, location);
176+
177+
// Projections like `(*x)[12]` are allowed but not `*(x[12])`, since a `Deref` of a
178+
// local acts like a `Copy` of that local.
179+
if let mir::PlaceElem::Deref = elem {
180+
has_disqualifying_projection = false;
181+
context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
182+
continue;
183+
}
184+
185+
// Ignoring `Deref`s, the only allowed projections are reads of scalar fields.
186+
if is_consume(context) && matches!(elem, mir::ProjectionElem::Field(..)) {
187+
let base_ty = mir::Place::ty_from(local, proj_base, self.fx.mir, self.fx.cx.tcx());
188+
let base_ty = self.fx.monomorphize(&base_ty);
189+
let span = self.fx.mir.local_decls[local].source_info.span;
190+
let layout = self.fx.cx.spanned_layout_of(base_ty.ty, span);
191+
192+
if !ty_requires_alloca(self.fx, layout) {
193+
continue;
194+
}
195+
}
196+
197+
has_disqualifying_projection = true;
198+
}
176199

177200
if has_disqualifying_projection {
178201
self.not_ssa(local);
179-
return;
180202
}
181203

182-
// Treat a `Deref` of a local as a `Copy` of that local.
183-
let context = if has_deref_projection {
184-
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy)
185-
} else {
186-
context
187-
};
188-
189204
self.visit_local(&local, context, location);
190205
}
191206

@@ -249,41 +264,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
249264
}
250265
}
251266

252-
fn visit_projection_elem(
253-
&mut self,
254-
local: mir::Local,
255-
proj_base: &[mir::PlaceElem<'tcx>],
256-
elem: mir::PlaceElem<'tcx>,
257-
context: PlaceContext,
258-
location: Location,
259-
) {
260-
self.super_projection_elem(local, proj_base, elem, context, location);
261-
262-
// Projections like `(*x)[12]` are allowed but not `*(x[12])`.
263-
if let mir::PlaceElem::Deref = elem {
264-
self.place_info.has_disqualifying_projection = false;
265-
self.place_info.has_deref_projection = true;
266-
return;
267-
}
268-
269-
if !is_consume(context) {
270-
self.place_info.has_disqualifying_projection = true;
271-
return;
272-
}
273-
274-
if let mir::ProjectionElem::Field(..) = elem {
275-
let base_ty = mir::Place::ty_from(local, proj_base, self.fx.mir, self.fx.cx.tcx());
276-
let base_ty = self.fx.monomorphize(&base_ty);
277-
let span = self.fx.mir.local_decls[local].source_info.span;
278-
let layout = self.fx.cx.spanned_layout_of(base_ty.ty, span);
279-
if !ty_requires_alloca(self.fx, layout) {
280-
return;
281-
}
282-
}
283-
284-
self.place_info.has_disqualifying_projection = true;
285-
}
286-
287267
fn visit_var_debug_info(&mut self, var_debug_info: &mir::VarDebugInfo<'tcx>) {
288268
// Indirect debuginfo requires going through memory, that only
289269
// the debugger accesses, following our emitted DWARF pointer ops.

0 commit comments

Comments
 (0)