From f63e9a0e78f501757e524cb6f8373edfabe47bab Mon Sep 17 00:00:00 2001 From: daxpedda Date: Sun, 17 May 2026 10:58:49 +0200 Subject: [PATCH] Implement `asm!` `interpolate` --- compiler/rustc_ast/src/ast.rs | 8 ++- compiler/rustc_ast_lowering/src/asm.rs | 20 +++++-- compiler/rustc_ast_lowering/src/errors.rs | 10 ++++ compiler/rustc_ast_pretty/src/pprust/state.rs | 6 ++ compiler/rustc_borrowck/src/lib.rs | 1 + .../src/polonius/legacy/loan_invalidations.rs | 1 + .../rustc_codegen_cranelift/src/global_asm.rs | 3 + .../rustc_codegen_cranelift/src/inline_asm.rs | 20 ++++++- compiler/rustc_codegen_gcc/src/asm.rs | 19 ++++++ compiler/rustc_codegen_llvm/src/asm.rs | 10 ++++ compiler/rustc_codegen_ssa/src/base.rs | 25 ++++++++ compiler/rustc_codegen_ssa/src/common.rs | 59 +++++++++++++++++++ compiler/rustc_codegen_ssa/src/mir/block.rs | 10 ++++ .../rustc_codegen_ssa/src/mir/naked_asm.rs | 25 ++++++++ compiler/rustc_codegen_ssa/src/traits/asm.rs | 4 ++ compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_hir/src/hir.rs | 4 ++ compiler/rustc_hir/src/intravisit.rs | 3 + compiler/rustc_hir_pretty/src/lib.rs | 6 ++ compiler/rustc_hir_typeck/src/errors.rs | 7 +++ compiler/rustc_hir_typeck/src/expr.rs | 3 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 1 + compiler/rustc_hir_typeck/src/inline_asm.rs | 30 +++++++++- compiler/rustc_middle/src/mir/pretty.rs | 3 + compiler/rustc_middle/src/mir/syntax.rs | 3 + compiler/rustc_middle/src/mir/visit.rs | 1 + compiler/rustc_middle/src/thir.rs | 4 ++ compiler/rustc_middle/src/thir/visit.rs | 1 + .../rustc_mir_build/src/builder/expr/into.rs | 9 +++ .../rustc_mir_build/src/check_unsafety.rs | 1 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 15 +++++ compiler/rustc_mir_build/src/thir/print.rs | 6 ++ .../src/impls/storage_liveness.rs | 1 + .../src/move_paths/builder.rs | 1 + compiler/rustc_monomorphize/src/collector.rs | 5 ++ compiler/rustc_parse/src/parser/asm.rs | 3 + compiler/rustc_parse/src/parser/token_type.rs | 4 ++ .../src/unstable/convert/stable/mir.rs | 1 + compiler/rustc_resolve/src/def_collector.rs | 3 +- compiler/rustc_resolve/src/late.rs | 3 +- compiler/rustc_span/src/symbol.rs | 2 + .../clippy_lints/src/loops/never_loop.rs | 7 ++- .../src/pointers_in_nomem_asm_block.rs | 1 + .../clippy/clippy_utils/src/hir_utils.rs | 2 +- tests/ui/asm/cfg-parse-error.rs | 4 +- tests/ui/asm/cfg-parse-error.stderr | 8 +-- tests/ui/asm/interpolate-const.rs | 14 +++++ tests/ui/asm/interpolate-const.stderr | 15 +++++ tests/ui/asm/interpolate-error.rs | 16 +++++ tests/ui/asm/interpolate-error.stderr | 32 ++++++++++ tests/ui/asm/interpolate.rs | 24 ++++++++ tests/ui/asm/parse-error.stderr | 8 +-- tests/ui/asm/x86_64/interpolate.rs | 32 ++++++++++ .../feature-gate-asm_interpolate.rs | 8 +++ .../feature-gate-asm_interpolate.stderr | 13 ++++ 55 files changed, 503 insertions(+), 24 deletions(-) create mode 100644 tests/ui/asm/interpolate-const.rs create mode 100644 tests/ui/asm/interpolate-const.stderr create mode 100644 tests/ui/asm/interpolate-error.rs create mode 100644 tests/ui/asm/interpolate-error.stderr create mode 100644 tests/ui/asm/interpolate.rs create mode 100644 tests/ui/asm/x86_64/interpolate.rs create mode 100644 tests/ui/feature-gates/feature-gate-asm_interpolate.rs create mode 100644 tests/ui/feature-gates/feature-gate-asm_interpolate.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index af8ad425507c4..d8dc98b8cae07 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2841,6 +2841,9 @@ pub enum InlineAsmOperand { Const { anon_const: AnonConst, }, + Interpolate { + anon_const: AnonConst, + }, Sym { sym: InlineAsmSym, }, @@ -2856,7 +2859,10 @@ impl InlineAsmOperand { | Self::Out { reg, .. } | Self::InOut { reg, .. } | Self::SplitInOut { reg, .. } => Some(reg), - Self::Const { .. } | Self::Sym { .. } | Self::Label { .. } => None, + Self::Const { .. } + | Self::Interpolate { .. } + | Self::Sym { .. } + | Self::Label { .. } => None, } } } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index e8df8ce6e6dc3..b24c335815a96 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -13,10 +13,10 @@ use super::LoweringContext; use super::errors::{ AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported, InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst, - InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass, - InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister, - InvalidRegisterClass, RegisterClassOnlyClobber, RegisterClassOnlyClobberStable, - RegisterConflict, + InvalidAsmTemplateModifierInterpolate, InvalidAsmTemplateModifierLabel, + InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub, + InvalidAsmTemplateModifierSym, InvalidRegister, InvalidRegisterClass, RegisterClassOnlyClobber, + RegisterClassOnlyClobberStable, RegisterConflict, }; use crate::{AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode}; @@ -199,6 +199,11 @@ impl<'hir> LoweringContext<'_, 'hir> { InlineAsmOperand::Const { anon_const } => hir::InlineAsmOperand::Const { anon_const: self.lower_const_block(anon_const), }, + InlineAsmOperand::Interpolate { anon_const } => { + hir::InlineAsmOperand::Interpolate { + anon_const: self.lower_const_block(anon_const), + } + } InlineAsmOperand::Sym { sym } => { let static_def_id = self .get_partial_res(sym.id) @@ -285,6 +290,12 @@ impl<'hir> LoweringContext<'_, 'hir> { op_span: op_sp, }); } + hir::InlineAsmOperand::Interpolate { .. } => { + self.dcx().emit_err(InvalidAsmTemplateModifierInterpolate { + placeholder_span, + op_span: op_sp, + }); + } hir::InlineAsmOperand::SymFn { .. } | hir::InlineAsmOperand::SymStatic { .. } => { self.dcx().emit_err(InvalidAsmTemplateModifierSym { @@ -354,6 +365,7 @@ impl<'hir> LoweringContext<'_, 'hir> { | hir::InlineAsmOperand::SplitInOut { .. } => (true, true), hir::InlineAsmOperand::Const { .. } + | hir::InlineAsmOperand::Interpolate { .. } | hir::InlineAsmOperand::SymFn { .. } | hir::InlineAsmOperand::SymStatic { .. } | hir::InlineAsmOperand::Label { .. } => { diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index a1c1d1e11d694..e665a2e9d1024 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -258,6 +258,16 @@ pub(crate) struct InvalidAsmTemplateModifierConst { pub op_span: Span, } +#[derive(Diagnostic)] +#[diag("asm template modifiers are not allowed for `interpolate` arguments")] +pub(crate) struct InvalidAsmTemplateModifierInterpolate { + #[primary_span] + #[label("template modifier")] + pub placeholder_span: Span, + #[label("argument")] + pub op_span: Span, +} + #[derive(Diagnostic)] #[diag("asm template modifiers are not allowed for `sym` arguments")] pub(crate) struct InvalidAsmTemplateModifierSym { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 8b2da2acaa520..d25eecc140bad 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1665,6 +1665,7 @@ impl<'a> State<'a> { matches!(reg, InlineAsmRegOrRegClass::Reg(_)) } InlineAsmOperand::Const { .. } + | InlineAsmOperand::Interpolate { .. } | InlineAsmOperand::Sym { .. } | InlineAsmOperand::Label { .. } => false, } @@ -1805,6 +1806,11 @@ impl<'a> State<'a> { s.space(); s.print_expr(&anon_const.value, FixupContext::default()); } + InlineAsmOperand::Interpolate { anon_const } => { + s.word("interpolate"); + s.space(); + s.print_expr(&anon_const.value, FixupContext::default()); + } InlineAsmOperand::Sym { sym } => { s.word("sym"); s.space(); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index e80969cd0cbb2..b8af51b75bb3a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -965,6 +965,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, } } InlineAsmOperand::Const { value: _ } + | InlineAsmOperand::Interpolate { value: _ } | InlineAsmOperand::SymFn { value: _ } | InlineAsmOperand::SymStatic { def_id: _ } | InlineAsmOperand::Label { target_index: _ } => {} diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 5a33b2d5bbe5b..13f47e00569c5 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -195,6 +195,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> { } } InlineAsmOperand::Const { value: _ } + | InlineAsmOperand::Interpolate { value: _ } | InlineAsmOperand::SymFn { value: _ } | InlineAsmOperand::SymStatic { def_id: _ } | InlineAsmOperand::Label { target_index: _ } => {} diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 0c5f4136a32d6..1a21fc897389d 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -111,6 +111,9 @@ fn codegen_global_asm_inner<'tcx>( GlobalAsmOperandRef::Const { ref string } => { global_asm.push_str(string); } + GlobalAsmOperandRef::Interpolate { string } => { + global_asm.push_str(string); + } GlobalAsmOperandRef::SymFn { instance } => { if cfg!(not(feature = "inline_asm_sym")) { tcx.dcx().span_err( diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 8100d565b3974..c46ee01b85b97 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -33,6 +33,9 @@ pub(crate) enum CInlineAsmOperand<'tcx> { Const { value: String, }, + Interpolate { + value: &'tcx str, + }, Symbol { symbol: String, }, @@ -104,6 +107,16 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>( ); CInlineAsmOperand::Const { value } } + InlineAsmOperand::Interpolate { ref value } => { + let (const_value, ty) = crate::constant::eval_mir_constant(fx, value); + let value = rustc_codegen_ssa::common::asm_interpolate_to_str( + fx.tcx, + span, + const_value, + fx.layout_of(ty), + ); + CInlineAsmOperand::Interpolate { value } + } InlineAsmOperand::SymFn { ref value } => { if cfg!(not(feature = "inline_asm_sym")) { fx.tcx @@ -227,7 +240,9 @@ pub(crate) fn codegen_inline_asm_inner<'tcx>( outputs.push((asm_gen.stack_slots_output[i].unwrap(), *out_place)); } } - CInlineAsmOperand::Const { value: _ } | CInlineAsmOperand::Symbol { symbol: _ } => {} + CInlineAsmOperand::Const { value: _ } + | CInlineAsmOperand::Interpolate { value: _ } + | CInlineAsmOperand::Symbol { symbol: _ } => {} } } @@ -585,6 +600,9 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { CInlineAsmOperand::Const { ref value } => { generated_asm.push_str(value); } + CInlineAsmOperand::Interpolate { value } => { + generated_asm.push_str(value); + } CInlineAsmOperand::Symbol { ref symbol } => { if binary_format == BinaryFormat::Macho { generated_asm.push('_'); diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 5bb65365ad6ad..b626cdfd73a7e 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -307,6 +307,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { constants_len += string.len() + att_dialect as usize; } + InlineAsmOperandRef::Interpolate { string } => { + constants_len += string.len() + att_dialect as usize; + } + InlineAsmOperandRef::SymFn { instance } => { // FIXME(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) @@ -422,6 +426,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // processed in the previous pass } + InlineAsmOperandRef::Interpolate { .. } => { + // processed in the previous pass + } + InlineAsmOperandRef::Label { .. } => { // processed in the previous pass } @@ -515,6 +523,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { template_str.push_str(string); } + InlineAsmOperandRef::Interpolate { string } => { + template_str.push_str(string); + } + InlineAsmOperandRef::Label { label } => { let label_gcc_index = labels.iter().position(|&l| l == label).expect("wrong rust index"); @@ -921,6 +933,13 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { template_str.push_str(string); } + GlobalAsmOperandRef::Interpolate { string } => { + // Interpolate operands get injected directly into the + // template. Note that we don't need to escape % + // here unlike normal inline assembly. + template_str.push_str(string); + } + GlobalAsmOperandRef::SymFn { instance } => { let function = get_fn(self, instance); self.add_used_function(function); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index c5ab9fc2336eb..25542c82d3ea4 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -208,6 +208,10 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { // Const operands get injected directly into the template template_str.push_str(string); } + InlineAsmOperandRef::Interpolate { string } => { + // Interpolate operands get injected directly into the template + template_str.push_str(string); + } InlineAsmOperandRef::SymFn { .. } | InlineAsmOperandRef::SymStatic { .. } => { // Only emit the raw symbol name @@ -409,6 +413,12 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { // here unlike normal inline assembly. template_str.push_str(string); } + GlobalAsmOperandRef::Interpolate { string } => { + // Interpolate operands get injected directly into the + // template. Note that we don't need to escape $ + // here unlike normal inline assembly. + template_str.push_str(string); + } GlobalAsmOperandRef::SymFn { instance } => { let llval = self.get_fn(instance); self.add_compiler_used_global(llval); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index b0ce3833446d3..8124ab1cd8e0e 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -439,6 +439,31 @@ where } } } + rustc_hir::InlineAsmOperand::Interpolate { ref anon_const } => { + match cx.tcx().const_eval_poly(anon_const.def_id.to_def_id()) { + Ok(const_value) => { + let ty = + cx.tcx().typeck_body(anon_const.body).node_type(anon_const.hir_id); + let string = common::asm_interpolate_to_str( + cx.tcx(), + *op_sp, + const_value, + cx.layout_of(ty), + ); + GlobalAsmOperandRef::Interpolate { string } + } + Err(ErrorHandled::Reported { .. }) => { + // An error has already been reported and + // compilation is guaranteed to fail if execution + // hits this path. So an empty string instead of + // a stringified constant value will suffice. + GlobalAsmOperandRef::Interpolate { string: "" } + } + Err(ErrorHandled::TooGeneric(_)) => { + span_bug!(*op_sp, "asm interpolate cannot be resolved; too generic") + } + } + } rustc_hir::InlineAsmOperand::SymFn { expr } => { let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr); let instance = match ty.kind() { diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index eca013c83cb4a..b497fe33fe0ad 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -1,7 +1,9 @@ #![allow(non_camel_case_types)] +use rustc_abi::{BackendRepr, Primitive, Scalar, Size}; use rustc_hir::LangItem; use rustc_hir::attrs::PeImportNameType; +use rustc_middle::mir::interpret::{self, alloc_range}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; @@ -170,6 +172,63 @@ pub fn asm_const_to_str<'tcx>( } } +pub fn asm_interpolate_to_str<'tcx>( + tcx: TyCtxt<'tcx>, + sp: Span, + const_value: mir::ConstValue, + ty_and_layout: TyAndLayout<'tcx>, +) -> &'tcx str { + let (alloc_id, range) = match const_value { + mir::ConstValue::Slice { alloc_id, meta } => { + (alloc_id, alloc_range(Size::ZERO, Size::from_bytes(meta))) + } + mir::ConstValue::Indirect { alloc_id, offset } => { + let alloc = tcx.global_alloc(alloc_id).unwrap_memory().inner(); + + let BackendRepr::ScalarPair( + a @ Scalar::Initialized { value: Primitive::Pointer(_), .. }, + b @ Scalar::Initialized { value: Primitive::Int(..), .. }, + ) = ty_and_layout.backend_repr + else { + span_bug!( + sp, + "expected slice ABI in Indirect for promoted asm interpolate, but got {:#?}", + ty_and_layout.backend_repr + ) + }; + + let (a_size, b_size) = (a.size(&tcx), b.size(&tcx)); + let b_offset = (offset + a_size).align_to(b.align(&tcx).abi); + + let ptr = alloc.read_scalar(&tcx, alloc_range(offset, a_size), true); + let size = alloc.read_scalar(&tcx, alloc_range(b_offset, b_size), false); + let Ok(interpret::Scalar::Ptr(ptr, _)) = ptr else { + span_bug!( + sp, + "expected Ptr in ScalarPair for promoted asm interpolate, but got {ptr:#?}", + ) + }; + let Ok(interpret::Scalar::Int(size)) = size else { + span_bug!( + sp, + "expected Int in ScalarPair for promoted asm interpolate, but got {size:#?}", + ) + }; + + (ptr.provenance.alloc_id(), alloc_range(Size::ZERO, Size::from_bytes(size))) + } + _ => span_bug!( + sp, + "expected Slice or Indirect for promoted asm interpolate, but got {:#?}", + const_value + ), + }; + + let alloc = tcx.global_alloc(alloc_id).unwrap_memory().inner(); + let bytes = alloc.get_bytes_strip_provenance(&tcx, range).unwrap(); + unsafe { str::from_utf8_unchecked(bytes) } +} + pub fn is_mingw_gnu_toolchain(target: &Target) -> bool { target.os == Os::Windows && target.env == Env::Gnu && target.cfg_abi == CfgAbi::Unspecified } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b6b95c5f12aae..b7992b576d522 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1438,6 +1438,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ); InlineAsmOperandRef::Const { string } } + mir::InlineAsmOperand::Interpolate { ref value } => { + let const_value = self.eval_mir_constant(value); + let string = common::asm_interpolate_to_str( + bx.tcx(), + span, + const_value, + bx.layout_of(value.ty()), + ); + InlineAsmOperandRef::Interpolate { string } + } mir::InlineAsmOperand::SymFn { ref value } => { let const_ = self.monomorphize(value.const_); if let ty::FnDef(def_id, args) = *const_.ty().kind() { diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index bdefacefd20b9..d03b477ad554a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -87,6 +87,31 @@ fn inline_to_global_operand<'a, 'tcx, Cx: LayoutOf<'tcx, LayoutOfResult = TyAndL GlobalAsmOperandRef::Const { string } } + InlineAsmOperand::Interpolate { value } => { + let const_value = instance + .instantiate_mir_and_normalize_erasing_regions( + cx.tcx(), + cx.typing_env(), + ty::EarlyBinder::bind(value.const_), + ) + .eval(cx.tcx(), cx.typing_env(), value.span) + .expect("erroneous constant missed by mono item collection"); + + let mono_type = instance.instantiate_mir_and_normalize_erasing_regions( + cx.tcx(), + cx.typing_env(), + ty::EarlyBinder::bind(value.ty()), + ); + + let string = common::asm_interpolate_to_str( + cx.tcx(), + value.span, + const_value, + cx.layout_of(mono_type), + ); + + GlobalAsmOperandRef::Interpolate { string } + } InlineAsmOperand::SymFn { value } => { let mono_type = instance.instantiate_mir_and_normalize_erasing_regions( cx.tcx(), diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index cc7a6a3f19e9e..1be0c4b3250f6 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -28,6 +28,9 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> { Const { string: String, }, + Interpolate { + string: &'tcx str, + }, SymFn { instance: Instance<'tcx>, }, @@ -42,6 +45,7 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> { #[derive(Debug)] pub enum GlobalAsmOperandRef<'tcx> { Const { string: String }, + Interpolate { string: &'tcx str }, SymFn { instance: Instance<'tcx> }, SymStatic { def_id: DefId }, } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index da45596d0b74e..1fe6544a978b9 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -402,6 +402,8 @@ declare_features! ( (unstable, asm_experimental_reg, "1.85.0", Some(133416)), /// Allows using `label` operands in inline assembly together with output operands. (unstable, asm_goto_with_outputs, "1.85.0", Some(119364)), + /// Enables experimental inline assembly support for the `interpolate` operator. + (unstable, asm_interpolate, "CURRENT_RUSTC_VERSION", Some(157043)), /// Allows the `may_unwind` option in inline assembly. (unstable, asm_unwind, "1.58.0", Some(93334)), /// Allows associated type defaults. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 59d1b4b5576ee..10a142c8efab1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3972,6 +3972,9 @@ pub enum InlineAsmOperand<'hir> { Const { anon_const: ConstBlock, }, + Interpolate { + anon_const: ConstBlock, + }, SymFn { expr: &'hir Expr<'hir>, }, @@ -3992,6 +3995,7 @@ impl<'hir> InlineAsmOperand<'hir> { | Self::InOut { reg, .. } | Self::SplitInOut { reg, .. } => Some(reg), Self::Const { .. } + | Self::Interpolate { .. } | Self::SymFn { .. } | Self::SymStatic { .. } | Self::Label { .. } => None, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 85f0e97a0a9d6..fd33c2d35559e 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1552,6 +1552,9 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>( InlineAsmOperand::Const { anon_const, .. } => { try_visit!(visitor.visit_inline_const(anon_const)); } + InlineAsmOperand::Interpolate { 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_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 637ae115131a1..1c2c19ed4183f 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1500,6 +1500,12 @@ impl<'a> State<'a> { // Not using `print_inline_const` to avoid additional `const { ... }` s.ann.nested(s, Nested::Body(anon_const.body)) } + hir::InlineAsmOperand::Interpolate { ref anon_const } => { + s.word("interpolate"); + s.space(); + // 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"); s.space(); diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 3457cc373413a..c061deda83224 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -18,6 +18,13 @@ use rustc_span::{Ident, Span, Spanned, Symbol}; use crate::FnCtxt; +#[derive(Diagnostic)] +#[diag("using the ASM `interpolate` operator is experimental")] +pub(crate) struct AsmInterpolateUnstable { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("base expression required after `..`", code = E0797)] pub(crate) struct BaseExpressionDoubleDot { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f1d9100a1d5f6..be11cfc0f64a1 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3715,7 +3715,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_asm_operand(out_expr, false); } } - hir::InlineAsmOperand::Const { ref anon_const } => { + hir::InlineAsmOperand::Const { ref anon_const } + | hir::InlineAsmOperand::Interpolate { ref anon_const } => { self.check_expr_const_block(anon_const, Expectation::NoExpectation); } hir::InlineAsmOperand::SymFn { expr } => { diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index a924a81f89b0d..62499a1ffedd7 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -494,6 +494,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } hir::InlineAsmOperand::Out { expr: None, .. } | hir::InlineAsmOperand::Const { .. } + | hir::InlineAsmOperand::Interpolate { .. } | hir::InlineAsmOperand::SymFn { .. } | hir::InlineAsmOperand::SymStatic { .. } => {} hir::InlineAsmOperand::Label { block } => { diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index 09d1d18ccfa85..2baaca84c8d6e 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -17,7 +17,7 @@ use rustc_target::asm::{ use rustc_trait_selection::infer::InferCtxtExt; use crate::FnCtxt; -use crate::errors::RegisterTypeUnstable; +use crate::errors::{AsmInterpolateUnstable, RegisterTypeUnstable}; pub(crate) struct InlineAsmCtxt<'a, 'tcx> { target_features: &'tcx FxIndexSet, @@ -560,6 +560,34 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } } } + hir::InlineAsmOperand::Interpolate { anon_const } => { + let ty = self.expr_ty(self.tcx().hir_body(anon_const.body).value); + match ty.kind() { + ty::Error(_) => {} + _ if ty.is_imm_ref_str() => { + if !self.tcx().features().asm_interpolate() { + self.tcx() + .sess + .create_feature_err( + AsmInterpolateUnstable { span: op_sp }, + sym::asm_interpolate, + ) + .emit(); + } + } + _ => { + self.fcx + .dcx() + .struct_span_err(op_sp, "invalid type for `interpolate` operand") + .with_span_label( + self.tcx().def_span(anon_const.def_id), + format!("is {} `{}`", ty.kind().article(), ty), + ) + .with_help("`interpolate` operands must be of an `&str` type") + .emit(); + } + } + } // Typeck has checked that SymFn refers to a function. hir::InlineAsmOperand::SymFn { expr } => { let ty = self.expr_ty(expr); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 60c829311c4b1..7bc5d11fd422d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -992,6 +992,9 @@ impl<'tcx> TerminatorKind<'tcx> { InlineAsmOperand::Const { value } => { write!(fmt, "const {value:?}")?; } + InlineAsmOperand::Interpolate { value } => { + write!(fmt, "interpolate {value:?}")?; + } InlineAsmOperand::SymFn { value } => { write!(fmt, "sym_fn {value:?}")?; } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 8b015e6cecaae..c9ab051cd4066 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1087,6 +1087,9 @@ pub enum InlineAsmOperand<'tcx> { Const { value: Box>, }, + Interpolate { + value: Box>, + }, SymFn { value: Box>, }, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index e6e911dece742..ad7f450448db8 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -646,6 +646,7 @@ macro_rules! make_mir_visitor { } } InlineAsmOperand::Const { value } + | InlineAsmOperand::Interpolate { value } | InlineAsmOperand::SymFn { value } => { self.visit_const_operand(value, location); } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 0cc57e5021f86..66df2a09b4b5d 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -628,6 +628,10 @@ pub enum InlineAsmOperand<'tcx> { value: mir::Const<'tcx>, span: Span, }, + Interpolate { + value: mir::Const<'tcx>, + span: Span, + }, SymFn { value: ExprId, }, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index a96f4e9457cb0..7ff03bb3f7897 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -179,6 +179,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( } Out { expr: None, reg: _, late: _ } | Const { value: _, span: _ } + | Interpolate { value: _, span: _ } | SymFn { value: _ } | SymStatic { def_id: _ } => {} Label { block } => visitor.visit_block(&visitor.thir()[*block]), diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 6ab1995751791..049c2ce4b3b5d 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -754,6 +754,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }), } } + thir::InlineAsmOperand::Interpolate { value, span } => { + mir::InlineAsmOperand::Interpolate { + value: Box::new(ConstOperand { + span, + user_ty: None, + const_: value, + }), + } + } thir::InlineAsmOperand::SymFn { value } => mir::InlineAsmOperand::SymFn { value: Box::new(this.as_constant(&this.thir[value])), }, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index f99d8934aa7fa..514622e46e6e5 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -535,6 +535,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } Out { expr: None, reg: _, late: _ } | Const { value: _, span: _ } + | Interpolate { value: _, span: _ } | SymFn { value: _ } | SymStatic { def_id: _ } => {} Label { block } => { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index b32d7dce4f4d3..2dfb30316ffdd 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -774,6 +774,21 @@ impl<'tcx> ThirBuildCx<'tcx> { let value = mir::Const::Unevaluated(uneval, ty); InlineAsmOperand::Const { value, span: tcx.def_span(did) } } + hir::InlineAsmOperand::Interpolate { ref anon_const } => { + let ty = self.typeck_results.node_type(anon_const.hir_id); + let did = anon_const.def_id; + let typeck_root_def_id = tcx.typeck_root_def_id_local(did); + let parent_args = tcx.erase_and_anonymize_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.to_def_id(), args); + let value = mir::Const::Unevaluated(uneval, ty); + InlineAsmOperand::Interpolate { value, span: tcx.def_span(did) } + } hir::InlineAsmOperand::SymFn { expr } => { InlineAsmOperand::SymFn { value: self.mirror_expr(expr) } } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 5330e3397db8e..ea54759debcb6 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -985,6 +985,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); print_indented!(self, "}", depth_lvl + 1); } + InlineAsmOperand::Interpolate { value, span } => { + print_indented!(self, "InlineAsmOperand::Interpolate {", depth_lvl); + print_indented!(self, format!("value: {:?}", value), depth_lvl + 1); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl + 1); + } InlineAsmOperand::SymFn { value } => { print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl); print_indented!(self, "value: ", depth_lvl + 1); diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 8b6a92071a7d7..cb8d54914470c 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -219,6 +219,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } InlineAsmOperand::In { .. } | InlineAsmOperand::Const { .. } + | InlineAsmOperand::Interpolate { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } | InlineAsmOperand::Label { .. } => {} diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index d7e0a819d7ea1..1480dac967522 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -527,6 +527,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { } } InlineAsmOperand::Const { value: _ } + | InlineAsmOperand::Interpolate { value: _ } | InlineAsmOperand::SymFn { value: _ } | InlineAsmOperand::SymStatic { def_id: _ } | InlineAsmOperand::Label { target_index: _ } => {} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 9ddd33678c341..86ff6a41826ee 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -508,6 +508,11 @@ fn collect_items_rec<'tcx>( // are supported. Therefore the value should not // depend on any other items. } + hir::InlineAsmOperand::Interpolate { .. } => { + // Only constants which resolve to a string + // are supported. Therefore the value should not + // depend on any other items. + } hir::InlineAsmOperand::SymFn { expr } => { let fn_ty = tcx.typeck(item_id.owner_id).expr_ty(expr); visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items); diff --git a/compiler/rustc_parse/src/parser/asm.rs b/compiler/rustc_parse/src/parser/asm.rs index 3fab234adaad4..508f213e1ab56 100644 --- a/compiler/rustc_parse/src/parser/asm.rs +++ b/compiler/rustc_parse/src/parser/asm.rs @@ -151,6 +151,9 @@ fn parse_asm_operand<'a>( } else if p.eat_keyword(exp!(Const)) { let anon_const = p.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; ast::InlineAsmOperand::Const { anon_const } + } else if eat_operand_keyword(p, exp!(Interpolate), asm_macro)? { + let anon_const = p.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; + ast::InlineAsmOperand::Interpolate { anon_const } } else if p.eat_keyword(exp!(Sym)) { let expr = p.parse_expr()?; let ast::ExprKind::Path(qself, path) = &expr.kind else { diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs index 2d1db430ac27c..af6ef94521b1d 100644 --- a/compiler/rustc_parse/src/parser/token_type.rs +++ b/compiler/rustc_parse/src/parser/token_type.rs @@ -134,6 +134,7 @@ pub enum TokenType { SymClobberAbi, SymInlateout, SymInout, + SymInterpolate, SymIs, SymLabel, SymLateout, @@ -271,6 +272,7 @@ impl TokenType { SymClobberAbi, SymInlateout, SymInout, + SymInterpolate, SymIs, SymLabel, SymLateout, @@ -348,6 +350,7 @@ impl TokenType { TokenType::SymClobberAbi => Some(sym::clobber_abi), TokenType::SymInlateout => Some(sym::inlateout), TokenType::SymInout => Some(sym::inout), + TokenType::SymInterpolate => Some(sym::interpolate), TokenType::SymIs => Some(sym::is), TokenType::SymLabel => Some(sym::label), TokenType::SymLateout => Some(sym::lateout), @@ -565,6 +568,7 @@ macro_rules! exp { (ClobberAbi) => { exp!(@sym, clobber_abi, SymClobberAbi) }; (Inlateout) => { exp!(@sym, inlateout, SymInlateout) }; (Inout) => { exp!(@sym, inout, SymInout) }; + (Interpolate) => { exp!(@sym, interpolate, SymInterpolate) }; (Is) => { exp!(@sym, is, SymIs) }; (Label) => { exp!(@sym, label, SymLabel) }; (Lateout) => { exp!(@sym, lateout, SymLateout) }; diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index 7e76d5a91ac66..7ca6681692c1d 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -676,6 +676,7 @@ impl<'tcx> Stable<'tcx> for mir::InlineAsmOperand<'tcx> { (Some(in_value.stable(tables, cx)), out_place.map(|place| place.stable(tables, cx))) } InlineAsmOperand::Const { .. } + | InlineAsmOperand::Interpolate { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } | InlineAsmOperand::Label { .. } => (None, None), diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index cdc2df5bf2945..eebf62ecfd33e 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -661,7 +661,8 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { self.visit_expr(expr); } } - InlineAsmOperand::Const { anon_const } => { + InlineAsmOperand::Const { anon_const } + | InlineAsmOperand::Interpolate { anon_const } => { let def = self .create_def( anon_const.id, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fb8de90d28aca..46b723dbde9a8 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1433,7 +1433,8 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc self.visit_expr(out_expr); } } - InlineAsmOperand::Const { anon_const, .. } => { + InlineAsmOperand::Const { anon_const, .. } + | InlineAsmOperand::Interpolate { anon_const, .. } => { // Although this is `DefKind::AnonConst`, it is allowed to reference outer // generic parameters like an inline const. self.resolve_anon_const(anon_const, AnonConstKind::InlineConst); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d220651fc9404..cb23b2782fdee 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -423,6 +423,7 @@ symbols! { asm_experimental_reg, asm_goto, asm_goto_with_outputs, + asm_interpolate, asm_sym, asm_unwind, assert, @@ -1109,6 +1110,7 @@ symbols! { internal, internal_eq_trait_method_impls, internal_features, + interpolate, into_async_iter_into_iter, into_future, into_iter, diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index ff0ac575550c9..ac7b7fe3e704d 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -413,9 +413,10 @@ fn never_loop_expr<'tcx>( local_labels, main_loop_id, ), - InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } => { - NeverLoopResult::Normal - }, + InlineAsmOperand::Const { .. } + | InlineAsmOperand::Interpolate { .. } + | InlineAsmOperand::SymFn { .. } + | InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Normal, InlineAsmOperand::Label { block } => // We do not know whether the label will be executed or not, so `Diverging` must be // downgraded to `Normal`. diff --git a/src/tools/clippy/clippy_lints/src/pointers_in_nomem_asm_block.rs b/src/tools/clippy/clippy_lints/src/pointers_in_nomem_asm_block.rs index 385f634a15050..deb37cd891248 100644 --- a/src/tools/clippy/clippy_lints/src/pointers_in_nomem_asm_block.rs +++ b/src/tools/clippy/clippy_lints/src/pointers_in_nomem_asm_block.rs @@ -71,6 +71,7 @@ fn has_in_operand_pointer(cx: &LateContext<'_>, asm_op: &InlineAsmOperand<'_>) - InlineAsmOperand::SymStatic { .. } | InlineAsmOperand::Out { .. } | InlineAsmOperand::Const { .. } + | InlineAsmOperand::Interpolate { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::Label { .. } => return false, InlineAsmOperand::SplitInOut { in_expr, .. } => in_expr, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 7590090f9be40..d064618bd9f65 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1310,7 +1310,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { InlineAsmOperand::SymFn { expr } => { self.hash_expr(expr); }, - InlineAsmOperand::Const { anon_const } => { + InlineAsmOperand::Const { anon_const } | InlineAsmOperand::Interpolate { anon_const } => { self.hash_body(anon_const.body); }, InlineAsmOperand::SymStatic { path, def_id: _ } => self.hash_qpath(path), diff --git a/tests/ui/asm/cfg-parse-error.rs b/tests/ui/asm/cfg-parse-error.rs index c13d003cbcebc..cbe63fe6dea42 100644 --- a/tests/ui/asm/cfg-parse-error.rs +++ b/tests/ui/asm/cfg-parse-error.rs @@ -14,7 +14,7 @@ fn main() { #[cfg(false)] a = out(reg) x, "", - //~^ ERROR expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` + //~^ ERROR expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `interpolate`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` ); asm!( #[cfg(false)] @@ -24,7 +24,7 @@ fn main() { 5 }, "", - //~^ ERROR expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` + //~^ ERROR expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `interpolate`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` ); asm!( diff --git a/tests/ui/asm/cfg-parse-error.stderr b/tests/ui/asm/cfg-parse-error.stderr index 8a70d39a43dc6..4a74d3e6e24f8 100644 --- a/tests/ui/asm/cfg-parse-error.stderr +++ b/tests/ui/asm/cfg-parse-error.stderr @@ -1,16 +1,16 @@ -error: expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` +error: expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `interpolate`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` --> $DIR/cfg-parse-error.rs:16:13 | LL | a = out(reg) x, - | - expected one of 11 possible tokens + | - expected one of 12 possible tokens LL | "", | ^^ unexpected token -error: expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` +error: expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `interpolate`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` --> $DIR/cfg-parse-error.rs:26:13 | LL | }, - | - expected one of 11 possible tokens + | - expected one of 12 possible tokens LL | "", | ^^ unexpected token diff --git a/tests/ui/asm/interpolate-const.rs b/tests/ui/asm/interpolate-const.rs new file mode 100644 index 0000000000000..e5534fc1518fc --- /dev/null +++ b/tests/ui/asm/interpolate-const.rs @@ -0,0 +1,14 @@ +//@ needs-asm-support + +#![feature(asm_interpolate)] + +use std::arch::asm; + +fn main() { + let x = ""; + + unsafe { + asm!("/* {0} */", interpolate x); + //~^ ERROR attempt to use a non-constant value in a constant [E0435] + } +} diff --git a/tests/ui/asm/interpolate-const.stderr b/tests/ui/asm/interpolate-const.stderr new file mode 100644 index 0000000000000..8282fa8193d39 --- /dev/null +++ b/tests/ui/asm/interpolate-const.stderr @@ -0,0 +1,15 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/interpolate-const.rs:11:39 + | +LL | asm!("/* {0} */", interpolate x); + | ^ non-constant value + | +help: consider using `const` instead of `let` + | +LL - let x = ""; +LL + const x: /* Type */ = ""; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/asm/interpolate-error.rs b/tests/ui/asm/interpolate-error.rs new file mode 100644 index 0000000000000..772f56d1c2e4d --- /dev/null +++ b/tests/ui/asm/interpolate-error.rs @@ -0,0 +1,16 @@ +//@ needs-asm-support + +#![feature(asm_interpolate)] + +use std::arch::asm; + +fn main() { + unsafe { + asm!("/* {0} */", interpolate 42); + //~^ ERROR invalid type for `interpolate` operand + asm!("/* {0} */", interpolate String::new()); + //~^ ERROR invalid type for `interpolate` operand + asm!("/* {0} */", interpolate &String::new()); + //~^ ERROR invalid type for `interpolate` operand + } +} diff --git a/tests/ui/asm/interpolate-error.stderr b/tests/ui/asm/interpolate-error.stderr new file mode 100644 index 0000000000000..c1fdb5d694730 --- /dev/null +++ b/tests/ui/asm/interpolate-error.stderr @@ -0,0 +1,32 @@ +error: invalid type for `interpolate` operand + --> $DIR/interpolate-error.rs:9:27 + | +LL | asm!("/* {0} */", interpolate 42); + | ^^^^^^^^^^^^-- + | | + | is an `i32` + | + = help: `interpolate` operands must be of an `&str` type + +error: invalid type for `interpolate` operand + --> $DIR/interpolate-error.rs:11:27 + | +LL | asm!("/* {0} */", interpolate String::new()); + | ^^^^^^^^^^^^------------- + | | + | is a `String` + | + = help: `interpolate` operands must be of an `&str` type + +error: invalid type for `interpolate` operand + --> $DIR/interpolate-error.rs:13:27 + | +LL | asm!("/* {0} */", interpolate &String::new()); + | ^^^^^^^^^^^^-------------- + | | + | is a `&String` + | + = help: `interpolate` operands must be of an `&str` type + +error: aborting due to 3 previous errors + diff --git a/tests/ui/asm/interpolate.rs b/tests/ui/asm/interpolate.rs new file mode 100644 index 0000000000000..9e7c7e2e67ec8 --- /dev/null +++ b/tests/ui/asm/interpolate.rs @@ -0,0 +1,24 @@ +//@ needs-asm-support +//@ build-pass + +#![feature(asm_interpolate)] + +use std::arch::asm; + +trait Foo { + const STR: &str; +} + +impl Foo for usize { + const STR: &str = "usize"; +} + +fn main() { + const TEST: &str = "test"; + + unsafe { + asm!("/* {0} */", interpolate usize::STR); + asm!("/* {0} */", interpolate "test"); + asm!("/* {0} */", interpolate TEST); + } +} diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index 9bb7b28b4424e..5421fbe001aec 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -176,17 +176,17 @@ LL | asm!("{a}", a = const foo, a = const bar); | = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` -error: expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` +error: expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `interpolate`, `label`, `lateout`, `options`, `out`, or `sym`, found `""` --> $DIR/parse-error.rs:83:29 | LL | asm!("", options(), ""); - | ^^ expected one of 11 possible tokens + | ^^ expected one of 12 possible tokens -error: expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `label`, `lateout`, `options`, `out`, or `sym`, found `"{}"` +error: expected one of `#`, `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `interpolate`, `label`, `lateout`, `options`, `out`, or `sym`, found `"{}"` --> $DIR/parse-error.rs:85:33 | LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); - | ^^^^ expected one of 11 possible tokens + | ^^^^ expected one of 12 possible tokens error: asm template must be a string literal --> $DIR/parse-error.rs:87:14 diff --git a/tests/ui/asm/x86_64/interpolate.rs b/tests/ui/asm/x86_64/interpolate.rs new file mode 100644 index 0000000000000..4f7fa7eb387cf --- /dev/null +++ b/tests/ui/asm/x86_64/interpolate.rs @@ -0,0 +1,32 @@ +//@ only-x86_64 +//@ run-pass +//@ needs-asm-support + +#![feature(asm_interpolate)] + +use std::arch::asm; + +trait Interpolate { + const OP: &str; +} + +impl Interpolate for usize { + const OP: &str = "mov"; +} + +fn main() { + unsafe { + let a: usize; + asm!("{} {}, {}", interpolate "mov", out(reg) a, const 5); + assert_eq!(a, 5); + + const MOV: &str = "mov"; + let b: usize; + asm!("{} {}, {}", interpolate MOV, out(reg) b, const 6); + assert_eq!(b, 6); + + let c: usize; + asm!("{} {}, {}", interpolate usize::OP, out(reg) c, const 7); + assert_eq!(c, 7); + } +} diff --git a/tests/ui/feature-gates/feature-gate-asm_interpolate.rs b/tests/ui/feature-gates/feature-gate-asm_interpolate.rs new file mode 100644 index 0000000000000..bc9cfa8c6dc2d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_interpolate.rs @@ -0,0 +1,8 @@ +//@ needs-asm-support + +fn main() { + unsafe { + std::arch::asm!("/* {0} */", interpolate "test"); + //~^ ERROR using the ASM `interpolate` operator is experimental + } +} diff --git a/tests/ui/feature-gates/feature-gate-asm_interpolate.stderr b/tests/ui/feature-gates/feature-gate-asm_interpolate.stderr new file mode 100644 index 0000000000000..4b0fb5ae1c0c4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_interpolate.stderr @@ -0,0 +1,13 @@ +error[E0658]: using the ASM `interpolate` operator is experimental + --> $DIR/feature-gate-asm_interpolate.rs:5:38 + | +LL | std::arch::asm!("/* {0} */", interpolate "test"); + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #157043 for more information + = help: add `#![feature(asm_interpolate)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`.