diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 13f9a04b286f0..a5294bbf71717 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -51,6 +51,20 @@ pub enum CanonAbi { X86(X86Call), } +impl CanonAbi { + pub fn is_rustic_abi(self) -> bool { + match self { + CanonAbi::Rust | CanonAbi::RustCold => true, + CanonAbi::C + | CanonAbi::Custom + | CanonAbi::Arm(_) + | CanonAbi::GpuKernel + | CanonAbi::Interrupt(_) + | CanonAbi::X86(_) => false, + } + } +} + impl fmt::Display for CanonAbi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // convert to the ExternAbi that *shares a string* with this CanonAbi. diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 9595a5b5ac7fb..bfb2edf286a20 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -12,6 +12,17 @@ monomorphize_abi_error_disabled_vector_type = } here .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) +monomorphize_abi_error_unsupported_unsized_parameter = + this function {$is_call -> + [true] call + *[false] definition + } uses unsized type `{$ty}` which is not supported with the chosen ABI + .label = function {$is_call -> + [true] called + *[false] defined + } here + .help = only rustic ABIs support unsized parameters + monomorphize_abi_error_unsupported_vector_type = this function {$is_call -> [true] call diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 89a78897dea91..a5040ef22dd03 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -80,6 +80,18 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> { pub is_call: bool, } +#[derive(Diagnostic)] +#[diag(monomorphize_abi_error_unsupported_unsized_parameter)] +#[help] +pub(crate) struct AbiErrorUnsupportedUnsizedParameter<'a> { + #[primary_span] + #[label] + pub span: Span, + pub ty: Ty<'a>, + /// Whether this is a problem at a call site or at a declaration. + pub is_call: bool, +} + #[derive(Diagnostic)] #[diag(monomorphize_abi_error_unsupported_vector_type)] pub(crate) struct AbiErrorUnsupportedVectorType<'a> { diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index b8c001d357e6c..2ee77e9deb0d3 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -78,8 +78,37 @@ fn do_check_simd_vector_abi<'tcx>( } } -/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments -/// or return values for which the corresponding target feature is not enabled. +/// Emit an error when a non-rustic ABI has unsized parameters. +/// Unsized types do not have a stable layout, so should not be used with stable ABIs. +/// `is_call` indicates whether this is a call-site check or a definition-site check; +/// this is only relevant for the wording in the emitted error. +fn do_check_unsized_params<'tcx>( + tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + is_call: bool, + loc: impl Fn() -> (Span, HirId), +) { + // Unsized parameters are allowed with the (unstable) "Rust" (and similar) ABIs. + if fn_abi.conv.is_rustic_abi() { + return; + } + + for arg_abi in fn_abi.args.iter() { + if !arg_abi.layout.layout.is_sized() { + let (span, _hir_id) = loc(); + tcx.dcx().emit_err(errors::AbiErrorUnsupportedUnsizedParameter { + span, + ty: arg_abi.layout.ty, + is_call, + }); + } + } +} + +/// Checks the ABI of an Instance, emitting an error when: +/// +/// - a non-rustic ABI uses unsized parameters +/// - the signature requires target features that are not enabled fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { let typing_env = ty::TypingEnv::fully_monomorphized(); let Ok(abi) = tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty()))) @@ -102,11 +131,14 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { def_id.as_local().map(|did| tcx.local_def_id_to_hir_id(did)).unwrap_or(CRATE_HIR_ID), ) }; + do_check_unsized_params(tcx, abi, /*is_call*/ false, loc); do_check_simd_vector_abi(tcx, abi, instance.def_id(), /*is_call*/ false, loc); } -/// Checks that a call expression does not try to pass a vector-passed argument which requires a -/// target feature that the caller does not have, as doing so causes UB because of ABI mismatch. +/// Check the ABI at a call site, emitting an error when: +/// +/// - a non-rustic ABI uses unsized parameters +/// - the signature requires target features that are not enabled fn check_call_site_abi<'tcx>( tcx: TyCtxt<'tcx>, callee: Ty<'tcx>, @@ -140,6 +172,7 @@ fn check_call_site_abi<'tcx>( // ABI failed to compute; this will not get through codegen. return; }; + do_check_unsized_params(tcx, callee_abi, /*is_call*/ true, loc); do_check_simd_vector_abi(tcx, callee_abi, caller.def_id(), /*is_call*/ true, loc); } diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index 2824d5dde9d84..09682ee9d4e67 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -82,6 +82,20 @@ fn reserved_r13( } } +fn reserved_r29( + arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxIndexSet, + _target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + if arch != InlineAsmArch::PowerPC { + Ok(()) + } else { + Err("r29 is used internally by LLVM and cannot be used as an operand for inline asm") + } +} + fn reserved_v20to31( _arch: InlineAsmArch, _reloc_model: RelocModel, @@ -129,6 +143,7 @@ def_regs! { r26: reg, reg_nonzero = ["r26", "26"], r27: reg, reg_nonzero = ["r27", "27"], r28: reg, reg_nonzero = ["r28", "28"], + r29: reg, reg_nonzero = ["r29", "29"] % reserved_r29, f0: freg = ["f0", "fr0"], f1: freg = ["f1", "fr1"], f2: freg = ["f2", "fr2"], @@ -274,8 +289,6 @@ def_regs! { "the stack pointer cannot be used as an operand for inline asm", #error = ["r2", "2"] => "r2 is a system reserved register and cannot be used as an operand for inline asm", - #error = ["r29", "29"] => - "r29 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r30", "30"] => "r30 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r31", "31", "fp"] => @@ -306,7 +319,7 @@ impl PowerPCInlineAsmReg { (r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7"); (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r13, "13"), (r14, "14"), (r15, "15"); (r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23"); - (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28"); + (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28"), (r29, "29"); (f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7"); (f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15"); (f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23"); diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 94de948a480eb..c96605fb7944c 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -31,8 +31,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | NVPTX | `reg64` | None\* | `l` | | Hexagon | `reg` | `r[0-28]` | `r` | | Hexagon | `preg` | `p[0-3]` | Only clobbers | -| PowerPC | `reg` | `r0`, `r[3-12]`, `r[14-28]` | `r` | -| PowerPC | `reg_nonzero` | `r[3-12]`, `r[14-28]` | `b` | +| PowerPC | `reg` | `r0`, `r[3-12]`, `r[14-29]`\* | `r` | +| PowerPC | `reg_nonzero` | `r[3-12]`, `r[14-29]`\* | `b` | | PowerPC | `freg` | `f[0-31]` | `f` | | PowerPC | `vreg` | `v[0-31]` | `v` | | PowerPC | `vsreg | `vs[0-63]` | `wa` | @@ -61,6 +61,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect > - NVPTX doesn't have a fixed register set, so named registers are not supported. > > - WebAssembly doesn't have registers, so named registers are not supported. +> +> - r29 is reserved only on 32 bit PowerPC targets. # Register class supported types @@ -148,7 +150,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp`, `r14`/`o6` (SPARC) | The stack pointer must be restored to its original value at the end of an asm code block. | | All | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r30`/`i6` (SPARC) | The frame pointer cannot be used as an input or output. | -| All | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames. | +| All | `r19` (Hexagon), `r29` (PowerPC 32 bit only), `r30` (PowerPC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | diff --git a/tests/ui/abi/non-rustic-unsized.rs b/tests/ui/abi/non-rustic-unsized.rs new file mode 100644 index 0000000000000..d26c4af72ccaf --- /dev/null +++ b/tests/ui/abi/non-rustic-unsized.rs @@ -0,0 +1,66 @@ +//@ add-minicore +//@ build-fail +#![no_core] +#![crate_type = "lib"] +#![feature(no_core, unsized_fn_params)] +#![allow(improper_ctypes_definitions, improper_ctypes)] + +extern crate minicore; +use minicore::*; + +fn rust(_: [u8]) {} +extern "C" fn c(_: [u8]) {} +//~^ ERROR this function definition uses unsized type `[u8]` which is not supported with the chosen ABI +extern "system" fn system(_: [u8]) {} +//~^ ERROR this function definition uses unsized type `[u8]` which is not supported with the chosen ABI + +#[repr(C)] +struct CustomUnsized { + a: i64, + b: [u8], +} + +extern "C" fn c_custom_unsized(x: CustomUnsized) {} +//~^ ERROR this function definition uses unsized type `CustomUnsized` which is not supported with the chosen ABI + +#[unsafe(no_mangle)] +fn entry(x: [u8], y: [u8], z: [u8], w: CustomUnsized) { + rust(x); + c(y); + //~^ ERROR this function call uses unsized type `[u8]` which is not supported with the chosen ABI + system(z); + //~^ ERROR this function call uses unsized type `[u8]` which is not supported with the chosen ABI + c_custom_unsized(w); + //~^ ERROR this function call uses unsized type `CustomUnsized` which is not supported with the chosen ABI +} + +#[unsafe(no_mangle)] +fn test_fn_ptr(rust: extern "Rust" fn(_: [u8]), c: extern "C" fn(_: [u8]), x: [u8], y: [u8]) { + rust(x); + c(y); + //~^ ERROR this function call uses unsized type `[u8]` which is not supported with the chosen ABI +} + +#[unsafe(no_mangle)] +fn test_extern(x: [u8], y: [u8]) { + unsafe extern "Rust" { + safe fn rust(_: [u8]); + } + + unsafe extern "system" { + safe fn system(_: [u8]); + } + + rust(x); + system(y); + //~^ ERROR this function call uses unsized type `[u8]` which is not supported with the chosen ABI +} + +extern "C" fn c_polymorphic(_: T) {} +//~^ ERROR this function definition uses unsized type `[u8]` which is not supported with the chosen ABI + +#[unsafe(no_mangle)] +fn test_polymorphic(x: [u8]) { + c_polymorphic(x); + //~^ ERROR this function call uses unsized type `[u8]` which is not supported with the chosen ABI +} diff --git a/tests/ui/abi/non-rustic-unsized.stderr b/tests/ui/abi/non-rustic-unsized.stderr new file mode 100644 index 0000000000000..30fbf2922fafd --- /dev/null +++ b/tests/ui/abi/non-rustic-unsized.stderr @@ -0,0 +1,88 @@ +error: this function call uses unsized type `[u8]` which is not supported with the chosen ABI + --> $DIR/non-rustic-unsized.rs:29:5 + | +LL | c(y); + | ^^^^ function called here + | + = help: only rustic ABIs support unsized parameters + +error: this function call uses unsized type `[u8]` which is not supported with the chosen ABI + --> $DIR/non-rustic-unsized.rs:31:5 + | +LL | system(z); + | ^^^^^^^^^ function called here + | + = help: only rustic ABIs support unsized parameters + +error: this function call uses unsized type `CustomUnsized` which is not supported with the chosen ABI + --> $DIR/non-rustic-unsized.rs:33:5 + | +LL | c_custom_unsized(w); + | ^^^^^^^^^^^^^^^^^^^ function called here + | + = help: only rustic ABIs support unsized parameters + +error: this function definition uses unsized type `[u8]` which is not supported with the chosen ABI + --> $DIR/non-rustic-unsized.rs:12:1 + | +LL | extern "C" fn c(_: [u8]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = help: only rustic ABIs support unsized parameters + +error: this function definition uses unsized type `[u8]` which is not supported with the chosen ABI + --> $DIR/non-rustic-unsized.rs:14:1 + | +LL | extern "system" fn system(_: [u8]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = help: only rustic ABIs support unsized parameters + +error: this function definition uses unsized type `CustomUnsized` which is not supported with the chosen ABI + --> $DIR/non-rustic-unsized.rs:23:1 + | +LL | extern "C" fn c_custom_unsized(x: CustomUnsized) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = help: only rustic ABIs support unsized parameters + +error: this function call uses unsized type `[u8]` which is not supported with the chosen ABI + --> $DIR/non-rustic-unsized.rs:40:5 + | +LL | c(y); + | ^^^^ function called here + | + = help: only rustic ABIs support unsized parameters + +error: this function call uses unsized type `[u8]` which is not supported with the chosen ABI + --> $DIR/non-rustic-unsized.rs:55:5 + | +LL | system(y); + | ^^^^^^^^^ function called here + | + = help: only rustic ABIs support unsized parameters + +error: this function call uses unsized type `[u8]` which is not supported with the chosen ABI + --> $DIR/non-rustic-unsized.rs:64:5 + | +LL | c_polymorphic(x); + | ^^^^^^^^^^^^^^^^ function called here + | + = help: only rustic ABIs support unsized parameters + +error: this function definition uses unsized type `[u8]` which is not supported with the chosen ABI + --> $DIR/non-rustic-unsized.rs:59:1 + | +LL | extern "C" fn c_polymorphic(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = help: only rustic ABIs support unsized parameters + +note: the above error was encountered while instantiating `fn c_polymorphic::<[u8]>` + --> $DIR/non-rustic-unsized.rs:64:5 + | +LL | c_polymorphic(x); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 10 previous errors + diff --git a/tests/ui/asm/powerpc/bad-reg.aix64.stderr b/tests/ui/asm/powerpc/bad-reg.aix64.stderr index 67ad0a5d2c45a..4490053215b5d 100644 --- a/tests/ui/asm/powerpc/bad-reg.aix64.stderr +++ b/tests/ui/asm/powerpc/bad-reg.aix64.stderr @@ -10,12 +10,6 @@ error: invalid register `r2`: r2 is a system reserved register and cannot be use LL | asm!("", out("r2") _); | ^^^^^^^^^^^ -error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:42:18 - | -LL | asm!("", out("r29") _); - | ^^^^^^^^^^^^ - error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm --> $DIR/bad-reg.rs:44:18 | @@ -856,5 +850,5 @@ LL | asm!("/* {} */", in(xer) x); | = note: register class `xer` supports these types: -error: aborting due to 113 previous errors +error: aborting due to 112 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr index 64a8f6a3d5b93..651e8cdfd3d51 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc.stderr @@ -10,12 +10,6 @@ error: invalid register `r2`: r2 is a system reserved register and cannot be use LL | asm!("", out("r2") _); | ^^^^^^^^^^^ -error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:42:18 - | -LL | asm!("", out("r29") _); - | ^^^^^^^^^^^^ - error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm --> $DIR/bad-reg.rs:44:18 | @@ -712,6 +706,12 @@ error: cannot use register `r13`: r13 is a reserved register on this target LL | asm!("", out("r13") _); | ^^^^^^^^^^^^ +error: cannot use register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:42:18 + | +LL | asm!("", out("r29") _); + | ^^^^^^^^^^^^ + error: register class `vreg` requires at least one of the following target features: altivec, vsx --> $DIR/bad-reg.rs:53:18 | diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr index 3315a00cc1ab4..552fb0504b8de 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc64.stderr @@ -10,12 +10,6 @@ error: invalid register `r2`: r2 is a system reserved register and cannot be use LL | asm!("", out("r2") _); | ^^^^^^^^^^^ -error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:42:18 - | -LL | asm!("", out("r29") _); - | ^^^^^^^^^^^^ - error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm --> $DIR/bad-reg.rs:44:18 | @@ -916,5 +910,5 @@ LL | asm!("/* {} */", in(xer) x); | = note: register class `xer` supports these types: -error: aborting due to 123 previous errors +error: aborting due to 122 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr index 67ad0a5d2c45a..4490053215b5d 100644 --- a/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr +++ b/tests/ui/asm/powerpc/bad-reg.powerpc64le.stderr @@ -10,12 +10,6 @@ error: invalid register `r2`: r2 is a system reserved register and cannot be use LL | asm!("", out("r2") _); | ^^^^^^^^^^^ -error: invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:42:18 - | -LL | asm!("", out("r29") _); - | ^^^^^^^^^^^^ - error: invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm --> $DIR/bad-reg.rs:44:18 | @@ -856,5 +850,5 @@ LL | asm!("/* {} */", in(xer) x); | = note: register class `xer` supports these types: -error: aborting due to 113 previous errors +error: aborting due to 112 previous errors diff --git a/tests/ui/asm/powerpc/bad-reg.rs b/tests/ui/asm/powerpc/bad-reg.rs index 6ded9b97eb88f..7ceae5c6d8d36 100644 --- a/tests/ui/asm/powerpc/bad-reg.rs +++ b/tests/ui/asm/powerpc/bad-reg.rs @@ -40,7 +40,7 @@ fn f() { asm!("", out("r13") _); //~^ ERROR cannot use register `r13`: r13 is a reserved register on this target asm!("", out("r29") _); - //~^ ERROR invalid register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm + //[powerpc]~^ ERROR cannot use register `r29`: r29 is used internally by LLVM and cannot be used as an operand for inline asm asm!("", out("r30") _); //~^ ERROR invalid register `r30`: r30 is used internally by LLVM and cannot be used as an operand for inline asm asm!("", out("fp") _);