Skip to content

Commit 1357144

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

File tree

10 files changed

+124
-0
lines changed

10 files changed

+124
-0
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

+5
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
468468
no_core, CrateLevel, template!(Word), WarnFollowing,
469469
@only_local: true, experimental!(no_core)
470470
),
471+
gated!(
472+
rustc_ub_check, CrateLevel, template!(Word), WarnFollowing,
473+
@only_local: true,
474+
"`#![rustc_ub_check]` is an internal feature of the standard library, marks annotated code to not have UB checks optimized.",
475+
),
471476
// RFC 2412
472477
gated!(
473478
optimize, Normal, template!(List: "size|speed"), ErrorPreceding,

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ declare_features! (
221221
(internal, profiler_runtime, "1.18.0", None),
222222
/// Allows using `rustc_*` attributes (RFC 572).
223223
(internal, rustc_attrs, "1.0.0", None),
224+
/// Keep UB checks for the standard library.
225+
(internal, rustc_ub_check, "CURRENT_RUSTC_VERSION", None),
224226
/// Allows using the `#[stable]` and `#[unstable]` attributes.
225227
(internal, staged_api, "1.0.0", None),
226228
/// Added for testing unstable lints; perma-unstable.

compiler/rustc_mir_transform/src/instsimplify.rs

+27
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,17 @@ 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 rustc_ub_check = attr::contains_name(tcx.hir().krate_attrs(), sym::rustc_ub_check)
29+
|| tcx.sess.instrument_coverage();
30+
let debug_assertions = tcx.sess.opts.debug_assertions;
2531
for block in body.basic_blocks.as_mut() {
2632
for statement in block.statements.iter_mut() {
2733
match statement.kind {
2834
StatementKind::Assign(box (_place, ref mut rvalue)) => {
35+
if !rustc_ub_check {
36+
ctx.simplify_ub_check(&statement.source_info, rvalue, debug_assertions);
37+
}
2938
ctx.simplify_bool_cmp(&statement.source_info, rvalue);
3039
ctx.simplify_ref_deref(&statement.source_info, rvalue);
3140
ctx.simplify_len(&statement.source_info, rvalue);
@@ -140,6 +149,24 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
140149
}
141150
}
142151

152+
fn simplify_ub_check(
153+
&self,
154+
source_info: &SourceInfo,
155+
rvalue: &mut Rvalue<'tcx>,
156+
debug_assertions: bool,
157+
) {
158+
if let Rvalue::NullaryOp(ref null_op, _) = *rvalue {
159+
match null_op {
160+
NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) => {}
161+
NullOp::UbCheck(_) => {
162+
let const_ = Const::from_bool(self.tcx, debug_assertions);
163+
let constant = ConstOperand { span: source_info.span, const_, user_ty: None };
164+
*rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
165+
}
166+
}
167+
}
168+
}
169+
143170
fn simplify_cast(&self, rvalue: &mut Rvalue<'tcx>) {
144171
if let Rvalue::Cast(kind, operand, cast_ty) = rvalue {
145172
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
@@ -1576,6 +1576,7 @@ symbols! {
15761576
rustc_test_marker,
15771577
rustc_then_this_would_need,
15781578
rustc_trivial_field_reads,
1579+
rustc_ub_check,
15791580
rustc_unsafe_specialization_marker,
15801581
rustc_variance,
15811582
rustc_variance_of_opaques,

library/core/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@
9494
))]
9595
#![no_core]
9696
#![rustc_coherence_is_core]
97+
#![cfg_attr(not(bootstrap), feature(rustc_ub_check))]
98+
#![cfg_attr(not(bootstrap), rustc_ub_check)]
9799
//
98100
// Lints:
99101
#![deny(rust_2021_incompatible_or_patterns)]

library/std/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@
238238
#![no_std]
239239
// Tell the compiler to link to either panic_abort or panic_unwind
240240
#![needs_panic_runtime]
241+
#![cfg_attr(not(bootstrap), feature(rustc_ub_check))]
242+
#![cfg_attr(not(bootstrap), rustc_ub_check)]
241243
//
242244
// Lints:
243245
#![warn(deprecated_in_future)]
+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+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#![rustc_ub_check] //~ERROR `#![rustc_ub_check]` is an internal feature of the standard library, marks annotated code to not have UB checks optimized.
2+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0658]: `#![rustc_ub_check]` is an internal feature of the standard library, marks annotated code to not have UB checks optimized.
2+
--> $DIR/feature-gate-rustc-ub-check.rs:1:1
3+
|
4+
LL | #![rustc_ub_check]
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: add `#![feature(rustc_ub_check)]` to the crate attributes to enable
8+
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)