Skip to content

Commit

Permalink
Rollup merge of rust-lang#131544 - nbdd0121:asm_goto_safe_block, r=pe…
Browse files Browse the repository at this point in the history
…trochenkov

Make asm label blocks safe context

Tracking issue: rust-lang#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: rust-lang#119364 (comment).

`@rustbot` labels: +A-inline-assembly +F-asm
  • Loading branch information
matthiaskrgr authored Nov 21, 2024
2 parents fe5403f + 809dc73 commit 3956495
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 2 deletions.
39 changes: 38 additions & 1 deletion compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,8 +537,45 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
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);

// 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 {
adt_def,
Expand Down
4 changes: 3 additions & 1 deletion src/doc/unstable-book/src/language-features/asm-goto.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
assembly will not fallthrough. It's allowed to jump to a label within the
Expand Down
23 changes: 23 additions & 0 deletions tests/ui/asm/x86_64/goto-block-safe.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions tests/ui/asm/x86_64/goto-block-safe.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 3956495

Please sign in to comment.