Skip to content

Commit 7357cfb

Browse files
authored
Rollup merge of #105147 - nbdd0121:inline_const_unsafe, r=oli-obk
Allow unsafe through inline const Handle similar to closures. Address #104087 (comment) Note that this PR does not fix the issue for `unsafe { [0; function_requiring_unsafe()] }`. This is fundamentally unfixable for MIR unsafeck IMO. This PR also does not fix unsafety checking for inline const in pattern position. It actually breaks it, allowing unsafe functions to be used in inline const in pattern position without unsafe blocks. Inline const in pattern position is not visible in MIR so ignored by MIR unsafety checking (currently it is also not checked by borrow checker, which is the reason why it's considered an incomplete feature). `@rustbot` label: +T-lang +F-inline_const
2 parents aa5b179 + d6dc912 commit 7357cfb

File tree

12 files changed

+177
-19
lines changed

12 files changed

+177
-19
lines changed

compiler/rustc_mir_build/src/build/custom/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use rustc_ast::Attribute;
2121
use rustc_data_structures::fx::FxHashMap;
2222
use rustc_hir::def_id::DefId;
23+
use rustc_hir::HirId;
2324
use rustc_index::vec::IndexVec;
2425
use rustc_middle::{
2526
mir::*,
@@ -33,6 +34,7 @@ mod parse;
3334
pub(super) fn build_custom_mir<'tcx>(
3435
tcx: TyCtxt<'tcx>,
3536
did: DefId,
37+
hir_id: HirId,
3638
thir: &Thir<'tcx>,
3739
expr: ExprId,
3840
params: &IndexVec<ParamId, Param<'tcx>>,
@@ -67,7 +69,10 @@ pub(super) fn build_custom_mir<'tcx>(
6769
parent_scope: None,
6870
inlined: None,
6971
inlined_parent_scope: None,
70-
local_data: ClearCrossCrate::Clear,
72+
local_data: ClearCrossCrate::Set(SourceScopeLocalData {
73+
lint_root: hir_id,
74+
safety: Safety::Safe,
75+
}),
7176
});
7277
body.injection_phase = Some(parse_attribute(attr));
7378

compiler/rustc_mir_build/src/build/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ fn construct_fn<'tcx>(
487487
return custom::build_custom_mir(
488488
tcx,
489489
fn_def.did.to_def_id(),
490+
fn_id,
490491
thir,
491492
expr,
492493
arguments,

compiler/rustc_mir_build/src/check_unsafety.rs

+19-15
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,18 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
132132
fn unsafe_op_in_unsafe_fn_allowed(&self) -> bool {
133133
self.tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, self.hir_context).0 == Level::Allow
134134
}
135+
136+
/// Handle closures/generators/inline-consts, which is unsafecked with their parent body.
137+
fn visit_inner_body(&mut self, def: ty::WithOptConstParam<LocalDefId>) {
138+
if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
139+
let inner_thir = &inner_thir.borrow();
140+
let hir_context = self.tcx.hir().local_def_id_to_hir_id(def.did);
141+
let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
142+
inner_visitor.visit_expr(&inner_thir[expr]);
143+
// Unsafe blocks can be used in the inner body, make sure to take it into account
144+
self.safety_context = inner_visitor.safety_context;
145+
}
146+
}
135147
}
136148

137149
// Searches for accesses to layout constrained fields.
@@ -408,16 +420,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
408420
} else {
409421
ty::WithOptConstParam::unknown(closure_id)
410422
};
411-
let (closure_thir, expr) = self.tcx.thir_body(closure_def).unwrap_or_else(|_| {
412-
(self.tcx.alloc_steal_thir(Thir::new()), ExprId::from_u32(0))
413-
});
414-
let closure_thir = &closure_thir.borrow();
415-
let hir_context = self.tcx.hir().local_def_id_to_hir_id(closure_id);
416-
let mut closure_visitor =
417-
UnsafetyVisitor { thir: closure_thir, hir_context, ..*self };
418-
closure_visitor.visit_expr(&closure_thir[expr]);
419-
// Unsafe blocks can be used in closures, make sure to take it into account
420-
self.safety_context = closure_visitor.safety_context;
423+
self.visit_inner_body(closure_def);
424+
}
425+
ExprKind::ConstBlock { did, substs: _ } => {
426+
let def_id = did.expect_local();
427+
self.visit_inner_body(ty::WithOptConstParam::unknown(def_id));
421428
}
422429
ExprKind::Field { lhs, .. } => {
423430
let lhs = &self.thir[lhs];
@@ -612,11 +619,8 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
612619
return;
613620
}
614621

615-
// Closures are handled by their owner, if it has a body
616-
if tcx.is_closure(def.did.to_def_id()) {
617-
let hir = tcx.hir();
618-
let owner = hir.enclosing_body_owner(hir.local_def_id_to_hir_id(def.did));
619-
tcx.ensure().thir_check_unsafety(owner);
622+
// Closures and inline consts are handled by their owner, if it has a body
623+
if tcx.is_typeck_child(def.did.to_def_id()) {
620624
return;
621625
}
622626

compiler/rustc_mir_transform/src/check_unsafety.rs

+32-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_data_structures::fx::FxHashSet;
22
use rustc_errors::struct_span_err;
33
use rustc_hir as hir;
4+
use rustc_hir::def::DefKind;
45
use rustc_hir::def_id::{DefId, LocalDefId};
56
use rustc_hir::hir_id::HirId;
67
use rustc_hir::intravisit;
@@ -134,6 +135,28 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
134135
self.super_rvalue(rvalue, location);
135136
}
136137

