1
Fork 0

Auto merge of #73210 - wesleywiser:consts_in_debuginfo, r=oli-obk

[mir-opt] Allow debuginfo to be generated for a constant or a Place

Prior to this commit, debuginfo was always generated by mapping a name
to a Place. This has the side-effect that `SimplifyLocals` cannot remove
locals that are only used for debuginfo because their other uses have
been const-propagated.

To allow these locals to be removed, we now allow debuginfo to point to
a constant value. The `ConstProp` pass detects when debuginfo points to
a local with a known constant value and replaces it with the value. This
allows the later `SimplifyLocals` pass to remove the local.
This commit is contained in:
bors 2020-12-15 08:46:00 +00:00
commit e99a89c7c0
16 changed files with 398 additions and 79 deletions

View file

@ -1409,10 +1409,11 @@ fn generator_layout_and_saved_local_names(
let state_arg = mir::Local::new(1);
for var in &body.var_debug_info {
if var.place.local != state_arg {
let place = if let mir::VarDebugInfoContents::Place(p) = var.value { p } else { continue };
if place.local != state_arg {
continue;
}
match var.place.projection[..] {
match place.projection[..] {
[
// Deref of the `Pin<&mut Self>` state argument.
mir::ProjectionElem::Field(..),

View file

@ -11,7 +11,7 @@ use super::FunctionCx;
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn eval_mir_constant_to_operand(
&mut self,
&self,
bx: &mut Bx,
constant: &mir::Constant<'tcx>,
) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
@ -21,7 +21,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
pub fn eval_mir_constant(
&mut self,
&self,
constant: &mir::Constant<'tcx>,
) -> Result<ConstValue<'tcx>, ErrorHandled> {
match self.monomorphize(constant.literal).val {

View file

@ -8,7 +8,7 @@ use rustc_span::symbol::{kw, Symbol};
use rustc_span::{BytePos, Span};
use rustc_target::abi::{LayoutOf, Size};
use super::operand::OperandValue;
use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
use super::{FunctionCx, LocalRef};
@ -116,6 +116,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
span
}
fn spill_operand_to_stack(
operand: &OperandRef<'tcx, Bx::Value>,
name: Option<String>,
bx: &mut Bx,
) -> PlaceRef<'tcx, Bx::Value> {
// "Spill" the value onto the stack, for debuginfo,
// without forcing non-debuginfo uses of the local
// to also load from the stack every single time.
// FIXME(#68817) use `llvm.dbg.value` instead,
// at least for the cases which LLVM handles correctly.
let spill_slot = PlaceRef::alloca(bx, operand.layout);
if let Some(name) = name {
bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill"));
}
operand.val.store(bx, spill_slot);
spill_slot
}
/// Apply debuginfo and/or name, after creating the `alloca` for a local,
/// or initializing the local with an operand (whichever applies).
pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
@ -226,17 +244,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return;
}
// "Spill" the value onto the stack, for debuginfo,
// without forcing non-debuginfo uses of the local
// to also load from the stack every single time.
// FIXME(#68817) use `llvm.dbg.value` instead,
// at least for the cases which LLVM handles correctly.
let spill_slot = PlaceRef::alloca(bx, operand.layout);
if let Some(name) = name {
bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill"));
}
operand.val.store(bx, spill_slot);
spill_slot
Self::spill_operand_to_stack(operand, name, bx)
}
LocalRef::Place(place) => *place,
@ -308,6 +316,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
/// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`.
pub fn compute_per_local_var_debug_info(
&self,
bx: &mut Bx,
) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> {
let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
@ -322,8 +331,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
None
};
let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
let place = var.place;
let (var_ty, var_kind) = match var.value {
mir::VarDebugInfoContents::Place(place) => {
let var_ty = self.monomorphized_place_ty(place.as_ref());
let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg
&& place.projection.is_empty()
@ -338,16 +349,46 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} else {
VariableKind::LocalVariable
};
(var_ty, var_kind)
}
mir::VarDebugInfoContents::Const(c) => {
let ty = self.monomorphize(c.literal.ty);
(ty, VariableKind::LocalVariable)
}
};
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
});
per_local[var.place.local].push(PerLocalVarDebugInfo {
match var.value {
mir::VarDebugInfoContents::Place(place) => {
per_local[place.local].push(PerLocalVarDebugInfo {
name: var.name,
source_info: var.source_info,
dbg_var,
projection: var.place.projection,
projection: place.projection,
});
}
mir::VarDebugInfoContents::Const(c) => {
if let Some(dbg_var) = dbg_var {
let dbg_loc = match self.dbg_loc(var.source_info) {
Some(dbg_loc) => dbg_loc,
None => continue,
};
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
let base = Self::spill_operand_to_stack(
&operand,
Some(var.name.to_string()),
bx,
);
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[]);
}
}
}
}
}
Some(per_local)
}
}

