Skip to content

Commit 9725c4b

Browse files
committed
Auto merge of #147537 - matthiaskrgr:rollup-2mfhpg4, r=matthiaskrgr
Rollup of 2 pull requests Successful merges: - #147479 (cmse: improve error messages) - #147523 (x86_64-bigint-helpers test: update test assertion to cover registers r8 and r9) r? `@ghost` `@rustbot` modify labels: rollup
2 parents b925a86 + 849bea3 commit 9725c4b

File tree

10 files changed

+198
-207
lines changed

10 files changed

+198
-207
lines changed

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,16 @@ hir_analysis_cannot_capture_late_bound_ty =
7272
hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
7373
.label = `for<...>` is here
7474
75-
hir_analysis_cmse_call_generic =
76-
function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type
75+
hir_analysis_cmse_generic =
76+
generics are not allowed in `extern {$abi}` signatures
7777
78-
hir_analysis_cmse_entry_generic =
79-
functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type
78+
hir_analysis_cmse_impl_trait =
79+
`impl Trait` is not allowed in `extern {$abi}` signatures
8080
8181
hir_analysis_cmse_inputs_stack_spill =
8282
arguments for `{$abi}` function too large to pass via registers
83-
.label = {$plural ->
84-
[false] this argument doesn't
85-
*[true] these arguments don't
86-
} fit in the available registers
87-
.note = functions with the `{$abi}` ABI must pass all their arguments via the 4 32-bit available argument registers
83+
.label = does not fit in the available registers
84+
.note = functions with the `{$abi}` ABI must pass all their arguments via the 4 32-bit argument registers
8885
8986
hir_analysis_cmse_output_stack_spill =
9087
return value of `{$abi}` function too large to pass via registers

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,8 +1616,7 @@ pub(crate) struct InvalidGenericReceiverTy<'tcx> {
16161616
pub(crate) struct CmseInputsStackSpill {
16171617
#[primary_span]
16181618
#[label]
1619-
pub span: Span,
1620-
pub plural: bool,
1619+
pub spans: Vec<Span>,
16211620
pub abi: ExternAbi,
16221621
}
16231622

@@ -1633,22 +1632,24 @@ pub(crate) struct CmseOutputStackSpill {
16331632
}
16341633

