Move naked fn checks to hir_typeck

This commit is contained in:
Oli Scherer
2025-05-30 15:19:58 +00:00
parent 685d1c9e29
commit 02e2766cc3
8 changed files with 73 additions and 77 deletions

View File

@@ -140,6 +140,15 @@ hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on
hir_typeck_naked_asm_outside_naked_fn =
the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
hir_typeck_naked_functions_asm_block =
naked functions must contain a single `naked_asm!` invocation
.label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
.label_non_asm = not allowed in naked functions
hir_typeck_naked_functions_must_naked_asm =
the `asm!` macro is not allowed in naked functions
.label = consider using the `naked_asm!` macro instead
hir_typeck_never_type_fallback_flowing_into_unsafe_call = never type fallback affects this call to an `unsafe` function
.help = specify the type explicitly
hir_typeck_never_type_fallback_flowing_into_unsafe_deref = never type fallback affects this raw pointer dereference
@@ -162,6 +171,9 @@ hir_typeck_no_field_on_variant = no field named `{$field}` on enum variant `{$co
hir_typeck_no_field_on_variant_enum = this enum variant...
hir_typeck_no_field_on_variant_field = ...does not have this field
hir_typeck_no_patterns =
patterns not allowed in naked function parameters
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}`
hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
@@ -170,6 +182,10 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte
hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}`
hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}`
hir_typeck_params_not_allowed =
referencing function parameters is not allowed in naked functions
.help = follow the calling convention in asm block to use parameters
hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function
.suggestion = cast the value to `{$cast_ty}`
.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

View File

@@ -4,8 +4,8 @@ use std::borrow::Cow;
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan,
Subdiagnostic,
Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic,
EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{self, Ty};
@@ -990,3 +990,48 @@ pub(crate) struct NakedAsmOutsideNakedFn {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_no_patterns)]
pub(crate) struct NoPatterns {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_params_not_allowed)]
#[help]
pub(crate) struct ParamsNotAllowed {
#[primary_span]
pub span: Span,
}
pub(crate) struct NakedFunctionsAsmBlock {
pub span: Span,
pub multiple_asms: Vec<Span>,
pub non_asms: Vec<Span>,
}
impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock {
#[track_caller]
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
let mut diag = Diag::new(dcx, level, fluent::hir_typeck_naked_functions_asm_block);
diag.span(self.span);
diag.code(E0787);
for span in self.multiple_asms.iter() {
diag.span_label(*span, fluent::hir_typeck_label_multiple_asm);
}
for span in self.non_asms.iter() {
diag.span_label(*span, fluent::hir_typeck_label_non_asm);
}
diag
}
}
#[derive(Diagnostic)]
#[diag(hir_typeck_naked_functions_must_naked_asm, code = E0787)]
pub(crate) struct NakedFunctionsMustNakedAsm {
#[primary_span]
#[label]
pub span: Span,
}

View File

@@ -31,6 +31,7 @@ mod fn_ctxt;
mod gather_locals;
mod intrinsicck;
mod method;
mod naked_functions;
mod op;
mod opaque_types;
mod pat;
@@ -171,7 +172,7 @@ fn typeck_with_inspect<'tcx>(
);
if tcx.has_attr(def_id, sym::naked) {
tcx.typeck_naked_fn(def_id, body);
naked_functions::typeck_naked_fn(tcx, def_id, body);
}
check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params());

View File

