Make a fake body to store typeck results for global_asm
This commit is contained in:
parent
37060aae13
commit
6ba39f7dc7
37 changed files with 244 additions and 232 deletions
|
@ -1,13 +1,12 @@
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use rustc_ast::ptr::P;
|
|
||||||
use rustc_ast::*;
|
use rustc_ast::*;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::{Span, kw, sym};
|
use rustc_span::{Span, sym};
|
||||||
use rustc_target::asm;
|
use rustc_target::asm;
|
||||||
|
|
||||||
use super::LoweringContext;
|
use super::LoweringContext;
|
||||||
|
@ -230,20 +229,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
tokens: None,
|
tokens: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wrap the expression in an AnonConst.
|
hir::InlineAsmOperand::SymFn { expr: self.lower_expr(&expr) }
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InlineAsmOperand::Label { block } => {
|
InlineAsmOperand::Label { block } => {
|
||||||
|
|
|
@ -252,7 +252,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
|
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
|
||||||
},
|
},
|
||||||
ItemKind::GlobalAsm(asm) => {
|
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, .. }) => {
|
ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => {
|
||||||
// We lower
|
// We lower
|
||||||
|
|
|
@ -126,6 +126,11 @@ pub(crate) enum DefiningTy<'tcx> {
|
||||||
/// The MIR represents an inline const. The signature has no inputs and a
|
/// The MIR represents an inline const. The signature has no inputs and a
|
||||||
/// single return value found via `InlineConstArgs::ty`.
|
/// single return value found via `InlineConstArgs::ty`.
|
||||||
InlineConst(DefId, GenericArgsRef<'tcx>),
|
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> {
|
impl<'tcx> DefiningTy<'tcx> {
|
||||||
|
@ -138,9 +143,10 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||||
DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
|
DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
|
||||||
DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(),
|
DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(),
|
||||||
DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(),
|
DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(),
|
||||||
DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
|
DefiningTy::FnDef(..)
|
||||||
ty::List::empty()
|
| DefiningTy::Const(..)
|
||||||
}
|
| DefiningTy::InlineConst(..)
|
||||||
|
| DefiningTy::GlobalAsm(_) => ty::List::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +158,10 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||||
DefiningTy::Closure(..)
|
DefiningTy::Closure(..)
|
||||||
| DefiningTy::CoroutineClosure(..)
|
| DefiningTy::CoroutineClosure(..)
|
||||||
| DefiningTy::Coroutine(..) => 1,
|
| 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::Coroutine(def_id, ..)
|
||||||
| DefiningTy::FnDef(def_id, ..)
|
| DefiningTy::FnDef(def_id, ..)
|
||||||
| DefiningTy::Const(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),
|
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)
|
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::FnDef(_, args) | DefiningTy::Const(_, args) => args,
|
||||||
|
|
||||||
|
DefiningTy::GlobalAsm(_) => ty::List::empty(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static));
|
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();
|
let ty = args.as_inline_const().ty();
|
||||||
ty::Binder::dummy(tcx.mk_type_list(&[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.
|
// FIXME(#129952): We probably want a more principled approach here.
|
||||||
|
|
|
@ -16,7 +16,7 @@ use crate::prelude::*;
|
||||||
|
|
||||||
pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
|
pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
|
||||||
let item = tcx.hir_item(item_id);
|
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 =
|
let is_x86 =
|
||||||
matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64);
|
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")) {
|
if cfg!(not(feature = "inline_asm_sym")) {
|
||||||
tcx.dcx().span_err(
|
tcx.dcx().span_err(
|
||||||
item.span,
|
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() {
|
let instance = match ty.kind() {
|
||||||
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
||||||
_ => span_bug!(op_sp, "asm sym is not a function"),
|
_ => span_bug!(op_sp, "asm sym is not a function"),
|
||||||
|
|
|
@ -36,7 +36,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
|
||||||
}
|
}
|
||||||
MonoItem::GlobalAsm(item_id) => {
|
MonoItem::GlobalAsm(item_id) => {
|
||||||
let item = cx.tcx().hir_item(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
|
let operands: Vec<_> = asm
|
||||||
.operands
|
.operands
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -71,11 +71,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::SymFn { ref anon_const } => {
|
hir::InlineAsmOperand::SymFn { expr } => {
|
||||||
let ty = cx
|
let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr);
|
||||||
.tcx()
|
|
||||||
.typeck_body(anon_const.body)
|
|
||||||
.node_type(anon_const.hir_id);
|
|
||||||
let instance = match ty.kind() {
|
let instance = match ty.kind() {
|
||||||
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
|
||||||
_ => span_bug!(*op_sp, "asm sym is not a function"),
|
_ => span_bug!(*op_sp, "asm sym is not a function"),
|
||||||
|
|
|
@ -1913,13 +1913,18 @@ pub enum BodyOwnerKind {
|
||||||
|
|
||||||
/// Initializer of a `static` item.
|
/// Initializer of a `static` item.
|
||||||
Static(Mutability),
|
Static(Mutability),
|
||||||
|
|
||||||
|
/// Fake body for a global asm to store its const-like value types.
|
||||||
|
GlobalAsm,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BodyOwnerKind {
|
impl BodyOwnerKind {
|
||||||
pub fn is_fn_or_closure(self) -> bool {
|
pub fn is_fn_or_closure(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
BodyOwnerKind::Fn | BodyOwnerKind::Closure => true,
|
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,
|
anon_const: &'hir AnonConst,
|
||||||
},
|
},
|
||||||
SymFn {
|
SymFn {
|
||||||
anon_const: &'hir AnonConst,
|
expr: &'hir Expr<'hir>,
|
||||||
},
|
},
|
||||||
SymStatic {
|
SymStatic {
|
||||||
path: QPath<'hir>,
|
path: QPath<'hir>,
|
||||||
|
@ -3848,7 +3853,7 @@ impl<'hir> Item<'hir> {
|
||||||
expect_foreign_mod, (ExternAbi, &'hir [ForeignItemRef]),
|
expect_foreign_mod, (ExternAbi, &'hir [ForeignItemRef]),
|
||||||
ItemKind::ForeignMod { abi, items }, (*abi, items);
|
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>),
|
expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>),
|
||||||
ItemKind::TyAlias(ty, generics), (ty, generics);
|
ItemKind::TyAlias(ty, generics), (ty, generics);
|
||||||
|
@ -4015,7 +4020,15 @@ pub enum ItemKind<'hir> {
|
||||||
/// An external module, e.g. `extern { .. }`.
|
/// An external module, e.g. `extern { .. }`.
|
||||||
ForeignMod { abi: ExternAbi, items: &'hir [ForeignItemRef] },
|
ForeignMod { abi: ExternAbi, items: &'hir [ForeignItemRef] },
|
||||||
/// Module-level inline assembly (from `global_asm!`).
|
/// 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>`.
|
/// A type alias, e.g., `type Foo = Bar<u8>`.
|
||||||
TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
|
TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
|
||||||
/// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
|
/// 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)),
|
}) => 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, .. }), .. }) => {
|
Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => {
|
||||||
Some((*def_id, *body))
|
Some((*def_id, *body))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
try_visit!(visitor.visit_id(item.hir_id()));
|
||||||
walk_list!(visitor, visit_foreign_item_ref, items);
|
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_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) => {
|
ItemKind::TyAlias(ref ty, ref generics) => {
|
||||||
try_visit!(visitor.visit_id(item.hir_id()));
|
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));
|
try_visit!(visitor.visit_expr(in_expr));
|
||||||
visit_opt!(visitor, visit_expr, out_expr);
|
visit_opt!(visitor, visit_expr, out_expr);
|
||||||
}
|
}
|
||||||
InlineAsmOperand::Const { anon_const, .. }
|
InlineAsmOperand::Const { anon_const, .. } => {
|
||||||
| InlineAsmOperand::SymFn { anon_const, .. } => {
|
|
||||||
try_visit!(visitor.visit_anon_const(anon_const));
|
try_visit!(visitor.visit_anon_const(anon_const));
|
||||||
}
|
}
|
||||||
|
InlineAsmOperand::SymFn { expr, .. } => {
|
||||||
|
try_visit!(visitor.visit_expr(expr));
|
||||||
|
}
|
||||||
InlineAsmOperand::SymStatic { path, .. } => {
|
InlineAsmOperand::SymStatic { path, .. } => {
|
||||||
try_visit!(visitor.visit_qpath(path, id, *op_sp));
|
try_visit!(visitor.visit_qpath(path, id, *op_sp));
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ use rustc_lint_defs::builtin::{
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
|
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
|
||||||
use rustc_middle::middle::stability::EvalResult;
|
use rustc_middle::middle::stability::EvalResult;
|
||||||
use rustc_middle::span_bug;
|
|
||||||
use rustc_middle::ty::error::TypeErrorToStringExt;
|
use rustc_middle::ty::error::TypeErrorToStringExt;
|
||||||
use rustc_middle::ty::fold::{BottomUpFolder, fold_regions};
|
use rustc_middle::ty::fold::{BottomUpFolder, fold_regions};
|
||||||
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
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::compare_impl_item::check_type_bounds;
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::check::intrinsicck::InlineAsmCtxt;
|
|
||||||
|
|
||||||
pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: ExternAbi) {
|
pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: ExternAbi) {
|
||||||
if !tcx.sess.target.is_abi_supported(abi) {
|
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);
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{self as hir, LangItem};
|
use rustc_hir::{self as hir, LangItem};
|
||||||
use rustc_middle::bug;
|
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_session::lint;
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::{Symbol, sym};
|
use rustc_span::{Symbol, sym};
|
||||||
|
@ -30,7 +30,11 @@ enum NonAsmTypeReason<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> InlineAsmCtxt<'a, '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 {
|
InlineAsmCtxt {
|
||||||
tcx,
|
tcx,
|
||||||
typing_env: ty::TypingEnv {
|
typing_env: ty::TypingEnv {
|
||||||
|
@ -38,23 +42,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||||
param_env: ty::ParamEnv::empty(),
|
param_env: ty::ParamEnv::empty(),
|
||||||
},
|
},
|
||||||
target_features: tcx.asm_target_features(def_id),
|
target_features: tcx.asm_target_features(def_id),
|
||||||
expr_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")),
|
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>,
|
|
||||||
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),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,11 +480,25 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Typeck has checked that SymFn refers to a function.
|
// Typeck has checked that SymFn refers to a function.
|
||||||
hir::InlineAsmOperand::SymFn { anon_const } => {
|
hir::InlineAsmOperand::SymFn { expr } => {
|
||||||
debug_assert_matches!(
|
let ty = self.expr_ty(expr);
|
||||||
self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
|
match ty.kind() {
|
||||||
ty::Error(_) | ty::FnDef(..)
|
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.
|
// AST lowering guarantees that SymStatic points to a static.
|
||||||
hir::InlineAsmOperand::SymStatic { .. } => {}
|
hir::InlineAsmOperand::SymStatic { .. } => {}
|
||||||
|
|
|
@ -189,8 +189,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||||
// Exclude `GlobalAsm` here which cannot have generics.
|
// Exclude `GlobalAsm` here which cannot have generics.
|
||||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||||
if asm.operands.iter().any(|(op, _op_sp)| match op {
|
if asm.operands.iter().any(|(op, _op_sp)| match op {
|
||||||
hir::InlineAsmOperand::Const { anon_const }
|
hir::InlineAsmOperand::Const { anon_const } => {
|
||||||
| hir::InlineAsmOperand::SymFn { anon_const } => {
|
|
||||||
anon_const.hir_id == hir_id
|
anon_const.hir_id == hir_id
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
|
@ -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_id = tcx.parent_hir_id(hir_id);
|
||||||
let parent_node = tcx.hir_node(parent_node_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 {
|
let find_const = |&(op, op_sp)| match op {
|
||||||
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
|
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
|
||||||
Some((anon_const, op_sp))
|
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.
|
// Anon consts outside the type system.
|
||||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
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_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 }, .. })
|
|
||||||
if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) =>
|
if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) =>
|
||||||
{
|
{
|
||||||
let ty = tcx.typeck(def_id).node_type(hir_id);
|
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);
|
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
|
||||||
Ty::new_adt(tcx, def, args)
|
Ty::new_adt(tcx, def, args)
|
||||||
}
|
}
|
||||||
|
ItemKind::GlobalAsm { .. } => tcx.typeck(def_id).node_type(hir_id),
|
||||||
ItemKind::Trait(..)
|
ItemKind::Trait(..)
|
||||||
| ItemKind::TraitAlias(..)
|
| ItemKind::TraitAlias(..)
|
||||||
| ItemKind::Macro(..)
|
| ItemKind::Macro(..)
|
||||||
| ItemKind::Mod(..)
|
| ItemKind::Mod(..)
|
||||||
| ItemKind::ForeignMod { .. }
|
| ItemKind::ForeignMod { .. }
|
||||||
| ItemKind::GlobalAsm { .. }
|
|
||||||
| ItemKind::ExternCrate(..)
|
| ItemKind::ExternCrate(..)
|
||||||
| ItemKind::Use(..) => {
|
| ItemKind::Use(..) => {
|
||||||
span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind);
|
span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind);
|
||||||
|
|
|
@ -692,7 +692,7 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
self.bclose(item.span);
|
self.bclose(item.span);
|
||||||
}
|
}
|
||||||
hir::ItemKind::GlobalAsm { asm } => {
|
hir::ItemKind::GlobalAsm { asm, .. } => {
|
||||||
self.head("global_asm!");
|
self.head("global_asm!");
|
||||||
self.print_inline_asm(asm);
|
self.print_inline_asm(asm);
|
||||||
self.end()
|
self.end()
|
||||||
|
@ -1431,10 +1431,10 @@ impl<'a> State<'a> {
|
||||||
s.space();
|
s.space();
|
||||||
s.print_anon_const(anon_const);
|
s.print_anon_const(anon_const);
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::SymFn { ref anon_const } => {
|
hir::InlineAsmOperand::SymFn { ref expr } => {
|
||||||
s.word("sym_fn");
|
s.word("sym_fn");
|
||||||
s.space();
|
s.space();
|
||||||
s.print_anon_const(anon_const);
|
s.print_expr(expr);
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::SymStatic { ref path, def_id: _ } => {
|
hir::InlineAsmOperand::SymStatic { ref path, def_id: _ } => {
|
||||||
s.word("sym_static");
|
s.word("sym_static");
|
||||||
|
|
|
@ -3763,7 +3763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let mut diverge = asm.asm_macro.diverges(asm.options);
|
let mut diverge = asm.asm_macro.diverges(asm.options);
|
||||||
|
|
||||||
for (op, _op_sp) in asm.operands {
|
for (op, _op_sp) in asm.operands {
|
||||||
match op {
|
match *op {
|
||||||
hir::InlineAsmOperand::In { expr, .. } => {
|
hir::InlineAsmOperand::In { expr, .. } => {
|
||||||
self.check_expr_asm_operand(expr, true);
|
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);
|
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.
|
// `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
|
// As they don't flow into the type system we don't need them to
|
||||||
// be well-formed.
|
// be well-formed.
|
||||||
hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {}
|
hir::InlineAsmOperand::Const { .. } => {}
|
||||||
hir::InlineAsmOperand::SymStatic { .. } => {}
|
hir::InlineAsmOperand::SymStatic { .. } => {}
|
||||||
hir::InlineAsmOperand::Label { block } => {
|
hir::InlineAsmOperand::Label { block } => {
|
||||||
let previous_diverges = self.diverges.get();
|
let previous_diverges = self.diverges.get();
|
||||||
|
|
|
@ -110,13 +110,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.tcx.erase_regions(ty)
|
self.tcx.erase_regions(ty)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
InlineAsmCtxt::new_in_fn(
|
InlineAsmCtxt::new(self.tcx, enclosing_id, expr_ty).check_asm(asm);
|
||||||
self.tcx,
|
|
||||||
self.infcx.typing_env(self.param_env),
|
|
||||||
enclosing_id,
|
|
||||||
expr_ty,
|
|
||||||
)
|
|
||||||
.check_asm(asm);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,12 @@ fn typeck_with_inspect<'tcx>(
|
||||||
}
|
}
|
||||||
let mut fcx = FnCtxt::new(&root_ctxt, param_env, def_id);
|
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() {
|
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
|
// 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
|
// 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))
|
Some(fcx.next_ty_var(span))
|
||||||
}
|
}
|
||||||
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), 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 {
|
asm.operands.iter().find_map(|(op, _op_sp)| match op {
|
||||||
hir::InlineAsmOperand::Const { anon_const }
|
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => {
|
||||||
| hir::InlineAsmOperand::SymFn { anon_const }
|
|
||||||
if anon_const.hir_id == id =>
|
|
||||||
{
|
|
||||||
Some(fcx.next_ty_var(span))
|
Some(fcx.next_ty_var(span))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
@ -48,13 +48,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
for param in body.params {
|
for param in body.params {
|
||||||
wbcx.visit_node_id(param.pat.span, param.hir_id);
|
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) {
|
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);
|
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);
|
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_body(body);
|
||||||
wbcx.visit_min_capture_map();
|
wbcx.visit_min_capture_map();
|
||||||
|
|
|
@ -2909,7 +2909,13 @@ enum AsmLabelKind {
|
||||||
impl<'tcx> LateLintPass<'tcx> for AsmLabels {
|
impl<'tcx> LateLintPass<'tcx> for AsmLabels {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||||
if let hir::Expr {
|
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
|
} = expr
|
||||||
{
|
{
|
||||||
|
|
|
@ -305,6 +305,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
DefKind::Static { safety: _, mutability, nested: false } => {
|
DefKind::Static { safety: _, mutability, nested: false } => {
|
||||||
BodyOwnerKind::Static(mutability)
|
BodyOwnerKind::Static(mutability)
|
||||||
}
|
}
|
||||||
|
DefKind::GlobalAsm => BodyOwnerKind::GlobalAsm,
|
||||||
dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
|
dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,7 +328,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
ConstContext::ConstFn
|
ConstContext::ConstFn
|
||||||
}
|
}
|
||||||
BodyOwnerKind::Fn if self.is_const_default_method(def_id) => 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)
|
Some(ccx)
|
||||||
|
|
|
@ -94,6 +94,7 @@ thir_with_elements! {
|
||||||
pub enum BodyTy<'tcx> {
|
pub enum BodyTy<'tcx> {
|
||||||
Const(Ty<'tcx>),
|
Const(Ty<'tcx>),
|
||||||
Fn(FnSig<'tcx>),
|
Fn(FnSig<'tcx>),
|
||||||
|
GlobalAsm(Ty<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Description of a type-checked function parameter.
|
/// Description of a type-checked function parameter.
|
||||||
|
@ -605,8 +606,7 @@ pub enum InlineAsmOperand<'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
SymFn {
|
SymFn {
|
||||||
value: mir::Const<'tcx>,
|
value: ExprId,
|
||||||
span: Span,
|
|
||||||
},
|
},
|
||||||
SymStatic {
|
SymStatic {
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
|
|
|
@ -172,7 +172,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
||||||
}
|
}
|
||||||
Out { expr: None, reg: _, late: _ }
|
Out { expr: None, reg: _, late: _ }
|
||||||
| Const { value: _, span: _ }
|
| Const { value: _, span: _ }
|
||||||
| SymFn { value: _, span: _ }
|
| SymFn { value: _ }
|
||||||
| SymStatic { def_id: _ } => {}
|
| SymStatic { def_id: _ } => {}
|
||||||
Label { block } => visitor.visit_block(&visitor.thir()[*block]),
|
Label { block } => visitor.visit_block(&visitor.thir()[*block]),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1472,7 +1472,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
self.codegen_fn_attrs(def_id)
|
self.codegen_fn_attrs(def_id)
|
||||||
} else if matches!(
|
} else if matches!(
|
||||||
def_kind,
|
def_kind,
|
||||||
DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst
|
DefKind::AnonConst
|
||||||
|
| DefKind::AssocConst
|
||||||
|
| DefKind::Const
|
||||||
|
| DefKind::InlineConst
|
||||||
|
| DefKind::GlobalAsm
|
||||||
) {
|
) {
|
||||||
CodegenFnAttrs::EMPTY
|
CodegenFnAttrs::EMPTY
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -482,15 +482,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thir::InlineAsmOperand::SymFn { value, span } => {
|
thir::InlineAsmOperand::SymFn { value } => mir::InlineAsmOperand::SymFn {
|
||||||
mir::InlineAsmOperand::SymFn {
|
value: Box::new(this.as_constant(&this.thir[value])),
|
||||||
value: Box::new(ConstOperand {
|
},
|
||||||
span,
|
|
||||||
user_ty: None,
|
|
||||||
const_: value,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thir::InlineAsmOperand::SymStatic { def_id } => {
|
thir::InlineAsmOperand::SymStatic { def_id } => {
|
||||||
mir::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 {
|
let asm_macro = match asm_macro {
|
||||||
AsmMacro::Asm => InlineAsmMacro::Asm,
|
AsmMacro::Asm | AsmMacro::GlobalAsm => InlineAsmMacro::Asm,
|
||||||
AsmMacro::GlobalAsm => {
|
|
||||||
span_bug!(expr_span, "unexpected global_asm! in inline asm")
|
|
||||||
}
|
|
||||||
AsmMacro::NakedAsm => InlineAsmMacro::NakedAsm,
|
AsmMacro::NakedAsm => InlineAsmMacro::NakedAsm,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,9 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
|
||||||
Ok((thir, expr)) => {
|
Ok((thir, expr)) => {
|
||||||
let build_mir = |thir: &Thir<'tcx>| match thir.body_type {
|
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::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
|
// this must run before MIR dump, because
|
||||||
|
@ -576,6 +578,7 @@ fn construct_const<'a, 'tcx>(
|
||||||
let span = tcx.def_span(def);
|
let span = tcx.def_span(def);
|
||||||
(span, span)
|
(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),
|
_ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::borrow::Cow;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
|
|
||||||
|
use rustc_ast::AsmMacro;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_errors::DiagArgValue;
|
use rustc_errors::DiagArgValue;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
|
@ -559,7 +560,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::InlineAsm(box InlineAsmExpr {
|
ExprKind::InlineAsm(box InlineAsmExpr {
|
||||||
asm_macro: _,
|
asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
|
||||||
ref operands,
|
ref operands,
|
||||||
template: _,
|
template: _,
|
||||||
options: _,
|
options: _,
|
||||||
|
@ -583,7 +584,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
Out { expr: None, reg: _, late: _ }
|
Out { expr: None, reg: _, late: _ }
|
||||||
| Const { value: _, span: _ }
|
| Const { value: _, span: _ }
|
||||||
| SymFn { value: _, span: _ }
|
| SymFn { value: _ }
|
||||||
| SymStatic { def_id: _ } => {}
|
| SymStatic { def_id: _ } => {}
|
||||||
Label { block } => {
|
Label { block } => {
|
||||||
// Label blocks are safe context.
|
// Label blocks are safe context.
|
||||||
|
|
|
@ -739,13 +739,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
||||||
|
|
||||||
InlineAsmOperand::Const { value, span }
|
InlineAsmOperand::Const { value, span }
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::SymFn { ref anon_const } => {
|
hir::InlineAsmOperand::SymFn { expr } => {
|
||||||
let value =
|
InlineAsmOperand::SymFn { value: self.mirror_expr(expr) }
|
||||||
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::SymStatic { path: _, def_id } => {
|
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
|
||||||
InlineAsmOperand::SymStatic { def_id }
|
InlineAsmOperand::SymStatic { def_id }
|
||||||
|
|
|
@ -76,23 +76,29 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
||||||
let hir = tcx.hir();
|
let hir = tcx.hir();
|
||||||
let hir_id = tcx.local_def_id_to_hir_id(def);
|
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) {
|
||||||
// fetch the fully liberated fn signature (that is, all bound
|
rustc_hir::BodyOwnerKind::Fn | rustc_hir::BodyOwnerKind::Closure => {
|
||||||
// types/lifetimes replaced)
|
// fetch the fully liberated fn signature (that is, all bound
|
||||||
BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
|
// types/lifetimes replaced)
|
||||||
} else {
|
BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
|
||||||
// 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
|
rustc_hir::BodyOwnerKind::Const { .. } | rustc_hir::BodyOwnerKind::Static(_) => {
|
||||||
// example:
|
// 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
|
||||||
// fn foo(_: &()) {}
|
// example:
|
||||||
// static X: fn(&'static ()) = foo;
|
//
|
||||||
//
|
// fn foo(_: &()) {}
|
||||||
// The adjusted type of the body of X is `for<'a> fn(&'a ())` which
|
// static X: fn(&'static ()) = foo;
|
||||||
// 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
|
// The adjusted type of the body of X is `for<'a> fn(&'a ())` which
|
||||||
// equate them.
|
// is not the same as the type of X. We need the type of the return
|
||||||
BodyTy::Const(typeck_results.node_type(hir_id))
|
// 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 {
|
Self {
|
||||||
|
|
|
@ -921,10 +921,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
||||||
print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
|
print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
|
||||||
print_indented!(self, "}", 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, "InlineAsmOperand::SymFn {", depth_lvl);
|
||||||
print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1);
|
print_indented!(self, "value: ", depth_lvl + 1);
|
||||||
print_indented!(self, format!("span: {:?}", span), depth_lvl + 1);
|
self.print_expr(*value, depth_lvl + 2);
|
||||||
print_indented!(self, "}", depth_lvl + 1);
|
print_indented!(self, "}", depth_lvl + 1);
|
||||||
}
|
}
|
||||||
InlineAsmOperand::SymStatic { def_id } => {
|
InlineAsmOperand::SymStatic { def_id } => {
|
||||||
|
|
|
@ -479,24 +479,23 @@ fn collect_items_rec<'tcx>(
|
||||||
recursion_depth_reset = None;
|
recursion_depth_reset = None;
|
||||||
|
|
||||||
let item = tcx.hir_item(item_id);
|
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 {
|
for (op, op_sp) in asm.operands {
|
||||||
match op {
|
match *op {
|
||||||
hir::InlineAsmOperand::Const { .. } => {
|
hir::InlineAsmOperand::Const { .. } => {
|
||||||
// Only constants which resolve to a plain integer
|
// Only constants which resolve to a plain integer
|
||||||
// are supported. Therefore the value should not
|
// are supported. Therefore the value should not
|
||||||
// depend on any other items.
|
// depend on any other items.
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::SymFn { anon_const } => {
|
hir::InlineAsmOperand::SymFn { expr } => {
|
||||||
let fn_ty =
|
let fn_ty = tcx.typeck(item_id.owner_id).expr_ty(expr);
|
||||||
tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id);
|
|
||||||
visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items);
|
visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items);
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
|
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) {
|
if tcx.should_codegen_locally(instance) {
|
||||||
trace!("collecting static {:?}", def_id);
|
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 { .. }
|
hir::InlineAsmOperand::In { .. }
|
||||||
|
|
|
@ -82,7 +82,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
self.const_span = Some(body_span);
|
self.const_span = Some(body_span);
|
||||||
},
|
},
|
||||||
hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (),
|
hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::GlobalAsm => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -968,7 +968,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
self.hash_expr(out_expr);
|
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);
|
self.hash_body(anon_const.body);
|
||||||
},
|
},
|
||||||
InlineAsmOperand::SymStatic { path, def_id: _ } => self.hash_qpath(path),
|
InlineAsmOperand::SymStatic { path, def_id: _ } => self.hash_qpath(path),
|
||||||
|
|
|
@ -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 ()>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
//@ known-bug: #96304
|
|
||||||
|
|
||||||
#![feature(asm_sym)]
|
|
||||||
core::arch::global_asm!("/* {} */", sym<&'static ()>::clone);
|
|
||||||
|
|
||||||
pub fn main() {}
|
|
11
tests/ui/asm/asm-with-nested-closure.rs
Normal file
11
tests/ui/asm/asm-with-nested-closure.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
//@ build-pass
|
||||||
|
//@ needs-asm-support
|
||||||
|
|
||||||
|
fn foo<const N: usize>() {}
|
||||||
|
|
||||||
|
core::arch::global_asm!("/* {} */", sym foo::<{
|
||||||
|
|| {};
|
||||||
|
0
|
||||||
|
}>);
|
||||||
|
|
||||||
|
fn main() {}
|
8
tests/ui/asm/global-asm-with-lifetimes.rs
Normal file
8
tests/ui/asm/global-asm-with-lifetimes.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
//@ build-pass
|
||||||
|
//@ needs-asm-support
|
||||||
|
|
||||||
|
fn foo<T>() {}
|
||||||
|
|
||||||
|
core::arch::global_asm!("/* {} */", sym foo::<&'static ()>);
|
||||||
|
|
||||||
|
fn main() {}
|
17
tests/ui/asm/inline-asm-with-lifetimes.bad.stderr
Normal file
17
tests/ui/asm/inline-asm-with-lifetimes.bad.stderr
Normal 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`.
|
22
tests/ui/asm/inline-asm-with-lifetimes.rs
Normal file
22
tests/ui/asm/inline-asm-with-lifetimes.rs
Normal 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() {}
|
Loading…
Add table
Add a link
Reference in a new issue