Skip to content

Commit 55ef540

Browse files
Auto merge of #141774 - oli-obk:naked-fn-queries, r=<try>
Change per-module naked fn checks to happen during typeck instead cc `@Lokathor` `@Amanieu` `@folkertdev` just seems nicer this way
2 parents 91fad92 + 02e2766 commit 55ef540

File tree

10 files changed

+105
-150
lines changed

10 files changed

+105
-150
lines changed

compiler/rustc_hir_typeck/messages.ftl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,18 @@ hir_typeck_lossy_provenance_ptr2int =
137137
138138
hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
139139
140+
hir_typeck_naked_asm_outside_naked_fn =
141+
the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
142+
143+
hir_typeck_naked_functions_asm_block =
144+
naked functions must contain a single `naked_asm!` invocation
145+
.label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
146+
.label_non_asm = not allowed in naked functions
147+
148+
hir_typeck_naked_functions_must_naked_asm =
149+
the `asm!` macro is not allowed in naked functions
150+
.label = consider using the `naked_asm!` macro instead
151+
140152
hir_typeck_never_type_fallback_flowing_into_unsafe_call = never type fallback affects this call to an `unsafe` function
141153
.help = specify the type explicitly
142154
hir_typeck_never_type_fallback_flowing_into_unsafe_deref = never type fallback affects this raw pointer dereference
@@ -159,6 +171,9 @@ hir_typeck_no_field_on_variant = no field named `{$field}` on enum variant `{$co
159171
hir_typeck_no_field_on_variant_enum = this enum variant...
160172
hir_typeck_no_field_on_variant_field = ...does not have this field
161173
174+
hir_typeck_no_patterns =
175+
patterns not allowed in naked function parameters
176+
162177
hir_typeck_note_caller_chooses_ty_for_ty_param = the caller chooses a type for `{$ty_param_name}` which can be different from `{$found_ty}`
163178
164179
hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
@@ -167,6 +182,10 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte
167182
hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}`
168183
hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}`
169184
185+
hir_typeck_params_not_allowed =
186+
referencing function parameters is not allowed in naked functions
187+
.help = follow the calling convention in asm block to use parameters
188+
170189
hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function
171190
.suggestion = cast the value to `{$cast_ty}`
172191
.teach_help = certain types, like `{$ty}`, must be cast before passing them to a variadic function to match the implicit cast that a C compiler would perform as part of C's numeric promotion rules

compiler/rustc_hir_typeck/src/errors.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use std::borrow::Cow;
44

55
use rustc_errors::codes::*;
66
use rustc_errors::{
7-
Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan,
8-
Subdiagnostic,
7+
Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic,
8+
EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic,
99
};
1010
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
1111
use rustc_middle::ty::{self, Ty};
@@ -983,3 +983,55 @@ pub(crate) struct RegisterTypeUnstable<'a> {
983983
pub span: Span,
984984
pub ty: Ty<'a>,
985985
}
986+
987+
#[derive(Diagnostic)]
988+
#[diag(hir_typeck_naked_asm_outside_naked_fn)]
989+
pub(crate) struct NakedAsmOutsideNakedFn {
990+
#[primary_span]
991+
pub span: Span,
992+
}
993+
994+
#[derive(Diagnostic)]
995+
#[diag(hir_typeck_no_patterns)]
996+
pub(crate) struct NoPatterns {
997+
#[primary_span]
998+
pub span: Span,
999+
}
1000+
1001+
#[derive(Diagnostic)]
1002+
#[diag(hir_typeck_params_not_allowed)]
1003+
#[help]
1004+
pub(crate) struct ParamsNotAllowed {
1005+
#[primary_span]
1006+
pub span: Span,
1007+
}
1008+
1009+
pub(crate) struct NakedFunctionsAsmBlock {
1010+
pub span: Span,
1011+
pub multiple_asms: Vec<Span>,
1012+
pub non_asms: Vec<Span>,
1013+
}
1014+
1015+
impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock {
1016+
#[track_caller]
1017+
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
1018+
let mut diag = Diag::new(dcx, level, fluent::hir_typeck_naked_functions_asm_block);
1019+
diag.span(self.span);
1020+
diag.code(E0787);
1021+
for span in self.multiple_asms.iter() {
1022+
diag.span_label(*span, fluent::hir_typeck_label_multiple_asm);
1023+
}
1024+
for span in self.non_asms.iter() {
1025+
diag.span_label(*span, fluent::hir_typeck_label_non_asm);
1026+
}
1027+
diag
1028+
}
1029+
}
1030+
1031+
#[derive(Diagnostic)]
1032+
#[diag(hir_typeck_naked_functions_must_naked_asm, code = E0787)]
1033+
pub(crate) struct NakedFunctionsMustNakedAsm {
1034+
#[primary_span]
1035+
#[label]
1036+
pub span: Span,
1037+
}

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ use crate::errors::{
4444
AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr,
4545
BaseExpressionDoubleDotEnableDefaultFieldValues, BaseExpressionDoubleDotRemove,
4646
CantDereference, FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
47-
HelpUseLatestEdition, NoFieldOnType, NoFieldOnVariant, ReturnLikeStatementKind,
48-
ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo,
49-
YieldExprOutsideOfCoroutine,
47+
HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType, NoFieldOnVariant,
48+
ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive,
49+
TypeMismatchFruTypo, YieldExprOutsideOfCoroutine,
5050
};
5151
use crate::{
5252
BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs,
@@ -524,7 +524,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
524524
ExprKind::InlineAsm(asm) => {
525525
// We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars).
526526
self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));
527-
self.check_expr_asm(asm)
527+
self.check_expr_asm(asm, expr.span)
528528
}
529529
ExprKind::OffsetOf(container, fields) => {
530530
self.check_expr_offset_of(container, fields, expr)
@@ -3761,7 +3761,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
37613761
}
37623762
}
37633763

3764-
fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
3764+
fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) -> Ty<'tcx> {
3765+
if let rustc_ast::AsmMacro::NakedAsm = asm.asm_macro {
3766+
if !self.tcx.has_attr(self.body_id, sym::naked) {
3767+
self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span });
3768+
}
3769+
}
3770+
37653771
let mut diverge = asm.asm_macro.diverges(asm.options);
37663772

37673773
for (op, _op_sp) in asm.operands {

compiler/rustc_hir_typeck/src/lib.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ mod fn_ctxt;
3131
mod gather_locals;
3232
mod intrinsicck;
3333
mod method;
34+
mod naked_functions;
3435
mod op;
3536
mod opaque_types;
3637
mod pat;
@@ -55,8 +56,8 @@ use rustc_middle::query::Providers;
5556
use rustc_middle::ty::{self, Ty, TyCtxt};
5657
use rustc_middle::{bug, span_bug};
5758
use rustc_session::config;
58-
use rustc_span::Span;
5959
use rustc_span::def_id::LocalDefId;
60+
use rustc_span::{Span, sym};
6061
use tracing::{debug, instrument};
6162
use typeck_root_ctxt::TypeckRootCtxt;
6263

@@ -170,6 +171,10 @@ fn typeck_with_inspect<'tcx>(
170171
.map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)),
171172
);
172173

174+
if tcx.has_attr(def_id, sym::naked) {
175+
naked_functions::typeck_naked_fn(tcx, def_id, body);
176+
}
177+
173178
check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params());
174179
} else {
175180
let expected_type = if let Some(infer_ty) = infer_type_if_missing(&fcx, node) {

compiler/rustc_passes/src/naked_functions.rs renamed to compiler/rustc_hir_typeck/src/naked_functions.rs

Lines changed: 14 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,29 @@
11
//! Checks validity of naked functions.
22
33
use rustc_hir as hir;
4-
use rustc_hir::def::DefKind;
5-
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
4+
use rustc_hir::def_id::LocalDefId;
65
use rustc_hir::intravisit::Visitor;
76
use rustc_hir::{ExprKind, HirIdSet, StmtKind};
8-
use rustc_middle::hir::nested_filter::OnlyBodies;
9-
use rustc_middle::query::Providers;
107
use rustc_middle::span_bug;
118
use rustc_middle::ty::TyCtxt;
129
use rustc_span::{Span, sym};
1310

1411
use crate::errors::{
15-
NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns,
16-
ParamsNotAllowed,
12+
NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed,
1713
};
1814

19-
pub(crate) fn provide(providers: &mut Providers) {
20-
*providers = Providers { check_mod_naked_functions, ..*providers };
21-
}
22-
23-
fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
24-
let items = tcx.hir_module_items(module_def_id);
25-
for def_id in items.definitions() {
26-
if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
27-
continue;
28-
}
29-
30-
let body = match tcx.hir_node_by_def_id(def_id) {
31-
hir::Node::Item(hir::Item {
32-
kind: hir::ItemKind::Fn { body: body_id, .. }, ..
33-
})
34-
| hir::Node::TraitItem(hir::TraitItem {
35-
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)),
36-
..
37-
})
38-
| hir::Node::ImplItem(hir::ImplItem {
39-
kind: hir::ImplItemKind::Fn(_, body_id), ..
40-
}) => tcx.hir_body(*body_id),
41-
_ => continue,
42-
};
43-
44-
if tcx.has_attr(def_id, sym::naked) {
45-
check_no_patterns(tcx, body.params);
46-
check_no_parameters_use(tcx, body);
47-
check_asm(tcx, def_id, body);
48-
} else {
49-
// `naked_asm!` is not allowed outside of functions marked as `#[naked]`
50-
let mut visitor = CheckNakedAsmInNakedFn { tcx };
51-
visitor.visit_body(body);
52-
}
53-
}
15+
/// Naked fns can only have trivial binding patterns in arguments,
16+
/// may not actually use those arguments, and the body must consist of just
17+
/// a single asm statement.
18+
pub(crate) fn typeck_naked_fn<'tcx>(
19+
tcx: TyCtxt<'tcx>,
20+
def_id: LocalDefId,
21+
body: &'tcx hir::Body<'tcx>,
22+
) {
23+
debug_assert!(tcx.has_attr(def_id, sym::naked));
24+
check_no_patterns(tcx, body.params);
25+
check_no_parameters_use(tcx, body);
26+
check_asm(tcx, def_id, body);
5427
}
5528

