Skip to content

Commit e70f5e6

Browse files
committed
Eliminate UbCheck for non-standard libraries
1 parent 094a620 commit e70f5e6

File tree

7 files changed

+102
-0
lines changed

7 files changed

+102
-0
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

+5
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
772772
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true,
773773
"#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
774774
),
775+
rustc_attr!(
776+
rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing,
777+
@only_local: true,
778+
"`#![rustc_preserve_ub_checks]` prevents the designated crate from evaluating whether UB checks are enabled when optimizing MIR",
779+
),
775780
rustc_attr!(
776781
rustc_deny_explicit_impl,
777782
AttributeType::Normal,

compiler/rustc_mir_transform/src/instsimplify.rs

+23
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
//! Performs various peephole optimizations.
22
33
use crate::simplify::simplify_duplicate_switch_targets;
4+
use rustc_ast::attr;
45
use rustc_middle::mir::*;
56
use rustc_middle::ty::layout;
67
use rustc_middle::ty::layout::ValidityRequirement;
78
use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt};
9+
use rustc_span::sym;
810
use rustc_span::symbol::Symbol;
911
use rustc_target::abi::FieldIdx;
1012
use rustc_target::spec::abi::Abi;
@@ -22,10 +24,18 @@ impl<'tcx> MirPass<'tcx> for InstSimplify {
2224
local_decls: &body.local_decls,
2325
param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
2426
};
27+
// FIXME(#116171) Coverage related, also see `unreachable_prop.rs`.
28+
let preserve_ub_checks =
29+
attr::contains_name(tcx.hir().krate_attrs(), sym::rustc_preserve_ub_checks)
30+
|| tcx.sess.instrument_coverage();
31+
let debug_assertions = tcx.sess.opts.debug_assertions;
2532
for block in body.basic_blocks.as_mut() {
2633
for statement in block.statements.iter_mut() {
2734
match statement.kind {
2835
StatementKind::Assign(box (_place, ref mut rvalue)) => {
36+
if !preserve_ub_checks {
37+
ctx.simplify_ub_check(&statement.source_info, rvalue, debug_assertions);
38+
}
2939
ctx.simplify_bool_cmp(&statement.source_info, rvalue);
3040
ctx.simplify_ref_deref(&statement.source_info, rvalue);
3141
ctx.simplify_len(&statement.source_info, rvalue);
@@ -140,6 +150,19 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
140150
}
141151
}
142152

153+
fn simplify_ub_check(
154+
&self,
155+
source_info: &SourceInfo,
156+
rvalue: &mut Rvalue<'tcx>,
157+
debug_assertions: bool,
158+
) {
159+
if let Rvalue::NullaryOp(NullOp::UbCheck(_), _) = *rvalue {
160+
let const_ = Const::from_bool(self.tcx, debug_assertions);
161+
let constant = ConstOperand { span: source_info.span, const_, user_ty: None };
162+
*rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
163+
}
164+
}
165+
143166
fn simplify_cast(&self, rvalue: &mut Rvalue<'tcx>) {
144167
if let Rvalue::Cast(kind, operand, cast_ty) = rvalue {
145168
let operand_ty = operand.ty(self.local_decls, self.tcx);

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1560,6 +1560,7 @@ symbols! {
15601560
rustc_peek_maybe_init,
15611561
rustc_peek_maybe_uninit,
15621562
rustc_polymorphize_error,
1563+
rustc_preserve_ub_checks,
15631564
rustc_private,
15641565
rustc_proc_macro_decls,
15651566
rustc_promotable,

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
))]
9595
#![no_core]
9696
#![rustc_coherence_is_core]
97+
#![cfg_attr(not(bootstrap), rustc_preserve_ub_checks)]
9798
//
9899
// Lints:
99100
#![deny(rust_2021_incompatible_or_patterns)]

library/std/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@
221221
//
222222
#![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
223223
#![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
224+
#![cfg_attr(not(bootstrap), rustc_preserve_ub_checks)]
224225
#![doc(
225226
html_playground_url = "https://play.rust-lang.org/",
226227
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//@ unit-test: InstSimplify
2+
//@ compile-flags: -Cdebug-assertions=no -Zinline-mir
3+
4+
// EMIT_MIR ub_check.unwrap_unchecked.InstSimplify.diff
5+
pub fn unwrap_unchecked(x: Option<i32>) -> i32 {
6+
// CHECK-LABEL: fn unwrap_unchecked(
7+
// CHECK-NOT: UbCheck(LanguageUb)
8+
// CHECK: [[assume:_.*]] = const false;
9+
// CHECK-NEXT: assume([[assume]]);
10+
// CHECK-NEXT: unreachable_unchecked::precondition_check
11+
unsafe { x.unwrap_unchecked() }
12+
}
13+
14+
fn main() {
15+
unwrap_unchecked(None);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
- // MIR for `unwrap_unchecked` before InstSimplify
2+
+ // MIR for `unwrap_unchecked` after InstSimplify
3+
4+
fn unwrap_unchecked(_1: Option<i32>) -> i32 {
5+
debug x => _1;
6+
let mut _0: i32;
7+
let mut _2: std::option::Option<i32>;
8+
scope 1 {
9+
scope 2 (inlined #[track_caller] Option::<i32>::unwrap_unchecked) {
10+
debug self => _2;
11+
let mut _3: isize;
12+
scope 3 {
13+
debug val => _0;
14+
}
15+
scope 4 {
16+
scope 5 (inlined unreachable_unchecked) {
17+
let mut _4: bool;
18+
let _5: ();
19+
scope 6 {
20+
}
21+
}
22+
}
23+
}
24+
}
25+
26+
bb0: {
27+
StorageLive(_2);
28+
_2 = _1;
29+
StorageLive(_3);
30+
StorageLive(_5);
31+
_3 = discriminant(_2);
32+
switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1];
33+
}
34+
35+
bb1: {
36+
unreachable;
37+
}
38+
39+
bb2: {
40+
StorageLive(_4);
41+
- _4 = UbCheck(LanguageUb);
42+
+ _4 = const false;
43+
assume(_4);
44+
_5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable];
45+
}
46+
47+
bb3: {
48+
_0 = move ((_2 as Some).0: i32);
49+
StorageDead(_5);
50+
StorageDead(_3);
51+
StorageDead(_2);
52+
return;
53+
}
54+
}
55+

0 commit comments

Comments
 (0)