View file

@ -186,7 +186,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
caller_location: None,
};
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info();
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx);
for const_ in &mir.required_consts {
if let Err(err) = fx.eval_mir_constant(const_) {

View file

@ -1060,6 +1060,23 @@ impl<'tcx> LocalDecl<'tcx> {
}
}
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub enum VarDebugInfoContents<'tcx> {
/// NOTE(eddyb) There's an unenforced invariant that this `Place` is
/// based on a `Local`, not a `Static`, and contains no indexing.
Place(Place<'tcx>),
Const(Constant<'tcx>),
}
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match self {
VarDebugInfoContents::Const(c) => write!(fmt, "{}", c),
VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p),
}
}
}
/// Debug information pertaining to a user variable.
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
pub struct VarDebugInfo<'tcx> {
@ -1071,9 +1088,7 @@ pub struct VarDebugInfo<'tcx> {
pub source_info: SourceInfo,
/// Where the data for this user variable is to be found.
/// NOTE(eddyb) There's an unenforced invariant that this `Place` is
/// based on a `Local`, not a `Static`, and contains no indexing.
pub place: Place<'tcx>,
pub value: VarDebugInfoContents<'tcx>,
}
///////////////////////////////////////////////////////////////////////////

View file

@ -829,16 +829,20 @@ macro_rules! make_mir_visitor {
let VarDebugInfo {
name: _,
source_info,
place,
value,
} = var_debug_info;
self.visit_source_info(source_info);
let location = START_BLOCK.start_location();
match value {
VarDebugInfoContents::Const(c) => self.visit_constant(c, location),
VarDebugInfoContents::Place(place) =>
self.visit_place(
place,
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
location,
);
location
),
}
}
fn super_source_scope(&mut self,

View file

@ -12,7 +12,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::mir::{
traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
PlaceRef,
PlaceRef, VarDebugInfoContents,
};
use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
@ -135,7 +135,8 @@ fn do_mir_borrowck<'a, 'tcx>(
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
for var_debug_info in &input_body.var_debug_info {
if let Some(local) = var_debug_info.place.as_local() {
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
if let Some(local) = place.as_local() {
if let Some(prev_name) = local_names[local] {
if var_debug_info.name != prev_name {
span_bug!(
@ -150,6 +151,7 @@ fn do_mir_borrowck<'a, 'tcx>(
local_names[local] = Some(var_debug_info.name);
}
}
}
// Gather the upvars of a closure, if any.
let tables = tcx.typeck_opt_const_arg(def);

View file

@ -0,0 +1,102 @@
//! Finds locals which are assigned once to a const and unused except for debuginfo and converts
//! their debuginfo to use the const directly, allowing the local to be removed.
use rustc_middle::{
mir::{
visit::{PlaceContext, Visitor},
Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents,
},
ty::TyCtxt,
};
use crate::transform::MirPass;
use rustc_index::{bit_set::BitSet, vec::IndexVec};
pub struct ConstDebugInfo;
impl<'tcx> MirPass<'tcx> for ConstDebugInfo {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
return;
}
trace!("running ConstDebugInfo on {:?}", body.source);
for (local, constant) in find_optimization_oportunities(body) {
for debuginfo in &mut body.var_debug_info {
if let VarDebugInfoContents::Place(p) = debuginfo.value {
if p.local == local && p.projection.is_empty() {
trace!(
"changing debug info for {:?} from place {:?} to constant {:?}",
debuginfo.name,
p,
constant
);
debuginfo.value = VarDebugInfoContents::Const(constant);
}
}
}
}
}
}
struct LocalUseVisitor {
local_mutating_uses: IndexVec<Local, u8>,
local_assignment_locations: IndexVec<Local, Option<Location>>,
}
fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> {
let mut visitor = LocalUseVisitor {
local_mutating_uses: IndexVec::from_elem(0, &body.local_decls),
local_assignment_locations: IndexVec::from_elem(None, &body.local_decls),
};
visitor.visit_body(body);
let mut locals_to_debuginfo = BitSet::new_empty(body.local_decls.len());
for debuginfo in &body.var_debug_info {
if let VarDebugInfoContents::Place(p) = debuginfo.value {
if let Some(l) = p.as_local() {
locals_to_debuginfo.insert(l);
}
}
}
let mut eligable_locals = Vec::new();
for (local, mutating_uses) in visitor.local_mutating_uses.drain_enumerated(..) {
if mutating_uses != 1 || !locals_to_debuginfo.contains(local) {
continue;
}
if let Some(location) = visitor.local_assignment_locations[local] {
let bb = &body[location.block];
// The value is assigned as the result of a call, not a constant
if bb.statements.len() == location.statement_index {
continue;
}
if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(box c)))) =
&bb.statements[location.statement_index].kind
{
if let Some(local) = p.as_local() {
eligable_locals.push((local, *c));
}
}
}
}
eligable_locals
}
impl<'tcx> Visitor<'tcx> for LocalUseVisitor {
fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) {
if context.is_mutating_use() {
self.local_mutating_uses[*local] = self.local_mutating_uses[*local].saturating_add(1);
if context.is_place_assignment() {
self.local_assignment_locations[*local] = Some(location);
}
}
}
}

