Skip to content

Commit 562ec5a

Browse files
committed
disallow asm! in #[naked] functions
also disallow the `noreturn` option, and infer `naked_asm!` as `!`
1 parent 1a9c1cb commit 562ec5a

27 files changed

Lines changed: 222 additions & 297 deletions

‎compiler/rustc_ast/src/ast.rs‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2278,7 +2278,7 @@ impl InlineAsmOptions {
22782278
pubconstCOUNT:usize = Self::all().bits().count_ones()asusize;
22792279

22802280
pubconstGLOBAL_OPTIONS:Self = Self::ATT_SYNTAX.union(Self::RAW);
2281-
pubconstNAKED_OPTIONS:Self = Self::ATT_SYNTAX.union(Self::RAW).union(Self::NORETURN);
2281+
pubconstNAKED_OPTIONS:Self = Self::ATT_SYNTAX.union(Self::RAW);
22822282

22832283
pubfnhuman_readable_names(&self) -> Vec<&'staticstr>{
22842284
letmut options = vec![];
@@ -2434,6 +2434,24 @@ pub enum AsmMacro {
24342434
NakedAsm,
24352435
}
24362436

2437+
implAsmMacro{
2438+
pubconstfnmacro_name(&self) -> &'staticstr{
2439+
matchself{
2440+
AsmMacro::Asm => "asm",
2441+
AsmMacro::GlobalAsm => "global_asm",
2442+
AsmMacro::NakedAsm => "naked_asm",
2443+
}
2444+
}
2445+
2446+
pubconstfnis_supported_option(&self,option:InlineAsmOptions) -> bool{
2447+
matchself{
2448+
AsmMacro::Asm => true,
2449+
AsmMacro::GlobalAsm => InlineAsmOptions::GLOBAL_OPTIONS.contains(option),
2450+
AsmMacro::NakedAsm => InlineAsmOptions::NAKED_OPTIONS.contains(option),
2451+
}
2452+
}
2453+
}
2454+
24372455
/// Inline assembly.
24382456
///
24392457
/// E.g., `asm!("NOP");`.

‎compiler/rustc_builtin_macros/src/asm.rs‎

Lines changed: 2 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -60,35 +60,6 @@ fn eat_operand_keyword<'a>(
6060
}
6161
}
6262

63-
// Public for rustfmt consumption.
64-
#[derive(Copy,Clone)]
65-
pubenumAsmMacro{
66-
/// The `asm!` macro
67-
Asm,
68-
/// The `global_asm!` macro
69-
GlobalAsm,
70-
/// The `naked_asm!` macro
71-
NakedAsm,
72-
}
73-
74-
implAsmMacro{
75-
constfnmacro_name(&self) -> &'staticstr{
76-
matchself{
77-
AsmMacro::Asm => "asm",
78-
AsmMacro::GlobalAsm => "global_asm",
79-
AsmMacro::NakedAsm => "naked_asm",
80-
}
81-
}
82-
83-
constfnis_supported_option(&self,option: ast::InlineAsmOptions) -> bool{
84-
matchself{
85-
AsmMacro::Asm => true,
86-
AsmMacro::GlobalAsm => ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option),
87-
AsmMacro::NakedAsm => ast::InlineAsmOptions::NAKED_OPTIONS.contains(option),
88-
}
89-
}
90-
}
91-
9263
fnparse_args<'a>(
9364
ecx:&ExtCtxt<'a>,
9465
sp:Span,
@@ -529,7 +500,7 @@ fn parse_reg<'a>(
529500

530501
fnexpand_preparsed_asm(
531502
ecx:&mutExtCtxt<'_>,
532-
asm_macro:ast::AsmMacro,
503+
asm_macro:AsmMacro,
533504
args:AsmArgs,
534505
) -> ExpandResult<Result<ast::InlineAsm,ErrorGuaranteed>,()>{
535506
letmut template = vec![];
@@ -872,7 +843,7 @@ pub(super) fn expand_naked_asm<'cx>(
872843
sp:Span,
873844
tts:TokenStream,
874845
) -> MacroExpanderResult<'cx>{
875-
ExpandResult::Ready(matchparse_args(ecx, sp, tts,false){
846+
ExpandResult::Ready(matchparse_args(ecx, sp, tts,AsmMacro::NakedAsm){
876847
Ok(args) => {
877848
letExpandResult::Ready(mac) = expand_preparsed_asm(ecx,AsmMacro::NakedAsm, args)
878849
else{
@@ -940,32 +911,3 @@ pub(super) fn expand_global_asm<'cx>(
940911
}
941912
})
942913
}
943-
944-
pub(super)fnexpand_naked_asm<'cx>(
945-
ecx:&'cxmutExtCtxt<'_>,
946-
sp:Span,
947-
tts:TokenStream,
948-
) -> MacroExpanderResult<'cx>{
949-
ExpandResult::Ready(matchparse_args(ecx, sp, tts,AsmMacro::NakedAsm){
950-
Ok(args) => {
951-
letExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args)else{
952-
returnExpandResult::Retry(());
953-
};
954-
let expr = match mac {
955-
Ok(inline_asm) => P(ast::Expr{
956-
id: ast::DUMMY_NODE_ID,
957-
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
958-
span: sp,
959-
attrs: ast::AttrVec::new(),
960-
tokens:None,
961-
}),
962-
Err(guar) => DummyResult::raw_expr(sp,Some(guar)),
963-
};
964-
MacEager::expr(expr)
965-
}
966-
Err(err) => {
967-
let guar = err.emit();
968-
DummyResult::any(sp, guar)
969-
}
970-
})
971-
}

