Rollup merge of #131544 - nbdd0121:asm_goto_safe_block, r=petrochenkov
Make asm label blocks safe context Tracking issue: https://github.com/rust-lang/rust/issues/119364 `asm!()` is forced to be wrapped inside unsafe. If there's no special treatment, the label blocks would also always be unsafe with no way of opting out. It was suggested that a simple fix is to make asm label blocks safe: https://github.com/rust-lang/rust/issues/119364#issuecomment-2316037703. `@rustbot` labels: +A-inline-assembly +F-asm
This commit is contained in:
commit
395649558a
4 changed files with 78 additions and 2 deletions
|
@ -537,8 +537,45 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||||
self.requires_unsafe(expr.span, DerefOfRawPointer);
|
self.requires_unsafe(expr.span, DerefOfRawPointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::InlineAsm { .. } => {
|
ExprKind::InlineAsm(box InlineAsmExpr {
|
||||||
|
asm_macro: _,
|
||||||
|
ref operands,
|
||||||
|
template: _,
|
||||||
|
options: _,
|
||||||
|
line_spans: _,
|
||||||
|
}) => {
|
||||||
self.requires_unsafe(expr.span, UseOfInlineAssembly);
|
self.requires_unsafe(expr.span, UseOfInlineAssembly);
|
||||||
|
|
||||||
|
// For inline asm, do not use `walk_expr`, since we want to handle the label block
|
||||||
|
// specially.
|
||||||
|
for op in &**operands {
|
||||||
|
use rustc_middle::thir::InlineAsmOperand::*;
|
||||||
|
match op {
|
||||||
|
In { expr, reg: _ }
|
||||||
|
| Out { expr: Some(expr), reg: _, late: _ }
|
||||||
|
| InOut { expr, reg: _, late: _ } => self.visit_expr(&self.thir()[*expr]),
|
||||||
|
SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
|
||||||
|
self.visit_expr(&self.thir()[*in_expr]);
|
||||||
|
if let Some(out_expr) = out_expr {
|
||||||
|
self.visit_expr(&self.thir()[*out_expr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Out { expr: None, reg: _, late: _ }
|
||||||
|
| Const { value: _, span: _ }
|
||||||
|
| SymFn { value: _, span: _ }
|
||||||
|
| SymStatic { def_id: _ } => {}
|
||||||
|
Label { block } => {
|
||||||
|
// Label blocks are safe context.
|
||||||
|
// `asm!()` is forced to be wrapped inside unsafe. If there's no special
|
||||||
|
// treatment, the label blocks would also always be unsafe with no way
|
||||||
|
// of opting out.
|
||||||
|
self.in_safety_context(SafetyContext::Safe, |this| {
|
||||||
|
visit::walk_block(this, &this.thir()[*block])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
ExprKind::Adt(box AdtExpr {
|
ExprKind::Adt(box AdtExpr {
|
||||||
adt_def,
|
adt_def,
|
||||||
|
|
|
@ -21,7 +21,9 @@ unsafe {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The block must have unit type or diverge.
|
The block must have unit type or diverge. The block starts a new safety context,
|
||||||
|
so despite outer `unsafe`, you need extra unsafe to perform unsafe operations
|
||||||
|
within `label <block>`.
|
||||||
|
|
||||||
When `label <block>` is used together with `noreturn` option, it means that the
|
When `label <block>` is used together with `noreturn` option, it means that the
|
||||||
assembly will not fallthrough. It's allowed to jump to a label within the
|
assembly will not fallthrough. It's allowed to jump to a label within the
|
||||||
|
|
23
tests/ui/asm/x86_64/goto-block-safe.rs
Normal file
23
tests/ui/asm/x86_64/goto-block-safe.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//@ only-x86_64
|
||||||
|
//@ needs-asm-support
|
||||||
|
|
||||||
|
#![deny(unreachable_code)]
|
||||||
|
#![feature(asm_goto)]
|
||||||
|
|
||||||
|
use std::arch::asm;
|
||||||
|
|
||||||
|
fn goto_fallthough() {
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"/* {} */",
|
||||||
|
label {
|
||||||
|
core::hint::unreachable_unchecked();
|
||||||
|
//~^ ERROR [E0133]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
goto_fallthough();
|
||||||
|
}
|
14
tests/ui/asm/x86_64/goto-block-safe.stderr
Normal file
14
tests/ui/asm/x86_64/goto-block-safe.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0133]: call to unsafe function `unreachable_unchecked` is unsafe and requires unsafe function or block
|
||||||
|
--> $DIR/goto-block-safe.rs:14:17
|
||||||
|
|
|
||||||
|
LL | unsafe {
|
||||||
|
| ------ items do not inherit unsafety from separate enclosing items
|
||||||
|
...
|
||||||
|
LL | core::hint::unreachable_unchecked();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
||||||
|
|
|
||||||
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0133`.
|
Loading…
Add table
Reference in a new issue