16351634
#[derive(Diagnostic)]
1636-
#[diag(hir_analysis_cmse_call_generic, code = E0798)]
1637-
pub(crate) struct CmseCallGeneric {
1635+
#[diag(hir_analysis_cmse_generic, code = E0798)]
1636+
pub(crate) struct CmseGeneric {
16381637
#[primary_span]
16391638
pub span: Span,
1639+
pub abi: ExternAbi,
16401640
}
16411641

16421642
#[derive(Diagnostic)]
1643-
#[diag(hir_analysis_bad_return_type_notation_position)]
1644-
pub(crate) struct BadReturnTypeNotation {
1643+
#[diag(hir_analysis_cmse_impl_trait, code = E0798)]
1644+
pub(crate) struct CmseImplTrait {
16451645
#[primary_span]
16461646
pub span: Span,
1647+
pub abi: ExternAbi,
16471648
}
16481649

16491650
#[derive(Diagnostic)]
1650-
#[diag(hir_analysis_cmse_entry_generic, code = E0798)]
1651-
pub(crate) struct CmseEntryGeneric {
1651+
#[diag(hir_analysis_bad_return_type_notation_position)]
1652+
pub(crate) struct BadReturnTypeNotation {
16521653
#[primary_span]
16531654
pub span: Span,
16541655
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs

Lines changed: 50 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use rustc_hir::{self as hir, HirId};
44
use rustc_middle::bug;
55
use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
66
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
7+
use rustc_span::Span;
78

89
use crate::errors;
910

@@ -17,15 +18,10 @@ pub(crate) fn validate_cmse_abi<'tcx>(
1718
abi: ExternAbi,
1819
fn_sig: ty::PolyFnSig<'tcx>,
1920
) {
20-
match abi {
21-
ExternAbi::CmseNonSecureCall => {
22-
let hir_node = tcx.hir_node(hir_id);
23-
let hir::Node::Ty(hir::Ty {
24-
span: fn_ptr_span,
25-
kind: hir::TyKind::FnPtr(fn_ptr_ty),
26-
..
27-
}) = hir_node
28-
else {
21+
let fn_decl = match abi {
22+
ExternAbi::CmseNonSecureCall => match tcx.hir_node(hir_id) {
23+
hir::Node::Ty(hir::Ty { kind: hir::TyKind::FnPtr(fn_ptr_ty), .. }) => fn_ptr_ty.decl,
24+
_ => {
2925
let span = match tcx.parent_hir_node(hir_id) {
3026
hir::Node::Item(hir::Item {
3127
kind: hir::ItemKind::ForeignMod { .. },
@@ -42,45 +38,10 @@ pub(crate) fn validate_cmse_abi<'tcx>(
4238
)
4339
.emit();
4440
return;
45-
};
46-
47-
match is_valid_cmse_inputs(tcx, fn_sig) {
48-
Ok(Ok(())) => {}
49-
Ok(Err(index)) => {
50-
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
51-
// ^^^^^^
52-
let span = if let Some(ident) = fn_ptr_ty.param_idents[index] {
53-
ident.span.to(fn_ptr_ty.decl.inputs[index].span)
54-
} else {
55-
fn_ptr_ty.decl.inputs[index].span
56-
}
57-
.to(fn_ptr_ty.decl.inputs.last().unwrap().span);
58-
let plural = fn_ptr_ty.param_idents.len() - index != 1;
59-
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi });
60-
}
61-
Err(layout_err) => {
62-
if should_emit_generic_error(abi, layout_err) {
63-
dcx.emit_err(errors::CmseCallGeneric { span: *fn_ptr_span });
64-
}
65-
}
6641
}
67-
68-
match is_valid_cmse_output(tcx, fn_sig) {
69-
Ok(true) => {}
70-
Ok(false) => {
71-
let span = fn_ptr_ty.decl.output.span();
72-
dcx.emit_err(errors::CmseOutputStackSpill { span, abi });
73-
}
74-
Err(layout_err) => {
75-
if should_emit_generic_error(abi, layout_err) {
76-
dcx.emit_err(errors::CmseCallGeneric { span: *fn_ptr_span });
77-
}
78-
}
79-
};
80-
}
42+
},
8143
ExternAbi::CmseNonSecureEntry => {
82-
let hir_node = tcx.hir_node(hir_id);
83-
let Some(hir::FnSig { decl, span: fn_sig_span, .. }) = hir_node.fn_sig() else {
44+
let Some(hir::FnSig { decl, .. }) = tcx.hir_node(hir_id).fn_sig() else {
8445
// might happen when this ABI is used incorrectly. That will be handled elsewhere
8546
return;
8647
};
@@ -91,53 +52,43 @@ pub(crate) fn validate_cmse_abi<'tcx>(
9152
return;
9253
}
9354

94-
match is_valid_cmse_inputs(tcx, fn_sig) {
95-
Ok(Ok(())) => {}
96-
Ok(Err(index)) => {
97-
// fn f(x: u32, y: u32, z: u32, w: u16, q: u16) -> u32,
98-
// ^^^^^^
99-
let span = decl.inputs[index].span.to(decl.inputs.last().unwrap().span);
100-
let plural = decl.inputs.len() - index != 1;
101-
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi });
102-
}
103-
Err(layout_err) => {
104-
if should_emit_generic_error(abi, layout_err) {
105-
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
106-
}
107-
}
108-
}
55+
decl
56+
}
57+
_ => return,
58+
};
10959

110-
match is_valid_cmse_output(tcx, fn_sig) {
111-
Ok(true) => {}
112-
Ok(false) => {
113-
let span = decl.output.span();
114-
dcx.emit_err(errors::CmseOutputStackSpill { span, abi });
115-
}
116-
Err(layout_err) => {
117-
if should_emit_generic_error(abi, layout_err) {
118-
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
119-
}
120-
}
121-
};
60+
if let Err((span, layout_err)) = is_valid_cmse_inputs(tcx, dcx, fn_sig, fn_decl, abi) {
61+
if should_emit_layout_error(abi, layout_err) {
62+
dcx.emit_err(errors::CmseGeneric { span, abi });
63+
}
64+
}
65+
66+
if let Err(layout_err) = is_valid_cmse_output(tcx, dcx, fn_sig, fn_decl, abi) {
67+
if should_emit_layout_error(abi, layout_err) {
68+
dcx.emit_err(errors::CmseGeneric { span: fn_decl.output.span(), abi });
12269
}
123-
_ => (),
12470
}
12571
}
12672

12773
/// Returns whether the inputs will fit into the available registers
12874
fn is_valid_cmse_inputs<'tcx>(
12975
tcx: TyCtxt<'tcx>,
76+
dcx: DiagCtxtHandle<'_>,
13077
fn_sig: ty::PolyFnSig<'tcx>,
131-
) -> Result<Result<(), usize>, &'tcx LayoutError<'tcx>> {
132-
let mut span = None;
78+
fn_decl: &hir::FnDecl<'tcx>,
79+
abi: ExternAbi,
80+
) -> Result<(), (Span, &'tcx LayoutError<'tcx>)> {
13381
let mut accum = 0u64;
82+
let mut excess_argument_spans = Vec::new();
13483

13584
// this type is only used for layout computation, which does not rely on regions
13685
let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
13786
let fn_sig = tcx.erase_and_anonymize_regions(fn_sig);
13887

139-
for (index, ty) in fn_sig.inputs().iter().enumerate() {
140-
let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?;
88+
for (ty, hir_ty) in fn_sig.inputs().iter().zip(fn_decl.inputs) {
89+
let layout = tcx
90+
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))
91+
.map_err(|e| (hir_ty.span, e))?;
14192

14293
let align = layout.layout.align().bytes();
14394
let size = layout.layout.size().bytes();
@@ -147,21 +98,27 @@ fn is_valid_cmse_inputs<'tcx>(
14798

14899
// i.e. exceeds 4 32-bit registers
149100
if accum > 16 {
150-
span = span.or(Some(index));
101+
excess_argument_spans.push(hir_ty.span);
151102
}
152103
}
153104

154-
match span {
155-
None => Ok(Ok(())),
156-
Some(span) => Ok(Err(span)),
105+
if !excess_argument_spans.is_empty() {
106+
// fn f(x: u32, y: u32, z: u32, w: u16, q: u16) -> u32,
107+
// ^^^^^^
108+
dcx.emit_err(errors::CmseInputsStackSpill { spans: excess_argument_spans, abi });
157109
}
110+
111+
Ok(())
158112
}
159113

160114
/// Returns whether the output will fit into the available registers
161115
fn is_valid_cmse_output<'tcx>(
162116
tcx: TyCtxt<'tcx>,
117+
dcx: DiagCtxtHandle<'_>,
163118
fn_sig: ty::PolyFnSig<'tcx>,
164-
) -> Result<bool, &'tcx LayoutError<'tcx>> {
119+
fn_decl: &hir::FnDecl<'tcx>,
120+
abi: ExternAbi,
121+
) -> Result<(), &'tcx LayoutError<'tcx>> {
165122
// this type is only used for layout computation, which does not rely on regions
166123
let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
167124
let fn_sig = tcx.erase_and_anonymize_regions(fn_sig);
@@ -176,14 +133,19 @@ fn is_valid_cmse_output<'tcx>(
176133
// `#[no_mangle]` or similar, so generics in the type really don't make sense.
177134
//
178135
// see also https://github.com/rust-lang/rust/issues/147242.
179-
if return_type.has_opaque_types() {
180-
return Err(tcx.arena.alloc(LayoutError::TooGeneric(return_type)));
136+
if abi == ExternAbi::CmseNonSecureEntry && return_type.has_opaque_types() {
137+
dcx.emit_err(errors::CmseImplTrait { span: fn_decl.output.span(), abi });
138+
return Ok(());
181139
}
182140

183141
let typing_env = ty::TypingEnv::fully_monomorphized();
184142
let layout = tcx.layout_of(typing_env.as_query_input(return_type))?;
185143

186-
Ok(is_valid_cmse_output_layout(layout))
144+
if !is_valid_cmse_output_layout(layout) {
145+
dcx.emit_err(errors::CmseOutputStackSpill { span: fn_decl.output.span(), abi });
146+
}
147+
148+
Ok(())
187149
}
188150

189151
/// Returns whether the output will fit into the available registers
@@ -208,15 +170,15 @@ fn is_valid_cmse_output_layout<'tcx>(layout: TyAndLayout<'tcx>) -> bool {
208170
matches!(value, Primitive::Int(Integer::I64, _) | Primitive::Float(Float::F64))
209171
}
210172

211-
fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError<'tcx>) -> bool {
173+
fn should_emit_layout_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError<'tcx>) -> bool {
212174
use LayoutError::*;
213175

214176
match layout_err {
215177
TooGeneric(ty) => {
216178
match abi {
217179
ExternAbi::CmseNonSecureCall => {
218180
// prevent double reporting of this error
219-
!ty.is_impl_trait()
181+
!ty.has_opaque_types()
220182
}
221183
ExternAbi::CmseNonSecureEntry => true,
222184
_ => bug!("invalid ABI: {abi}"),

tests/assembly-llvm/x86_64-bigint-helpers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub unsafe extern "sysv64" fn bigint_chain_borrowing_sub(
4444
n: usize,
4545
mut carry: bool,
4646
) -> bool {
47-
// CHECK: mov [[TEMP:r..]], qword ptr [rsi + 8*[[IND:r..]] + 8]
47+
// CHECK: mov [[TEMP:r.+]], qword ptr [rsi + 8*[[IND:r.+]] + 8]
4848
// CHECK: sbb [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8]
4949
// CHECK: mov qword ptr [rdi + 8*[[IND]] + 8], [[TEMP]]
5050
// CHECK: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 16]

tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ struct Test<T: Copy> {
1717
f2: extern "cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> impl Copy,
1818
//~^ ERROR `impl Trait` is not allowed in `fn` pointer parameters
1919
//~| ERROR `impl Trait` is not allowed in `fn` pointer return types
20-
f3: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798]
21-
f4: extern "cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64, //~ ERROR [E0798]
20+
f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> (impl Copy, u32),
21+
//~^ ERROR `impl Trait` is not allowed in `fn` pointer parameters
22+
//~| ERROR `impl Trait` is not allowed in `fn` pointer return types
23+
f4: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798]
24+
f5: extern "cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64, //~ ERROR [E0798]
2225
}
2326

2427
type WithReference = extern "cmse-nonsecure-call" fn(&usize);

tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,36 @@ LL | f2: extern "cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> impl C
3838
|
3939
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
4040

41-
error[E0798]: function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type
42-
--> $DIR/generics.rs:20:9
41+
error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters
42+
--> $DIR/generics.rs:20:42
43+
|
44+
LL | f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> (impl Copy, u32),
45+
| ^^^^^^^^^
46+
|
47+
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
48+
49+
error[E0562]: `impl Trait` is not allowed in `fn` pointer return types
50+
--> $DIR/generics.rs:20:78
51+
|
52+
LL | f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> (impl Copy, u32),
53+
| ^^^^^^^^^
54+
|
55+
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
56+
57+
error[E0798]: generics are not allowed in `extern "cmse-nonsecure-call"` signatures
58+
--> $DIR/generics.rs:23:41
4359
|
44-
LL | f3: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64,
45-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
60+
LL | f4: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64,
61+
| ^
4662

47-
error[E0798]: function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type
48-
--> $DIR/generics.rs:21:9
63+
error[E0798]: generics are not allowed in `extern "cmse-nonsecure-call"` signatures
64+
--> $DIR/generics.rs:24:41
4965
|
50-
LL | f4: extern "cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64,
51-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66+
LL | f5: extern "cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64,
67+
| ^^^^^^^^^^
5268

5369
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
54-
--> $DIR/generics.rs:27:71
70+
--> $DIR/generics.rs:30:71
5571
|
5672
LL | type WithTraitObject = extern "cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait;
5773
| ^^^^^^^^^^ this type doesn't fit in the available registers
@@ -60,7 +76,7 @@ LL | type WithTraitObject = extern "cmse-nonsecure-call" fn(&dyn Trait) -> &dyn
6076
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
6177

6278
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
63-
--> $DIR/generics.rs:31:60
79+
--> $DIR/generics.rs:34:60
6480
|
6581
LL | extern "cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait;
6682
| ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
@@ -69,7 +85,7 @@ LL | extern "cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Tra
6985
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
7086

7187
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
72-
--> $DIR/generics.rs:38:60
88+
--> $DIR/generics.rs:41:60
7389
|
7490
LL | extern "cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent;
7591
| ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
@@ -78,12 +94,12 @@ LL | extern "cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTranspare
7894
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
7995

8096
error[E0045]: C-variadic functions with the "cmse-nonsecure-call" calling convention are not supported
81-
--> $DIR/generics.rs:41:20
97+
--> $DIR/generics.rs:44:20
8298
|
8399
LL | type WithVarArgs = extern "cmse-nonsecure-call" fn(u32, ...);
84100
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
85101

86-
error: aborting due to 10 previous errors
102+
error: aborting due to 12 previous errors
87103

88104
Some errors have detailed explanations: E0045, E0412, E0562, E0798.
89105
For more information about an error, try `rustc --explain E0045`.

0 commit comments

Comments
 (0)