1
Fork 0

Rollup merge of #137180 - compiler-errors:sym-regions, r=oli-obk

Give `global_asm` a fake body to store typeck results, represent `sym fn` as a hir expr to fix `sym fn` operands with lifetimes

There are a few intertwined problems with `sym fn` operands in both inline and global asm macros.

Specifically, unlike other anon consts, they may evaluate to a type with free regions in them without actually having an item-level type annotation to give them a "proper" type. This is in contrast to named constants, which always have an item-level type annotation, or unnamed constants which are constrained by their position (e.g. a const arg in a turbofish, or a const array length).

Today, we infer the type of the operand by looking at the HIR typeck results; however, those results are region-erased, so during borrowck we ICE since we don't expect to encounter erased regions. We can't just fill this type with something like `'static`, since we may want to use real (free) regions:

```rust
fn foo<'a>() {
  asm!("/* ... */", sym bar::<&'a ()>);
}
```

The first idea may be to represent `sym fn` operands using *inline* consts instead of anon consts. This makes sense, since inline consts can reference regions from the parent body (like the `'a` in the example above). However, this introduces a problem with `global_asm!`, which doesn't *have* a parent body; inline consts *must* be associated with a parent body since they are not a body owner of their own. In #116087, I attempted to fix this by using two separate `sym` operands for global and inline asm. However, this led to a lot of confusion and also some unattractive code duplication.

In this PR, I adjust the lowering of `global_asm!` so that it's lowered in a "fake" HIR body. This body contains a single expression which is `ExprKind::InlineAsm`; we don't *use* this HIR body, but it's used in typeck and borrowck so that we can properly infer and validate the the lifetimes of `sym fn` operands.

I then adjust the lowering of `sym fn` to instead be represented with a HIR expression. This is both because it's no longer necessary to represent this operand as an anon const, since it's *just* a path expression, and also more importantly to sidestep yet another ICE (https://github.com/rust-lang/rust/issues/137179), which has to do with the existing code breaking an invariant of def-id creation and anon consts. Specifically, we are not allowed to synthesize a def-id for an anon const when that anon const contains expressions with def-ids whose parent is *not* that anon const. This is somewhat related to https://github.com/rust-lang/rust/pull/130443#issuecomment-2445678945, which is also a place in the compiler where synthesizing anon consts leads to def-id parenting issue.

As a side-effect, this consolidates the type checking for inline and global asm, so it allows us to simplify `InlineAsmCtxt` a bit. It also allows us to delete a bit of hacky code from anon const `type_of` which was there to detect `sym fn` operands specifically. This also could be generalized to support `const` asm operands with types with lifetimes in them. Since we specifically reject these consts today, I'm not going to change the representation of those consts (but they'd just be turned into inline consts).

r? oli-obk -- mostly b/c you're patient and also understand the breadth of the code that this touches, please reassign if you don't want to review this.

Fixes #111709
Fixes #96304
Fixes #137179
This commit is contained in:
Matthias Krüger 2025-02-23 00:16:19 +01:00 committed by GitHub
commit 4115f51d15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
49 changed files with 284 additions and 291 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

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

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(&'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>}`.
@ -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))
}

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

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

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

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};
@ -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<dyn Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
target_features: &'tcx FxIndexSet<Symbol>,
expr_ty: Box<dyn Fn(&hir::Expr<'tcx>) -> 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<InlineAsmType>)>,
target_features: &FxIndexSet<Symbol>,
) -> Option<InlineAsmType> {
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::<String>(),
);
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 { .. } => {}

View file

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

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

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

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

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

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

@ -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<u8>`
HirItem::TyAlias(..) => ("ItemTy", LABELS_HIR_ONLY),

View file

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

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

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

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

@ -737,13 +737,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,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 {

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

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

View file

@ -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, _) => {

View file

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

View file

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

View file

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

View file

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

View file

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

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