5629
/// Checks that parameters don't use patterns. Mirrors the checks for function declarations.
@@ -231,25 +204,3 @@ impl<'tcx> Visitor<'tcx> for CheckInlineAssembly {
231204
self.check_expr(expr, expr.span);
232205
}
233206
}
234-
235-
struct CheckNakedAsmInNakedFn<'tcx> {
236-
tcx: TyCtxt<'tcx>,
237-
}
238-
239-
impl<'tcx> Visitor<'tcx> for CheckNakedAsmInNakedFn<'tcx> {
240-
type NestedFilter = OnlyBodies;
241-
242-
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
243-
self.tcx
244-
}
245-
246-
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
247-
if let ExprKind::InlineAsm(inline_asm) = expr.kind {
248-
if let rustc_ast::AsmMacro::NakedAsm = inline_asm.asm_macro {
249-
self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span: expr.span });
250-
}
251-
}
252-
253-
hir::intravisit::walk_expr(self, expr);
254-
}
255-
}

compiler/rustc_interface/src/passes.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
960960
tcx.par_hir_for_each_module(|module| {
961961
tcx.ensure_ok().check_mod_loops(module);
962962
tcx.ensure_ok().check_mod_attrs(module);
963-
tcx.ensure_ok().check_mod_naked_functions(module);
964963
tcx.ensure_ok().check_mod_unstable_api_usage(module);
965964
});
966965
},

