Skip to content

Commit ebdd859

Browse files
Differentiate between asm!(), global_asm!() and naked_asm!(), and make only asm!() unsafe
1 parent 7b39139 commit ebdd859

File tree

16 files changed

+198
-16
lines changed

16 files changed

+198
-16
lines changed

src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use tt::TextRange;
1010

1111
use crate::{
1212
expr_store::lower::{ExprCollector, FxIndexSet},
13-
hir::{AsmOperand, AsmOptions, Expr, ExprId, InlineAsm, InlineAsmRegOrRegClass},
13+
hir::{AsmOperand, AsmOptions, Expr, ExprId, InlineAsm, InlineAsmKind, InlineAsmRegOrRegClass},
1414
};
1515

1616
impl ExprCollector<'_> {
@@ -269,8 +269,17 @@ impl ExprCollector<'_> {
269269
}
270270
})
271271
};
272+
273+
let kind = if asm.global_asm_token().is_some() {
274+
InlineAsmKind::GlobalAsm
275+
} else if asm.naked_asm_token().is_some() {
276+
InlineAsmKind::NakedAsm
277+
} else {
278+
InlineAsmKind::Asm
279+
};
280+
272281
let idx = self.alloc_expr(
273-
Expr::InlineAsm(InlineAsm { operands: operands.into_boxed_slice(), options }),
282+
Expr::InlineAsm(InlineAsm { operands: operands.into_boxed_slice(), options, kind }),
274283
syntax_ptr,
275284
);
276285
self.source_map

