Skip to content

Move inline asm check to typeck, properly handle aliases #140302

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 29, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
@@ -3794,7 +3794,6 @@ dependencies = [
"rustc_middle",
"rustc_session",
"rustc_span",
"rustc_target",
"rustc_trait_selection",
"smallvec",
"tracing",
@@ -3833,6 +3832,7 @@ dependencies = [
"rustc_middle",
"rustc_session",
"rustc_span",
"rustc_target",
"rustc_trait_selection",
"smallvec",
"tracing",
1 change: 0 additions & 1 deletion compiler/rustc_hir_analysis/Cargo.toml
Original file line number Diff line number Diff line change
@@ -26,7 +26,6 @@ rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
tracing = "0.1"
3 changes: 0 additions & 3 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
@@ -450,9 +450,6 @@ hir_analysis_recursive_generic_parameter = {$param_def_kind} `{$param_name}` is
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
hir_analysis_register_type_unstable =
type `{$ty}` cannot be used with this register class in stable
hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`
hir_analysis_return_type_notation_equality_bound =
1 change: 0 additions & 1 deletion compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
@@ -67,7 +67,6 @@ mod check;
mod compare_impl_item;
mod entry;
pub mod intrinsic;
pub mod intrinsicck;
mod region;
pub mod wfcheck;

8 changes: 0 additions & 8 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1675,14 +1675,6 @@ pub(crate) struct CmseEntryGeneric {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_register_type_unstable)]
pub(crate) struct RegisterTypeUnstable<'a> {
#[primary_span]
pub span: Span,
pub ty: Ty<'a>,
}

#[derive(LintDiagnostic)]
#[diag(hir_analysis_supertrait_item_shadowing)]
pub(crate) struct SupertraitItemShadowing {
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/Cargo.toml
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
tracing = "0.1"
3 changes: 3 additions & 0 deletions compiler/rustc_hir_typeck/messages.ftl
Original file line number Diff line number Diff line change
@@ -179,6 +179,9 @@ hir_typeck_ptr_cast_add_auto_to_object = cannot add {$traits_len ->
.help = use `transmute` if you're sure this is sound
.label = unsupported cast
hir_typeck_register_type_unstable =
type `{$ty}` cannot be used with this register class in stable
hir_typeck_remove_semi_for_coerce = you might have meant to return the `match` expression
hir_typeck_remove_semi_for_coerce_expr = this could be implicitly returned but it is a statement, not a tail expression
hir_typeck_remove_semi_for_coerce_ret = the `match` arms can conform to this return type
8 changes: 8 additions & 0 deletions compiler/rustc_hir_typeck/src/errors.rs
Original file line number Diff line number Diff line change
@@ -963,3 +963,11 @@ pub(crate) enum SupertraitItemShadowee {
traits: DiagSymbolList,
},
}

#[derive(Diagnostic)]
#[diag(hir_typeck_register_type_unstable)]
pub(crate) struct RegisterTypeUnstable<'a> {
#[primary_span]
pub span: Span,
pub ty: Ty<'a>,
}
10 changes: 2 additions & 8 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, HirId, Node, QPath};
use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
use rustc_hir_analysis::check::potentially_plural_count;
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_index::IndexVec;
@@ -33,6 +32,7 @@ use crate::errors::SuggestPtrNullMut;
use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
use crate::fn_ctxt::infer::FnCall;
use crate::gather_locals::Declaration;
use crate::inline_asm::InlineAsmCtxt;
use crate::method::MethodCallee;
use crate::method::probe::IsSuggestion;
use crate::method::probe::Mode::MethodCall;
@@ -98,13 +98,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);
InlineAsmCtxt::new(
enclosing_id,
&self.infcx,
self.typing_env(self.param_env),
&*self.typeck_results.borrow(),
)
.check_asm(asm);
InlineAsmCtxt::new(self, enclosing_id).check_asm(asm);
}
}

Original file line number Diff line number Diff line change
@@ -3,25 +3,22 @@ use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, LangItem};
use rustc_infer::infer::InferCtxt;
use rustc_middle::bug;
use rustc_middle::ty::{
self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, TypeckResults, 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};
use rustc_span::{Span, Symbol, sym};
use rustc_target::asm::{
InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo,
};
use rustc_trait_selection::infer::InferCtxtExt;

use crate::FnCtxt;
use crate::errors::RegisterTypeUnstable;

pub struct InlineAsmCtxt<'a, 'tcx> {
typing_env: ty::TypingEnv<'tcx>,
pub(crate) struct InlineAsmCtxt<'a, 'tcx> {
target_features: &'tcx FxIndexSet<Symbol>,
infcx: &'a InferCtxt<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
fcx: &'a FnCtxt<'a, 'tcx>,
}

enum NonAsmTypeReason<'tcx> {
@@ -33,27 +30,17 @@ enum NonAsmTypeReason<'tcx> {
}

impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
pub fn new(
def_id: LocalDefId,
infcx: &'a InferCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
) -> Self {
InlineAsmCtxt {
typing_env,
target_features: infcx.tcx.asm_target_features(def_id),
infcx,
typeck_results,
}
pub(crate) fn new(fcx: &'a FnCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
InlineAsmCtxt { target_features: fcx.tcx.asm_target_features(def_id), fcx }
}

fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
self.fcx.tcx
}

fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> {
let ty = self.typeck_results.expr_ty_adjusted(expr);
let ty = self.infcx.resolve_vars_if_possible(ty);
let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted(expr);
let ty = self.fcx.try_structurally_resolve_type(expr.span, ty);
if ty.has_non_region_infer() {
Ty::new_misc_error(self.tcx())
} else {
@@ -62,19 +49,23 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
}

// FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
fn is_thin_ptr_ty(&self, span: Span, ty: Ty<'tcx>) -> bool {
// Type still may have region variables, but `Sized` does not depend
// on those, so just erase them before querying.
if ty.is_sized(self.tcx(), self.typing_env) {
if self.fcx.type_is_sized_modulo_regions(self.fcx.param_env, ty) {
return true;
}
if let ty::Foreign(..) = ty.kind() {
if let ty::Foreign(..) = self.fcx.try_structurally_resolve_type(span, ty).kind() {
return true;
}
false
}

fn get_asm_ty(&self, ty: Ty<'tcx>) -> Result<InlineAsmType, NonAsmTypeReason<'tcx>> {
fn get_asm_ty(
&self,
span: Span,
ty: Ty<'tcx>,
) -> Result<InlineAsmType, NonAsmTypeReason<'tcx>> {
let asm_ty_isize = match self.tcx().sess.target.pointer_width {
16 => InlineAsmType::I16,
32 => InlineAsmType::I32,
@@ -95,7 +86,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
ty::Float(FloatTy::F128) => Ok(InlineAsmType::F128),
ty::FnPtr(..) => Ok(asm_ty_isize),
ty::RawPtr(elem_ty, _) => {
if self.is_thin_ptr_ty(elem_ty) {
if self.is_thin_ptr_ty(span, elem_ty) {
Ok(asm_ty_isize)
} else {
Err(NonAsmTypeReason::NotSizedPtr(ty))
@@ -109,11 +100,20 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
let field = &fields[FieldIdx::ZERO];
let elem_ty = field.ty(self.tcx(), args);

let (size, ty) = match elem_ty.kind() {
let (size, ty) = match *elem_ty.kind() {
ty::Array(ty, len) => {
let len = self.tcx().normalize_erasing_regions(self.typing_env, *len);
// FIXME: `try_structurally_resolve_const` doesn't eval consts
// in the old solver.
let len = if self.fcx.next_trait_solver() {
self.fcx.try_structurally_resolve_const(span, len)
} else {
self.fcx.tcx.normalize_erasing_regions(
self.fcx.typing_env(self.fcx.param_env),
len,
)
};
if let Some(len) = len.try_to_target_usize(self.tcx()) {
(len, *ty)
(len, ty)
} else {
return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength(
field.did, len,
@@ -183,17 +183,17 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
);
let fields = &ty.non_enum_variant().fields;
let ty = fields[FieldIdx::ZERO].ty(self.tcx(), args);
self.get_asm_ty(ty)
self.get_asm_ty(expr.span, ty)
}
_ => self.get_asm_ty(ty),
_ => self.get_asm_ty(expr.span, ty),
};
let asm_ty = match asm_ty {
Ok(asm_ty) => asm_ty,
Err(reason) => {
match reason {
NonAsmTypeReason::UnevaluatedSIMDArrayLength(did, len) => {
let msg = format!("cannot evaluate SIMD vector length `{len}`");
self.infcx
self.fcx
.dcx()
.struct_span_err(self.tcx().def_span(did), msg)
.with_span_note(
@@ -204,7 +204,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
}
NonAsmTypeReason::Invalid(ty) => {
let msg = format!("cannot use value of type `{ty}` for inline assembly");
self.infcx.dcx().struct_span_err(expr.span, msg).with_note(
self.fcx.dcx().struct_span_err(expr.span, msg).with_note(
"only integers, floats, SIMD vectors, pointers and function pointers \
can be used as arguments for inline assembly",
).emit();
@@ -213,7 +213,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
let msg = format!(
"cannot use value of unsized pointer type `{ty}` for inline assembly"
);
self.infcx
self.fcx
.dcx()
.struct_span_err(expr.span, msg)
.with_note("only sized pointers can be used in inline assembly")
@@ -223,7 +223,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
let msg = format!(
"cannot use SIMD vector with element type `{ty}` for inline assembly"
);
self.infcx.dcx()
self.fcx.dcx()
.struct_span_err(self.tcx().def_span(did), msg).with_span_note(
expr.span,
"only integers, floats, SIMD vectors, pointers and function pointers \
@@ -232,7 +232,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
}
NonAsmTypeReason::EmptySIMDArray(ty) => {
let msg = format!("use of empty SIMD vector `{ty}`");
self.infcx.dcx().struct_span_err(expr.span, msg).emit();
self.fcx.dcx().struct_span_err(expr.span, msg).emit();
}
}
return None;
@@ -241,9 +241,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {

// Check that the type implements Copy. The only case where this can
// possibly fail is for SIMD types which don't #[derive(Copy)].
if !self.tcx().type_is_copy_modulo_regions(self.typing_env, ty) {
if !self.fcx.type_is_copy_modulo_regions(self.fcx.param_env, ty) {
let msg = "arguments for inline assembly must be copyable";
self.infcx
self.fcx
.dcx()
.struct_span_err(expr.span, msg)
.with_note(format!("`{ty}` does not implement the Copy trait"))
@@ -263,7 +263,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
if in_asm_ty != asm_ty {
let msg = "incompatible types for asm inout argument";
let in_expr_ty = self.expr_ty(in_expr);
self.infcx
self.fcx
.dcx()
.struct_span_err(vec![in_expr.span, expr.span], msg)
.with_span_label(in_expr.span, format!("type `{in_expr_ty}`"))
@@ -296,7 +296,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
)
} else {
let msg = format!("type `{ty}` cannot be used with this register class");
let mut err = self.infcx.dcx().struct_span_err(expr.span, msg);
let mut err = self.fcx.dcx().struct_span_err(expr.span, msg);
let supported_tys: Vec<_> =
supported_tys.iter().map(|(t, _)| t.to_string()).collect();
err.note(format!(
@@ -326,7 +326,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
if let Some(feature) = feature {
if !self.target_features.contains(feature) {
let msg = format!("`{feature}` target feature is not enabled");
self.infcx
self.fcx
.dcx()
.struct_span_err(expr.span, msg)
.with_note(format!(
@@ -384,9 +384,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
Some(asm_ty)
}

pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
pub(crate) fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) {
let Some(asm_arch) = self.tcx().sess.asm_arch else {
self.infcx.dcx().delayed_bug("target architecture does not support asm");
self.fcx.dcx().delayed_bug("target architecture does not support asm");
return;
};
let allow_experimental_reg = self.tcx().features().asm_experimental_reg();
@@ -418,7 +418,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
op.is_clobber(),
) {
let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
self.infcx.dcx().span_err(op_sp, msg);
self.fcx.dcx().span_err(op_sp, msg);
continue;
}
}
@@ -458,7 +458,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
reg_class.name(),
feature
);
self.infcx.dcx().span_err(op_sp, msg);
self.fcx.dcx().span_err(op_sp, msg);
// register isn't enabled, don't do more checks
continue;
}
@@ -472,7 +472,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
.intersperse(", ")
.collect::<String>(),
);
self.infcx.dcx().span_err(op_sp, msg);
self.fcx.dcx().span_err(op_sp, msg);
// register isn't enabled, don't do more checks
continue;
}
@@ -512,7 +512,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
ty::Error(_) => {}
_ if ty.is_integral() => {}
_ => {
self.infcx
self.fcx
.dcx()
.struct_span_err(op_sp, "invalid type for `const` operand")
.with_span_label(
@@ -531,7 +531,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
ty::FnDef(..) => {}
ty::Error(_) => {}
_ => {
self.infcx
self.fcx
.dcx()
.struct_span_err(op_sp, "invalid `sym` operand")
.with_span_label(
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ mod diverges;
mod errors;
mod expectation;
mod expr;
mod inline_asm;
// Used by clippy;
pub mod expr_use_visitor;
mod fallback;
3 changes: 3 additions & 0 deletions tests/ui/asm/named_const_simd_vec_len.rs
Original file line number Diff line number Diff line change
@@ -3,6 +3,9 @@
//@ only-x86_64
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

#![feature(repr_simd)]

16 changes: 16 additions & 0 deletions tests/ui/asm/normalizable-asm-ty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ check-pass
//@ needs-asm-support
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver

fn invoke(pc_section: &[usize]) {
unsafe {
std::arch::asm!(
"/* {} */",
in(reg) pc_section[0]
);
}
}

fn main() {}