From 02e2766cc38e6df79ec45c9bb2012ab14a1ae8de Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 30 May 2025 15:19:58 +0000 Subject: Move naked fn checks to hir_typeck --- compiler/rustc_hir_typeck/messages.ftl | 16 ++ compiler/rustc_hir_typeck/src/errors.rs | 49 +++++- compiler/rustc_hir_typeck/src/lib.rs | 3 +- compiler/rustc_hir_typeck/src/naked_functions.rs | 206 +++++++++++++++++++++++ compiler/rustc_middle/src/hooks/mod.rs | 5 - compiler/rustc_passes/messages.ftl | 16 -- compiler/rustc_passes/src/errors.rs | 45 ----- compiler/rustc_passes/src/lib.rs | 2 - compiler/rustc_passes/src/naked_functions.rs | 204 ---------------------- 9 files changed, 271 insertions(+), 275 deletions(-) create mode 100644 compiler/rustc_hir_typeck/src/naked_functions.rs delete mode 100644 compiler/rustc_passes/src/naked_functions.rs diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 90a53ab3c81..6c33dfb4ec0 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -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 diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 8ba2db0bf9f..97a90548fc5 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}; @@ -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, + 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/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 30651534d7b..b0346f8d32e 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; @@ -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()); diff --git a/compiler/rustc_hir_typeck/src/naked_functions.rs b/compiler/rustc_hir_typeck/src/naked_functions.rs new file mode 100644 index 00000000000..2518d6478e6 --- /dev/null +++ b/compiler/rustc_hir_typeck/src/naked_functions.rs @@ -0,0 +1,206 @@ +//! Checks validity of naked functions. + +use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::Visitor; +use rustc_hir::{ExprKind, HirIdSet, StmtKind}; +use rustc_middle::span_bug; +use rustc_middle::ty::TyCtxt; +use rustc_span::{Span, sym}; + +use crate::errors::{ + NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed, +}; + +/// 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. +fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { + for param in params { + match param.pat.kind { + hir::PatKind::Wild | hir::PatKind::Binding(hir::BindingMode::NONE, _, _, None) => {} + _ => { + tcx.dcx().emit_err(NoPatterns { span: param.pat.span }); + } + } + } +} + +/// Checks that function parameters aren't used in the function body. +fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) { + let mut params = HirIdSet::default(); + for param in body.params { + param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| { + params.insert(hir_id); + }); + } + CheckParameters { tcx, params }.visit_body(body); +} + +struct CheckParameters<'tcx> { + tcx: TyCtxt<'tcx>, + params: HirIdSet, +} + +impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Path(hir::QPath::Resolved( + _, + hir::Path { res: hir::def::Res::Local(var_hir_id), .. }, + )) = expr.kind + { + if self.params.contains(var_hir_id) { + self.tcx.dcx().emit_err(ParamsNotAllowed { span: expr.span }); + return; + } + } + hir::intravisit::walk_expr(self, expr); + } +} + +/// Checks that function body contains a single inline assembly block. +fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { + let mut this = CheckInlineAssembly { items: Vec::new() }; + this.visit_body(body); + if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] { + // Ok. + } else { + let mut must_show_error = false; + let mut has_naked_asm = false; + let mut has_err = false; + let mut multiple_asms = vec![]; + let mut non_asms = vec![]; + for &(kind, span) in &this.items { + match kind { + ItemKind::NakedAsm if has_naked_asm => { + must_show_error = true; + multiple_asms.push(span); + } + ItemKind::NakedAsm => has_naked_asm = true, + ItemKind::InlineAsm => { + has_err = true; + + tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span }); + } + ItemKind::NonAsm => { + must_show_error = true; + non_asms.push(span); + } + ItemKind::Err => has_err = true, + } + } + + // If the naked function only contains a single asm block and a non-zero number of + // errors, then don't show an additional error. This allows for appending/prepending + // `compile_error!("...")` statements and reduces error noise. + if must_show_error || !has_err { + tcx.dcx().emit_err(NakedFunctionsAsmBlock { + span: tcx.def_span(def_id), + multiple_asms, + non_asms, + }); + } + } +} + +struct CheckInlineAssembly { + items: Vec<(ItemKind, Span)>, +} + +#[derive(Copy, Clone)] +enum ItemKind { + NakedAsm, + InlineAsm, + NonAsm, + Err, +} + +impl CheckInlineAssembly { + fn check_expr<'tcx>(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { + match expr.kind { + ExprKind::ConstBlock(..) + | ExprKind::Array(..) + | ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Use(..) + | ExprKind::Tup(..) + | ExprKind::Binary(..) + | ExprKind::Unary(..) + | ExprKind::Lit(..) + | ExprKind::Cast(..) + | ExprKind::Type(..) + | ExprKind::UnsafeBinderCast(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::If(..) + | ExprKind::Closure { .. } + | ExprKind::Assign(..) + | ExprKind::AssignOp(..) + | ExprKind::Field(..) + | ExprKind::Index(..) + | ExprKind::Path(..) + | ExprKind::AddrOf(..) + | ExprKind::Let(..) + | ExprKind::Break(..) + | ExprKind::Continue(..) + | ExprKind::Ret(..) + | ExprKind::OffsetOf(..) + | ExprKind::Become(..) + | ExprKind::Struct(..) + | ExprKind::Repeat(..) + | ExprKind::Yield(..) => { + self.items.push((ItemKind::NonAsm, span)); + } + + ExprKind::InlineAsm(asm) => match asm.asm_macro { + rustc_ast::AsmMacro::Asm => { + self.items.push((ItemKind::InlineAsm, span)); + } + rustc_ast::AsmMacro::NakedAsm => { + self.items.push((ItemKind::NakedAsm, span)); + } + rustc_ast::AsmMacro::GlobalAsm => { + span_bug!(span, "`global_asm!` is not allowed in this position") + } + }, + + ExprKind::DropTemps(..) | ExprKind::Block(..) => { + hir::intravisit::walk_expr(self, expr); + } + + ExprKind::Err(_) => { + self.items.push((ItemKind::Err, span)); + } + } + } +} + +impl<'tcx> Visitor<'tcx> for CheckInlineAssembly { + fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { + match stmt.kind { + StmtKind::Item(..) => {} + StmtKind::Let(..) => { + self.items.push((ItemKind::NonAsm, stmt.span)); + } + StmtKind::Expr(expr) | StmtKind::Semi(expr) => { + self.check_expr(expr, stmt.span); + } + } + } + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + self.check_expr(expr, expr.span); + } +} diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 12110c36044..c5ce6efcb81 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -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] diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index f690af64b89..983e562cdf3 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -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} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index bb16eea0528..b995781719b 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 { diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index aa4c56846c5..639ca683cf6 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -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); diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs deleted file mode 100644 index 4397a323dfc..00000000000 --- a/compiler/rustc_passes/src/naked_functions.rs +++ /dev/null @@ -1,204 +0,0 @@ -//! Checks validity of naked functions. - -use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; -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>) { - 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. -fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { - for param in params { - match param.pat.kind { - hir::PatKind::Wild | hir::PatKind::Binding(hir::BindingMode::NONE, _, _, None) => {} - _ => { - tcx.dcx().emit_err(NoPatterns { span: param.pat.span }); - } - } - } -} - -/// Checks that function parameters aren't used in the function body. -fn check_no_parameters_use<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>) { - let mut params = HirIdSet::default(); - for param in body.params { - param.pat.each_binding(|_binding_mode, hir_id, _span, _ident| { - params.insert(hir_id); - }); - } - CheckParameters { tcx, params }.visit_body(body); -} - -struct CheckParameters<'tcx> { - tcx: TyCtxt<'tcx>, - params: HirIdSet, -} - -impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: hir::def::Res::Local(var_hir_id), .. }, - )) = expr.kind - { - if self.params.contains(var_hir_id) { - self.tcx.dcx().emit_err(ParamsNotAllowed { span: expr.span }); - return; - } - } - hir::intravisit::walk_expr(self, expr); - } -} - -/// Checks that function body contains a single inline assembly block. -fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { - let mut this = CheckInlineAssembly { items: Vec::new() }; - this.visit_body(body); - if let [(ItemKind::NakedAsm | ItemKind::Err, _)] = this.items[..] { - // Ok. - } else { - let mut must_show_error = false; - let mut has_naked_asm = false; - let mut has_err = false; - let mut multiple_asms = vec![]; - let mut non_asms = vec![]; - for &(kind, span) in &this.items { - match kind { - ItemKind::NakedAsm if has_naked_asm => { - must_show_error = true; - multiple_asms.push(span); - } - ItemKind::NakedAsm => has_naked_asm = true, - ItemKind::InlineAsm => { - has_err = true; - - tcx.dcx().emit_err(NakedFunctionsMustNakedAsm { span }); - } - ItemKind::NonAsm => { - must_show_error = true; - non_asms.push(span); - } - ItemKind::Err => has_err = true, - } - } - - // If the naked function only contains a single asm block and a non-zero number of - // errors, then don't show an additional error. This allows for appending/prepending - // `compile_error!("...")` statements and reduces error noise. - if must_show_error || !has_err { - tcx.dcx().emit_err(NakedFunctionsAsmBlock { - span: tcx.def_span(def_id), - multiple_asms, - non_asms, - }); - } - } -} - -struct CheckInlineAssembly { - items: Vec<(ItemKind, Span)>, -} - -#[derive(Copy, Clone)] -enum ItemKind { - NakedAsm, - InlineAsm, - NonAsm, - Err, -} - -impl CheckInlineAssembly { - fn check_expr<'tcx>(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) { - match expr.kind { - ExprKind::ConstBlock(..) - | ExprKind::Array(..) - | ExprKind::Call(..) - | ExprKind::MethodCall(..) - | ExprKind::Use(..) - | ExprKind::Tup(..) - | ExprKind::Binary(..) - | ExprKind::Unary(..) - | ExprKind::Lit(..) - | ExprKind::Cast(..) - | ExprKind::Type(..) - | ExprKind::UnsafeBinderCast(..) - | ExprKind::Loop(..) - | ExprKind::Match(..) - | ExprKind::If(..) - | ExprKind::Closure { .. } - | ExprKind::Assign(..) - | ExprKind::AssignOp(..) - | ExprKind::Field(..) - | ExprKind::Index(..) - | ExprKind::Path(..) - | ExprKind::AddrOf(..) - | ExprKind::Let(..) - | ExprKind::Break(..) - | ExprKind::Continue(..) - | ExprKind::Ret(..) - | ExprKind::OffsetOf(..) - | ExprKind::Become(..) - | ExprKind::Struct(..) - | ExprKind::Repeat(..) - | ExprKind::Yield(..) => { - self.items.push((ItemKind::NonAsm, span)); - } - - ExprKind::InlineAsm(asm) => match asm.asm_macro { - rustc_ast::AsmMacro::Asm => { - self.items.push((ItemKind::InlineAsm, span)); - } - rustc_ast::AsmMacro::NakedAsm => { - self.items.push((ItemKind::NakedAsm, span)); - } - rustc_ast::AsmMacro::GlobalAsm => { - span_bug!(span, "`global_asm!` is not allowed in this position") - } - }, - - ExprKind::DropTemps(..) | ExprKind::Block(..) => { - hir::intravisit::walk_expr(self, expr); - } - - ExprKind::Err(_) => { - self.items.push((ItemKind::Err, span)); - } - } - } -} - -impl<'tcx> Visitor<'tcx> for CheckInlineAssembly { - fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { - match stmt.kind { - StmtKind::Item(..) => {} - StmtKind::Let(..) => { - self.items.push((ItemKind::NonAsm, stmt.span)); - } - StmtKind::Expr(expr) | StmtKind::Semi(expr) => { - self.check_expr(expr, stmt.span); - } - } - } - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - self.check_expr(expr, expr.span); - } -} -- cgit 1.4.1-3-g733a5