1
Fork 0

Make a fake body to store typeck results for global_asm

This commit is contained in:
Michael Goulet 2025-02-17 16:09:46 +00:00
parent 37060aae13
commit 6ba39f7dc7
37 changed files with 244 additions and 232 deletions

View file

@ -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 } => {

View file

@ -252,7 +252,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
},
ItemKind::GlobalAsm(asm) => {
hir::ItemKind::GlobalAsm { asm: self.lower_inline_asm(span, 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

View file

@ -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.

View file

@ -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"),

View file

@ -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"),

View file

@ -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 { asm: &'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<u8>`.
TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
/// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
@ -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))
}

View file

@ -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));
}

View file

@ -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, def_id).check_asm(asm);
}
_ => {}
}
}

View file

@ -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};
@ -30,7 +30,11 @@ enum NonAsmTypeReason<'tcx> {
}
impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
pub fn new_global_asm(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> 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 {
@ -38,23 +42,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
param_env: ty::ParamEnv::empty(),
},
target_features: tcx.asm_target_features(def_id),
expr_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")),
}
}
// 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>,
def_id: LocalDefId,
expr_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
) -> Self {
InlineAsmCtxt {
tcx,
typing_env,
target_features: tcx.asm_target_features(def_id),
expr_ty: Box::new(expr_ty),
expr_ty: Box::new(get_operand_ty),
}
}
@ -492,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 { .. } => {}

View file

@ -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,

View file

@ -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);

View file

@ -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");

View file

@ -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();

View file

@ -110,13 +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),
enclosing_id,
expr_ty,
)
.check_asm(asm);
InlineAsmCtxt::new(self.tcx, enclosing_id, expr_ty).check_asm(asm);
}
}

View file

@ -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,

View file

@ -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();

View file

@ -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
{

View file

@ -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)

View file

@ -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,

View file

@ -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]),
}

View file

@ -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 {

View file

@ -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,
};

View file

@ -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),
};

View file

@ -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.

View file

@ -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 }

View file

@ -76,11 +76,13 @@ 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() {
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])
} else {
}
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:
@ -93,6 +95,10 @@ impl<'tcx> ThirBuildCx<'tcx> {
// 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 {

View file

@ -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 } => {

View file

@ -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 { .. }

View file

@ -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 => (),
}
}

View file

@ -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),

View file

@ -1,15 +0,0 @@
//@ known-bug: #111709
//@ edition: 2021
use core::arch::asm;
extern "C" fn test<T>() {}
fn uwu() {
unsafe {
asm!(
"/* {0} */",
sym test::<&mut ()>
);
}
}

View file

@ -1,25 +0,0 @@
//@ known-bug: #111709
//@ edition:2021
use core::arch::asm;
struct TrapFrame;
unsafe extern "C" fn _rust_abi_shim1<A, R>(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)
)
}

View file

@ -1,6 +0,0 @@
//@ known-bug: #96304
#![feature(asm_sym)]
core::arch::global_asm!("/* {} */", sym<&'static ()>::clone);
pub fn main() {}

View file

@ -0,0 +1,11 @@
//@ build-pass
//@ needs-asm-support
fn foo<const N: usize>() {}
core::arch::global_asm!("/* {} */", sym foo::<{
|| {};
0
}>);
fn main() {}

View file

@ -0,0 +1,8 @@
//@ build-pass
//@ needs-asm-support
fn foo<T>() {}
core::arch::global_asm!("/* {} */", sym foo::<&'static ()>);
fn main() {}

View file

@ -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`.

View file

@ -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() {}