View file

@ -21,6 +21,7 @@ pub mod check_consts;
pub mod check_packed_ref;
pub mod check_unsafety;
pub mod cleanup_post_borrowck;
pub mod const_debuginfo;
pub mod const_prop;
pub mod coverage;
pub mod deaggregator;
@ -408,6 +409,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&remove_noop_landing_pads::RemoveNoopLandingPads,
&simplify::SimplifyCfg::new("final"),
&nrvo::RenameReturnPlace,
&const_debuginfo::ConstDebugInfo,
&simplify::SimplifyLocals,
&multiple_return_terminators::MultipleReturnTerminators,
];

View file

@ -246,12 +246,17 @@ fn get_arm_identity_info<'a, 'tcx>(
tmp_assigned_vars.insert(*r);
}
let dbg_info_to_adjust: Vec<_> =
debug_info
let dbg_info_to_adjust: Vec<_> = debug_info
.iter()
.enumerate()
.filter_map(|(i, var_info)| {
if tmp_assigned_vars.contains(var_info.place.local) { Some(i) } else { None }
if let VarDebugInfoContents::Place(p) = var_info.value {
if tmp_assigned_vars.contains(p.local) {
return Some(i);
}
}
None
})
.collect();
@ -340,11 +345,13 @@ fn optimization_applies<'tcx>(
// Check that debug info only points to full Locals and not projections.
for dbg_idx in &opt_info.dbg_info_to_adjust {
let dbg_info = &var_debug_info[*dbg_idx];
if !dbg_info.place.projection.is_empty() {
trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, dbg_info.place);
if let VarDebugInfoContents::Place(p) = dbg_info.value {
if !p.projection.is_empty() {
trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, p);
return false;
}
}
}
if source_local != opt_info.local_temp_0 {
trace!(
@ -423,9 +430,15 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
// Fix the debug info to point to the right local
for dbg_index in opt_info.dbg_info_to_adjust {
let dbg_info = &mut debug_info[dbg_index];
assert!(dbg_info.place.projection.is_empty());
dbg_info.place.local = opt_info.local_0;
dbg_info.place.projection = opt_info.dbg_projection;
assert!(
matches!(dbg_info.value, VarDebugInfoContents::Place(_)),
"value was not a Place"
);
if let VarDebugInfoContents::Place(p) = &mut dbg_info.value {
assert!(p.projection.is_empty());
p.local = opt_info.local_0;
p.projection = opt_info.dbg_projection;
}
}
trace!("block is now {:?}", bb.statements);

View file

@ -220,7 +220,7 @@ fn write_graph_label<'tcx, W: Write>(
w,
r#"debug {} =&gt; {};<br align="left"/>"#,
var_debug_info.name,
escape(&var_debug_info.place)
escape(&var_debug_info.value),
)?;
}

View file

