diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 96c230ec243a2..cfd32fc066f41 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -1,13 +1,12 @@ use std::collections::hash_map::Entry; use std::fmt::Write; -use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_session::parse::feature_err; -use rustc_span::{Span, kw, sym}; +use rustc_span::{Span, sym}; use rustc_target::asm; use super::LoweringContext; @@ -230,20 +229,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { tokens: None, }; - // Wrap the expression in an AnonConst. - let parent_def_id = self.current_hir_id_owner.def_id; - let node_id = self.next_node_id(); - self.create_def( - parent_def_id, - node_id, - kw::Empty, - DefKind::AnonConst, - *op_sp, - ); - let anon_const = AnonConst { id: node_id, value: P(expr) }; - hir::InlineAsmOperand::SymFn { - anon_const: self.lower_anon_const_to_anon_const(&anon_const), - } + hir::InlineAsmOperand::SymFn { expr: self.lower_expr(&expr) } } } InlineAsmOperand::Label { block } => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index bc2db41546989..1d3db64b47ed9 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -251,7 +251,12 @@ impl<'hir> LoweringContext<'_, 'hir> { .arena .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))), }, - ItemKind::GlobalAsm(asm) => hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)), + ItemKind::GlobalAsm(asm) => { + let asm = self.lower_inline_asm(span, asm); + let fake_body = + self.lower_body(|this| (&[], this.expr(span, hir::ExprKind::InlineAsm(asm)))); + hir::ItemKind::GlobalAsm { asm, fake_body } + } ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => { // We lower // diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 9a68eeb3326eb..a71ca37bf1306 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -126,6 +126,11 @@ pub(crate) enum DefiningTy<'tcx> { /// The MIR represents an inline const. The signature has no inputs and a /// single return value found via `InlineConstArgs::ty`. InlineConst(DefId, GenericArgsRef<'tcx>), + + // Fake body for a global asm. Not particularly useful or interesting, + // but we need it so we can properly store the typeck results of the asm + // operands, which aren't associated with a body otherwise. + GlobalAsm(DefId), } impl<'tcx> DefiningTy<'tcx> { @@ -138,9 +143,10 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(), DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(), DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(), - DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => { - ty::List::empty() - } + DefiningTy::FnDef(..) + | DefiningTy::Const(..) + | DefiningTy::InlineConst(..) + | DefiningTy::GlobalAsm(_) => ty::List::empty(), } } @@ -152,7 +158,10 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Closure(..) | DefiningTy::CoroutineClosure(..) | DefiningTy::Coroutine(..) => 1, - DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0, + DefiningTy::FnDef(..) + | DefiningTy::Const(..) + | DefiningTy::InlineConst(..) + | DefiningTy::GlobalAsm(_) => 0, } } @@ -171,7 +180,8 @@ impl<'tcx> DefiningTy<'tcx> { | DefiningTy::Coroutine(def_id, ..) | DefiningTy::FnDef(def_id, ..) | DefiningTy::Const(def_id, ..) - | DefiningTy::InlineConst(def_id, ..) => def_id, + | DefiningTy::InlineConst(def_id, ..) + | DefiningTy::GlobalAsm(def_id) => def_id, } } } @@ -411,6 +421,7 @@ impl<'tcx> UniversalRegions<'tcx> { tcx.def_path_str_with_args(def_id, args), )); } + DefiningTy::GlobalAsm(_) => unreachable!(), } } @@ -633,6 +644,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { DefiningTy::InlineConst(self.mir_def.to_def_id(), args) } } + + BodyOwnerKind::GlobalAsm => DefiningTy::GlobalAsm(self.mir_def.to_def_id()), } } @@ -666,6 +679,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } DefiningTy::FnDef(_, args) | DefiningTy::Const(_, args) => args, + + DefiningTy::GlobalAsm(_) => ty::List::empty(), }; let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); @@ -802,6 +817,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let ty = args.as_inline_const().ty(); ty::Binder::dummy(tcx.mk_type_list(&[ty])) } + + DefiningTy::GlobalAsm(def_id) => { + ty::Binder::dummy(tcx.mk_type_list(&[tcx.type_of(def_id).instantiate_identity()])) + } }; // FIXME(#129952): We probably want a more principled approach here. diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 54745b0d8c104..9ea92c300f898 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -16,7 +16,7 @@ use crate::prelude::*; pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) { let item = tcx.hir_item(item_id); - if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind { + if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind { let is_x86 = matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); @@ -55,7 +55,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, } } } - InlineAsmOperand::SymFn { anon_const } => { + InlineAsmOperand::SymFn { expr } => { if cfg!(not(feature = "inline_asm_sym")) { tcx.dcx().span_err( item.span, @@ -63,7 +63,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, ); } - let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); + let ty = tcx.typeck(item_id.owner_id).expr_ty(expr); let instance = match ty.kind() { &ty::FnDef(def_id, args) => Instance::new(def_id, args), _ => span_bug!(op_sp, "asm sym is not a function"), diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 5f95b6615bd30..f6af889fd6ecb 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -36,7 +36,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { } MonoItem::GlobalAsm(item_id) => { let item = cx.tcx().hir_item(item_id); - if let hir::ItemKind::GlobalAsm(asm) = item.kind { + if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind { let operands: Vec<_> = asm .operands .iter() @@ -71,11 +71,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { } } } - hir::InlineAsmOperand::SymFn { ref anon_const } => { - let ty = cx - .tcx() - .typeck_body(anon_const.body) - .node_type(anon_const.hir_id); + hir::InlineAsmOperand::SymFn { expr } => { + let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr); let instance = match ty.kind() { &ty::FnDef(def_id, args) => Instance::new(def_id, args), _ => span_bug!(*op_sp, "asm sym is not a function"), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index eafc60f9d72f7..61f64e62058fc 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1913,13 +1913,18 @@ pub enum BodyOwnerKind { /// Initializer of a `static` item. Static(Mutability), + + /// Fake body for a global asm to store its const-like value types. + GlobalAsm, } impl BodyOwnerKind { pub fn is_fn_or_closure(self) -> bool { match self { BodyOwnerKind::Fn | BodyOwnerKind::Closure => true, - BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false, + BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) | BodyOwnerKind::GlobalAsm => { + false + } } } } @@ -3420,7 +3425,7 @@ pub enum InlineAsmOperand<'hir> { anon_const: &'hir AnonConst, }, SymFn { - anon_const: &'hir AnonConst, + expr: &'hir Expr<'hir>, }, SymStatic { path: QPath<'hir>, @@ -3848,7 +3853,7 @@ impl<'hir> Item<'hir> { expect_foreign_mod, (ExternAbi, &'hir [ForeignItemRef]), ItemKind::ForeignMod { abi, items }, (*abi, items); - expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm(asm), asm; + expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm { asm, .. }, asm; expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>), ItemKind::TyAlias(ty, generics), (ty, generics); @@ -4015,7 +4020,15 @@ pub enum ItemKind<'hir> { /// An external module, e.g. `extern { .. }`. ForeignMod { abi: ExternAbi, items: &'hir [ForeignItemRef] }, /// Module-level inline assembly (from `global_asm!`). - GlobalAsm(&'hir InlineAsm<'hir>), + GlobalAsm { + asm: &'hir InlineAsm<'hir>, + /// A fake body which stores typeck results for the global asm's sym_fn + /// operands, which are represented as path expressions. This body contains + /// a single [`ExprKind::InlineAsm`] which points to the asm in the field + /// above, and which is typechecked like a inline asm expr just for the + /// typeck results. + fake_body: BodyId, + }, /// A type alias, e.g., `type Foo = Bar`. TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>), /// An enum definition, e.g., `enum Foo {C, D}`. @@ -4081,7 +4094,7 @@ impl ItemKind<'_> { ItemKind::Macro(..) => "macro", ItemKind::Mod(..) => "module", ItemKind::ForeignMod { .. } => "extern block", - ItemKind::GlobalAsm(..) => "global asm item", + ItemKind::GlobalAsm { .. } => "global asm item", ItemKind::TyAlias(..) => "type alias", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", @@ -4540,6 +4553,10 @@ impl<'hir> Node<'hir> { .. }) => Some((owner_id.def_id, *body)), + Node::Item(Item { + owner_id, kind: ItemKind::GlobalAsm { asm: _, fake_body }, .. + }) => Some((owner_id.def_id, *fake_body)), + Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => { Some((*def_id, *body)) } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index bd96fe9ee32c7..89a58e947cb56 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -573,9 +573,13 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_id(item.hir_id())); walk_list!(visitor, visit_foreign_item_ref, items); } - ItemKind::GlobalAsm(asm) => { + ItemKind::GlobalAsm { asm: _, fake_body } => { try_visit!(visitor.visit_id(item.hir_id())); - try_visit!(visitor.visit_inline_asm(asm, item.hir_id())); + // Visit the fake body, which contains the asm statement. + // Therefore we should not visit the asm statement again + // outside of the body, or some visitors won't have their + // typeck results set correctly. + try_visit!(visitor.visit_nested_body(fake_body)); } ItemKind::TyAlias(ref ty, ref generics) => { try_visit!(visitor.visit_id(item.hir_id())); @@ -1442,10 +1446,12 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>( try_visit!(visitor.visit_expr(in_expr)); visit_opt!(visitor, visit_expr, out_expr); } - InlineAsmOperand::Const { anon_const, .. } - | InlineAsmOperand::SymFn { anon_const, .. } => { + InlineAsmOperand::Const { anon_const, .. } => { try_visit!(visitor.visit_anon_const(anon_const)); } + InlineAsmOperand::SymFn { expr, .. } => { + try_visit!(visitor.visit_expr(expr)); + } InlineAsmOperand::SymStatic { path, .. } => { try_visit!(visitor.visit_qpath(path, id, *op_sp)); } diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index f3e8f059c9e3c..70e95a84e68cc 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -110,7 +110,7 @@ impl Target { ItemKind::Macro(..) => Target::MacroDef, ItemKind::Mod(..) => Target::Mod, ItemKind::ForeignMod { .. } => Target::ForeignMod, - ItemKind::GlobalAsm(..) => Target::GlobalAsm, + ItemKind::GlobalAsm { .. } => Target::GlobalAsm, ItemKind::TyAlias(..) => Target::TyAlias, ItemKind::Enum(..) => Target::Enum, ItemKind::Struct(..) => Target::Struct, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index b1b046d71752b..3236e0a3644d9 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -15,7 +15,6 @@ use rustc_lint_defs::builtin::{ use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; -use rustc_middle::span_bug; use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::fold::{BottomUpFolder, fold_regions}; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; @@ -35,7 +34,6 @@ use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::compare_impl_item::check_type_bounds; use super::*; -use crate::check::intrinsicck::InlineAsmCtxt; pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: ExternAbi) { if !tcx.sess.target.is_abi_supported(abi) { @@ -895,13 +893,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } } - DefKind::GlobalAsm => { - let it = tcx.hir().expect_item(def_id); - let hir::ItemKind::GlobalAsm(asm) = it.kind else { - span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) - }; - InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, def_id); - } _ => {} } } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 90e93bdbb5075..e1727fc48a833 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; use rustc_middle::bug; -use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; +use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::{Symbol, sym}; @@ -16,10 +16,11 @@ use rustc_target::asm::{ use crate::errors::RegisterTypeUnstable; -pub struct InlineAsmCtxt<'a, 'tcx> { +pub struct InlineAsmCtxt<'a, 'tcx: 'a> { tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - get_operand_ty: Box) -> Ty<'tcx> + 'a>, + target_features: &'tcx FxIndexSet, + expr_ty: Box) -> Ty<'tcx> + 'a>, } enum NonAsmTypeReason<'tcx> { @@ -29,25 +30,24 @@ enum NonAsmTypeReason<'tcx> { } impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { - pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { + pub fn new( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + get_operand_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a, + ) -> Self { InlineAsmCtxt { tcx, typing_env: ty::TypingEnv { typing_mode: ty::TypingMode::non_body_analysis(), param_env: ty::ParamEnv::empty(), }, - get_operand_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")), + target_features: tcx.asm_target_features(def_id), + expr_ty: Box::new(get_operand_ty), } } - // FIXME(#132279): This likely causes us to incorrectly handle opaque types in their - // defining scope. - pub fn new_in_fn( - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a, - ) -> Self { - InlineAsmCtxt { tcx, typing_env, get_operand_ty: Box::new(get_operand_ty) } + fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> { + (self.expr_ty)(expr) } // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()` @@ -139,9 +139,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { template: &[InlineAsmTemplatePiece], is_input: bool, tied_input: Option<(&'tcx hir::Expr<'tcx>, Option)>, - target_features: &FxIndexSet, ) -> Option { - let ty = (self.get_operand_ty)(expr); + let ty = self.expr_ty(expr); if ty.has_non_region_infer() { bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty); } @@ -229,7 +228,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if let Some((in_expr, Some(in_asm_ty))) = tied_input { if in_asm_ty != asm_ty { let msg = "incompatible types for asm inout argument"; - let in_expr_ty = (self.get_operand_ty)(in_expr); + let in_expr_ty = self.expr_ty(in_expr); self.tcx .dcx() .struct_span_err(vec![in_expr.span, expr.span], msg) @@ -291,7 +290,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // (!). In that case we still need the earlier check to verify that the // register class is usable at all. if let Some(feature) = feature { - if !target_features.contains(feature) { + if !self.target_features.contains(feature) { let msg = format!("`{feature}` target feature is not enabled"); self.tcx .dcx() @@ -351,14 +350,13 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { Some(asm_ty) } - pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) { - let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id()); + pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) { let Some(asm_arch) = self.tcx.sess.asm_arch else { self.tcx.dcx().delayed_bug("target architecture does not support asm"); return; }; let allow_experimental_reg = self.tcx.features().asm_experimental_reg(); - for (idx, (op, op_sp)) in asm.operands.iter().enumerate() { + for (idx, &(op, op_sp)) in asm.operands.iter().enumerate() { // Validate register classes against currently enabled target // features. We check that at least one type is available for // the enabled features. @@ -381,12 +379,12 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if let Err(msg) = reg.validate( asm_arch, self.tcx.sess.relocation_model(), - target_features, + self.target_features, &self.tcx.sess.target, op.is_clobber(), ) { let msg = format!("cannot use register `{}`: {}", reg.name(), msg); - self.tcx.dcx().span_err(*op_sp, msg); + self.tcx.dcx().span_err(op_sp, msg); continue; } } @@ -401,7 +399,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { { match feature { Some(feature) => { - if target_features.contains(&feature) { + if self.target_features.contains(&feature) { missing_required_features.clear(); break; } else { @@ -426,7 +424,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { reg_class.name(), feature ); - self.tcx.dcx().span_err(*op_sp, msg); + self.tcx.dcx().span_err(op_sp, msg); // register isn't enabled, don't do more checks continue; } @@ -440,7 +438,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { .intersperse(", ") .collect::(), ); - self.tcx.dcx().span_err(*op_sp, msg); + self.tcx.dcx().span_err(op_sp, msg); // register isn't enabled, don't do more checks continue; } @@ -448,52 +446,21 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } } - match *op { + match op { hir::InlineAsmOperand::In { reg, expr } => { - self.check_asm_operand_type( - idx, - reg, - expr, - asm.template, - true, - None, - target_features, - ); + self.check_asm_operand_type(idx, reg, expr, asm.template, true, None); } hir::InlineAsmOperand::Out { reg, late: _, expr } => { if let Some(expr) = expr { - self.check_asm_operand_type( - idx, - reg, - expr, - asm.template, - false, - None, - target_features, - ); + self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); } } hir::InlineAsmOperand::InOut { reg, late: _, expr } => { - self.check_asm_operand_type( - idx, - reg, - expr, - asm.template, - false, - None, - target_features, - ); + self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); } hir::InlineAsmOperand::SplitInOut { reg, late: _, in_expr, out_expr } => { - let in_ty = self.check_asm_operand_type( - idx, - reg, - in_expr, - asm.template, - true, - None, - target_features, - ); + let in_ty = + self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None); if let Some(out_expr) = out_expr { self.check_asm_operand_type( idx, @@ -502,7 +469,6 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { asm.template, false, Some((in_expr, in_ty)), - target_features, ); } } @@ -514,11 +480,25 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ); } // Typeck has checked that SymFn refers to a function. - hir::InlineAsmOperand::SymFn { anon_const } => { - debug_assert_matches!( - self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(), - ty::Error(_) | ty::FnDef(..) - ); + hir::InlineAsmOperand::SymFn { expr } => { + let ty = self.expr_ty(expr); + match ty.kind() { + ty::FnDef(..) => {} + ty::Error(_) => {} + _ => { + self.tcx + .dcx() + .struct_span_err(op_sp, "invalid `sym` operand") + .with_span_label( + expr.span, + format!("is {} `{}`", ty.kind().article(), ty), + ) + .with_help( + "`sym` operands must refer to either a function or a static", + ) + .emit(); + } + } } // AST lowering guarantees that SymStatic points to a static. hir::InlineAsmOperand::SymStatic { .. } => {} diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 5bb77c096dcf8..d2334c8cec5a9 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -680,7 +680,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { | hir::ItemKind::Use(..) | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(_) - | hir::ItemKind::GlobalAsm(_) => {} + | hir::ItemKind::GlobalAsm { .. } => {} hir::ItemKind::ForeignMod { items, .. } => { for item in *items { let item = tcx.hir_foreign_item(item.id); diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index a363076b75ac1..2cdd9a3a9348a 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -189,8 +189,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // Exclude `GlobalAsm` here which cannot have generics. Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) if asm.operands.iter().any(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } - | hir::InlineAsmOperand::SymFn { anon_const } => { + hir::InlineAsmOperand::Const { anon_const } => { anon_const.hir_id == hir_id } _ => false, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 759c981a8f768..b5333f393bcd8 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -630,7 +630,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::Mod(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Static(..) - | hir::ItemKind::GlobalAsm(..) => { + | hir::ItemKind::GlobalAsm { .. } => { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 717713d93399d..37c9e0610912f 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -35,13 +35,6 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx let parent_node_id = tcx.parent_hir_id(hir_id); let parent_node = tcx.hir_node(parent_node_id); - let find_sym_fn = |&(op, op_sp)| match op { - hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == hir_id => { - Some((anon_const, op_sp)) - } - _ => None, - }; - let find_const = |&(op, op_sp)| match op { hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => { Some((anon_const, op_sp)) @@ -59,31 +52,7 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx // Anon consts outside the type system. Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) - | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) - if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_sym_fn) => - { - let ty = tcx.typeck(def_id).node_type(hir_id); - - match ty.kind() { - ty::Error(_) => ty, - ty::FnDef(..) => ty, - _ => { - let guar = tcx - .dcx() - .struct_span_err(op_sp, "invalid `sym` operand") - .with_span_label( - tcx.def_span(anon_const.def_id), - format!("is {} `{}`", ty.kind().article(), ty), - ) - .with_help("`sym` operands must refer to either a function or a static") - .emit(); - - Ty::new_error(tcx, guar) - } - } - } - Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) - | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) + | Node::Item(&Item { kind: ItemKind::GlobalAsm { asm, .. }, .. }) if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) => { let ty = tcx.typeck(def_id).node_type(hir_id); @@ -313,12 +282,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_adt(tcx, def, args) } + ItemKind::GlobalAsm { .. } => tcx.typeck(def_id).node_type(hir_id), ItemKind::Trait(..) | ItemKind::TraitAlias(..) | ItemKind::Macro(..) | ItemKind::Mod(..) | ItemKind::ForeignMod { .. } - | ItemKind::GlobalAsm(..) | ItemKind::ExternCrate(..) | ItemKind::Use(..) => { span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 34124a6aa11a3..b9cdf3ddc346a 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -692,7 +692,7 @@ impl<'a> State<'a> { } self.bclose(item.span); } - hir::ItemKind::GlobalAsm(asm) => { + hir::ItemKind::GlobalAsm { asm, .. } => { self.head("global_asm!"); self.print_inline_asm(asm); self.end() @@ -1431,10 +1431,10 @@ impl<'a> State<'a> { s.space(); s.print_anon_const(anon_const); } - hir::InlineAsmOperand::SymFn { ref anon_const } => { + hir::InlineAsmOperand::SymFn { ref expr } => { s.word("sym_fn"); s.space(); - s.print_anon_const(anon_const); + s.print_expr(expr); } hir::InlineAsmOperand::SymStatic { ref path, def_id: _ } => { s.word("sym_static"); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 277396da19c13..0c71ef4655c5c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3763,7 +3763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut diverge = asm.asm_macro.diverges(asm.options); for (op, _op_sp) in asm.operands { - match op { + match *op { hir::InlineAsmOperand::In { expr, .. } => { self.check_expr_asm_operand(expr, true); } @@ -3778,10 +3778,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_asm_operand(out_expr, false); } } + hir::InlineAsmOperand::SymFn { expr } => { + self.check_expr(expr); + } // `AnonConst`s have their own body and is type-checked separately. // As they don't flow into the type system we don't need them to // be well-formed. - hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {} + hir::InlineAsmOperand::Const { .. } => {} hir::InlineAsmOperand::SymStatic { .. } => {} hir::InlineAsmOperand::Label { block } => { let previous_diverges = self.diverges.get(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index cf61659479b13..120a43576e814 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len()); for (asm, hir_id) in deferred_asm_checks.drain(..) { let enclosing_id = self.tcx.hir_enclosing_body_owner(hir_id); - let get_operand_ty = |expr| { + let expr_ty = |expr: &hir::Expr<'tcx>| { let ty = self.typeck_results.borrow().expr_ty_adjusted(expr); let ty = self.resolve_vars_if_possible(ty); if ty.has_non_region_infer() { @@ -110,12 +110,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.erase_regions(ty) } }; - InlineAsmCtxt::new_in_fn( - self.tcx, - self.infcx.typing_env(self.param_env), - get_operand_ty, - ) - .check_asm(asm, enclosing_id); + InlineAsmCtxt::new(self.tcx, enclosing_id, expr_ty).check_asm(asm); } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 9d5184acb3ca7..0130ad775d9e7 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -133,7 +133,12 @@ fn typeck_with_inspect<'tcx>( } let mut fcx = FnCtxt::new(&root_ctxt, param_env, def_id); - if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() { + if let hir::Node::Item(hir::Item { kind: hir::ItemKind::GlobalAsm { .. }, .. }) = node { + // Check the fake body of a global ASM. There's not much to do here except + // for visit the asm expr of the body. + let ty = fcx.check_expr(body.value); + fcx.write_ty(id, ty); + } else if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() { let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() { // In the case that we're recovering `fn() -> W<_>` or some other return // type that has an infer in it, lower the type directly so that it'll @@ -277,12 +282,9 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti Some(fcx.next_ty_var(span)) } Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. }) - | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => { + | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm { asm, .. }, span, .. }) => { asm.operands.iter().find_map(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } - | hir::InlineAsmOperand::SymFn { anon_const } - if anon_const.hir_id == id => - { + hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => { Some(fcx.next_ty_var(span)) } _ => None, diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 8c50cc59c1d5e..3e9ce0e11e402 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -48,13 +48,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for param in body.params { wbcx.visit_node_id(param.pat.span, param.hir_id); } - // Type only exists for constants and statics, not functions. match self.tcx.hir_body_owner_kind(item_def_id) { - hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => { + // Visit the type of a const or static, which is used during THIR building. + hir::BodyOwnerKind::Const { .. } + | hir::BodyOwnerKind::Static(_) + | hir::BodyOwnerKind::GlobalAsm => { let item_hir_id = self.tcx.local_def_id_to_hir_id(item_def_id); wbcx.visit_node_id(body.value.span, item_hir_id); } - hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), + // For closures and consts, we already plan to visit liberated signatures. + hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {} } wbcx.visit_body(body); wbcx.visit_min_capture_map(); diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 118a6fed036ed..56858679af663 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -261,7 +261,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { HirItem::ForeignMod { .. } => ("ItemForeignMod", LABELS_HIR_ONLY), // Module-level inline assembly (from global_asm!) - HirItem::GlobalAsm(..) => ("ItemGlobalAsm", LABELS_HIR_ONLY), + HirItem::GlobalAsm { .. } => ("ItemGlobalAsm", LABELS_HIR_ONLY), // A type alias, e.g., `type Foo = Bar` HirItem::TyAlias(..) => ("ItemTy", LABELS_HIR_ONLY), diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index b5f09ff346a7a..6c5a2dcd1460e 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2909,7 +2909,13 @@ enum AsmLabelKind { impl<'tcx> LateLintPass<'tcx> for AsmLabels { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::Expr { - kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, options, .. }), + kind: + hir::ExprKind::InlineAsm(hir::InlineAsm { + asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm, + template_strs, + options, + .. + }), .. } = expr { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 68b1f435a4cf7..4930cc35c9c3d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1740,7 +1740,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { hir::ItemKind::Impl(..) | hir::ItemKind::TraitAlias(..) | hir::ItemKind::Trait(..) - | hir::ItemKind::GlobalAsm(..) + | hir::ItemKind::GlobalAsm { .. } | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Mod(..) | hir::ItemKind::Macro(..) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 40dd6aa73fd4c..ec046d82ef645 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -305,6 +305,7 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::Static { safety: _, mutability, nested: false } => { BodyOwnerKind::Static(mutability) } + DefKind::GlobalAsm => BodyOwnerKind::GlobalAsm, dk => bug!("{:?} is not a body node: {:?}", def_id, dk), } } @@ -327,7 +328,7 @@ impl<'tcx> TyCtxt<'tcx> { ConstContext::ConstFn } BodyOwnerKind::Fn if self.is_const_default_method(def_id) => ConstContext::ConstFn, - BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None, + BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None, }; Some(ccx) @@ -1166,7 +1167,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { ItemKind::Macro(..) => "macro", ItemKind::Mod(..) => "mod", ItemKind::ForeignMod { .. } => "foreign mod", - ItemKind::GlobalAsm(..) => "global asm", + ItemKind::GlobalAsm { .. } => "global asm", ItemKind::TyAlias(..) => "ty", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 98cc00c367cfe..6a2672ac02b75 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -94,6 +94,7 @@ thir_with_elements! { pub enum BodyTy<'tcx> { Const(Ty<'tcx>), Fn(FnSig<'tcx>), + GlobalAsm(Ty<'tcx>), } /// Description of a type-checked function parameter. @@ -605,8 +606,7 @@ pub enum InlineAsmOperand<'tcx> { span: Span, }, SymFn { - value: mir::Const<'tcx>, - span: Span, + value: ExprId, }, SymStatic { def_id: DefId, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 13b8af55e518e..e347a64e45d0f 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -172,7 +172,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( } Out { expr: None, reg: _, late: _ } | Const { value: _, span: _ } - | SymFn { value: _, span: _ } + | SymFn { value: _ } | SymStatic { def_id: _ } => {} Label { block } => visitor.visit_block(&visitor.thir()[*block]), } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 32a9e67f9ad53..361e204fb0f0f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1472,7 +1472,11 @@ impl<'tcx> TyCtxt<'tcx> { self.codegen_fn_attrs(def_id) } else if matches!( def_kind, - DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst + DefKind::AnonConst + | DefKind::AssocConst + | DefKind::Const + | DefKind::InlineConst + | DefKind::GlobalAsm ) { CodegenFnAttrs::EMPTY } else { diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 65dd061003d8d..72443e2f60ddc 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -482,15 +482,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }), } } - thir::InlineAsmOperand::SymFn { value, span } => { - mir::InlineAsmOperand::SymFn { - value: Box::new(ConstOperand { - span, - user_ty: None, - const_: value, - }), - } - } + thir::InlineAsmOperand::SymFn { value } => mir::InlineAsmOperand::SymFn { + value: Box::new(this.as_constant(&this.thir[value])), + }, thir::InlineAsmOperand::SymStatic { def_id } => { mir::InlineAsmOperand::SymStatic { def_id } } @@ -518,10 +512,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let asm_macro = match asm_macro { - AsmMacro::Asm => InlineAsmMacro::Asm, - AsmMacro::GlobalAsm => { - span_bug!(expr_span, "unexpected global_asm! in inline asm") - } + AsmMacro::Asm | AsmMacro::GlobalAsm => InlineAsmMacro::Asm, AsmMacro::NakedAsm => InlineAsmMacro::NakedAsm, }; diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 4348b7a4b4cc9..949559549345f 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -61,7 +61,9 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> { Ok((thir, expr)) => { let build_mir = |thir: &Thir<'tcx>| match thir.body_type { thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig), - thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty), + thir::BodyTy::Const(ty) | thir::BodyTy::GlobalAsm(ty) => { + construct_const(tcx, def, thir, expr, ty) + } }; // this must run before MIR dump, because @@ -576,6 +578,7 @@ fn construct_const<'a, 'tcx>( let span = tcx.def_span(def); (span, span) } + Node::Item(hir::Item { kind: hir::ItemKind::GlobalAsm { .. }, span, .. }) => (*span, *span), _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), }; diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index d65c2097d226e..c2eafd0a74e65 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use std::mem; use std::ops::Bound; +use rustc_ast::AsmMacro; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::DiagArgValue; use rustc_hir::def::DefKind; @@ -559,7 +560,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } } ExprKind::InlineAsm(box InlineAsmExpr { - asm_macro: _, + asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm, ref operands, template: _, options: _, @@ -583,7 +584,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } Out { expr: None, reg: _, late: _ } | Const { value: _, span: _ } - | SymFn { value: _, span: _ } + | SymFn { value: _ } | SymStatic { def_id: _ } => {} Label { block } => { // Label blocks are safe context. diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index d0fca76fcf05d..29bc1d6572dfa 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -739,13 +739,8 @@ impl<'tcx> ThirBuildCx<'tcx> { InlineAsmOperand::Const { value, span } } - hir::InlineAsmOperand::SymFn { ref anon_const } => { - let value = - mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id()) - .instantiate_identity(); - let span = tcx.def_span(anon_const.def_id); - - InlineAsmOperand::SymFn { value, span } + hir::InlineAsmOperand::SymFn { expr } => { + InlineAsmOperand::SymFn { value: self.mirror_expr(expr) } } hir::InlineAsmOperand::SymStatic { path: _, def_id } => { InlineAsmOperand::SymStatic { def_id } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 7a9f6e4630456..c32082c609ec4 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -76,23 +76,29 @@ impl<'tcx> ThirBuildCx<'tcx> { let hir = tcx.hir(); let hir_id = tcx.local_def_id_to_hir_id(def); - let body_type = if tcx.hir_body_owner_kind(def).is_fn_or_closure() { - // fetch the fully liberated fn signature (that is, all bound - // types/lifetimes replaced) - BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id]) - } else { - // Get the revealed type of this const. This is *not* the adjusted - // type of its body, which may be a subtype of this type. For - // example: - // - // fn foo(_: &()) {} - // static X: fn(&'static ()) = foo; - // - // The adjusted type of the body of X is `for<'a> fn(&'a ())` which - // is not the same as the type of X. We need the type of the return - // place to be the type of the constant because NLL typeck will - // equate them. - BodyTy::Const(typeck_results.node_type(hir_id)) + let body_type = match tcx.hir_body_owner_kind(def) { + rustc_hir::BodyOwnerKind::Fn | rustc_hir::BodyOwnerKind::Closure => { + // fetch the fully liberated fn signature (that is, all bound + // types/lifetimes replaced) + BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id]) + } + rustc_hir::BodyOwnerKind::Const { .. } | rustc_hir::BodyOwnerKind::Static(_) => { + // Get the revealed type of this const. This is *not* the adjusted + // type of its body, which may be a subtype of this type. For + // example: + // + // fn foo(_: &()) {} + // static X: fn(&'static ()) = foo; + // + // The adjusted type of the body of X is `for<'a> fn(&'a ())` which + // is not the same as the type of X. We need the type of the return + // place to be the type of the constant because NLL typeck will + // equate them. + BodyTy::Const(typeck_results.node_type(hir_id)) + } + rustc_hir::BodyOwnerKind::GlobalAsm => { + BodyTy::GlobalAsm(typeck_results.node_type(hir_id)) + } }; Self { diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 9ab87dd99ffc0..cd56d93afcf75 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -921,10 +921,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); print_indented!(self, "}", depth_lvl + 1); } - InlineAsmOperand::SymFn { value, span } => { + InlineAsmOperand::SymFn { value } => { print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl); - print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1); - print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "value: ", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } InlineAsmOperand::SymStatic { def_id } => { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1195c25e13087..694a4dd5b4c4c 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -479,24 +479,23 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = None; let item = tcx.hir_item(item_id); - if let hir::ItemKind::GlobalAsm(asm) = item.kind { + if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind { for (op, op_sp) in asm.operands { - match op { + match *op { hir::InlineAsmOperand::Const { .. } => { // Only constants which resolve to a plain integer // are supported. Therefore the value should not // depend on any other items. } - hir::InlineAsmOperand::SymFn { anon_const } => { - let fn_ty = - tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); + hir::InlineAsmOperand::SymFn { expr } => { + let fn_ty = tcx.typeck(item_id.owner_id).expr_ty(expr); visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items); } hir::InlineAsmOperand::SymStatic { path: _, def_id } => { - let instance = Instance::mono(tcx, *def_id); + let instance = Instance::mono(tcx, def_id); if tcx.should_codegen_locally(instance) { trace!("collecting static {:?}", def_id); - used_items.push(dummy_spanned(MonoItem::Static(*def_id))); + used_items.push(dummy_spanned(MonoItem::Static(def_id))); } } hir::InlineAsmOperand::In { .. } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 1fe44bd3d21a9..fd465717bf766 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -246,7 +246,7 @@ impl<'tcx> ReachableContext<'tcx> { | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) - | hir::ItemKind::GlobalAsm(..) => {} + | hir::ItemKind::GlobalAsm { .. } => {} } } Node::TraitItem(trait_method) => { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 6faa2c1a00d23..41725d0c6a4f9 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -645,7 +645,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // The interface is empty, and no nested items. hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(..) - | hir::ItemKind::GlobalAsm(..) => {} + | hir::ItemKind::GlobalAsm { .. } => {} // The interface is empty, and all nested items are processed by `visit_item`. hir::ItemKind::Mod(..) => {} hir::ItemKind::Macro(macro_def, _) => { diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 658d5965b3d2a..ce9c42c01cc73 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -288,7 +288,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { | ItemKind::Use(_, _) | ItemKind::ExternCrate(_) | ItemKind::ForeignMod { .. } - | ItemKind::GlobalAsm(_) + | ItemKind::GlobalAsm { .. } // We already have "visit_mod" above so no need to check it here. | ItemKind::Mod(_) => {} } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f606a3d8a9270..7b6921afa0808 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -439,7 +439,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } // If we're inlining, skip private items. _ if self.inlining && !is_pub => {} - hir::ItemKind::GlobalAsm(..) => {} + hir::ItemKind::GlobalAsm { .. } => {} hir::ItemKind::Use(_, hir::UseKind::ListStem) => {} hir::ItemKind::Use(path, kind) => { for &res in &path.res { diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index aff40fa846be2..c0ae4960e10d9 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -362,7 +362,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { } } else if let ItemKind::ForeignMod { .. } = item.kind { continue; - } else if let ItemKind::GlobalAsm(_) = item.kind { + } else if let ItemKind::GlobalAsm { .. } = item.kind { continue; } else if let ItemKind::Use(path, use_kind) = item.kind { if path.segments.is_empty() { @@ -467,7 +467,7 @@ fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleIte ItemKind::Macro(..) => Macro, ItemKind::Mod(..) => Mod, ItemKind::ForeignMod { .. } => ForeignMod, - ItemKind::GlobalAsm(..) => GlobalAsm, + ItemKind::GlobalAsm { .. } => GlobalAsm, ItemKind::TyAlias(..) => TyAlias, ItemKind::Enum(..) => Enum, ItemKind::Struct(..) => Struct, diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 06e92985e6648..47a9e17b3cfe1 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -217,7 +217,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { | hir::ItemKind::Union(..) => {}, hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::GlobalAsm(..) + | hir::ItemKind::GlobalAsm { .. } | hir::ItemKind::Impl { .. } | hir::ItemKind::Use(..) => note_prev_span_then_ret!(self.prev_span, it.span), } diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index fdc0930e957a0..3cf1a80607e8b 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { | hir::ItemKind::Static(..) | hir::ItemKind::Struct(..) | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::GlobalAsm(..) + | hir::ItemKind::GlobalAsm { .. } | hir::ItemKind::TyAlias(..) | hir::ItemKind::Union(..) | hir::ItemKind::ExternCrate(..) diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index cda99a362dcae..c261fd9bd9cb0 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -82,7 +82,7 @@ impl Context { } self.const_span = Some(body_span); }, - hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (), + hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::GlobalAsm => (), } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 9ee30094d608c..0ac675345ae0c 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -968,7 +968,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(out_expr); } }, - InlineAsmOperand::Const { anon_const } | InlineAsmOperand::SymFn { anon_const } => { + InlineAsmOperand::SymFn { expr } => { + self.hash_expr(expr); + } + InlineAsmOperand::Const { anon_const } => { self.hash_body(anon_const.body); }, InlineAsmOperand::SymStatic { path, def_id: _ } => self.hash_qpath(path), diff --git a/tests/crashes/111709-2.rs b/tests/crashes/111709-2.rs deleted file mode 100644 index 6c4fb9f28c7de..0000000000000 --- a/tests/crashes/111709-2.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #111709 -//@ edition: 2021 - -use core::arch::asm; - -extern "C" fn test() {} - -fn uwu() { - unsafe { - asm!( - "/* {0} */", - sym test::<&mut ()> - ); - } -} diff --git a/tests/crashes/111709.rs b/tests/crashes/111709.rs deleted file mode 100644 index eef375b8924b7..0000000000000 --- a/tests/crashes/111709.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ known-bug: #111709 -//@ edition:2021 - -use core::arch::asm; - -struct TrapFrame; - -unsafe extern "C" fn _rust_abi_shim1(arg: A, f: fn(A) -> R) -> R { - f(arg) -} - -unsafe extern "C" fn _start_trap() { - extern "Rust" { - fn interrupt(tf: &mut TrapFrame); - } - asm!( - " - la a1, {irq} - call {shim} - ", - shim = sym crate::_rust_abi_shim1::<&mut TrapFrame, ()>, - irq = sym interrupt, - options(noreturn) - ) -} diff --git a/tests/crashes/96304.rs b/tests/crashes/96304.rs deleted file mode 100644 index 637012f45858f..0000000000000 --- a/tests/crashes/96304.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #96304 - -#![feature(asm_sym)] -core::arch::global_asm!("/* {} */", sym<&'static ()>::clone); - -pub fn main() {} diff --git a/tests/ui/asm/asm-with-nested-closure.rs b/tests/ui/asm/asm-with-nested-closure.rs new file mode 100644 index 0000000000000..3a5cd48d5d4df --- /dev/null +++ b/tests/ui/asm/asm-with-nested-closure.rs @@ -0,0 +1,11 @@ +//@ build-pass +//@ needs-asm-support + +fn foo() {} + +core::arch::global_asm!("/* {} */", sym foo::<{ + || {}; + 0 +}>); + +fn main() {} diff --git a/tests/ui/asm/global-asm-with-lifetimes.rs b/tests/ui/asm/global-asm-with-lifetimes.rs new file mode 100644 index 0000000000000..2709ff90fe333 --- /dev/null +++ b/tests/ui/asm/global-asm-with-lifetimes.rs @@ -0,0 +1,8 @@ +//@ build-pass +//@ needs-asm-support + +fn foo() {} + +core::arch::global_asm!("/* {} */", sym foo::<&'static ()>); + +fn main() {} diff --git a/tests/ui/asm/inline-asm-with-lifetimes.bad.stderr b/tests/ui/asm/inline-asm-with-lifetimes.bad.stderr new file mode 100644 index 0000000000000..f04482f9c5916 --- /dev/null +++ b/tests/ui/asm/inline-asm-with-lifetimes.bad.stderr @@ -0,0 +1,17 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/inline-asm-with-lifetimes.rs:17:26 + | +LL | fn test<'a: 'a, T>() { + | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... +LL | unsafe { +LL | asm!("/* {} */", sym dep::<'a, T> ); + | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn test<'a: 'a, T: 'a>() { + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/tests/ui/asm/inline-asm-with-lifetimes.rs b/tests/ui/asm/inline-asm-with-lifetimes.rs new file mode 100644 index 0000000000000..79def03eeb232 --- /dev/null +++ b/tests/ui/asm/inline-asm-with-lifetimes.rs @@ -0,0 +1,22 @@ +//@ revisions: good bad +//@[good] build-pass +//@ needs-asm-support + +use std::arch::asm; + +// lifetime requirement, we should check it!! +#[cfg(bad)] +fn dep<'a, T: 'a>() {} + +// no lifetime requirement +#[cfg(good)] +fn dep<'a: 'a, T>() {} + +fn test<'a: 'a, T>() { + unsafe { + asm!("/* {} */", sym dep::<'a, T> ); + //[bad]~^ ERROR the parameter type `T` may not live long enough + } +} + +fn main() {}