Skip to content
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

Handle asm const similar to inline const #137686

Merged
merged 3 commits into from
Mar 1, 2025
Merged
Show file tree
Hide file tree
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 compiler/rustc_ast_lowering/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
InlineAsmOperand::Const { anon_const } => hir::InlineAsmOperand::Const {
anon_const: self.lower_anon_const_to_anon_const(anon_const),
anon_const: self.lower_const_block(anon_const),
},
InlineAsmOperand::Sym { sym } => {
let static_def_id = self
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3506,7 +3506,7 @@ pub enum InlineAsmOperand<'hir> {
out_expr: Option<&'hir Expr<'hir>>,
},
Const {
anon_const: &'hir AnonConst,
anon_const: ConstBlock,
},
SymFn {
expr: &'hir Expr<'hir>,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>(
visit_opt!(visitor, visit_expr, out_expr);
}
InlineAsmOperand::Const { anon_const, .. } => {
try_visit!(visitor.visit_anon_const(anon_const));
try_visit!(visitor.visit_inline_const(anon_const));
}
InlineAsmOperand::SymFn { expr, .. } => {
try_visit!(visitor.visit_expr(expr));
Expand Down
34 changes: 25 additions & 9 deletions compiler/rustc_hir_analysis/src/check/intrinsicck.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::assert_matches::debug_assert_matches;

use rustc_abi::FieldIdx;
use rustc_ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxIndexSet;
Expand All @@ -21,6 +19,7 @@ pub struct InlineAsmCtxt<'a, 'tcx: 'a> {
typing_env: ty::TypingEnv<'tcx>,
target_features: &'tcx FxIndexSet<Symbol>,
expr_ty: Box<dyn Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a>,
node_ty: Box<dyn Fn(hir::HirId) -> Ty<'tcx> + 'a>,
}

enum NonAsmTypeReason<'tcx> {
Expand All @@ -35,20 +34,26 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
typing_env: ty::TypingEnv<'tcx>,
get_operand_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
expr_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
node_ty: impl Fn(hir::HirId) -> Ty<'tcx> + 'a,
) -> Self {
Comment on lines +37 to +38
Copy link
Member

@compiler-errors compiler-errors Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are morally the same function--hir::Expr has a HirId. No need to have two.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expr_ty callback in fn_ctxt/checks.rs currently uses the expr_ty_adjusted; switching to node_type will cause adjustment to be lost.

InlineAsmCtxt {
tcx,
typing_env,
target_features: tcx.asm_target_features(def_id),
expr_ty: Box::new(get_operand_ty),
expr_ty: Box::new(expr_ty),
node_ty: Box::new(node_ty),
}
}

fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> {
(self.expr_ty)(expr)
}

fn node_ty(&self, hir_id: hir::HirId) -> Ty<'tcx> {
(self.node_ty)(hir_id)
}

// FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
// Type still may have region variables, but `Sized` does not depend
Expand Down Expand Up @@ -487,12 +492,23 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
);
}
}
// Typeck has checked that Const operands are integers.
hir::InlineAsmOperand::Const { anon_const } => {
debug_assert_matches!(
self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(),
ty::Error(_) | ty::Int(_) | ty::Uint(_)
);
let ty = self.node_ty(anon_const.hir_id);
match ty.kind() {
ty::Error(_) => {}
_ if ty.is_integral() => {}
_ => {
self.tcx
.dcx()
.struct_span_err(op_sp, "invalid type for `const` operand")
.with_span_label(
self.tcx.def_span(anon_const.def_id),
format!("is {} `{}`", ty.kind().article(), ty),
)
.with_help("`const` operands must be of an integer type")
.emit();
}
}
}
// Typeck has checked that SymFn refers to a function.
hir::InlineAsmOperand::SymFn { expr } => {
Expand Down
11 changes: 0 additions & 11 deletions compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,17 +186,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
{
Some(parent_did)
}
// 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 } => {
anon_const.hir_id == hir_id
}
_ => false,
}) =>
{
Some(parent_did)
}
Node::TyPat(_) => Some(parent_did),
_ => None,
}
Expand Down
34 changes: 1 addition & 33 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_middle::query::plumbing::CyclePlaceholder;
use rustc_middle::ty::fold::fold_regions;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::{bug, span_bug};
use rustc_span::{DUMMY_SP, Ident, Span};