@@ -6,18 +6,20 @@ use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, HirIdSet, StmtKind};
use rustc_middle::span_bug;
use rustc_middle::ty::TyCtxt;
use rustc_middle::util::Providers;
use rustc_span::{Span, sym};
use crate::errors::{
NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed,
};
pub(crate) fn provide(providers: &mut Providers) {
providers.hooks.typeck_naked_fn = typeck_naked_fn;
}
fn typeck_naked_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
/// Naked fns can only have trivial binding patterns in arguments,
/// may not actually use those arguments, and the body must consist of just
/// a single asm statement.
pub(crate) fn typeck_naked_fn<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
body: &'tcx hir::Body<'tcx>,
) {
debug_assert!(tcx.has_attr(def_id, sym::naked));
check_no_patterns(tcx, body.params);
check_no_parameters_use(tcx, body);

View File

@@ -102,11 +102,6 @@ declare_hooks! {
/// Ensure the given scalar is valid for the given type.
/// This checks non-recursive runtime validity.
hook validate_scalar_in_layout(scalar: crate::ty::ScalarInt, ty: Ty<'tcx>) -> bool;
/// Naked fns can only have trivial binding patterns in arguments,
/// may not actually use those arguments, and the body must consist of just
/// a single asm statement.
hook typeck_naked_fn(def_id: LocalDefId, body: &'tcx rustc_hir::Body<'tcx>) -> ();
}
#[cold]

View File

@@ -509,20 +509,11 @@ passes_must_not_suspend =
passes_must_use_no_effect =
`#[must_use]` has no effect when applied to {$article} {$target}
passes_naked_functions_asm_block =
naked functions must contain a single `naked_asm!` invocation
.label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
.label_non_asm = not allowed in naked functions
passes_naked_functions_incompatible_attribute =
attribute incompatible with `#[unsafe(naked)]`
.label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
.naked_attribute = function marked with `#[unsafe(naked)]` here
passes_naked_functions_must_naked_asm =
the `asm!` macro is not allowed in naked functions
.label = consider using the `naked_asm!` macro instead
passes_no_link =
attribute should be applied to an `extern crate` item
.label = not an `extern crate` item
@@ -553,9 +544,6 @@ passes_no_mangle_foreign =
.note = symbol names in extern blocks are not mangled
.suggestion = remove this attribute
passes_no_patterns =
patterns not allowed in naked function parameters
passes_no_sanitize =
`#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind}
.label = not {$accepted_kind}
@@ -603,10 +591,6 @@ passes_panic_unwind_without_std =
.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
.help = using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
passes_params_not_allowed =
referencing function parameters is not allowed in naked functions
.help = follow the calling convention in asm block to use parameters
passes_parent_info =
{$num ->
[one] {$descr}

View File

@@ -1196,51 +1196,6 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> {
pub cf_type: &'a str,
}
#[derive(Diagnostic)]
#[diag(passes_no_patterns)]
pub(crate) struct NoPatterns {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_params_not_allowed)]
#[help]
pub(crate) struct ParamsNotAllowed {
#[primary_span]
pub span: Span,
}
pub(crate) struct NakedFunctionsAsmBlock {
pub span: Span,
pub multiple_asms: Vec<Span>,
pub non_asms: Vec<Span>,
}
impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock {
#[track_caller]
fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
let mut diag = Diag::new(dcx, level, fluent::passes_naked_functions_asm_block);
diag.span(self.span);
diag.code(E0787);
for span in self.multiple_asms.iter() {
diag.span_label(*span, fluent::passes_label_multiple_asm);
}
for span in self.non_asms.iter() {
diag.span_label(*span, fluent::passes_label_non_asm);
}
diag
}
}
#[derive(Diagnostic)]
#[diag(passes_naked_functions_must_naked_asm, code = E0787)]
pub(crate) struct NakedFunctionsMustNakedAsm {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(passes_naked_functions_incompatible_attribute, code = E0736)]
pub(crate) struct NakedFunctionIncompatibleAttribute {

View File

@@ -32,7 +32,6 @@ pub mod layout_test;
mod lib_features;
mod liveness;
pub mod loops;
mod naked_functions;
mod reachable;
pub mod stability;
mod upvars;
@@ -49,7 +48,6 @@ pub fn provide(providers: &mut Providers) {
lang_items::provide(providers);
lib_features::provide(providers);
loops::provide(providers);
naked_functions::provide(providers);
liveness::provide(providers);
reachable::provide(providers);
stability::provide(providers);