Auto merge of #141774 - oli-obk:naked-fn-queries, r=petrochenkov
Change per-module naked fn checks to happen during typeck instead cc `@Lokathor` `@Amanieu` `@folkertdev` just seems nicer this way
This commit is contained in:
commit
44f415c1d6
10 changed files with 105 additions and 150 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -956,7 +956,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);
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1120,10 +1120,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) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue