Skip to content

Commit 52bfde2

Browse files
committed
error on non-rustic ABIs using unsized parameters
1 parent c6d42d7 commit 52bfde2

File tree

6 files changed

+228
-4
lines changed

6 files changed

+228
-4
lines changed

compiler/rustc_abi/src/canon_abi.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,20 @@ pub enum CanonAbi {
5151
X86(X86Call),
5252
}
5353

54+
impl CanonAbi {
55+
pub fn is_rustic_abi(self) -> bool {
56+
match self {
57+
CanonAbi::Rust | CanonAbi::RustCold => true,
58+
CanonAbi::C
59+
| CanonAbi::Custom
60+
| CanonAbi::Arm(_)
61+
| CanonAbi::GpuKernel
62+
| CanonAbi::Interrupt(_)
63+
| CanonAbi::X86(_) => false,
64+
}
65+
}
66+
}
67+
5468
impl fmt::Display for CanonAbi {
5569
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5670
// convert to the ExternAbi that *shares a string* with this CanonAbi.

compiler/rustc_monomorphize/messages.ftl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ monomorphize_abi_error_disabled_vector_type =
1212
} here
1313
.help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`)
1414
15+
monomorphize_abi_error_unsupported_unsized_parameter =
16+
this function {$is_call ->
17+
[true] call
18+
*[false] definition
19+
} uses unsized type `{$ty}` which is not supported with the chosen ABI
20+
.label = function {$is_call ->
21+
[true] called
22+
*[false] defined
23+
} here
24+
.help = only rustic ABIs support unsized parameters
25+
1526
monomorphize_abi_error_unsupported_vector_type =
1627
this function {$is_call ->
1728
[true] call

compiler/rustc_monomorphize/src/errors.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,18 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> {
8080
pub is_call: bool,
8181
}
8282

83+
#[derive(Diagnostic)]
84+
#[diag(monomorphize_abi_error_unsupported_unsized_parameter)]
85+
#[help]
86+
pub(crate) struct AbiErrorUnsupportedUnsizedParameter<'a> {
87+
#[primary_span]
88+
#[label]
89+
pub span: Span,
90+
pub ty: Ty<'a>,
91+
/// Whether this is a problem at a call site or at a declaration.
92+
pub is_call: bool,
93+
}
94+
8395
#[derive(Diagnostic)]
8496
#[diag(monomorphize_abi_error_unsupported_vector_type)]
8597
pub(crate) struct AbiErrorUnsupportedVectorType<'a> {

compiler/rustc_monomorphize/src/mono_checks/abi_check.rs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,37 @@ fn do_check_simd_vector_abi<'tcx>(
7878
}
7979
}
8080

81-
/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments
82-
/// or return values for which the corresponding target feature is not enabled.
81+
/// Emit an error when a non-rustic ABI has unsized parameters.
82+
/// Unsized types do not have a stable layout, so should not be used with stable ABIs.
83+
/// `is_call` indicates whether this is a call-site check or a definition-site check;
84+
/// this is only relevant for the wording in the emitted error.
85+
fn do_check_unsized_params<'tcx>(
86+
tcx: TyCtxt<'tcx>,
87+
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
88+
is_call: bool,
89+
loc: impl Fn() -> (Span, HirId),
90+
) {
91+
// Unsized parameters are allowed with the (unstable) "Rust" (and similar) ABIs.
92+
if fn_abi.conv.is_rustic_abi() {
93+
return;
94+
}
95+
96+
for arg_abi in fn_abi.args.iter() {
97+
if !arg_abi.layout.layout.is_sized() {
98+
let (span, _hir_id) = loc();
99+
tcx.dcx().emit_err(errors::AbiErrorUnsupportedUnsizedParameter {
100+
span,
101+
ty: arg_abi.layout.ty,
102+
is_call,
103+
});
104+
}
105+
}
106+
}
107+
108+
/// Checks the ABI of an Instance, emitting an error when:
109+
///
110+
/// - a non-rustic ABI uses unsized parameters
111+
/// - the signature requires target features that are not enabled
83112
fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
84113
let typing_env = ty::TypingEnv::fully_monomorphized();
85114
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>) {
102131
def_id.as_local().map(|did| tcx.local_def_id_to_hir_id(did)).unwrap_or(CRATE_HIR_ID),
103132
)
104133
};
134+
do_check_unsized_params(tcx, abi, /*is_call*/ false, loc);
105135
do_check_simd_vector_abi(tcx, abi, instance.def_id(), /*is_call*/ false, loc);
106136
}
107137

108-
/// Checks that a call expression does not try to pass a vector-passed argument which requires a
109-
/// target feature that the caller does not have, as doing so causes UB because of ABI mismatch.
138+
/// Check the ABI at a call site, emitting an error when:
139+
///
140+
/// - a non-rustic ABI uses unsized parameters
141+
/// - the signature requires target features that are not enabled
110142
fn check_call_site_abi<'tcx>(
111143
tcx: TyCtxt<'tcx>,
112144
callee: Ty<'tcx>,
@@ -140,6 +172,7 @@ fn check_call_site_abi<'tcx>(
140172
// ABI failed to compute; this will not get through codegen.
141173
return;
142174
};
175+
do_check_unsized_params(tcx, callee_abi, /*is_call*/ true, loc);
143176
do_check_simd_vector_abi(tcx, callee_abi, caller.def_id(), /*is_call*/ true, loc);
144177
}
145178

tests/ui/abi/non-rustic-unsized.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//@ add-core-stubs
2+
//@ build-fail
3+
#![no_core]
4+
#![crate_type = "lib"]
5+
#![feature(no_core, unsized_fn_params)]
6+
#![allow(improper_ctypes_definitions, improper_ctypes)]
7+
8+
extern crate minicore;
9+
use minicore::*;
10+
11+
fn rust(_: [u8]) {}
12+
extern "C" fn c(_: [u8]) {}
13+
//~^ ERROR this function definition uses unsized type `[u8]` which is not supported with the chosen ABI
14+
extern "system" fn system(_: [u8]) {}
15+
//~^ ERROR this function definition uses unsized type `[u8]` which is not supported with the chosen ABI
16+
17+
#[repr(C)]
18+
struct CustomUnsized {
19+
a: i64,
20+
b: [u8],
21+
}
22+
23+
extern "C" fn c_custom_unsized(x: CustomUnsized) {}
24+
//~^ ERROR this function definition uses unsized type `CustomUnsized` which is not supported with the chosen ABI
25+
26+
#[unsafe(no_mangle)]
27+
fn entry(x: [u8], y: [u8], z: [u8], w: CustomUnsized) {
28+
rust(x);
29+
c(y);
30+
//~^ ERROR this function call uses unsized type `[u8]` which is not supported with the chosen ABI
31+
system(z);
32+
//~^ ERROR this function call uses unsized type `[u8]` which is not supported with the chosen ABI
33+
c_custom_unsized(w);
34+
//~^ ERROR this function call uses unsized type `CustomUnsized` which is not supported with the chosen ABI
35+
}
36+
37+
#[unsafe(no_mangle)]
38+
fn test_fn_ptr(rust: extern "Rust" fn(_: [u8]), c: extern "C" fn(_: [u8]), x: [u8], y: [u8]) {
39+
rust(x);
40+
c(y);
41+
//~^ ERROR this function call uses unsized type `[u8]` which is not supported with the chosen ABI
42+
}
43+
44+
#[unsafe(no_mangle)]
45+
fn test_extern(x: [u8], y: [u8]) {
46+
unsafe extern "Rust" {
47+
safe fn rust(_: [u8]);
48+
}
49+
50+
unsafe extern "system" {
51+
safe fn system(_: [u8]);
52+
}
53+
54+
rust(x);
55+
system(y);
56+
//~^ ERROR this function call uses unsized type `[u8]` which is not supported with the chosen ABI
57+
}
58+
59+
extern "C" fn c_polymorphic<T: ?Sized>(_: T) {}
60+
//~^ ERROR this function definition uses unsized type `[u8]` which is not supported with the chosen ABI
61+
62+
#[unsafe(no_mangle)]
63+
fn test_polymorphic(x: [u8]) {
64+
c_polymorphic(x);
65+
//~^ ERROR this function call uses unsized type `[u8]` which is not supported with the chosen ABI
66+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
error: this function call uses unsized type `[u8]` which is not supported with the chosen ABI
2+
--> $DIR/non-rustic-unsized.rs:29:5
3+
|
4+
LL | c(y);
5+
| ^^^^ function called here
6+
|
7+
= help: only rustic ABIs support unsized parameters
8+
9+
error: this function call uses unsized type `[u8]` which is not supported with the chosen ABI
10+
--> $DIR/non-rustic-unsized.rs:31:5
11+
|
12+
LL | system(z);
13+
| ^^^^^^^^^ function called here
14+
|
15+
= help: only rustic ABIs support unsized parameters
16+
17+
error: this function call uses unsized type `CustomUnsized` which is not supported with the chosen ABI
18+
--> $DIR/non-rustic-unsized.rs:33:5
19+
|
20+
LL | c_custom_unsized(w);
21+
| ^^^^^^^^^^^^^^^^^^^ function called here
22+
|
23+
= help: only rustic ABIs support unsized parameters
24+
25+
error: this function definition uses unsized type `[u8]` which is not supported with the chosen ABI
26+
--> $DIR/non-rustic-unsized.rs:12:1
27+
|
28+
LL | extern "C" fn c(_: [u8]) {}
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
30+
|
31+
= help: only rustic ABIs support unsized parameters
32+
33+
error: this function definition uses unsized type `[u8]` which is not supported with the chosen ABI
34+
--> $DIR/non-rustic-unsized.rs:14:1
35+
|
36+
LL | extern "system" fn system(_: [u8]) {}
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
38+
|
39+
= help: only rustic ABIs support unsized parameters
40+
41+
error: this function definition uses unsized type `CustomUnsized` which is not supported with the chosen ABI
42+
--> $DIR/non-rustic-unsized.rs:23:1
43+
|
44+
LL | extern "C" fn c_custom_unsized(x: CustomUnsized) {}
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
46+
|
47+
= help: only rustic ABIs support unsized parameters
48+
49+
error: this function call uses unsized type `[u8]` which is not supported with the chosen ABI
50+
--> $DIR/non-rustic-unsized.rs:40:5
51+
|
52+
LL | c(y);
53+
| ^^^^ function called here
54+
|
55+
= help: only rustic ABIs support unsized parameters
56+
57+
error: this function call uses unsized type `[u8]` which is not supported with the chosen ABI
58+
--> $DIR/non-rustic-unsized.rs:55:5
59+
|
60+
LL | system(y);
61+
| ^^^^^^^^^ function called here
62+
|
63+
= help: only rustic ABIs support unsized parameters
64+
65+
error: this function call uses unsized type `[u8]` which is not supported with the chosen ABI
66+
--> $DIR/non-rustic-unsized.rs:64:5
67+
|
68+
LL | c_polymorphic(x);
69+
| ^^^^^^^^^^^^^^^^ function called here
70+
|
71+
= help: only rustic ABIs support unsized parameters
72+
73+
error: this function definition uses unsized type `[u8]` which is not supported with the chosen ABI
74+
--> $DIR/non-rustic-unsized.rs:59:1
75+
|
76+
LL | extern "C" fn c_polymorphic<T: ?Sized>(_: T) {}
77+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
78+
|
79+
= help: only rustic ABIs support unsized parameters
80+
81+
note: the above error was encountered while instantiating `fn c_polymorphic::<[u8]>`
82+
--> $DIR/non-rustic-unsized.rs:64:5
83+
|
84+
LL | c_polymorphic(x);
85+
| ^^^^^^^^^^^^^^^^
86+
87+
error: aborting due to 10 previous errors
88+

0 commit comments

Comments
 (0)