compiler/rustc_middle/src/query/mod.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,10 +1119,6 @@ rustc_queries! {
11191119
desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
11201120
}
11211121

1122-
query check_mod_naked_functions(key: LocalModDefId) {
1123-
desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) }
1124-
}
1125-
11261122
query check_mod_privacy(key: LocalModDefId) {
11271123
desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) }
11281124
}

compiler/rustc_passes/messages.ftl

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -509,23 +509,11 @@ passes_must_not_suspend =
509509
passes_must_use_no_effect =
510510
`#[must_use]` has no effect when applied to {$article} {$target}
511511
512-
passes_naked_asm_outside_naked_fn =
513-
the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
514-
515-
passes_naked_functions_asm_block =
516-
naked functions must contain a single `naked_asm!` invocation
517-
.label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
518-
.label_non_asm = not allowed in naked functions
519-
520512
passes_naked_functions_incompatible_attribute =
521513
attribute incompatible with `#[unsafe(naked)]`
522514
.label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
523515
.naked_attribute = function marked with `#[unsafe(naked)]` here
524516
525-
passes_naked_functions_must_naked_asm =
526-
the `asm!` macro is not allowed in naked functions
527-
.label = consider using the `naked_asm!` macro instead
528-
529517
passes_no_link =
530518
attribute should be applied to an `extern crate` item
531519
.label = not an `extern crate` item
@@ -556,9 +544,6 @@ passes_no_mangle_foreign =
556544
.note = symbol names in extern blocks are not mangled
557545
.suggestion = remove this attribute
558546
559-
passes_no_patterns =
560-
patterns not allowed in naked function parameters
561-
562547
passes_no_sanitize =
563548
`#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind}
564549
.label = not {$accepted_kind}
@@ -606,10 +591,6 @@ passes_panic_unwind_without_std =
606591
.note = since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem
607592
.help = using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
608593
609-
passes_params_not_allowed =
610-
referencing function parameters is not allowed in naked functions
611-
.help = follow the calling convention in asm block to use parameters
612-
613594
passes_parent_info =
614595
{$num ->
615596
[one] {$descr}

compiler/rustc_passes/src/errors.rs

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,51 +1196,6 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> {
11961196
pub cf_type: &'a str,
11971197
}
11981198

1199-
#[derive(Diagnostic)]
1200-
#[diag(passes_no_patterns)]
1201-
pub(crate) struct NoPatterns {
1202-
#[primary_span]
1203-
pub span: Span,
1204-
}
1205-
1206-
#[derive(Diagnostic)]
1207-
#[diag(passes_params_not_allowed)]
1208-
#[help]
1209-
pub(crate) struct ParamsNotAllowed {
1210-
#[primary_span]
1211-
pub span: Span,
1212-
}
1213-
1214-
pub(crate) struct NakedFunctionsAsmBlock {
1215-
pub span: Span,
1216-
pub multiple_asms: Vec<Span>,
1217-
pub non_asms: Vec<Span>,
1218-
}
1219-
1220-
impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock {
1221-
#[track_caller]
1222-
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
1223-
let mut diag = Diag::new(dcx, level, fluent::passes_naked_functions_asm_block);
1224-
diag.span(self.span);
1225-
diag.code(E0787);
1226-
for span in self.multiple_asms.iter() {
1227-
diag.span_label(*span, fluent::passes_label_multiple_asm);
1228-
}
1229-
for span in self.non_asms.iter() {
1230-
diag.span_label(*span, fluent::passes_label_non_asm);
1231-
}
1232-
diag
1233-
}
1234-
}
1235-
1236-
#[derive(Diagnostic)]
1237-
#[diag(passes_naked_functions_must_naked_asm, code = E0787)]
1238-
pub(crate) struct NakedFunctionsMustNakedAsm {
1239-
#[primary_span]
1240-
#[label]
1241-
pub span: Span,
1242-
}
1243-
12441199
#[derive(Diagnostic)]
12451200
#[diag(passes_naked_functions_incompatible_attribute, code = E0736)]
12461201
pub(crate) struct NakedFunctionIncompatibleAttribute {
@@ -1252,13 +1207,6 @@ pub(crate) struct NakedFunctionIncompatibleAttribute {
12521207
pub attr: String,
12531208
}
12541209

1255-
#[derive(Diagnostic)]
1256-
#[diag(passes_naked_asm_outside_naked_fn)]
1257-
pub(crate) struct NakedAsmOutsideNakedFn {
1258-
#[primary_span]
1259-
pub span: Span,
1260-
}
1261-
12621210
#[derive(Diagnostic)]
12631211
#[diag(passes_attr_only_in_functions)]
12641212
pub(crate) struct AttrOnlyInFunctions {

0 commit comments

Comments
 (0)