1
Fork 0

Initial cleanups of InlineAsmCtxt

This commit is contained in:
Michael Goulet 2025-02-17 16:14:34 +00:00
parent 2a6daaf89a
commit 37060aae13
3 changed files with 39 additions and 60 deletions

View file

@ -900,7 +900,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let hir::ItemKind::GlobalAsm { asm } = it.kind else { let hir::ItemKind::GlobalAsm { asm } = it.kind else {
span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it)
}; };
InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, def_id); InlineAsmCtxt::new_global_asm(tcx, def_id).check_asm(asm);
} }
_ => {} _ => {}
} }

View file

@ -16,10 +16,11 @@ use rustc_target::asm::{
use crate::errors::RegisterTypeUnstable; use crate::errors::RegisterTypeUnstable;
pub struct InlineAsmCtxt<'a, 'tcx> { pub struct InlineAsmCtxt<'a, 'tcx: 'a> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'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> { enum NonAsmTypeReason<'tcx> {
@ -29,14 +30,15 @@ enum NonAsmTypeReason<'tcx> {
} }
impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { pub fn new_global_asm(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
InlineAsmCtxt { InlineAsmCtxt {
tcx, tcx,
typing_env: ty::TypingEnv { typing_env: ty::TypingEnv {
typing_mode: ty::TypingMode::non_body_analysis(), typing_mode: ty::TypingMode::non_body_analysis(),
param_env: ty::ParamEnv::empty(), 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(|e| bug!("asm operand in global asm: {e:?}")),
} }
} }
@ -45,9 +47,19 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
pub fn new_in_fn( pub fn new_in_fn(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>, typing_env: ty::TypingEnv<'tcx>,
get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a, def_id: LocalDefId,
expr_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
) -> Self { ) -> Self {
InlineAsmCtxt { tcx, typing_env, get_operand_ty: Box::new(get_operand_ty) } InlineAsmCtxt {
tcx,
typing_env,
target_features: tcx.asm_target_features(def_id),
expr_ty: Box::new(expr_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 == ()` // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
@ -139,9 +151,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
template: &[InlineAsmTemplatePiece], template: &[InlineAsmTemplatePiece],
is_input: bool, is_input: bool,
tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>, tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>,
target_features: &FxIndexSet<Symbol>,
) -> Option<InlineAsmType> { ) -> Option<InlineAsmType> {
let ty = (self.get_operand_ty)(expr); let ty = self.expr_ty(expr);
if ty.has_non_region_infer() { if ty.has_non_region_infer() {
bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty); bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
} }
@ -229,7 +240,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
if let Some((in_expr, Some(in_asm_ty))) = tied_input { if let Some((in_expr, Some(in_asm_ty))) = tied_input {
if in_asm_ty != asm_ty { if in_asm_ty != asm_ty {
let msg = "incompatible types for asm inout argument"; 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 self.tcx
.dcx() .dcx()
.struct_span_err(vec![in_expr.span, expr.span], msg) .struct_span_err(vec![in_expr.span, expr.span], msg)
@ -291,7 +302,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
// (!). In that case we still need the earlier check to verify that the // (!). In that case we still need the earlier check to verify that the
// register class is usable at all. // register class is usable at all.
if let Some(feature) = feature { 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"); let msg = format!("`{feature}` target feature is not enabled");
self.tcx self.tcx
.dcx() .dcx()
@ -351,14 +362,13 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
Some(asm_ty) Some(asm_ty)
} }
pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) { pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id());
let Some(asm_arch) = self.tcx.sess.asm_arch else { let Some(asm_arch) = self.tcx.sess.asm_arch else {
self.tcx.dcx().delayed_bug("target architecture does not support asm"); self.tcx.dcx().delayed_bug("target architecture does not support asm");
return; return;
}; };
let allow_experimental_reg = self.tcx.features().asm_experimental_reg(); 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 // Validate register classes against currently enabled target
// features. We check that at least one type is available for // features. We check that at least one type is available for
// the enabled features. // the enabled features.
@ -381,12 +391,12 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
if let Err(msg) = reg.validate( if let Err(msg) = reg.validate(
asm_arch, asm_arch,
self.tcx.sess.relocation_model(), self.tcx.sess.relocation_model(),
target_features, self.target_features,
&self.tcx.sess.target, &self.tcx.sess.target,
op.is_clobber(), op.is_clobber(),
) { ) {
let msg = format!("cannot use register `{}`: {}", reg.name(), msg); 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; continue;
} }
} }
@ -401,7 +411,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
{ {
match feature { match feature {
Some(feature) => { Some(feature) => {
if target_features.contains(&feature) { if self.target_features.contains(&feature) {
missing_required_features.clear(); missing_required_features.clear();
break; break;
} else { } else {
@ -426,7 +436,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
reg_class.name(), reg_class.name(),
feature 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 // register isn't enabled, don't do more checks
continue; continue;
} }
@ -440,7 +450,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
.intersperse(", ") .intersperse(", ")
.collect::<String>(), .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 // register isn't enabled, don't do more checks
continue; continue;
} }
@ -448,52 +458,21 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
} }
} }
match *op { match op {
hir::InlineAsmOperand::In { reg, expr } => { hir::InlineAsmOperand::In { reg, expr } => {
self.check_asm_operand_type( self.check_asm_operand_type(idx, reg, expr, asm.template, true, None);
idx,
reg,
expr,
asm.template,
true,
None,
target_features,
);
} }
hir::InlineAsmOperand::Out { reg, late: _, expr } => { hir::InlineAsmOperand::Out { reg, late: _, expr } => {
if let Some(expr) = expr { if let Some(expr) = expr {
self.check_asm_operand_type( self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
idx,
reg,
expr,
asm.template,
false,
None,
target_features,
);
} }
} }
hir::InlineAsmOperand::InOut { reg, late: _, expr } => { hir::InlineAsmOperand::InOut { reg, late: _, expr } => {
self.check_asm_operand_type( self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
idx,
reg,
expr,
asm.template,
false,
None,
target_features,
);
} }
hir::InlineAsmOperand::SplitInOut { reg, late: _, in_expr, out_expr } => { hir::InlineAsmOperand::SplitInOut { reg, late: _, in_expr, out_expr } => {
let in_ty = self.check_asm_operand_type( let in_ty =
idx, self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None);
reg,
in_expr,
asm.template,
true,
None,
target_features,
);
if let Some(out_expr) = out_expr { if let Some(out_expr) = out_expr {
self.check_asm_operand_type( self.check_asm_operand_type(
idx, idx,
@ -502,7 +481,6 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
asm.template, asm.template,
false, false,
Some((in_expr, in_ty)), Some((in_expr, in_ty)),
target_features,
); );
} }
} }

View file

@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len()); debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len());
for (asm, hir_id) in deferred_asm_checks.drain(..) { for (asm, hir_id) in deferred_asm_checks.drain(..) {
let enclosing_id = self.tcx.hir_enclosing_body_owner(hir_id); 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.typeck_results.borrow().expr_ty_adjusted(expr);
let ty = self.resolve_vars_if_possible(ty); let ty = self.resolve_vars_if_possible(ty);
if ty.has_non_region_infer() { if ty.has_non_region_infer() {
@ -113,9 +113,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
InlineAsmCtxt::new_in_fn( InlineAsmCtxt::new_in_fn(
self.tcx, self.tcx,
self.infcx.typing_env(self.param_env), self.infcx.typing_env(self.param_env),
get_operand_ty, enclosing_id,
expr_ty,
) )
.check_asm(asm, enclosing_id); .check_asm(asm);
} }
} }