@ -495,7 +495,7 @@ fn write_scope_tree(
let indented_debug_info = format!(
"{0:1$}debug {2} => {3:?};",
INDENT, indent, var_debug_info.name, var_debug_info.place,
INDENT, indent, var_debug_info.name, var_debug_info.value,
);
writeln!(

View file

@ -1925,7 +1925,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.var_debug_info.push(VarDebugInfo {
name,
source_info: debug_source_info,
place: for_arm_body.into(),
value: VarDebugInfoContents::Place(for_arm_body.into()),
});
let locals = if has_guard.0 {
let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> {
@ -1944,7 +1944,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.var_debug_info.push(VarDebugInfo {
name,
source_info: debug_source_info,
place: ref_for_guard.into(),
value: VarDebugInfoContents::Place(ref_for_guard.into()),
});
LocalsForNode::ForGuard { ref_for_guard, for_arm_body }
} else {

View file

@ -809,7 +809,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.var_debug_info.push(VarDebugInfo {
name: ident.name,
source_info,
place: arg_local.into(),
value: VarDebugInfoContents::Place(arg_local.into()),
});
}
}
@ -882,10 +882,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.var_debug_info.push(VarDebugInfo {
name,
source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
place: Place {
value: VarDebugInfoContents::Place(Place {
local: closure_env_arg,
projection: tcx.intern_place_elems(&projs),
},
}),
});
mutability

View file

@ -0,0 +1,115 @@
- // MIR for `main` before ConstDebugInfo
+ // MIR for `main` after ConstDebugInfo
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/const_debuginfo.rs:8:11: 8:11
let _1: u8; // in scope 0 at $DIR/const_debuginfo.rs:9:9: 9:10
let mut _5: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:15: 12:20
let mut _6: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:15: 12:16
let mut _7: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:19: 12:20
let mut _8: u8; // in scope 0 at $DIR/const_debuginfo.rs:12:23: 12:24
let mut _14: u32; // in scope 0 at $DIR/const_debuginfo.rs:21:13: 21:16
let mut _15: u32; // in scope 0 at $DIR/const_debuginfo.rs:21:19: 21:22
scope 1 {
- debug x => _1; // in scope 1 at $DIR/const_debuginfo.rs:9:9: 9:10
+ debug x => const 1_u8; // in scope 1 at $DIR/const_debuginfo.rs:9:9: 9:10
let _2: u8; // in scope 1 at $DIR/const_debuginfo.rs:10:9: 10:10
scope 2 {
- debug y => _2; // in scope 2 at $DIR/const_debuginfo.rs:10:9: 10:10
+ debug y => const 2_u8; // in scope 2 at $DIR/const_debuginfo.rs:10:9: 10:10
let _3: u8; // in scope 2 at $DIR/const_debuginfo.rs:11:9: 11:10
scope 3 {
- debug z => _3; // in scope 3 at $DIR/const_debuginfo.rs:11:9: 11:10
+ debug z => const 3_u8; // in scope 3 at $DIR/const_debuginfo.rs:11:9: 11:10
let _4: u8; // in scope 3 at $DIR/const_debuginfo.rs:12:9: 12:12
scope 4 {
- debug sum => _4; // in scope 4 at $DIR/const_debuginfo.rs:12:9: 12:12
+ debug sum => const 6_u8; // in scope 4 at $DIR/const_debuginfo.rs:12:9: 12:12
let _9: &str; // in scope 4 at $DIR/const_debuginfo.rs:14:9: 14:10
scope 5 {
- debug s => _9; // in scope 5 at $DIR/const_debuginfo.rs:14:9: 14:10
+ debug s => const "hello, world!"; // in scope 5 at $DIR/const_debuginfo.rs:14:9: 14:10
let _10: (bool, bool, u32); // in scope 5 at $DIR/const_debuginfo.rs:16:9: 16:10
scope 6 {
debug f => _10; // in scope 6 at $DIR/const_debuginfo.rs:16:9: 16:10
let _11: std::option::Option<u16>; // in scope 6 at $DIR/const_debuginfo.rs:18:9: 18:10
scope 7 {
debug o => _11; // in scope 7 at $DIR/const_debuginfo.rs:18:9: 18:10
let _12: Point; // in scope 7 at $DIR/const_debuginfo.rs:20:9: 20:10
scope 8 {
debug p => _12; // in scope 8 at $DIR/const_debuginfo.rs:20:9: 20:10
let _13: u32; // in scope 8 at $DIR/const_debuginfo.rs:21:9: 21:10
scope 9 {
- debug a => _13; // in scope 9 at $DIR/const_debuginfo.rs:21:9: 21:10
+ debug a => const 64_u32; // in scope 9 at $DIR/const_debuginfo.rs:21:9: 21:10
}
}
}
}
}
}
}
}
}
bb0: {
StorageLive(_1); // scope 0 at $DIR/const_debuginfo.rs:9:9: 9:10
_1 = const 1_u8; // scope 0 at $DIR/const_debuginfo.rs:9:13: 9:16
StorageLive(_2); // scope 1 at $DIR/const_debuginfo.rs:10:9: 10:10
_2 = const 2_u8; // scope 1 at $DIR/const_debuginfo.rs:10:13: 10:16
StorageLive(_3); // scope 2 at $DIR/const_debuginfo.rs:11:9: 11:10
_3 = const 3_u8; // scope 2 at $DIR/const_debuginfo.rs:11:13: 11:16
StorageLive(_4); // scope 3 at $DIR/const_debuginfo.rs:12:9: 12:12
StorageLive(_5); // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:20
StorageLive(_6); // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:16
_6 = const 1_u8; // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:16
StorageLive(_7); // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20
_7 = const 2_u8; // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20
_5 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:20
StorageDead(_7); // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20
StorageDead(_6); // scope 3 at $DIR/const_debuginfo.rs:12:19: 12:20
StorageLive(_8); // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24
_8 = const 3_u8; // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24
_4 = const 6_u8; // scope 3 at $DIR/const_debuginfo.rs:12:15: 12:24
StorageDead(_8); // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24
StorageDead(_5); // scope 3 at $DIR/const_debuginfo.rs:12:23: 12:24
StorageLive(_9); // scope 4 at $DIR/const_debuginfo.rs:14:9: 14:10
_9 = const "hello, world!"; // scope 4 at $DIR/const_debuginfo.rs:14:13: 14:28
// ty::Const
// + ty: &str
// + val: Value(Slice { data: Allocation { bytes: [104, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [8191], len: Size { raw: 13 } }, size: Size { raw: 13 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 13 })
// mir::Constant
// + span: $DIR/const_debuginfo.rs:14:13: 14:28
// + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [104, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [8191], len: Size { raw: 13 } }, size: Size { raw: 13 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 13 }) }
StorageLive(_10); // scope 5 at $DIR/const_debuginfo.rs:16:9: 16:10
(_10.0: bool) = const true; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34
(_10.1: bool) = const false; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34
(_10.2: u32) = const 123_u32; // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34
StorageLive(_11); // scope 6 at $DIR/const_debuginfo.rs:18:9: 18:10
((_11 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:18:13: 18:24
discriminant(_11) = 1; // scope 6 at $DIR/const_debuginfo.rs:18:13: 18:24
StorageLive(_12); // scope 7 at $DIR/const_debuginfo.rs:20:9: 20:10
(_12.0: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:20:13: 20:35
(_12.1: u32) = const 32_u32; // scope 7 at $DIR/const_debuginfo.rs:20:13: 20:35
StorageLive(_13); // scope 8 at $DIR/const_debuginfo.rs:21:9: 21:10
StorageLive(_14); // scope 8 at $DIR/const_debuginfo.rs:21:13: 21:16
_14 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:21:13: 21:16
StorageLive(_15); // scope 8 at $DIR/const_debuginfo.rs:21:19: 21:22
_15 = const 32_u32; // scope 8 at $DIR/const_debuginfo.rs:21:19: 21:22
_13 = const 64_u32; // scope 8 at $DIR/const_debuginfo.rs:21:13: 21:22
StorageDead(_15); // scope 8 at $DIR/const_debuginfo.rs:21:21: 21:22
StorageDead(_14); // scope 8 at $DIR/const_debuginfo.rs:21:21: 21:22
_0 = const (); // scope 0 at $DIR/const_debuginfo.rs:8:11: 22:2
StorageDead(_13); // scope 8 at $DIR/const_debuginfo.rs:22:1: 22:2
StorageDead(_12); // scope 7 at $DIR/const_debuginfo.rs:22:1: 22:2
StorageDead(_11); // scope 6 at $DIR/const_debuginfo.rs:22:1: 22:2
StorageDead(_10); // scope 5 at $DIR/const_debuginfo.rs:22:1: 22:2
StorageDead(_9); // scope 4 at $DIR/const_debuginfo.rs:22:1: 22:2
StorageDead(_4); // scope 3 at $DIR/const_debuginfo.rs:22:1: 22:2
StorageDead(_3); // scope 2 at $DIR/const_debuginfo.rs:22:1: 22:2
StorageDead(_2); // scope 1 at $DIR/const_debuginfo.rs:22:1: 22:2
StorageDead(_1); // scope 0 at $DIR/const_debuginfo.rs:22:1: 22:2
return; // scope 0 at $DIR/const_debuginfo.rs:22:2: 22:2
}
}

View file

@ -0,0 +1,24 @@
// compile-flags: -C overflow-checks=no -Zunsound-mir-opts
struct Point {
x: u32,
y: u32,
}
fn main() {
let x = 1u8;
let y = 2u8;
let z = 3u8;
let sum = x + y + z;
let s = "hello, world!";
let f = (true, false, 123u32);
let o = Some(99u16);
let p = Point { x: 32, y: 32 };
let a = p.x + p.y;
}
// EMIT_MIR const_debuginfo.main.ConstDebugInfo.diff