Skip to content

Commit 46af169

Browse files
committed
codegen: fix OperandRef subtype handling
1 parent be33ad8 commit 46af169

File tree

6 files changed

+101
-29
lines changed

6 files changed

+101
-29
lines changed

compiler/rustc_codegen_ssa/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#![feature(if_let_guard)]
55
#![feature(int_roundings)]
66
#![feature(let_chains)]
7+
#![feature(negative_impls)]
78
#![feature(never_type)]
89
#![feature(strict_provenance)]
910
#![feature(try_blocks)]

compiler/rustc_codegen_ssa/src/mir/block.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1729,7 +1729,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
17291729
IndirectOperand(tmp, index) => {
17301730
let op = bx.load_operand(tmp);
17311731
tmp.storage_dead(bx);
1732-
self.locals[index] = LocalRef::Operand(op);
1732+
self.overwrite_local(index, LocalRef::Operand(op));
17331733
self.debug_introduce_local(bx, index);
17341734
}
17351735
DirectOperand(index) => {
@@ -1744,7 +1744,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
17441744
} else {
17451745
OperandRef::from_immediate_or_packed_pair(bx, llval, ret_abi.layout)
17461746
};
1747-
self.locals[index] = LocalRef::Operand(op);
1747+
self.overwrite_local(index, LocalRef::Operand(op));
17481748
self.debug_introduce_local(bx, index);
17491749
}
17501750
}

compiler/rustc_codegen_ssa/src/mir/debuginfo.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
248248
}
249249

250250
fn spill_operand_to_stack(
251-
operand: &OperandRef<'tcx, Bx::Value>,
251+
operand: OperandRef<'tcx, Bx::Value>,
252252
name: Option<String>,
253253
bx: &mut Bx,
254254
) -> PlaceRef<'tcx, Bx::Value> {
@@ -375,7 +375,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
375375
return;
376376
}
377377

378-
Self::spill_operand_to_stack(operand, name, bx)
378+
Self::spill_operand_to_stack(*operand, name, bx)
379379
}
380380

381381
LocalRef::Place(place) => *place,
@@ -550,7 +550,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
550550
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
551551
self.set_debug_loc(bx, var.source_info);
552552
let base = Self::spill_operand_to_stack(
553-
&operand,
553+
operand,
554554
Some(var.name.to_string()),
555555
bx,
556556
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//! Locals are in a private module as updating `LocalRef::Operand` has to
2+
//! be careful wrt to subtyping. To deal with this we only allow updates by using
3+
//! `FunctionCx::overwrite_local` which handles it automatically.
4+
use crate::mir::{FunctionCx, LocalRef};
5+
use crate::traits::BuilderMethods;
6+
use rustc_index::IndexVec;
7+
use rustc_middle::mir;
8+
use rustc_middle::ty::print::with_no_trimmed_paths;
9+
use std::ops::{Index, IndexMut};
10+
11+
pub(super) struct Locals<'tcx, V> {
12+
values: IndexVec<mir::Local, LocalRef<'tcx, V>>,
13+
}
14+
15+
impl<'tcx, V> Index<mir::Local> for Locals<'tcx, V> {
16+
type Output = LocalRef<'tcx, V>;
17+
#[inline]
18+
fn index(&self, index: mir::Local) -> &LocalRef<'tcx, V> {
19+
&self.values[index]
20+
}
21+
}
22+
23+
/// To mutate locals, use `FunctionCx::overwrite_local` instead.
24+
impl<'tcx, V, Idx: ?Sized> !IndexMut<Idx> for Locals<'tcx, V> {}
25+
26+
impl<'tcx, V> Locals<'tcx, V> {
27+
pub(super) fn empty() -> Locals<'tcx, V> {
28+
Locals { values: IndexVec::default() }
29+
}
30+
31+
pub(super) fn indices(&self) -> impl DoubleEndedIterator<Item = mir::Local> + Clone + 'tcx {
32+
self.values.indices()
33+
}
34+
}
35+
36+
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
37+
pub(super) fn initialize_locals(&mut self, values: Vec<LocalRef<'tcx, Bx::Value>>) {
38+
assert!(self.locals.values.is_empty());
39+
40+
for (local, value) in values.into_iter().enumerate() {
41+
match value {
42+
LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
43+
LocalRef::Operand(op) => {
44+
let local = mir::Local::from_usize(local);
45+
let expected_ty = self.monomorphize(self.mir.local_decls[local].ty);
46+
assert_eq!(expected_ty, op.layout.ty, "unexpected initial operand type");
47+
}
48+
}
49+
50+
self.locals.values.push(value);
51+
}
52+
}
53+
54+
pub(super) fn overwrite_local(
55+
&mut self,
56+
local: mir::Local,
57+
mut value: LocalRef<'tcx, Bx::Value>,
58+
) {
59+
match value {
60+
LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
61+
LocalRef::Operand(ref mut op) => {
62+
let local_ty = self.monomorphize(self.mir.local_decls[local].ty);
63+
if local_ty != op.layout.ty {
64+
debug!("updating type of operand due to subtyping");
65+
with_no_trimmed_paths!(debug!(?op.layout.ty));
66+
with_no_trimmed_paths!(debug!(?local_ty));
67+
op.layout.ty = local_ty;
68+
}
69+
}
70+
};
71+
72+
self.locals.values[local] = value;
73+
}
74+
}

