From ad72e0dd98783128124945578e62b128c8f7dc18 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 17 Oct 2024 04:58:36 +0100 Subject: [PATCH 1/6] Rename `*AsmOperandRef::Const` to `Interpolate` This is used for string interpolation currently, so rename it as so. The name `Const` will be used to denote a general CTFE constant that can either be integer or pointer. --- compiler/rustc_codegen_gcc/src/asm.rs | 8 ++++---- compiler/rustc_codegen_llvm/src/asm.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/naked_asm.rs | 2 +- compiler/rustc_codegen_ssa/src/mono_item.rs | 4 ++-- compiler/rustc_codegen_ssa/src/traits/asm.rs | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 415f8affab901..8f6a0ec97819e 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -272,7 +272,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } } - InlineAsmOperandRef::Const { ref string } => { + InlineAsmOperandRef::Interpolate { ref string } => { constants_len += string.len() + att_dialect as usize; } @@ -387,7 +387,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { }); } - InlineAsmOperandRef::Const { .. } => { + InlineAsmOperandRef::Interpolate { .. } => { // processed in the previous pass } @@ -480,7 +480,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { template_str.push_str(name); } - InlineAsmOperandRef::Const { ref string } => { + InlineAsmOperandRef::Interpolate { ref string } => { template_str.push_str(string); } @@ -830,7 +830,7 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => { match operands[operand_idx] { - GlobalAsmOperandRef::Const { ref string } => { + GlobalAsmOperandRef::Interpolate { ref string } => { // Const operands get injected directly into the // template. Note that we don't need to escape % // here unlike normal inline assembly. diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 88daa02574048..33a3ca4d44729 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -205,7 +205,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { template_str.push_str(&format!("${{{}}}", op_idx[&operand_idx])); } } - InlineAsmOperandRef::Const { ref string } => { + InlineAsmOperandRef::Interpolate { ref string } => { // Const operands get injected directly into the template template_str.push_str(string); } @@ -398,7 +398,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { InlineAsmTemplatePiece::String(ref s) => template_str.push_str(s), InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => { match operands[operand_idx] { - GlobalAsmOperandRef::Const { ref string } => { + GlobalAsmOperandRef::Interpolate { ref string } => { // Const operands get injected directly into the // template. Note that we don't need to escape $ // here unlike normal inline assembly. diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 6d1930a402d37..b6dcd7f66fcdb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1238,7 +1238,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { const_value, bx.layout_of(value.ty()), ); - InlineAsmOperandRef::Const { string } + InlineAsmOperandRef::Interpolate { string } } mir::InlineAsmOperand::SymFn { ref value } => { let const_ = self.monomorphize(value.const_); diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index bc9cde1b2a15f..2c232ed09cc4f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -76,7 +76,7 @@ fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx.layout_of(mono_type), ); - GlobalAsmOperandRef::Const { string } + GlobalAsmOperandRef::Interpolate { string } } InlineAsmOperand::SymFn { value } => { let mono_type = instance.instantiate_mir_and_normalize_erasing_regions( diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index f6af889fd6ecb..c94ac00a490f3 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -54,14 +54,14 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { const_value, cx.layout_of(ty), ); - GlobalAsmOperandRef::Const { string } + 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::Const { string: String::new() } + GlobalAsmOperandRef::Interpolate { string: String::new() } } Err(ErrorHandled::TooGeneric(_)) => { span_bug!( diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index 7767bffbfbfd6..b29a5d0773c7f 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -25,7 +25,7 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> { in_value: OperandRef<'tcx, B::Value>, out_place: Option>, }, - Const { + Interpolate { string: String, }, SymFn { @@ -41,7 +41,7 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> { #[derive(Debug)] pub enum GlobalAsmOperandRef<'tcx> { - Const { string: String }, + Interpolate { string: String }, SymFn { instance: Instance<'tcx> }, SymStatic { def_id: DefId }, } From 6ce4c5d01b5433cfd5aa0451fd0b4b58803fac6a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 17 Oct 2024 08:31:35 +0100 Subject: [PATCH 2/6] Add `InlineAsmOperandRef::Const` This is intended for supporting passing arbitrary CTFE const into inline assembly. --- compiler/rustc_codegen_gcc/src/asm.rs | 21 ++++++++++++++++++++ compiler/rustc_codegen_llvm/src/asm.rs | 8 ++++++++ compiler/rustc_codegen_ssa/src/traits/asm.rs | 3 +++ 3 files changed, 32 insertions(+) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 8f6a0ec97819e..d9d052b4ff885 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -276,6 +276,14 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { constants_len += string.len() + att_dialect as usize; } + InlineAsmOperandRef::Const { value } => { + inputs.push(AsmInOperand { + constraint: Cow::Borrowed("i"), + rust_idx, + val: value.immediate(), + }); + } + InlineAsmOperandRef::SymFn { instance } => { // TODO(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) @@ -391,6 +399,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // processed in the previous pass } + InlineAsmOperandRef::Const { .. } => { + // processed in the previous pass + } + InlineAsmOperandRef::Label { .. } => { // processed in the previous pass } @@ -464,6 +476,15 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { push_to_template(modifier, gcc_index); } + InlineAsmOperandRef::Const { .. } => { + let in_gcc_index = inputs + .iter() + .position(|op| operand_idx == op.rust_idx) + .expect("wrong rust index"); + let gcc_index = in_gcc_index + outputs.len(); + push_to_template(None, gcc_index); + } + InlineAsmOperandRef::SymFn { instance } => { // TODO(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 33a3ca4d44729..0473bcbdee363 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -158,6 +158,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { constraints.push(format!("{}", op_idx[&idx])); } } + InlineAsmOperandRef::Const { value } => { + inputs.push(value.immediate()); + op_idx.insert(idx, constraints.len()); + constraints.push("i".to_string()); + } InlineAsmOperandRef::SymFn { instance } => { inputs.push(self.cx.get_fn(instance)); op_idx.insert(idx, constraints.len()); @@ -205,6 +210,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { template_str.push_str(&format!("${{{}}}", op_idx[&operand_idx])); } } + InlineAsmOperandRef::Const { .. } => { + template_str.push_str(&format!("${{{}:c}}", op_idx[&operand_idx])); + } InlineAsmOperandRef::Interpolate { ref string } => { // Const operands get injected directly into the template template_str.push_str(string); diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index b29a5d0773c7f..2ea62dd35598f 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> { Interpolate { string: String, }, + Const { + value: OperandRef<'tcx, B::Value>, + }, SymFn { instance: Instance<'tcx>, }, From f13024488f0f6df3e2554170c8002143ca8e6d94 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 24 Oct 2024 06:22:18 +0100 Subject: [PATCH 3/6] Implement asm_const_ptr for inline asm --- compiler/rustc_codegen_ssa/src/mir/block.rs | 21 ++++++---- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_hir_analysis/messages.ftl | 3 ++ .../src/check/intrinsicck.rs | 35 ++++++++++++++++- compiler/rustc_hir_analysis/src/errors.rs | 7 ++++ compiler/rustc_span/src/symbol.rs | 1 + tests/ui/asm/const-refs-to-static.rs | 9 +++-- tests/ui/asm/const-refs-to-static.stderr | 22 ----------- tests/ui/asm/invalid-const-operand.rs | 6 +-- tests/ui/asm/invalid-const-operand.stderr | 38 +++++-------------- .../feature-gate-asm_const_ptr.rs | 10 +++++ .../feature-gate-asm_const_ptr.stderr | 13 +++++++ 12 files changed, 99 insertions(+), 68 deletions(-) delete mode 100644 tests/ui/asm/const-refs-to-static.stderr create mode 100644 tests/ui/feature-gates/feature-gate-asm_const_ptr.rs create mode 100644 tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b6dcd7f66fcdb..f25ef6c45b25c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1231,14 +1231,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { InlineAsmOperandRef::InOut { reg, late, in_value, out_place } } mir::InlineAsmOperand::Const { ref value } => { - let const_value = self.eval_mir_constant(value); - let string = common::asm_const_to_str( - bx.tcx(), - span, - const_value, - bx.layout_of(value.ty()), - ); - InlineAsmOperandRef::Interpolate { string } + if value.ty().is_any_ptr() { + let value = self.eval_mir_constant_to_operand(bx, value); + InlineAsmOperandRef::Const { value } + } else { + let const_value = self.eval_mir_constant(value); + let string = common::asm_const_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_); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 3c61bfd1c93f5..5e47cba867cb4 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -368,6 +368,8 @@ declare_features! ( (unstable, arbitrary_self_types, "1.23.0", Some(44874)), /// Allows inherent and trait methods with arbitrary self types that are raw pointers. (unstable, arbitrary_self_types_pointers, "1.83.0", Some(44874)), + /// Allows using `const` operands with pointer in inline assembly. + (unstable, asm_const_ptr, "CURRENT_RUSTC_VERSION", Some(128464)), /// Enables experimental inline assembly support for additional architectures. (unstable, asm_experimental_arch, "1.58.0", Some(93335)), /// Enables experimental register support in inline assembly. diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 194f2cd04e468..e0b86219d8af1 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -4,6 +4,9 @@ hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ hir_analysis_ambiguous_lifetime_bound = ambiguous lifetime bound, explicit lifetime bound required +hir_analysis_asm_const_ptr_unstable = + using pointers in asm `const` operand is experimental + hir_analysis_assoc_item_constraints_not_allowed_here = associated item constraints are not allowed here .label = associated item constraint not allowed here diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index d63165f0f1698..6c99b8b54b68a 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -15,7 +15,7 @@ use rustc_target::asm::{ InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo, }; -use crate::errors::RegisterTypeUnstable; +use crate::errors::{AsmConstPtrUnstable, RegisterTypeUnstable}; pub struct InlineAsmCtxt<'a, 'tcx> { typing_env: ty::TypingEnv<'tcx>, @@ -503,7 +503,36 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { match ty.kind() { ty::Error(_) => {} _ if ty.is_integral() => {} + ty::FnPtr(..) => { + if !self.tcx().features().asm_const_ptr() { + self.tcx() + .sess + .create_feature_err( + AsmConstPtrUnstable { span: op_sp }, + sym::asm_const_ptr, + ) + .emit(); + } + } + ty::RawPtr(pointee, _) | ty::Ref(_, pointee, _) + if self.is_thin_ptr_ty(*pointee) => + { + if !self.tcx().features().asm_const_ptr() { + self.tcx() + .sess + .create_feature_err( + AsmConstPtrUnstable { span: op_sp }, + sym::asm_const_ptr, + ) + .emit(); + } + } _ => { + let const_possible_ty = if !self.tcx().features().asm_const_ptr() { + "integer" + } else { + "integer or thin pointer" + }; self.infcx .dcx() .struct_span_err(op_sp, "invalid type for `const` operand") @@ -511,7 +540,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { self.tcx().def_span(anon_const.def_id), format!("is {} `{}`", ty.kind().article(), ty), ) - .with_help("`const` operands must be of an integer type") + .with_help(format!( + "`const` operands must be of an {const_possible_ty} type" + )) .emit(); } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index f2560f22874bc..0d72f1accccd8 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1683,6 +1683,13 @@ pub(crate) struct RegisterTypeUnstable<'a> { pub ty: Ty<'a>, } +#[derive(Diagnostic)] +#[diag(hir_analysis_asm_const_ptr_unstable)] +pub(crate) struct AsmConstPtrUnstable { + #[primary_span] + pub span: Span, +} + #[derive(LintDiagnostic)] #[diag(hir_analysis_supertrait_item_shadowing)] pub(crate) struct SupertraitItemShadowing { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a8bec35d8194..9d2da1ddca38d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -459,6 +459,7 @@ symbols! { as_str, asm, asm_const, + asm_const_ptr, asm_experimental_arch, asm_experimental_reg, asm_goto, diff --git a/tests/ui/asm/const-refs-to-static.rs b/tests/ui/asm/const-refs-to-static.rs index ce2c5b3246ec8..8058d70550aba 100644 --- a/tests/ui/asm/const-refs-to-static.rs +++ b/tests/ui/asm/const-refs-to-static.rs @@ -1,19 +1,20 @@ //@ needs-asm-support //@ ignore-nvptx64 //@ ignore-spirv +//@ build-pass + +#![feature(asm_const_ptr)] use std::arch::{asm, global_asm}; use std::ptr::addr_of; static FOO: u8 = 42; -global_asm!("{}", const addr_of!(FOO)); -//~^ ERROR invalid type for `const` operand +global_asm!("/* {} */", const addr_of!(FOO)); #[no_mangle] fn inline() { - unsafe { asm!("{}", const addr_of!(FOO)) }; - //~^ ERROR invalid type for `const` operand + unsafe { asm!("/* {} */", const addr_of!(FOO)) }; } fn main() {} diff --git a/tests/ui/asm/const-refs-to-static.stderr b/tests/ui/asm/const-refs-to-static.stderr deleted file mode 100644 index 10e1ca5bd6068..0000000000000 --- a/tests/ui/asm/const-refs-to-static.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: invalid type for `const` operand - --> $DIR/const-refs-to-static.rs:10:19 - | -LL | global_asm!("{}", const addr_of!(FOO)); - | ^^^^^^------------- - | | - | is a `*const u8` - | - = help: `const` operands must be of an integer type - -error: invalid type for `const` operand - --> $DIR/const-refs-to-static.rs:15:25 - | -LL | unsafe { asm!("{}", const addr_of!(FOO)) }; - | ^^^^^^------------- - | | - | is a `*const u8` - | - = help: `const` operands must be of an integer type - -error: aborting due to 2 previous errors - diff --git a/tests/ui/asm/invalid-const-operand.rs b/tests/ui/asm/invalid-const-operand.rs index bbf4001752a4b..e8f437196ec1c 100644 --- a/tests/ui/asm/invalid-const-operand.rs +++ b/tests/ui/asm/invalid-const-operand.rs @@ -2,6 +2,8 @@ //@ ignore-nvptx64 //@ ignore-spirv +#![feature(asm_const_ptr)] + use std::arch::{asm, global_asm}; // Const operands must be integers and must be constants. @@ -12,7 +14,6 @@ global_asm!("{}", const 0i128); global_asm!("{}", const 0f32); //~^ ERROR invalid type for `const` operand global_asm!("{}", const 0 as *mut u8); -//~^ ERROR invalid type for `const` operand fn test1() { unsafe { @@ -24,8 +25,7 @@ fn test1() { asm!("{}", const 0f32); //~^ ERROR invalid type for `const` operand asm!("{}", const 0 as *mut u8); - //~^ ERROR invalid type for `const` operand - asm!("{}", const &0); + asm!("{}", const b"Foo".as_slice()); //~^ ERROR invalid type for `const` operand } } diff --git a/tests/ui/asm/invalid-const-operand.stderr b/tests/ui/asm/invalid-const-operand.stderr index 01aa843c6fb19..d09571a49221a 100644 --- a/tests/ui/asm/invalid-const-operand.stderr +++ b/tests/ui/asm/invalid-const-operand.stderr @@ -35,55 +35,35 @@ LL + const x: /* Type */ = 0; | error: invalid type for `const` operand - --> $DIR/invalid-const-operand.rs:12:19 + --> $DIR/invalid-const-operand.rs:14:19 | LL | global_asm!("{}", const 0f32); | ^^^^^^---- | | | is an `f32` | - = help: `const` operands must be of an integer type - -error: invalid type for `const` operand - --> $DIR/invalid-const-operand.rs:14:19 - | -LL | global_asm!("{}", const 0 as *mut u8); - | ^^^^^^------------ - | | - | is a `*mut u8` - | - = help: `const` operands must be of an integer type + = help: `const` operands must be of an integer or thin pointer type error: invalid type for `const` operand - --> $DIR/invalid-const-operand.rs:24:20 + --> $DIR/invalid-const-operand.rs:25:20 | LL | asm!("{}", const 0f32); | ^^^^^^---- | | | is an `f32` | - = help: `const` operands must be of an integer type - -error: invalid type for `const` operand - --> $DIR/invalid-const-operand.rs:26:20 - | -LL | asm!("{}", const 0 as *mut u8); - | ^^^^^^------------ - | | - | is a `*mut u8` - | - = help: `const` operands must be of an integer type + = help: `const` operands must be of an integer or thin pointer type error: invalid type for `const` operand --> $DIR/invalid-const-operand.rs:28:20 | -LL | asm!("{}", const &0); - | ^^^^^^-- +LL | asm!("{}", const b"Foo".as_slice()); + | ^^^^^^----------------- | | - | is a `&i32` + | is a `&[u8]` | - = help: `const` operands must be of an integer type + = help: `const` operands must be of an integer or thin pointer type -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/feature-gates/feature-gate-asm_const_ptr.rs b/tests/ui/feature-gates/feature-gate-asm_const_ptr.rs new file mode 100644 index 0000000000000..cc124ae39a399 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_const_ptr.rs @@ -0,0 +1,10 @@ +//@ only-x86_64 + +use std::arch::asm; + +fn main() { + unsafe { + asm!("/* {} */", const &0); + //~^ ERROR using pointers in asm `const` operand is experimental + } +} diff --git a/tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr b/tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr new file mode 100644 index 0000000000000..8cc21dd853b49 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr @@ -0,0 +1,13 @@ +error[E0658]: using pointers in asm `const` operand is experimental + --> $DIR/feature-gate-asm_const_ptr.rs:7:26 + | +LL | asm!("/* {} */", const &0); + | ^^^^^^^^ + | + = note: see issue #128464 for more information + = help: add `#![feature(asm_const_ptr)]` 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`. From fe2294125427223d29ffd2c68ec751cd78f85b85 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 12 Mar 2025 21:22:03 +0000 Subject: [PATCH 4/6] Give global_asm mangled names `global_asm!` themselves don't need symbol names; they currently only have a symbol name during mono collecion to identify them to partitioning algorithm. However it will have shims generated under it which will need unique symbol names. The name themselves ultimately doesn't matter, so they're generated like other shim instances. --- compiler/rustc_middle/src/mir/mono.rs | 2 +- compiler/rustc_symbol_mangling/src/legacy.rs | 5 +++++ compiler/rustc_symbol_mangling/src/v0.rs | 11 ++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 897119c071223..d4f3eb3f173f0 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -87,7 +87,7 @@ impl<'tcx> MonoItem<'tcx> { MonoItem::Fn(instance) => tcx.symbol_name(instance), MonoItem::Static(def_id) => tcx.symbol_name(Instance::mono(tcx, def_id)), MonoItem::GlobalAsm(item_id) => { - SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.owner_id)) + tcx.symbol_name(Instance::mono(tcx, item_id.owner_id.to_def_id())) } } } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 88754f1f15b46..b92e66764114f 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -33,6 +33,11 @@ pub(super) fn mangle<'tcx>( debug!(?instance_ty); break; } + DefPathData::GlobalAsm => { + // `global_asm!` doesn't have a type. + instance_ty = tcx.types.unit; + break; + } _ => { // if we're making a symbol for something, there ought // to be a value or type-def or something in there diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index bc3923e4b4d67..df06294d78a96 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -792,6 +792,16 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { // are effectively living in their parent modules. DefPathData::ForeignMod => return print_prefix(self), + // Global asm are handled similar to shims. + DefPathData::GlobalAsm => { + return self.path_append_ns( + print_prefix, + 'S', + disambiguated_data.disambiguator as u64, + "global_asm", + ); + } + // Uppercase categories are more stable than lowercase ones. DefPathData::TypeNs(_) => 't', DefPathData::ValueNs(_) => 'v', @@ -803,7 +813,6 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { // These should never show up as `path_append` arguments. DefPathData::CrateRoot | DefPathData::Use - | DefPathData::GlobalAsm | DefPathData::Impl | DefPathData::MacroNs(_) | DefPathData::LifetimeNs(_) => { From a393bbf1452b1db06c9a1d30c051515ee5218d39 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 12 Mar 2025 22:48:32 +0000 Subject: [PATCH 5/6] Collect constants within `global_asm!` in collector This is currently a no-op, but will be useful when const in `global_asm!` can be pointers. --- compiler/rustc_monomorphize/src/collector.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 67fca1d7c2947..2a1a3698378eb 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -482,10 +482,19 @@ fn collect_items_rec<'tcx>( if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind { for (op, op_sp) in asm.operands { match *op { - hir::InlineAsmOperand::Const { .. } => { - // Only constants which resolve to a plain integer - // are supported. Therefore the value should not - // depend on any other items. + hir::InlineAsmOperand::Const { anon_const } => { + match tcx.const_eval_poly(anon_const.def_id.to_def_id()) { + Ok(val) => { + collect_const_value(tcx, val, &mut used_items); + } + Err(ErrorHandled::TooGeneric(..)) => { + span_bug!(*op_sp, "asm const cannot be resolved; too generic") + } + Err(err @ ErrorHandled::Reported(..)) => { + err.emit_note(tcx); + continue; + } + } } hir::InlineAsmOperand::SymFn { expr } => { let fn_ty = tcx.typeck(item_id.owner_id).expr_ty(expr); From 92c0cc49bba78fb0697c28e787d5f97f20748a7a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 14 Mar 2025 16:36:59 +0000 Subject: [PATCH 6/6] Implement asm_const_ptr for global_asm and naked_asm --- compiler/rustc_codegen_gcc/src/asm.rs | 124 ++++++++++++---- compiler/rustc_codegen_llvm/src/asm.rs | 139 ++++++++++++++---- compiler/rustc_codegen_ssa/src/common.rs | 2 +- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 32 ++-- compiler/rustc_codegen_ssa/src/mono_item.rs | 28 ++-- compiler/rustc_codegen_ssa/src/traits/asm.rs | 18 ++- compiler/rustc_monomorphize/src/collector.rs | 3 +- tests/assembly/asm/global_asm.rs | 5 + tests/assembly/asm/x86-types.rs | 14 +- tests/ui/asm/invalid-const-operand.rs | 7 +- tests/ui/asm/invalid-const-operand.stderr | 20 ++- .../feature-gate-asm_const_ptr.rs | 16 +- .../feature-gate-asm_const_ptr.stderr | 24 ++- 13 files changed, 337 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index d9d052b4ff885..5389c3418e508 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use gccjit::{LValue, RValue, ToRValue, Type}; +use gccjit::{GlobalKind, LValue, RValue, ToRValue, Type}; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; use rustc_codegen_ssa::mir::place::PlaceRef; @@ -8,8 +8,8 @@ use rustc_codegen_ssa::traits::{ AsmBuilderMethods, AsmCodegenMethods, BaseTypeCodegenMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef, }; -use rustc_middle::bug; use rustc_middle::ty::Instance; +use rustc_middle::{bug, mir}; use rustc_span::Span; use rustc_target::asm::*; @@ -827,6 +827,98 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let att_dialect = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) && options.contains(InlineAsmOptions::ATT_SYNTAX); + // Convert all operands to string interpolations + let converted_operands = operands + .iter() + .enumerate() + .map(|(operand_idx, operand)| { + match *operand { + GlobalAsmOperandRef::Interpolate { ref string } => { + // Const operands get injected directly into the + // template. Note that we don't need to escape $ + // here unlike normal inline assembly. + string.to_owned() + } + GlobalAsmOperandRef::ConstPointer { value, instance } => { + let (prov, offset) = value.into_parts(); + let global_alloc = self.tcx.global_alloc(prov.alloc_id()); + let symbol = 'sym: { + let alloc = match global_alloc { + mir::interpret::GlobalAlloc::Function { instance } => { + let function = get_fn(self, instance); + self.add_used_function(function); + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O) + // or byte count suffixes (x86 Windows). + break 'sym self.tcx.symbol_name(instance).name.to_owned(); + } + mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => self + .tcx + .global_alloc(self.tcx.vtable_allocation(( + ty, + dyn_ty.principal().map(|principal| { + self.tcx + .instantiate_bound_regions_with_erased(principal) + }), + ))) + .unwrap_memory(), + mir::interpret::GlobalAlloc::Static(def_id) => { + // TODO(antoyo): set the global variable as used. + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O). + let instance = Instance::mono(self.tcx, def_id); + break 'sym self.tcx.symbol_name(instance).name.to_owned(); + } + mir::interpret::GlobalAlloc::Memory(alloc) => alloc, + }; + + // For ZSTs directly codegen an aligned pointer. + if alloc.inner().len() == 0 { + assert_eq!(offset.bytes(), 0); + return format!("{}", alloc.inner().align.bytes()); + } + + let asm_name = self.tcx.symbol_name(instance); + let sym_name = format!("{asm_name}.{operand_idx}"); + + let init = crate::consts::const_alloc_to_gcc(self, alloc); + let alloc = alloc.inner(); + let typ = self.val_ty(init).get_aligned(alloc.align.bytes()); + + let global = self.declare_global_with_linkage( + &sym_name, + typ, + GlobalKind::Exported, + ); + global.global_set_initializer_rvalue(init); + // TODO(nbdd0121): set unnamed address. + // TODO(nbdd0121): set the global variable as used. + + sym_name + }; + + let offset = offset.bytes(); + if offset != 0 { format!("{symbol}+{offset}") } else { symbol } + } + GlobalAsmOperandRef::SymFn { instance } => { + let function = get_fn(self, instance); + self.add_used_function(function); + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O) + // or byte count suffixes (x86 Windows). + self.tcx.symbol_name(instance).name.to_owned() + } + GlobalAsmOperandRef::SymStatic { def_id } => { + // TODO(antoyo): set the global variable as used. + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O). + let instance = Instance::mono(self.tcx, def_id); + self.tcx.symbol_name(instance).name.to_owned() + } + } + }) + .collect::>(); + // Build the template string let mut template_str = ".pushsection .text\n".to_owned(); if att_dialect { @@ -850,33 +942,7 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => { - match operands[operand_idx] { - GlobalAsmOperandRef::Interpolate { ref string } => { - // Const 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); - // TODO(@Amanieu): Additional mangling is needed on - // some targets to add a leading underscore (Mach-O) - // or byte count suffixes (x86 Windows). - let name = self.tcx.symbol_name(instance).name; - template_str.push_str(name); - } - - GlobalAsmOperandRef::SymStatic { def_id } => { - // TODO(antoyo): set the global variable as used. - // TODO(@Amanieu): Additional mangling is needed on - // some targets to add a leading underscore (Mach-O). - let instance = Instance::mono(self.tcx, def_id); - let name = self.tcx.symbol_name(instance).name; - template_str.push_str(name); - } - } + template_str.push_str(&converted_operands[operand_idx]); } } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 0473bcbdee363..c54f63ac94255 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -7,7 +7,7 @@ use rustc_codegen_ssa::traits::*; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::Instance; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::{bug, span_bug}; +use rustc_middle::{bug, mir, span_bug}; use rustc_span::{Pos, Span, Symbol, sym}; use rustc_target::asm::*; use smallvec::SmallVec; @@ -396,6 +396,111 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { let intel_syntax = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) && !options.contains(InlineAsmOptions::ATT_SYNTAX); + // Convert all operands to string interpolations + let converted_operands = operands + .iter() + .enumerate() + .map(|(operand_idx, operand)| { + match *operand { + GlobalAsmOperandRef::Interpolate { ref string } => { + // Const operands get injected directly into the + // template. Note that we don't need to escape $ + // here unlike normal inline assembly. + string.to_owned() + } + GlobalAsmOperandRef::ConstPointer { value, instance } => { + let (prov, offset) = value.into_parts(); + let global_alloc = self.tcx.global_alloc(prov.alloc_id()); + let llval = 'llval: { + let alloc = match global_alloc { + mir::interpret::GlobalAlloc::Function { instance } => { + break 'llval self.get_fn(instance); + } + mir::interpret::GlobalAlloc::VTable(ty, dyn_ty) => self + .tcx + .global_alloc(self.tcx.vtable_allocation(( + ty, + dyn_ty.principal().map(|principal| { + self.tcx + .instantiate_bound_regions_with_erased(principal) + }), + ))) + .unwrap_memory(), + mir::interpret::GlobalAlloc::Static(def_id) => { + break 'llval self + .renamed_statics + .borrow() + .get(&def_id) + .copied() + .unwrap_or_else(|| self.get_static(def_id)); + } + mir::interpret::GlobalAlloc::Memory(alloc) => alloc, + }; + + // For ZSTs directly codegen an aligned pointer. + if alloc.inner().len() == 0 { + assert_eq!(offset.bytes(), 0); + return format!("{}", alloc.inner().align.bytes()); + } + + let asm_name = self.tcx.symbol_name(instance); + let sym_name = format!("{asm_name}.{operand_idx}"); + + let init = crate::consts::const_alloc_to_llvm( + self, alloc, /*static*/ false, + ); + let alloc = alloc.inner(); + let g = self.static_addr_of_mut(init, alloc.align, None); + if alloc.mutability.is_not() { + // NB: we can't use `static_addr_of_impl` here to avoid sharing + // the global, as we need to set name and linkage. + unsafe { llvm::LLVMSetGlobalConstant(g, llvm::True) }; + } + + llvm::set_value_name(g, sym_name.as_bytes()); + + // `static_addr_of_mut` gives us a private global which can't be + // used by global asm. Update it to a hidden internal global instead. + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); + llvm::set_visibility(g, llvm::Visibility::Hidden); + g + }; + self.add_compiler_used_global(llval); + let symbol = llvm::build_string(|s| unsafe { + llvm::LLVMRustGetMangledName(llval, s); + }) + .expect("symbol is not valid UTF-8"); + + let offset = offset.bytes(); + if offset != 0 { format!("{symbol}+{offset}") } else { symbol } + } + GlobalAsmOperandRef::SymFn { instance } => { + let llval = self.get_fn(instance); + self.add_compiler_used_global(llval); + let symbol = llvm::build_string(|s| unsafe { + llvm::LLVMRustGetMangledName(llval, s); + }) + .expect("symbol is not valid UTF-8"); + symbol + } + GlobalAsmOperandRef::SymStatic { def_id } => { + let llval = self + .renamed_statics + .borrow() + .get(&def_id) + .copied() + .unwrap_or_else(|| self.get_static(def_id)); + self.add_compiler_used_global(llval); + let symbol = llvm::build_string(|s| unsafe { + llvm::LLVMRustGetMangledName(llval, s); + }) + .expect("symbol is not valid UTF-8"); + symbol + } + } + }) + .collect::>(); + // Build the template string let mut template_str = String::new(); if intel_syntax { @@ -405,37 +510,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { match *piece { InlineAsmTemplatePiece::String(ref s) => template_str.push_str(s), InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => { - match operands[operand_idx] { - GlobalAsmOperandRef::Interpolate { ref string } => { - // Const 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); - let symbol = llvm::build_string(|s| unsafe { - llvm::LLVMRustGetMangledName(llval, s); - }) - .expect("symbol is not valid UTF-8"); - template_str.push_str(&symbol); - } - GlobalAsmOperandRef::SymStatic { def_id } => { - let llval = self - .renamed_statics - .borrow() - .get(&def_id) - .copied() - .unwrap_or_else(|| self.get_static(def_id)); - self.add_compiler_used_global(llval); - let symbol = llvm::build_string(|s| unsafe { - llvm::LLVMRustGetMangledName(llval, s); - }) - .expect("symbol is not valid UTF-8"); - template_str.push_str(&symbol); - } - } + template_str.push_str(&converted_operands[operand_idx]) } } } diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 965bd34ac147b..468b4594db687 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -166,7 +166,7 @@ pub fn asm_const_to_str<'tcx>( }; let value = scalar.assert_scalar_int().to_bits(ty_and_layout.size); match ty_and_layout.ty.kind() { - ty::Uint(_) => value.to_string(), + ty::Uint(_) | ty::RawPtr(..) | ty::Ref(..) => value.to_string(), ty::Int(int_ty) => match int_ty.normalize(tcx.sess.target.pointer_width) { ty::IntTy::I8 => (value as i8).to_string(), ty::IntTy::I16 => (value as i16).to_string(), diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 2c232ed09cc4f..c87de6f796412 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -2,7 +2,7 @@ use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind}; use rustc_attr_parsing::InstructionSetAttr; use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; -use rustc_middle::mir::{Body, InlineAsmOperand}; +use rustc_middle::mir::{self, Body, InlineAsmOperand}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; @@ -69,14 +69,28 @@ fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ty::EarlyBinder::bind(value.ty()), ); - let string = common::asm_const_to_str( - cx.tcx(), - value.span, - const_value, - cx.layout_of(mono_type), - ); - - GlobalAsmOperandRef::Interpolate { string } + let mir::ConstValue::Scalar(scalar) = const_value else { + span_bug!( + value.span, + "expected Scalar for promoted asm const, but got {:#?}", + const_value + ) + }; + match scalar { + mir::interpret::Scalar::Int(_) => { + let string = common::asm_const_to_str( + cx.tcx(), + value.span, + const_value, + cx.layout_of(mono_type), + ); + GlobalAsmOperandRef::Interpolate { string } + } + mir::interpret::Scalar::Ptr(value, _) => GlobalAsmOperandRef::ConstPointer { + value, + instance: Instance::mono(cx.tcx(), instance.def_id()), + }, + } } InlineAsmOperand::SymFn { value } => { let mono_type = instance.instantiate_mir_and_normalize_erasing_regions( diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index c94ac00a490f3..d1dd5cc7ef7d2 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,10 +1,10 @@ use rustc_hir as hir; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::mir::interpret::{ErrorHandled, Scalar}; use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; use rustc_middle::ty::Instance; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; -use rustc_middle::{span_bug, ty}; +use rustc_middle::{mir, span_bug, ty}; use tracing::debug; use crate::traits::*; @@ -48,13 +48,23 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { .tcx() .typeck_body(anon_const.body) .node_type(anon_const.hir_id); - let string = common::asm_const_to_str( - cx.tcx(), - *op_sp, - const_value, - cx.layout_of(ty), - ); - GlobalAsmOperandRef::Interpolate { string } + let mir::ConstValue::Scalar(scalar) = const_value else { + span_bug!(*op_sp, "expected Scalar for promoted asm const, but got {:#?}", const_value) + }; + match scalar { + Scalar::Int(_) => { + let string = common::asm_const_to_str( + cx.tcx(), + *op_sp, + const_value, + cx.layout_of(ty), + ); + GlobalAsmOperandRef::Interpolate { string } + } + Scalar::Ptr(value, _) => { + GlobalAsmOperandRef::ConstPointer { value, instance: Instance::mono(cx.tcx(), item_id.owner_id.to_def_id()) } + } + } } Err(ErrorHandled::Reported { .. }) => { // An error has already been reported and diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index 2ea62dd35598f..db1124bd785b0 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -1,5 +1,6 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::def_id::DefId; +use rustc_middle::mir; use rustc_middle::ty::Instance; use rustc_span::Span; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -44,9 +45,20 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> { #[derive(Debug)] pub enum GlobalAsmOperandRef<'tcx> { - Interpolate { string: String }, - SymFn { instance: Instance<'tcx> }, - SymStatic { def_id: DefId }, + Interpolate { + string: String, + }, + ConstPointer { + value: mir::interpret::Pointer, + /// Instance that instantiates this const operand. + instance: Instance<'tcx>, + }, + SymFn { + instance: Instance<'tcx>, + }, + SymStatic { + def_id: DefId, + }, } pub trait AsmBuilderMethods<'tcx>: BackendTypes { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 2a1a3698378eb..0410e0e599c4d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -490,8 +490,7 @@ fn collect_items_rec<'tcx>( Err(ErrorHandled::TooGeneric(..)) => { span_bug!(*op_sp, "asm const cannot be resolved; too generic") } - Err(err @ ErrorHandled::Reported(..)) => { - err.emit_note(tcx); + Err(ErrorHandled::Reported(..)) => { continue; } } diff --git a/tests/assembly/asm/global_asm.rs b/tests/assembly/asm/global_asm.rs index 8a4bf98c7450b..deb8d72f076b5 100644 --- a/tests/assembly/asm/global_asm.rs +++ b/tests/assembly/asm/global_asm.rs @@ -5,6 +5,7 @@ //@ compile-flags: -C symbol-mangling-version=v0 #![crate_type = "rlib"] +#![feature(asm_const_ptr)] use std::arch::global_asm; @@ -26,6 +27,10 @@ global_asm!("call {}", sym my_func); global_asm!("lea rax, [rip + {}]", sym MY_STATIC); // CHECK: call _RNvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_10global_asm6foobar global_asm!("call {}", sym foobar); +// CHECK: lea rax, [rip + _RNSC[[CRATE_IDENT]]_10global_asms4_10global_asm.0] +global_asm!("lea rax, [rip + {}]", const &1); +// CHECK: lea rax, [rip + _RNSC[[CRATE_IDENT]]_10global_asms5_10global_asm.0+4] +global_asm!("lea rax, [rip + {}]", const &[1; 2][1]); // CHECK: _RNvC[[CRATE_IDENT]]_10global_asm6foobar: fn foobar() { loop {} diff --git a/tests/assembly/asm/x86-types.rs b/tests/assembly/asm/x86-types.rs index 6120ed0d53275..921dfc69b646a 100644 --- a/tests/assembly/asm/x86-types.rs +++ b/tests/assembly/asm/x86-types.rs @@ -9,7 +9,7 @@ //@ compile-flags: -C target-feature=+avx512bw //@ compile-flags: -Zmerge-functions=disabled -#![feature(no_core, repr_simd, f16, f128)] +#![feature(no_core, repr_simd, f16, f128, asm_const_ptr)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -92,6 +92,18 @@ pub unsafe fn sym_fn() { asm!("call {}", sym extern_func); } +// NOTE: this only works for x64, as this test is compiled with PIC, +// and on x86 PIC symbol can't be constant. +// x86_64-LABEL: const_ptr: +// x86_64: #APP +// x86_64: mov al, byte ptr [{{.*}}anon{{.*}}] +// x86_64: #NO_APP +#[cfg(x86_64)] +#[no_mangle] +pub unsafe fn const_ptr() { + asm!("mov al, byte ptr [{}]", const &1); +} + // CHECK-LABEL: sym_static: // CHECK: #APP // CHECK: mov al, byte ptr [extern_static] diff --git a/tests/ui/asm/invalid-const-operand.rs b/tests/ui/asm/invalid-const-operand.rs index e8f437196ec1c..218b49ecb8e1e 100644 --- a/tests/ui/asm/invalid-const-operand.rs +++ b/tests/ui/asm/invalid-const-operand.rs @@ -17,7 +17,7 @@ global_asm!("{}", const 0 as *mut u8); fn test1() { unsafe { - // Const operands must be integers and must be constants. + // Const operands must be integers or thin pointers asm!("{}", const 0); asm!("{}", const 0i32); @@ -25,8 +25,13 @@ fn test1() { asm!("{}", const 0f32); //~^ ERROR invalid type for `const` operand asm!("{}", const 0 as *mut u8); + asm!("{}", const &0); asm!("{}", const b"Foo".as_slice()); //~^ ERROR invalid type for `const` operand + + asm!("{}", const test1 as fn()); + asm!("{}", const test1); + //~^ ERROR invalid type for `const` operand } } diff --git a/tests/ui/asm/invalid-const-operand.stderr b/tests/ui/asm/invalid-const-operand.stderr index d09571a49221a..c6b492788b0dc 100644 --- a/tests/ui/asm/invalid-const-operand.stderr +++ b/tests/ui/asm/invalid-const-operand.stderr @@ -1,5 +1,5 @@ error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/invalid-const-operand.rs:44:26 + --> $DIR/invalid-const-operand.rs:49:26 | LL | asm!("{}", const x); | ^ non-constant value @@ -11,7 +11,7 @@ LL + const x: /* Type */ = 0; | error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/invalid-const-operand.rs:47:36 + --> $DIR/invalid-const-operand.rs:52:36 | LL | asm!("{}", const const_foo(x)); | ^ non-constant value @@ -23,7 +23,7 @@ LL + const x: /* Type */ = 0; | error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/invalid-const-operand.rs:50:36 + --> $DIR/invalid-const-operand.rs:55:36 | LL | asm!("{}", const const_bar(x)); | ^ non-constant value @@ -55,7 +55,7 @@ LL | asm!("{}", const 0f32); = help: `const` operands must be of an integer or thin pointer type error: invalid type for `const` operand - --> $DIR/invalid-const-operand.rs:28:20 + --> $DIR/invalid-const-operand.rs:29:20 | LL | asm!("{}", const b"Foo".as_slice()); | ^^^^^^----------------- @@ -64,6 +64,16 @@ LL | asm!("{}", const b"Foo".as_slice()); | = help: `const` operands must be of an integer or thin pointer type -error: aborting due to 6 previous errors +error: invalid type for `const` operand + --> $DIR/invalid-const-operand.rs:33:20 + | +LL | asm!("{}", const test1); + | ^^^^^^----- + | | + | is a `fn() {test1}` + | + = help: `const` operands must be of an integer or thin pointer type + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/feature-gates/feature-gate-asm_const_ptr.rs b/tests/ui/feature-gates/feature-gate-asm_const_ptr.rs index cc124ae39a399..3f338c71be7ac 100644 --- a/tests/ui/feature-gates/feature-gate-asm_const_ptr.rs +++ b/tests/ui/feature-gates/feature-gate-asm_const_ptr.rs @@ -1,8 +1,22 @@ //@ only-x86_64 -use std::arch::asm; +#![feature(naked_functions)] + +use std::arch::{asm, global_asm, naked_asm}; + +global_asm!("/* {} */", const &0); +//~^ ERROR using pointers in asm `const` operand is experimental + +#[naked] +extern "C" fn naked() { + unsafe { + naked_asm!("ret /* {} */", const &0); + //~^ ERROR using pointers in asm `const` operand is experimental + } +} fn main() { + naked(); unsafe { asm!("/* {} */", const &0); //~^ ERROR using pointers in asm `const` operand is experimental diff --git a/tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr b/tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr index 8cc21dd853b49..f31562b49cc21 100644 --- a/tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr +++ b/tests/ui/feature-gates/feature-gate-asm_const_ptr.stderr @@ -1,5 +1,25 @@ error[E0658]: using pointers in asm `const` operand is experimental - --> $DIR/feature-gate-asm_const_ptr.rs:7:26 + --> $DIR/feature-gate-asm_const_ptr.rs:7:25 + | +LL | global_asm!("/* {} */", const &0); + | ^^^^^^^^ + | + = note: see issue #128464 for more information + = help: add `#![feature(asm_const_ptr)]` 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[E0658]: using pointers in asm `const` operand is experimental + --> $DIR/feature-gate-asm_const_ptr.rs:13:36 + | +LL | naked_asm!("ret /* {} */", const &0); + | ^^^^^^^^ + | + = note: see issue #128464 for more information + = help: add `#![feature(asm_const_ptr)]` 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[E0658]: using pointers in asm `const` operand is experimental + --> $DIR/feature-gate-asm_const_ptr.rs:21:26 | LL | asm!("/* {} */", const &0); | ^^^^^^^^ @@ -8,6 +28,6 @@ LL | asm!("/* {} */", const &0); = help: add `#![feature(asm_const_ptr)]` 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 +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`.