Skip to content

Make CTFE able to check for UB... #78407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jan 12, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
--emit=mir now emits both mir_for_ctfe and optimized_mir for `con…
…st fn`
  • Loading branch information
oli-obk committed Jan 11, 2021
commit e90b521a15f12863fced1023e700d02e015931a4
32 changes: 21 additions & 11 deletions compiler/rustc_mir/src/util/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,25 +273,35 @@ pub fn write_mir_pretty<'tcx>(

let mut first = true;
for def_id in dump_mir_def_ids(tcx, single) {
let body = match tcx.hir().body_const_context(def_id.expect_local()) {
// For `const fn` we want to render the optimized MIR. If you want the mir used in
// ctfe, you can dump the MIR after the `Deaggregator` optimization pass.
None | Some(rustc_hir::ConstContext::ConstFn) => tcx.optimized_mir(def_id),
Some(_) => tcx.mir_for_ctfe(def_id),
};

if first {
first = false;
} else {
// Put empty lines between all items
writeln!(w)?;
}

write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;

for body in tcx.promoted_mir(def_id) {
writeln!(w)?;
let render_body = |w: &mut dyn Write, body| -> io::Result<()> {
write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;

for body in tcx.promoted_mir(def_id) {
writeln!(w)?;
write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
}
Ok(())
};
match tcx.hir().body_const_context(def_id.expect_local()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expect_local call here means that write_mir_pretty no longer works for non local def_ids. The ability to print out MIR for non local functions this way is critical for the MIRAI project.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the fix as simple as adding if let Some(local) = def_id.expect_local()? If so, are you interested in making a PR for that change?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt that the fix is that simple. I need a way of actually getting the MIR of non local functions. Perhaps use as_local and keep the old code for the None case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what we can do is to check is_const_fn_raw for the const fn path, and use tcx.instance_mir(ty::InstanceDef::Item(def_id)) for the other two paths

None => render_body(w, tcx.optimized_mir(def_id))?,
// For `const fn` we want to render the optimized MIR. If you want the mir used in
// ctfe, you can dump the MIR after the `Deaggregator` optimization pass.
Some(rustc_hir::ConstContext::ConstFn) => {
render_body(w, tcx.optimized_mir(def_id))?;
writeln!(w)?;
writeln!(w, "// MIR FOR CTFE")?;
// Do not use `render_body`, as that would render the promoteds again, but these
// are shared between mir_for_ctfe and optimized_mir
write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?;
}
Some(_) => render_body(w, tcx.mir_for_ctfe(def_id))?,
}
}
Ok(())
Expand Down
10 changes: 10 additions & 0 deletions src/test/run-make/const_fn_mir/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-include ../../run-make-fulldeps/tools.mk

all:
$(RUSTC) main.rs --emit=mir -o "$(TMPDIR)"/dump.mir

ifdef RUSTC_BLESS_TEST
cp "$(TMPDIR)"/dump.mir dump.mir
else
$(DIFF) dump.mir "$(TMPDIR)"/dump.mir
endif
45 changes: 45 additions & 0 deletions src/test/run-make/const_fn_mir/dump.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// WARNING: This output format is intended for human consumers only
// and is subject to change without notice. Knock yourself out.
fn main() -> () {
let mut _0: (); // return place in scope 0 at main.rs:8:11: 8:11
let _1: i32; // in scope 0 at main.rs:9:5: 9:10

bb0: {
StorageLive(_1); // scope 0 at main.rs:9:5: 9:10
_1 = foo() -> bb1; // scope 0 at main.rs:9:5: 9:10
// mir::Constant
// + span: main.rs:9:5: 9:8
// + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) }
}

bb1: {
StorageDead(_1); // scope 0 at main.rs:9:10: 9:11
_0 = const (); // scope 0 at main.rs:8:11: 10:2
return; // scope 0 at main.rs:10:2: 10:2
}
}

fn foo() -> i32 {
let mut _0: i32; // return place in scope 0 at main.rs:4:19: 4:22

bb0: {
_0 = const 11_i32; // scope 0 at main.rs:5:5: 5:10
return; // scope 0 at main.rs:6:2: 6:2
}
}

// MIR FOR CTFE
fn foo() -> i32 {
let mut _0: i32; // return place in scope 0 at main.rs:4:19: 4:22
let mut _1: (i32, bool); // in scope 0 at main.rs:5:5: 5:10

bb0: {
_1 = CheckedAdd(const 5_i32, const 6_i32); // scope 0 at main.rs:5:5: 5:10
assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 5_i32, const 6_i32) -> bb1; // scope 0 at main.rs:5:5: 5:10
}

bb1: {
_0 = move (_1.0: i32); // scope 0 at main.rs:5:5: 5:10
return; // scope 0 at main.rs:6:2: 6:2
}
}
10 changes: 10 additions & 0 deletions src/test/run-make/const_fn_mir/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// emit-mir
// check-pass

const fn foo() -> i32 {
5 + 6
}

fn main() {
foo();
}