‎compiler/rustc_error_codes/src/error_codes/E0787.md‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ pub extern "C" fn f() -> u32 {
1111
}
1212
```
1313

14-
The naked functions must be defined using a single inline assembly
15-
block.
14+
The naked function must be defined using a single `naked_asm!` assembly block.
1615

1716
The execution must never fall through past the end of the assembly
18-
code so the block must use `noreturn` option. The asm block can also
17+
code, so it must either return or diverge. The asm block can also
1918
use `att_syntax` and `raw` options, but others options are not allowed.
2019

2120
The asm block must not contain any operands other than `const` and

‎compiler/rustc_hir_typeck/src/expr.rs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3507,7 +3507,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
35073507
}
35083508

35093509
fncheck_expr_asm(&self,asm:&'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx>{
3510-
letmut diverge = asm.options.contains(ast::InlineAsmOptions::NORETURN);
3510+
letmut diverge = match asm.asm_macro{
3511+
rustc_ast::AsmMacro::Asm => asm.options.contains(ast::InlineAsmOptions::NORETURN),
3512+
rustc_ast::AsmMacro::GlobalAsm => true,
3513+
rustc_ast::AsmMacro::NakedAsm => true,
3514+
};
35113515

35123516
for(op, _op_sp)in asm.operands{
35133517
match op {

‎compiler/rustc_passes/messages.ftl‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -488,9 +488,9 @@ passes_naked_asm_outside_naked_fn =
488488
the `naked_asm!` macro can only be used in functions marked with `#[naked]`
489489
490490
passes_naked_functions_asm_block =
491-
naked functions must contain a single asm block
492-
.label_multiple_asm = multiple asm blocks are unsupported in naked functions
493-
.label_non_asm = non-asm is unsupported in naked functions
491+
naked functions must contain a single `naked_asm!` invocation
492+
.label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
493+
.label_non_asm = not allowed in naked functions
494494
495495
passes_naked_functions_asm_options =
496496
asm options unsupported in naked functions: {$unsupported_options}
@@ -500,9 +500,9 @@ passes_naked_functions_incompatible_attribute =
500500
.label = the `{$attr}` attribute is incompatible with `#[naked]`
501501
.naked_attribute = function marked with `#[naked]` here
502502
503-
passes_naked_functions_must_use_noreturn =
504-
asm in naked functions must use `noreturn` option
505-
.suggestion = consider specifying that the asm block is responsible for returning from the function
503+
passes_naked_functions_must_naked_asm =
504+
the `asm!` macro is not allowed in naked functions
505+
.suggestion = consider using the `naked_asm!` macro instead
506506
507507
passes_naked_functions_operands =
508508
only `const` and `sym` operands are supported in naked functions

‎compiler/rustc_passes/src/errors.rs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,12 +1202,12 @@ pub(crate) struct NakedFunctionsAsmOptions {
12021202
}
12031203