src/tools/rust-analyzer/crates/hir-def/src/hir.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,17 @@ pub struct OffsetOf {
332332
pub struct InlineAsm {
333333
pub operands: Box<[(Option<Name>, AsmOperand)]>,
334334
pub options: AsmOptions,
335+
pub kind: InlineAsmKind,
336+
}
337+
338+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
339+
pub enum InlineAsmKind {
340+
/// `asm!()`.
341+
Asm,
342+
/// `global_asm!()`.
343+
GlobalAsm,
344+
/// `naked_asm!()`.
345+
NakedAsm,
335346
}
336347

337348
#[derive(Clone, Copy, PartialEq, Eq, Hash)]

src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,20 @@ fn test_asm_expand() {
2828
r#"
2929
#[rustc_builtin_macro]
3030
macro_rules! asm {() => {}}
31+
#[rustc_builtin_macro]
32+
macro_rules! global_asm {() => {}}
33+
#[rustc_builtin_macro]
34+
macro_rules! naked_asm {() => {}}
35+
36+
// FIXME: This creates an error
37+
// global_asm! {
38+
// ""
39+
// }
40+
41+
#[unsafe(naked)]
42+
extern "C" fn foo() {
43+
naked_asm!("");
44+
}
3145
3246
fn main() {
3347
let i: u64 = 3;
@@ -45,6 +59,20 @@ fn main() {
4559
expect![[r##"
4660
#[rustc_builtin_macro]
4761
macro_rules! asm {() => {}}
62+
#[rustc_builtin_macro]
63+
macro_rules! global_asm {() => {}}
64+
#[rustc_builtin_macro]
65+
macro_rules! naked_asm {() => {}}
66+
67+
// FIXME: This creates an error
68+
// global_asm! {
69+
// ""
70+
// }
71+
72+
#[unsafe(naked)]
73+
extern "C" fn foo() {
74+
builtin #naked_asm ("");
75+
}
4876
4977
fn main() {
5078
let i: u64 = 3;

src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ register_builtin! {
125125
(assert, Assert) => assert_expand,
126126
(stringify, Stringify) => stringify_expand,
127127
(asm, Asm) => asm_expand,
128-
(global_asm, GlobalAsm) => asm_expand,
129-
(naked_asm, NakedAsm) => asm_expand,
128+
(global_asm, GlobalAsm) => global_asm_expand,
129+
(naked_asm, NakedAsm) => naked_asm_expand,
130130
(cfg, Cfg) => cfg_expand,
131131
(core_panic, CorePanic) => panic_expand,
132132
(std_panic, StdPanic) => panic_expand,
@@ -325,6 +325,36 @@ fn asm_expand(
325325
ExpandResult::ok(expanded)
326326
}
327327

328+
fn global_asm_expand(
329+
_db: &dyn ExpandDatabase,
330+
_id: MacroCallId,
331+
tt: &tt::TopSubtree,
332+
span: Span,
333+
) -> ExpandResult<tt::TopSubtree> {
334+
let mut tt = tt.clone();
335+
tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis;
336+
let pound = mk_pound(span);
337+
let expanded = quote! {span =>
338+
builtin #pound global_asm #tt
339+
};
340+
ExpandResult::ok(expanded)
341+
}
342+
343+
fn naked_asm_expand(
344+
_db: &dyn ExpandDatabase,
345+
_id: MacroCallId,
346+
tt: &tt::TopSubtree,
347+
span: Span,
348+
) -> ExpandResult<tt::TopSubtree> {
349+
let mut tt = tt.clone();
350+
tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis;
351+
let pound = mk_pound(span);
352+
let expanded = quote! {span =>
353+
builtin #pound naked_asm #tt
354+
};
355+
ExpandResult::ok(expanded)
356+
}
357+
328358
fn cfg_expand(
329359
db: &dyn ExpandDatabase,
330360
id: MacroCallId,

src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use either::Either;
77
use hir_def::{
88
AdtId, DefWithBodyId, FieldId, FunctionId, VariantId,
99
expr_store::{Body, path::Path},
10-
hir::{AsmOperand, Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp},
10+
hir::{AsmOperand, Expr, ExprId, ExprOrPatId, InlineAsmKind, Pat, PatId, Statement, UnaryOp},
1111
resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
1212
signatures::StaticFlags,
1313
type_ref::Rawness,
@@ -315,7 +315,12 @@ impl<'db> UnsafeVisitor<'db> {
315315
self.inside_assignment = old_inside_assignment;
316316
}
317317
Expr::InlineAsm(asm) => {
318-
self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm);
318+
if asm.kind == InlineAsmKind::Asm {
319+
// `naked_asm!()` requires `unsafe` on the attribute (`#[unsafe(naked)]`),
320+
// and `global_asm!()` doesn't require it at all.
321+
self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm);
322+
}
323+
319324
asm.operands.iter().for_each(|(_, op)| match op {
320325
AsmOperand::In { expr, .. }
321326
| AsmOperand::Out { expr: Some(expr), .. }

src/tools/rust-analyzer/crates/hir/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3220,7 +3220,8 @@ impl Macro {
32203220
}
32213221
}
32223222

3223-
pub fn is_asm_or_global_asm(&self, db: &dyn HirDatabase) -> bool {
3223+
/// Is this `asm!()`, or a variant of it (e.g. `global_asm!()`)?
3224+
pub fn is_asm_like(&self, db: &dyn HirDatabase) -> bool {
32243225
match self.id {
32253226
MacroId::Macro2Id(it) => {
32263227
matches!(it.lookup(db).expander, MacroExpander::BuiltIn(m) if m.is_asm())

src/tools/rust-analyzer/crates/hir/src/semantics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1776,7 +1776,7 @@ impl<'db> SemanticsImpl<'db> {
17761776

17771777
pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
17781778
let Some(mac) = self.resolve_macro_call(macro_call) else { return false };
1779-
if mac.is_asm_or_global_asm(self.db) {
1779+
if mac.is_asm_like(self.db) {
17801780
return true;
17811781
}
17821782

src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,4 +983,19 @@ fn test() {
983983
"#,
984984
);
985985
}
986+
987+
#[test]
988+
fn naked_asm_is_safe() {
989+
check_diagnostics(
990+
r#"
991+
#[rustc_builtin_macro]
992+
macro_rules! naked_asm { () => {} }
993+
994+
#[unsafe(naked)]
995+
extern "C" fn naked() {
996+
naked_asm!("");
997+
}
998+
"#,
999+
);
1000+
}
9861001
}

src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,7 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
253253
let m = p.start();
254254
p.bump_remap(T![builtin]);
255255
p.bump(T![#]);
256-
if p.at_contextual_kw(T![offset_of]) {
257-
p.bump_remap(T![offset_of]);
256+
if p.eat_contextual_kw(T![offset_of]) {
258257
p.expect(T!['(']);
259258
type_(p);
260259
p.expect(T![,]);
@@ -278,8 +277,7 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
278277
p.expect(T![')']);
279278
}
280279
Some(m.complete(p, OFFSET_OF_EXPR))
281-
} else if p.at_contextual_kw(T![format_args]) {
282-
p.bump_remap(T![format_args]);
280+
} else if p.eat_contextual_kw(T![format_args]) {
283281
p.expect(T!['(']);
284282
expr(p);
285283
if p.eat(T![,]) {
@@ -302,7 +300,16 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
302300
}
303301
p.expect(T![')']);
304302
Some(m.complete(p, FORMAT_ARGS_EXPR))
305-
} else if p.at_contextual_kw(T![asm]) {
303+
} else if p.eat_contextual_kw(T![asm])
304+
|| p.eat_contextual_kw(T![global_asm])
305+
|| p.eat_contextual_kw(T![naked_asm])
306+
{
307+
// test asm_kinds
308+
// fn foo() {
309+
// builtin#asm("");
310+
// builtin#global_asm("");
311+
// builtin#naked_asm("");
312+
// }
306313
parse_asm_expr(p, m)
307314
} else {
308315
m.abandon(p);
@@ -322,7 +329,6 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
322329
// );
323330
// }
324331
fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> {
325-
p.bump_remap(T![asm]);
326332
p.expect(T!['(']);
327333
if expr(p).is_none() {
328334
p.err_and_bump("expected asm template");

src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs

Lines changed: 11 additions & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)