compiler/rustc_codegen_ssa/src/mir/mod.rs

+20-23
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
use crate::base;
22
use crate::traits::*;
3+
use rustc_index::bit_set::BitSet;
4+
use rustc_index::IndexVec;
35
use rustc_middle::mir;
46
use rustc_middle::mir::interpret::ErrorHandled;
7+
use rustc_middle::mir::traversal;
58
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
69
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
710
use rustc_target::abi::call::{FnAbi, PassMode};
811

912
use std::iter;
1013

11-
use rustc_index::bit_set::BitSet;
12-
use rustc_index::IndexVec;
14+
mod analyze;
15+
mod block;
16+
pub mod constant;
17+
pub mod coverageinfo;
18+
pub mod debuginfo;
19+
mod intrinsic;
20+
mod locals;
21+
pub mod operand;
22+
pub mod place;
23+
mod rvalue;
24+
mod statement;
1325

1426
use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
15-
use self::place::PlaceRef;
16-
use rustc_middle::mir::traversal;
17-
1827
use self::operand::{OperandRef, OperandValue};
28+
use self::place::PlaceRef;
1929

2030
// Used for tracking the state of generated basic blocks.
2131
enum CachedLlbb<T> {
@@ -91,7 +101,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
91101
///
92102
/// Avoiding allocs can also be important for certain intrinsics,
93103
/// notably `expect`.
94-
locals: IndexVec<mir::Local, LocalRef<'tcx, Bx::Value>>,
104+
locals: locals::Locals<'tcx, Bx::Value>,
95105

96106
/// All `VarDebugInfo` from the MIR body, partitioned by `Local`.
97107
/// This is `None` if no var`#[non_exhaustive]`iable debuginfo/names are needed.
@@ -192,7 +202,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
192202
cleanup_kinds,
193203
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
194204
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
195-
locals: IndexVec::new(),
205+
locals: locals::Locals::empty(),
196206
debug_context,
197207
per_local_var_debug_info: None,
198208
caller_location: None,
@@ -223,7 +233,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
223233
let memory_locals = analyze::non_ssa_locals(&fx);
224234

225235
// Allocate variable and temp allocas
226-
fx.locals = {
236+
let local_values = {
227237
let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals);
228238

229239
let mut allocate_local = |local| {
@@ -256,6 +266,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
256266
.chain(mir.vars_and_temps_iter().map(allocate_local))
257267
.collect()
258268
};
269+
fx.initialize_locals(local_values);
259270

260271
// Apply debuginfo to the newly allocated locals.
261272
fx.debug_introduce_locals(&mut start_bx);
@@ -289,14 +300,13 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
289300
.enumerate()
290301
.map(|(arg_index, local)| {
291302
let arg_decl = &mir.local_decls[local];
303+
let arg_ty = fx.monomorphize(arg_decl.ty);
292304

293305
if Some(local) == mir.spread_arg {
294306
// This argument (e.g., the last argument in the "rust-call" ABI)
295307
// is a tuple that was spread at the ABI level and now we have
296308
// to reconstruct it into a tuple local variable, from multiple
297309
// individual LLVM function arguments.
298-
299-
let arg_ty = fx.monomorphize(arg_decl.ty);
300310
let ty::Tuple(tupled_arg_tys) = arg_ty.kind() else {
301311
bug!("spread argument isn't a tuple?!");
302312
};
@@ -331,8 +341,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
331341
}
332342

333343
if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() {
334-
let arg_ty = fx.monomorphize(arg_decl.ty);
335-
336344
let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
337345
bx.va_start(va_list.llval);
338346

@@ -429,14 +437,3 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
429437

430438
args
431439
}
432-
433-
mod analyze;
434-
mod block;
435-
pub mod constant;
436-
pub mod coverageinfo;
437-
pub mod debuginfo;
438-
mod intrinsic;
439-
pub mod operand;
440-
pub mod place;
441-
mod rvalue;
442-
mod statement;

compiler/rustc_codegen_ssa/src/mir/statement.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2020
}
2121
LocalRef::PendingOperand => {
2222
let operand = self.codegen_rvalue_operand(bx, rvalue);
23-
self.locals[index] = LocalRef::Operand(operand);
23+
self.overwrite_local(index, LocalRef::Operand(operand));
2424
self.debug_introduce_local(bx, index);
2525
}
2626
LocalRef::Operand(op) => {

0 commit comments

Comments
 (0)