Expand All @@ -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_const = |&(op, op_sp)| match op {
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => {
Some((anon_const, op_sp))
}
_ => None,
};

match parent_node {
// Anon consts "inside" the type system.
Node::ConstArg(&ConstArg {
Expand All @@ -50,31 +43,6 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx
..
}) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span),

// 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_const) =>
{
let ty = tcx.typeck(def_id).node_type(hir_id);

match ty.kind() {
ty::Error(_) => ty,
ty::Int(_) | ty::Uint(_) => ty,
_ => {
let guar = tcx
.dcx()
.struct_span_err(op_sp, "invalid type for `const` operand")
.with_span_label(
tcx.def_span(anon_const.def_id),
format!("is {} `{}`", ty.kind().article(), ty),
)
.with_help("`const` operands must be of an integer type")
.emit();

Ty::new_error(tcx, guar)
}
}
}
Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
tcx.adt_def(tcx.hir_get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1414,7 +1414,8 @@ impl<'a> State<'a> {
hir::InlineAsmOperand::Const { ref anon_const } => {
s.word("const");
s.space();
s.print_anon_const(anon_const);
// Not using `print_inline_const` to avoid additional `const { ... }`
s.ann.nested(s, Nested::Body(anon_const.body))
}
hir::InlineAsmOperand::SymFn { ref expr } => {
s.word("sym_fn");
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3778,13 +3778,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_asm_operand(out_expr, false);
}
}
hir::InlineAsmOperand::Const { ref anon_const } => {
self.check_expr_const_block(anon_const, Expectation::NoExpectation);
}
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::SymStatic { .. } => {}
hir::InlineAsmOperand::Label { block } => {
let previous_diverges = self.diverges.get();
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.erase_regions(ty)
}
};
InlineAsmCtxt::new(self.tcx, enclosing_id, self.typing_env(self.param_env), expr_ty)
.check_asm(asm);
let node_ty = |hir_id: HirId| self.typeck_results.borrow().node_type(hir_id);
InlineAsmCtxt::new(
self.tcx,
enclosing_id,
self.typing_env(self.param_env),
expr_ty,
node_ty,
)
.check_asm(asm);
}
}

Expand Down
21 changes: 8 additions & 13 deletions compiler/rustc_hir_typeck/src/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,13 +248,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
}
}
}

fn visit_const_block(&mut self, span: Span, anon_const: &hir::ConstBlock) {
self.visit_node_id(span, anon_const.hir_id);

let body = self.tcx().hir_body(anon_const.body);
self.visit_body(body);
}
}

///////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -284,9 +277,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => {
self.visit_field_id(e.hir_id);
}
hir::ExprKind::ConstBlock(ref anon_const) => {
self.visit_const_block(e.span, anon_const);
}
_ => {}
}

Expand All @@ -297,6 +287,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
self.fix_index_builtin_expr(e);
}

fn visit_inline_const(&mut self, anon_const: &hir::ConstBlock) {
let span = self.tcx().def_span(anon_const.def_id);
self.visit_node_id(span, anon_const.hir_id);

let body = self.tcx().hir_body(anon_const.body);
self.visit_body(body);
}

fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
match &p.kind {
hir::GenericParamKind::Lifetime { .. } => {
Expand Down Expand Up @@ -343,9 +341,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {

fn visit_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) {
self.visit_node_id(expr.span, expr.hir_id);
if let hir::PatExprKind::ConstBlock(c) = &expr.kind {
self.visit_const_block(expr.span, c);
}
intravisit::walk_pat_expr(self, expr);
}

Expand Down
20 changes: 14 additions & 6 deletions compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -730,12 +730,20 @@ impl<'tcx> ThirBuildCx<'tcx> {
}
}
hir::InlineAsmOperand::Const { 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::Const { value, span }
let ty = self.typeck_results.node_type(anon_const.hir_id);
let did = anon_const.def_id.to_def_id();
let typeck_root_def_id = tcx.typeck_root_def_id(did);
let parent_args = tcx.erase_regions(GenericArgs::identity_for_item(
tcx,
typeck_root_def_id,
));
let args =
InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty })
.args;

