diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index cfd32fc066f..87af7959a88 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 f0eaec55dbd..b7d24c745dc 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 d5fa7ec366b..e349e23f7dc 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 51194740450..590ade516ec 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 2cdd9a3a934..af1338e50d0 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 d564dc9699a..6936544838c 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 5c7426d76b3..de5fe0479e7 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 4815627a0ce..50538e9efb1 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 63c1c060827..a017aa0998f 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 88877d05ffa..7139516702e 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); + 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; - InlineAsmOperand::Const { value, span } + 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 75972a71c8e..9d78c71b76a 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), + } + } + } }