12041204
#[derive(Diagnostic)]
1205-
#[diag(passes_naked_functions_must_use_noreturn, code = E0787)]
1206-
pub(crate)structNakedFunctionsMustUseNoreturn{
1205+
#[diag(passes_naked_functions_must_naked_asm, code = E0787)]
1206+
pub(crate)structNakedFunctionsMustNakedAsm{
12071207
#[primary_span]
12081208
pubspan:Span,
1209-
#[suggestion(code = ", options(noreturn)", applicability = "machine-applicable")]
1210-
publast_span:Span,
1209+
#[suggestion(code = "naked_asm!", applicability = "machine-applicable")]
1210+
pubmacro_span:Span,
12111211
}
12121212

12131213
#[derive(Diagnostic)]

‎compiler/rustc_passes/src/naked_functions.rs‎

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ use rustc_middle::hir::nested_filter::OnlyBodies;
1010
use rustc_middle::query::Providers;
1111
use rustc_middle::ty::TyCtxt;
1212
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
13-
use rustc_span::Span;
1413
use rustc_span::symbol::sym;
14+
use rustc_span::{BytePos,Span};
1515
use rustc_target::spec::abi::Abi;
1616

1717
usecrate::errors::{
1818
NakedAsmOutsideNakedFn,NakedFunctionsAsmBlock,NakedFunctionsAsmOptions,
19-
NakedFunctionsMustUseNoreturn,NakedFunctionsOperands,NoPatterns,ParamsNotAllowed,
19+
NakedFunctionsMustNakedAsm,NakedFunctionsOperands,NoPatterns,ParamsNotAllowed,
2020
UndefinedNakedFunctionAbi,
2121
};
2222

@@ -121,21 +121,29 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
121121
fncheck_asm<'tcx>(tcx:TyCtxt<'tcx>,def_id:LocalDefId,body:&'tcx hir::Body<'tcx>){
122122
letmut this = CheckInlineAssembly{ tcx,items:Vec::new()};
123123
this.visit_body(body);
124-
iflet[(ItemKind::Asm | ItemKind::Err, _)] = this.items[..]{
124+
iflet[(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..]{
125125
// Ok.
126126
}else{
127127
letmut must_show_error = false;
128-
letmuthas_asm = false;
128+
letmuthas_naked_asm = false;
129129
letmut has_err = false;
130130
letmut multiple_asms = vec![];
131131
letmut non_asms = vec![];
132132
for&(kind, span)in&this.items{
133133
match kind {
134-
ItemKind::Asmifhas_asm => {
134+
ItemKind::NakedAsmifhas_naked_asm => {
135135
must_show_error = true;
136136
multiple_asms.push(span);
137137
}
138-
ItemKind::Asm => has_asm = true,
138+
ItemKind::NakedAsm => has_naked_asm = true,
139+
ItemKind::InlineAsm => {
140+
has_err = true;
141+
142+
// the span that contains the `asm!` call,
143+
// so tooling can replace it with `naked_asm!`
144+
let macro_span = span.with_hi(span.lo() + BytePos("asm!".len()asu32));
145+
tcx.dcx().emit_err(NakedFunctionsMustNakedAsm{ span, macro_span });
146+
}
139147
ItemKind::NonAsm => {
140148
must_show_error = true;
141149
non_asms.push(span);
@@ -164,7 +172,8 @@ struct CheckInlineAssembly<'tcx> {
164172

165173
#[derive(Copy,Clone)]
166174
enumItemKind{
167-
Asm,
175+
NakedAsm,
176+
InlineAsm,
168177
NonAsm,
169178
Err,
170179
}
@@ -205,8 +214,18 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
205214
}
206215

207216
ExprKind::InlineAsm(asm) => {
208-
self.items.push((ItemKind::Asm, span));
209-
self.check_inline_asm(asm, span);
217+
match asm.asm_macro{
218+
rustc_ast::AsmMacro::Asm => {
219+
self.items.push((ItemKind::InlineAsm, span));
220+
}
221+
rustc_ast::AsmMacro::NakedAsm => {
222+
self.items.push((ItemKind::NakedAsm, span));
223+
self.check_inline_asm(asm, span);
224+
}
225+
rustc_ast::AsmMacro::GlobalAsm => {
226+
// not allowed in this position
227+
}
228+
}
210229
}
211230

212231
ExprKind::DropTemps(..) | ExprKind::Block(..) => {
@@ -250,16 +269,6 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
250269
.join(", "),
251270
});
252271
}
253-
254-
if !asm.options.contains(InlineAsmOptions::NORETURN){
255-
let last_span = asm
256-
.operands
257-
.last()
258-
.map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1)
259-
.shrink_to_hi();
260-
261-
self.tcx.dcx().emit_err(NakedFunctionsMustUseNoreturn{ span, last_span });
262-
}
263272
}
264273
}
265274

‎library/core/src/arch.rs‎

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,3 @@ pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?)
7777
pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?){
7878
/* compiler built-in */
7979
}
80-
81-
/// Inline assembly used in combination with `#[naked]` functions.
82-
///
83-
/// Refer to [Rust By Example] for a usage guide and the [reference] for
84-
/// detailed information about the syntax and available options.
85-
///
86-
/// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html
87-
/// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html
88-
#[unstable(feature = "naked_functions", issue = "90957")]
89-
#[rustc_builtin_macro]
90-
#[cfg(not(bootstrap))]
91-
pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?){
92-
/* compiler built-in */
93-
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use rustc_ast::ast;
2-
use rustc_builtin_macros::asm::{parse_asm_args,AsmArgs,AsmMacro};
2+
use rustc_builtin_macros::asm::{parse_asm_args,AsmArgs};
33

44
usecrate::rewrite::RewriteContext;
55

66
#[allow(dead_code)]
77
pub(crate)fnparse_asm(context:&RewriteContext<'_>,mac:&ast::MacCall) -> Option<AsmArgs>{
88
let ts = mac.args.tokens.clone();
99
letmut parser = super::build_parser(context, ts);
10-
parse_asm_args(&mut parser, mac.span(),AsmMacro::Asm).ok()
10+
parse_asm_args(&mut parser, mac.span(),ast::AsmMacro::Asm).ok()
1111
}

‎tests/codegen/naked-fn/aligned.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#![crate_type = "lib"]
66
#![feature(naked_functions, fn_align)]
7-
use std::arch::asm;
7+
use std::arch::naked_asm;
88

99
// CHECK: Function Attrs: naked
1010
// CHECK-NEXT: define{{.*}}void @naked_empty()
@@ -16,5 +16,5 @@ pub unsafe extern "C" fn naked_empty() {
1616
// CHECK-NEXT: start:
1717
// CHECK-NEXT: call void asm
1818
// CHECK-NEXT: unreachable
19-
asm!("ret", options(noreturn));
19+
naked_asm!("ret");
2020
}

0 commit comments

Comments
 (0)