Skip to content

Commit f7f8bdf

Browse files
committed
Auto merge of rust-lang#130195 - folkertdev:naked-asm-outside-naked-fn, r=Amanieu
disallow `naked_asm!` outside of `#[naked]` functions tracking issue: rust-lang#90957 parent PR: rust-lang#128651 I split this out from the parent PR because it's self-contained and because the analysis has to search through all functions and there might be performance regressions. r? `@Amanieu`
2 parents 16beabe + 6ca5ec7 commit f7f8bdf

File tree

11 files changed

+132
-16
lines changed

11 files changed

+132
-16
lines changed

compiler/rustc_ast/src/ast.rs

+11
Original file line numberDiff line numberDiff line change
@@ -2418,11 +2418,22 @@ impl InlineAsmOperand {
24182418
}
24192419
}
24202420

2421+
#[derive(Clone, Copy, Encodable, Decodable, Debug, HashStable_Generic)]
2422+
pub enum AsmMacro {
2423+
/// The `asm!` macro
2424+
Asm,
2425+
/// The `global_asm!` macro
2426+
GlobalAsm,
2427+
/// The `naked_asm!` macro
2428+
NakedAsm,
2429+
}
2430+
24212431
/// Inline assembly.
24222432
///
24232433
/// E.g., `asm!("NOP");`.
24242434
#[derive(Clone, Encodable, Decodable, Debug)]
24252435
pub struct InlineAsm {
2436+
pub asm_macro: AsmMacro,
24262437
pub template: Vec<InlineAsmTemplatePiece>,
24272438
pub template_strs: Box<[(Symbol, Option<Symbol>, Span)]>,
24282439
pub operands: Vec<(InlineAsmOperand, Span)>,

compiler/rustc_ast/src/mut_visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1388,6 +1388,7 @@ fn walk_anon_const<T: MutVisitor>(vis: &mut T, AnonConst { id, value }: &mut Ano
13881388
fn walk_inline_asm<T: MutVisitor>(vis: &mut T, asm: &mut InlineAsm) {
13891389
// FIXME: Visit spans inside all this currently ignored stuff.
13901390
let InlineAsm {
1391+
asm_macro: _,
13911392
template: _,
13921393
template_strs: _,
13931394
operands,

compiler/rustc_ast/src/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,7 @@ pub fn walk_anon_const<'a, V: Visitor<'a>>(visitor: &mut V, constant: &'a AnonCo
976976

977977
pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) -> V::Result {
978978
let InlineAsm {
979+
asm_macro: _,
979980
template: _,
980981
template_strs: _,
981982
operands,

compiler/rustc_ast_lowering/src/asm.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -474,8 +474,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
474474
);
475475
let line_spans =
476476
self.arena.alloc_from_iter(asm.line_spans.iter().map(|span| self.lower_span(*span)));
477-
let hir_asm =
478-
hir::InlineAsm { template, template_strs, operands, options: asm.options, line_spans };
477+
let hir_asm = hir::InlineAsm {
478+
asm_macro: asm.asm_macro,
479+
template,
480+
template_strs,
481+
operands,
482+
options: asm.options,
483+
line_spans,
484+
};
479485
self.arena.alloc(hir_asm)
480486
}
481487
}

compiler/rustc_builtin_macros/src/asm.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use lint::BuiltinLintDiag;
33
use rustc_ast::ptr::P;
44
use rustc_ast::token::{self, Delimiter};
55
use rustc_ast::tokenstream::TokenStream;
6+
use rustc_ast::AsmMacro;
67
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
78
use rustc_errors::PResult;
89
use rustc_expand::base::*;
@@ -484,6 +485,7 @@ fn parse_reg<'a>(
484485

485486
fn expand_preparsed_asm(
486487
ecx: &mut ExtCtxt<'_>,
488+
asm_macro: ast::AsmMacro,
487489
args: AsmArgs,
488490
) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
489491
let mut template = vec![];
@@ -774,6 +776,7 @@ fn expand_preparsed_asm(
774776
}
775777

776778
ExpandResult::Ready(Ok(ast::InlineAsm {
779+
asm_macro,
777780
template,
778781
template_strs: template_strs.into_boxed_slice(),
779782
operands: args.operands,
@@ -790,7 +793,7 @@ pub(super) fn expand_asm<'cx>(
790793
) -> MacroExpanderResult<'cx> {
791794
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
792795
Ok(args) => {
793-
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
796+
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::Asm, args) else {
794797
return ExpandResult::Retry(());
795798
};
796799
let expr = match mac {
@@ -819,7 +822,8 @@ pub(super) fn expand_naked_asm<'cx>(
819822
) -> MacroExpanderResult<'cx> {
820823
ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
821824
Ok(args) => {
822-
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
825+
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::NakedAsm, args)
826+
else {
823827
return ExpandResult::Retry(());
824828
};
825829
let expr = match mac {
@@ -857,7 +861,8 @@ pub(super) fn expand_global_asm<'cx>(
857861
) -> MacroExpanderResult<'cx> {
858862
ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
859863
Ok(args) => {
860-
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
864+
let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, AsmMacro::GlobalAsm, args)
865+
else {
861866
return ExpandResult::Retry(());
862867
};
863868
match mac {

compiler/rustc_hir/src/hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2927,6 +2927,7 @@ impl<'hir> InlineAsmOperand<'hir> {
29272927

29282928
#[derive(Debug, Clone, Copy, HashStable_Generic)]
29292929
pub struct InlineAsm<'hir> {
2930+
pub asm_macro: ast::AsmMacro,
29302931
pub template: &'hir [InlineAsmTemplatePiece],
29312932
pub template_strs: &'hir [(Symbol, Option<Symbol>, Span)],
29322933
pub operands: &'hir [(InlineAsmOperand<'hir>, Span)],

compiler/rustc_passes/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,9 @@ passes_must_not_suspend =
484484
passes_must_use_no_effect =
485485
`#[must_use]` has no effect when applied to {$article} {$target}
486486
487+
passes_naked_asm_outside_naked_fn =
488+
the `naked_asm!` macro can only be used in functions marked with `#[naked]`
489+
487490
passes_naked_functions_asm_block =
488491
naked functions must contain a single asm block
489492
.label_multiple_asm = multiple asm blocks are unsupported in naked functions

compiler/rustc_passes/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,13 @@ pub(crate) struct NakedFunctionIncompatibleAttribute {
12211221
pub attr: Symbol,
12221222
}
12231223

1224+
#[derive(Diagnostic)]
1225+
#[diag(passes_naked_asm_outside_naked_fn)]
1226+
pub(crate) struct NakedAsmOutsideNakedFn {
1227+
#[primary_span]
1228+
pub span: Span,
1229+
}
1230+
12241231
#[derive(Diagnostic)]
12251232
#[diag(passes_attr_only_in_functions)]
12261233
pub(crate) struct AttrOnlyInFunctions {

compiler/rustc_passes/src/naked_functions.rs

+37-11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_hir::def::DefKind;
66
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
77
use rustc_hir::intravisit::Visitor;
88
use rustc_hir::{ExprKind, HirIdSet, InlineAsmOperand, StmtKind};
9+
use rustc_middle::hir::nested_filter::OnlyBodies;
910
use rustc_middle::query::Providers;
1011
use rustc_middle::ty::TyCtxt;
1112
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
@@ -14,8 +15,9 @@ use rustc_span::Span;
1415
use rustc_target::spec::abi::Abi;
1516

1617
use crate::errors::{
17-
NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, NakedFunctionsMustUseNoreturn,
18-
NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, UndefinedNakedFunctionAbi,
18+
NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions,
19+
NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed,
20+
UndefinedNakedFunctionAbi,
1921
};
2022

2123
pub(crate) fn provide(providers: &mut Providers) {
@@ -29,11 +31,6 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
2931
continue;
3032
}
3133

32-
let naked = tcx.has_attr(def_id, sym::naked);
33-
if !naked {
34-
continue;
35-
}
36-
3734
let (fn_header, body_id) = match tcx.hir_node_by_def_id(def_id) {
3835
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })
3936
| hir::Node::TraitItem(hir::TraitItem {
@@ -48,10 +45,17 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
4845
};
4946

5047
let body = tcx.hir().body(body_id);
51-
check_abi(tcx, def_id, fn_header.abi);
52-
check_no_patterns(tcx, body.params);
53-
check_no_parameters_use(tcx, body);
54-
check_asm(tcx, def_id, body);
48+
49+
if tcx.has_attr(def_id, sym::naked) {
50+
check_abi(tcx, def_id, fn_header.abi);
51+
check_no_patterns(tcx, body.params);
52+
check_no_parameters_use(tcx, body);
53+
check_asm(tcx, def_id, body);
54+
} else {
55+
// `naked_asm!` is not allowed outside of functions marked as `#[naked]`
56+
let mut visitor = CheckNakedAsmInNakedFn { tcx };
57+
visitor.visit_body(body);
58+
}
5559
}
5660
}
5761

@@ -276,3 +280,25 @@ impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> {
276280
self.check_expr(expr, expr.span);
277281
}
278282
}
283+
284+
struct CheckNakedAsmInNakedFn<'tcx> {
285+
tcx: TyCtxt<'tcx>,
286+
}
287+
288+
impl<'tcx> Visitor<'tcx> for CheckNakedAsmInNakedFn<'tcx> {
289+
type NestedFilter = OnlyBodies;
290+
291+
fn nested_visit_map(&mut self) -> Self::Map {
292+
self.tcx.hir()
293+
}
294+
295+
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
296+
if let ExprKind::InlineAsm(inline_asm) = expr.kind {
297+
if let rustc_ast::AsmMacro::NakedAsm = inline_asm.asm_macro {
298+
self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span: expr.span });
299+
}
300+
}
301+
302+
hir::intravisit::walk_expr(self, expr);
303+
}
304+
}
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@ edition: 2021
2+
//@ needs-asm-support
3+
//@ ignore-nvptx64
4+
//@ ignore-spirv
5+
6+
#![feature(naked_functions)]
7+
#![crate_type = "lib"]
8+
9+
use std::arch::naked_asm;
10+
11+
fn main() {
12+
test1();
13+
}
14+
15+
#[naked]
16+
extern "C" fn test1() {
17+
unsafe { naked_asm!("") }
18+
}
19+
20+
extern "C" fn test2() {
21+
unsafe { naked_asm!("") }
22+
//~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]`
23+
}
24+
25+
extern "C" fn test3() {
26+
unsafe { (|| naked_asm!(""))() }
27+
//~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]`
28+
}
29+
30+
fn test4() {
31+
async move {
32+
unsafe { naked_asm!("") } ;
33+
//~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]`
34+
};
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: the `naked_asm!` macro can only be used in functions marked with `#[naked]`
2+
--> $DIR/naked-asm-outside-naked-fn.rs:21:14
3+
|
4+
LL | unsafe { naked_asm!("") }
5+
| ^^^^^^^^^^^^^^
6+
7+
error: the `naked_asm!` macro can only be used in functions marked with `#[naked]`
8+
--> $DIR/naked-asm-outside-naked-fn.rs:26:18
9+
|
10+
LL | unsafe { (|| naked_asm!(""))() }
11+
| ^^^^^^^^^^^^^^
12+
13+
error: the `naked_asm!` macro can only be used in functions marked with `#[naked]`
14+
--> $DIR/naked-asm-outside-naked-fn.rs:32:19
15+
|
16+
LL | unsafe { naked_asm!("") } ;
17+
| ^^^^^^^^^^^^^^
18+
19+
error: aborting due to 3 previous errors
20+

0 commit comments

Comments
 (0)