diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 5e79d10612dbf..6c33dfb4ec050 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -137,6 +137,18 @@ hir_typeck_lossy_provenance_ptr2int = hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` +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 @@ -159,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 @@ -167,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 diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 06103fe1c91bc..97a90548fc54a 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -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}; @@ -983,3 +983,55 @@ pub(crate) struct RegisterTypeUnstable<'a> { pub span: Span, pub ty: Ty<'a>, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_naked_asm_outside_naked_fn)] +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, + pub non_asms: Vec, +} + +impl 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, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 082ddac7e5ae2..a1287e8afec1b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -44,9 +44,9 @@ use crate::errors::{ AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr, BaseExpressionDoubleDotEnableDefaultFieldValues, BaseExpressionDoubleDotRemove, CantDereference, FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, - HelpUseLatestEdition, NoFieldOnType, NoFieldOnVariant, ReturnLikeStatementKind, - ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo, - YieldExprOutsideOfCoroutine, + HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType, NoFieldOnVariant, + ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, + TypeMismatchFruTypo, YieldExprOutsideOfCoroutine, }; use crate::{ BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs, @@ -524,7 +524,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::InlineAsm(asm) => { // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars). self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); - self.check_expr_asm(asm) + self.check_expr_asm(asm, expr.span) } ExprKind::OffsetOf(container, fields) => { self.check_expr_offset_of(container, fields, expr) @@ -3761,7 +3761,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> { + fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) -> Ty<'tcx> { + if let rustc_ast::AsmMacro::NakedAsm = asm.asm_macro { + if !self.tcx.has_attr(self.body_id, sym::naked) { + self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span }); + } + } + let mut diverge = asm.asm_macro.diverges(asm.options); for (op, _op_sp) in asm.operands { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 5a8148221631d..b0346f8d32ebc 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -31,6 +31,7 @@ mod fn_ctxt; mod gather_locals; mod intrinsicck; mod method; +mod naked_functions; mod op; mod opaque_types; mod pat; @@ -55,8 +56,8 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config; -use rustc_span::Span; use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, sym}; use tracing::{debug, instrument}; use typeck_root_ctxt::TypeckRootCtxt; @@ -170,6 +171,10 @@ fn typeck_with_inspect<'tcx>( .map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)), ); + if tcx.has_attr(def_id, sym::naked) { + 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()); } else { let expected_type = if let Some(infer_ty) = infer_type_if_missing(&fcx, node) { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_hir_typeck/src/naked_functions.rs similarity index 73% rename from compiler/rustc_passes/src/naked_functions.rs rename to compiler/rustc_hir_typeck/src/naked_functions.rs index 3c9f8b72c3635..2518d6478e655 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_hir_typeck/src/naked_functions.rs @@ -1,56 +1,29 @@ //! Checks validity of naked functions. use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{LocalDefId, LocalModDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirIdSet, StmtKind}; -use rustc_middle::hir::nested_filter::OnlyBodies; -use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_span::{Span, sym}; use crate::errors::{ - NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, - ParamsNotAllowed, + NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed, }; -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { check_mod_naked_functions, ..*providers }; -} - -fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { - let items = tcx.hir_module_items(module_def_id); - for def_id in items.definitions() { - if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { - continue; - } - - let body = match tcx.hir_node_by_def_id(def_id) { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn { body: body_id, .. }, .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)), - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_, body_id), .. - }) => tcx.hir_body(*body_id), - _ => continue, - }; - - if tcx.has_attr(def_id, sym::naked) { - check_no_patterns(tcx, body.params); - check_no_parameters_use(tcx, body); - check_asm(tcx, def_id, body); - } else { - // `naked_asm!` is not allowed outside of functions marked as `#[naked]` - let mut visitor = CheckNakedAsmInNakedFn { tcx }; - visitor.visit_body(body); - } - } +/// 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); + check_asm(tcx, def_id, body); } /// Checks that parameters don't use patterns. Mirrors the checks for function declarations. @@ -231,25 +204,3 @@ impl<'tcx> Visitor<'tcx> for CheckInlineAssembly { self.check_expr(expr, expr.span); } } - -struct CheckNakedAsmInNakedFn<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for CheckNakedAsmInNakedFn<'tcx> { - type NestedFilter = OnlyBodies; - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.tcx - } - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let ExprKind::InlineAsm(inline_asm) = expr.kind { - if let rustc_ast::AsmMacro::NakedAsm = inline_asm.asm_macro { - self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span: expr.span }); - } - } - - hir::intravisit::walk_expr(self, expr); - } -} diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 75d92ae7a2ed6..696f4b493f25e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -960,7 +960,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { tcx.par_hir_for_each_module(|module| { tcx.ensure_ok().check_mod_loops(module); tcx.ensure_ok().check_mod_attrs(module); - tcx.ensure_ok().check_mod_naked_functions(module); tcx.ensure_ok().check_mod_unstable_api_usage(module); }); }, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 279033ee0724c..bb0b0a41d5a10 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1119,10 +1119,6 @@ rustc_queries! { desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } } - query check_mod_naked_functions(key: LocalModDefId) { - desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } - } - query check_mod_privacy(key: LocalModDefId) { desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6d815e510ea20..983e562cdf3ce 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -509,23 +509,11 @@ passes_must_not_suspend = passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} -passes_naked_asm_outside_naked_fn = - the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` - -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 @@ -556,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} @@ -606,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} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 00682a9c7a794..b995781719b6c 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -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, - pub non_asms: Vec, -} - -impl 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 { @@ -1252,13 +1207,6 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { pub attr: String, } -#[derive(Diagnostic)] -#[diag(passes_naked_asm_outside_naked_fn)] -pub(crate) struct NakedAsmOutsideNakedFn { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_attr_only_in_functions)] pub(crate) struct AttrOnlyInFunctions { diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index f9445485f6054..639ca683cf606 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -14,7 +14,7 @@ #![feature(try_blocks)] // tidy-alphabetical-end -use rustc_middle::query::Providers; +use rustc_middle::util::Providers; pub mod abi_test; mod check_attr; @@ -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);