138+
fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
139+
if let Operand::Constant(constant) = op {
140+
let maybe_uneval = match constant.literal {
141+
ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
142+
ConstantKind::Unevaluated(uv, _) => Some(uv),
143+
};
144+
145+
if let Some(uv) = maybe_uneval {
146+
if uv.promoted.is_none() {
147+
let def_id = uv.def.def_id_for_type_of();
148+
if self.tcx.def_kind(def_id) == DefKind::InlineConst {
149+
let local_def_id = def_id.expect_local();
150+
let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
151+
self.tcx.unsafety_check_result(local_def_id);
152+
self.register_violations(violations, used_unsafe_blocks.iter().copied());
153+
}
154+
}
155+
}
156+
}
157+
self.super_operand(op, location);
158+
}
159+
137160
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
138161
// On types with `scalar_valid_range`, prevent
139162
// * `&mut x.field`
@@ -410,6 +433,12 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
410433
intravisit::walk_block(self, block);
411434
}
412435

436+
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
437+
if matches!(self.tcx.def_kind(c.def_id), DefKind::InlineConst) {
438+
self.visit_body(self.tcx.hir().body(c.body))
439+
}
440+
}
441+
413442
fn visit_fn(
414443
&mut self,
415444
fk: intravisit::FnKind<'tcx>,
@@ -484,7 +513,7 @@ fn unsafety_check_result<'tcx>(
484513
let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env);
485514
checker.visit_body(&body);
486515

487-
let unused_unsafes = (!tcx.is_closure(def.did.to_def_id()))
516+
let unused_unsafes = (!tcx.is_typeck_child(def.did.to_def_id()))
488517
.then(|| check_unused_unsafe(tcx, def.did, &checker.used_unsafe_blocks));
489518

490519
tcx.arena.alloc(UnsafetyCheckResult {
@@ -516,8 +545,8 @@ fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
516545
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
517546
debug!("check_unsafety({:?})", def_id);
518547

519-
// closures are handled by their parent fn.
520-
if tcx.is_closure(def_id.to_def_id()) {
548+
// closures and inline consts are handled by their parent fn.
549+
if tcx.is_typeck_child(def_id.to_def_id()) {
521550
return;
522551
}
523552

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
2+
--> $DIR/expr-unsafe-err.rs:8:9
3+
|
4+
LL | require_unsafe();
5+
| ^^^^^^^^^^^^^^^^ call to unsafe function
6+
|
7+
= note: consult the function's documentation for information on how to avoid undefined behavior
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0133`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// revisions: mir thir
2+
// [thir]compile-flags: -Z thir-unsafeck
3+
#![feature(inline_const)]
4+
const unsafe fn require_unsafe() -> usize { 1 }
5+
6+
fn main() {
7+
const {
8+
require_unsafe();
9+
//~^ ERROR [E0133]
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
2+
--> $DIR/expr-unsafe-err.rs:8:9
3+
|
4+
LL | require_unsafe();
5+
| ^^^^^^^^^^^^^^^^ call to unsafe function
6+
|
7+
= note: consult the function's documentation for information on how to avoid undefined behavior
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0133`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
warning: unnecessary `unsafe` block
2+
--> $DIR/expr-unsafe.rs:12:13
3+
|
4+
LL | unsafe {}
5+
| ^^^^^^ unnecessary `unsafe` block
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/expr-unsafe.rs:4:9
9+
|
10+
LL | #![warn(unused_unsafe)]
11+
| ^^^^^^^^^^^^^
12+
13+
warning: 1 warning emitted
14+
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// check-pass
2+
// revisions: mir thir
3+
// [thir]compile-flags: -Z thir-unsafeck
4+
#![warn(unused_unsafe)]
5+
#![feature(inline_const)]
6+
const unsafe fn require_unsafe() -> usize { 1 }
7+
8+
fn main() {
9+
unsafe {
10+
const {
11+
require_unsafe();
12+
unsafe {}
13+
//~^ WARNING unnecessary `unsafe` block
14+
}
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
warning: unnecessary `unsafe` block
2+
--> $DIR/expr-unsafe.rs:12:13
3+
|
4+
LL | unsafe {
5+
| ------ because it's nested under this `unsafe` block
6+
...
7+
LL | unsafe {}
8+
| ^^^^^^ unnecessary `unsafe` block
9+
|
10+
note: the lint level is defined here
11+
--> $DIR/expr-unsafe.rs:4:9
12+
|
13+
LL | #![warn(unused_unsafe)]
14+
| ^^^^^^^^^^^^^
15+
16+
warning: 1 warning emitted
17+
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// ignore-test This is currently broken
2+
// revisions: mir thir
3+
// [thir]compile-flags: -Z thir-unsafeck
4+
5+
#![allow(incomplete_features)]
6+
#![feature(inline_const_pat)]
7+
8+
const unsafe fn require_unsafe() -> usize { 1 }
9+
10+
fn main() {
11+
match () {
12+
const {
13+
require_unsafe();
14+
//~^ ERROR [E0133]
15+
} => (),
16+
}
17+
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// ignore-test This is currently broken
2+
// check-pass
3+
// revisions: mir thir
4+
// [thir]compile-flags: -Z thir-unsafeck
5+
6+
#![allow(incomplete_features)]
7+
#![warn(unused_unsafe)]
8+
#![feature(inline_const_pat)]
9+
10+
const unsafe fn require_unsafe() -> usize { 1 }
11+
12+
fn main() {
13+
unsafe {
14+
match () {
15+
const {
16+
require_unsafe();
17+
unsafe {}
18+
//~^ WARNING unnecessary `unsafe` block
19+
} => (),
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)