From 6e4adbed76ff406994682ee526366f6f2ea11b9f Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 26 Feb 2025 15:59:38 +0000 Subject: [PATCH 1/3] Remove visit_const_block in typeck writeback There is a `visit_inline_const` visitor method and it is used instead. --- compiler/rustc_hir_typeck/src/writeback.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 3e9ce0e11e402..6c6538d09def0 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -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); - } } /////////////////////////////////////////////////////////////////////////// @@ -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); - } _ => {} } @@ -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 { .. } => { @@ -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); } From f482460f92e8713f701bb3eefcd6866f9b065d39 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 26 Feb 2025 16:28:37 +0000 Subject: [PATCH 2/3] Handle asm const similar to inline const --- compiler/rustc_ast_lowering/src/asm.rs | 2 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir/src/intravisit.rs | 2 +- .../src/check/intrinsicck.rs | 34 +++++++++++----- .../src/collect/generics_of.rs | 11 ------ .../rustc_hir_analysis/src/collect/type_of.rs | 34 +--------------- compiler/rustc_hir_pretty/src/lib.rs | 3 +- compiler/rustc_hir_typeck/src/expr.rs | 7 ++-- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 11 +++++- compiler/rustc_mir_build/src/thir/cx/expr.rs | 20 +++++++--- compiler/rustc_resolve/src/def_collector.rs | 39 +++++++++++++++++++ 11 files changed, 96 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index cfd32fc066f41..87af7959a884d 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -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 diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f0eaec55dbdd3..b7d24c745dc99 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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>, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index d5fa7ec366b28..e349e23f7dcf5 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -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)); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 511947404506c..590ade516ec64 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -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; @@ -21,6 +19,7 @@ pub struct InlineAsmCtxt<'a, 'tcx: 'a> { typing_env: ty::TypingEnv<'tcx>, target_features: &'tcx FxIndexSet, expr_ty: Box) -> Ty<'tcx> + 'a>, + node_ty: Box Ty<'tcx> + 'a>, } enum NonAsmTypeReason<'tcx> { @@ -35,13 +34,15 @@ 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 { 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), } } @@ -49,6 +50,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, '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 @@ -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 } => { diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 2cdd9a3a9348a..af1338e50d007 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -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, } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index d564dc9699a88..6936544838c81 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -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}; @@ -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 { @@ -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) } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5c7426d76b31c..de5fe0479e728 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -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"); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 4815627a0ce0b..50538e9efb1fc 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -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(); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 63c1c0608274a..a017aa0998f16 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -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); } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 88877d05ffadf..7139516702e99 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -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) } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 75972a71c8e57..9d78c71b76aa7 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -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), + } + } + } } From 395b0fb4d9c969b5db0ec1a6b9a0b3203cacbed6 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 26 Feb 2025 17:13:01 +0000 Subject: [PATCH 3/3] Bless tests --- tests/crashes/117877.rs | 13 ------------- tests/ui/asm/const-resolve-error.rs | 10 ++++++++++ tests/ui/asm/const-resolve-error.stderr | 14 ++++++++++++++ tests/ui/asm/fail-const-eval-issue-121099.rs | 4 ++-- tests/ui/asm/fail-const-eval-issue-121099.stderr | 4 ++-- tests/ui/asm/invalid-const-operand.stderr | 2 +- 6 files changed, 29 insertions(+), 18 deletions(-) delete mode 100644 tests/crashes/117877.rs create mode 100644 tests/ui/asm/const-resolve-error.rs create mode 100644 tests/ui/asm/const-resolve-error.stderr diff --git a/tests/crashes/117877.rs b/tests/crashes/117877.rs deleted file mode 100644 index b1effc0cbcb1a..0000000000000 --- a/tests/crashes/117877.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #117877 -//@ edition:2021 -//@ needs-rustc-debug-assertions -//@ only-x86_64 -#![feature(asm_const)] - -use std::arch::asm; - -async unsafe fn foo<'a>() { - asm!("/* {0} */", const N); -} - -fn main() {} diff --git a/tests/ui/asm/const-resolve-error.rs b/tests/ui/asm/const-resolve-error.rs new file mode 100644 index 0000000000000..19c8af0d542ef --- /dev/null +++ b/tests/ui/asm/const-resolve-error.rs @@ -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() {} diff --git a/tests/ui/asm/const-resolve-error.stderr b/tests/ui/asm/const-resolve-error.stderr new file mode 100644 index 0000000000000..f02a7f0a6b127 --- /dev/null +++ b/tests/ui/asm/const-resolve-error.stderr @@ -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`. diff --git a/tests/ui/asm/fail-const-eval-issue-121099.rs b/tests/ui/asm/fail-const-eval-issue-121099.rs index 36d00b1e5d23c..c91bbfd1b73f9 100644 --- a/tests/ui/asm/fail-const-eval-issue-121099.rs +++ b/tests/ui/asm/fail-const-eval-issue-121099.rs @@ -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 diff --git a/tests/ui/asm/fail-const-eval-issue-121099.stderr b/tests/ui/asm/fail-const-eval-issue-121099.stderr index 5d86c3a5f7bdd..eb662dadffb1b 100644 --- a/tests/ui/asm/fail-const-eval-issue-121099.stderr +++ b/tests/ui/asm/fail-const-eval-issue-121099.stderr @@ -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); diff --git a/tests/ui/asm/invalid-const-operand.stderr b/tests/ui/asm/invalid-const-operand.stderr index 13bb10e84a533..1cedabeef2892 100644 --- a/tests/ui/asm/invalid-const-operand.stderr +++ b/tests/ui/asm/invalid-const-operand.stderr @@ -80,7 +80,7 @@ error: invalid type for `const` operand LL | asm!("{}", const &0); | ^^^^^^-- | | - | is a `&i32` + | is a `&{integer}` | = help: `const` operands must be of an integer type