let uneval = mir::UnevaluatedConst::new(did, args);
let value = mir::Const::Unevaluated(uneval, ty);
InlineAsmOperand::Const { value, span: tcx.def_span(did) }
}
hir::InlineAsmOperand::SymFn { expr } => {
InlineAsmOperand::SymFn { value: self.mirror_expr(expr) }
Expand Down
39 changes: 39 additions & 0 deletions compiler/rustc_resolve/src/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,4 +459,43 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
visit::walk_attribute(self, attr);
self.in_attr = orig_in_attr;
}

fn visit_inline_asm(&mut self, asm: &'a InlineAsm) {
let InlineAsm {
asm_macro: _,
template: _,
template_strs: _,
operands,
clobber_abis: _,
options: _,
line_spans: _,
} = asm;
for (op, _span) in operands {
match op {
InlineAsmOperand::In { expr, reg: _ }
| InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ }
| InlineAsmOperand::InOut { expr, reg: _, late: _ } => {
self.visit_expr(expr);
}
InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {}
InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
self.visit_expr(in_expr);
if let Some(expr) = out_expr {
self.visit_expr(expr);
}
}
InlineAsmOperand::Const { anon_const } => {
let def = self.create_def(
anon_const.id,
kw::Empty,
DefKind::InlineConst,
anon_const.value.span,
);
self.with_parent(def, |this| visit::walk_anon_const(this, anon_const));
}
InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym),
InlineAsmOperand::Label { block } => self.visit_block(block),
}
}
}
}
13 changes: 0 additions & 13 deletions tests/crashes/117877.rs

This file was deleted.

10 changes: 10 additions & 0 deletions tests/ui/asm/const-resolve-error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//@ edition:2021
//@ needs-asm-support

use std::arch::asm;

async unsafe fn foo<'a>() {
asm!("/* {0} */", const N); //~ ERROR E0425
}

fn main() {}
14 changes: 14 additions & 0 deletions tests/ui/asm/const-resolve-error.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0425]: cannot find value `N` in this scope
--> $DIR/const-resolve-error.rs:7:29
|
LL | asm!("/* {0} */", const N);
| ^ not found in this scope
|
help: you might be missing a const parameter
|
LL | async unsafe fn foo<'a, const N: /* Type */>() {
| +++++++++++++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0425`.
4 changes: 2 additions & 2 deletions tests/ui/asm/fail-const-eval-issue-121099.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ use std::arch::global_asm;

fn main() {}

global_asm!("/* {} */", const 1 << 500); //~ ERROR evaluation of constant value failed [E0080]
global_asm!("/* {} */", const 1 << 500); //~ ERROR E0080

global_asm!("/* {} */", const 1 / 0); //~ ERROR evaluation of constant value failed [E0080]
global_asm!("/* {} */", const 1 / 0); //~ ERROR E0080
4 changes: 2 additions & 2 deletions tests/ui/asm/fail-const-eval-issue-121099.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0080]: evaluation of constant value failed
error[E0080]: evaluation of `{global_asm#0}::{constant#0}` failed
--> $DIR/fail-const-eval-issue-121099.rs:8:31
|
LL | global_asm!("/* {} */", const 1 << 500);
| ^^^^^^^^ attempt to shift left by `500_i32`, which would overflow

error[E0080]: evaluation of constant value failed
error[E0080]: evaluation of `{global_asm#1}::{constant#0}` failed
--> $DIR/fail-const-eval-issue-121099.rs:10:31
|
LL | global_asm!("/* {} */", const 1 / 0);
Expand Down
Loading
Loading