Skip to content

Commit f4d8bd3

Browse files
committed
cmse: more accurate spans for excess parameters
Use the span of the types that don't fit, rather than the span of the whole signature.
1 parent f62be66 commit f4d8bd3

File tree

4 files changed

+43
-58
lines changed

4 files changed

+43
-58
lines changed

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1616,7 +1616,7 @@ pub(crate) struct InvalidGenericReceiverTy<'tcx> {
16161616
pub(crate) struct CmseInputsStackSpill {
16171617
#[primary_span]
16181618
#[label]
1619-
pub span: Span,
1619+
pub spans: Vec<Span>,
16201620
pub plural: bool,
16211621
pub abi: ExternAbi,
16221622
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs

Lines changed: 35 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -44,39 +44,20 @@ pub(crate) fn validate_cmse_abi<'tcx>(
4444
return;
4545
};
4646

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-
}
47+
match is_valid_cmse_inputs(tcx, dcx, fn_sig, fn_ptr_ty.decl, abi) {
48+
Ok(()) => {}
6149
Err(layout_err) => {
6250
if should_emit_generic_error(abi, layout_err) {
6351
dcx.emit_err(errors::CmseCallGeneric { span: *fn_ptr_span });
6452
}
6553
}
6654
}
6755

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-
}
56+
if let Err(layout_err) = is_valid_cmse_output(tcx, dcx, fn_sig, fn_ptr_ty.decl, abi) {
57+
if should_emit_generic_error(abi, layout_err) {
58+
dcx.emit_err(errors::CmseCallGeneric { span: *fn_ptr_span });
7859
}
79-
};
60+
}
8061
}
8162
ExternAbi::CmseNonSecureEntry => {
8263
let hir_node = tcx.hir_node(hir_id);
@@ -91,34 +72,20 @@ pub(crate) fn validate_cmse_abi<'tcx>(
9172
return;
9273
}
9374

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-
}
75+
match is_valid_cmse_inputs(tcx, dcx, fn_sig, decl, abi) {
76+
Ok(()) => {}
10377
Err(layout_err) => {
10478
if should_emit_generic_error(abi, layout_err) {
10579
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
10680
}
10781
}
10882
}
10983

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-
}
84+
if let Err(layout_err) = is_valid_cmse_output(tcx, dcx, fn_sig, decl, abi) {
85+
if should_emit_generic_error(abi, layout_err) {
86+
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
12087
}
121-
};
88+
}
12289
}
12390
_ => (),
12491
}
@@ -127,16 +94,19 @@ pub(crate) fn validate_cmse_abi<'tcx>(
12794
/// Returns whether the inputs will fit into the available registers
12895
fn is_valid_cmse_inputs<'tcx>(
12996
tcx: TyCtxt<'tcx>,
97+
dcx: DiagCtxtHandle<'_>,
13098
fn_sig: ty::PolyFnSig<'tcx>,
131-
) -> Result<Result<(), usize>, &'tcx LayoutError<'tcx>> {
132-
let mut span = None;
99+
fn_decl: &hir::FnDecl<'tcx>,
100+
abi: ExternAbi,
101+
) -> Result<(), &'tcx LayoutError<'tcx>> {
133102
let mut accum = 0u64;
103+
let mut excess_argument_spans = Vec::new();
134104

135105
// this type is only used for layout computation, which does not rely on regions
136106
let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
137107
let fn_sig = tcx.erase_and_anonymize_regions(fn_sig);
138108

139-
for (index, ty) in fn_sig.inputs().iter().enumerate() {
109+
for (ty, hir_ty) in fn_sig.inputs().iter().zip(fn_decl.inputs) {
140110
let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?;
141111

142112
let align = layout.layout.align().bytes();
@@ -147,21 +117,28 @@ fn is_valid_cmse_inputs<'tcx>(
147117

148118
// i.e. exceeds 4 32-bit registers
149119
if accum > 16 {
150-
span = span.or(Some(index));
120+
excess_argument_spans.push(hir_ty.span);
151121
}
152122
}
153123

154-
match span {
155-
None => Ok(Ok(())),
156-
Some(span) => Ok(Err(span)),
124+
if !excess_argument_spans.is_empty() {
125+
// fn f(x: u32, y: u32, z: u32, w: u16, q: u16) -> u32,
126+
// ^^^^^^
127+
let plural = excess_argument_spans.len() != 1;
128+
dcx.emit_err(errors::CmseInputsStackSpill { spans: excess_argument_spans, plural, abi });
157129
}
130+
131+
Ok(())
158132
}
159133

160134
/// Returns whether the output will fit into the available registers
161135
fn is_valid_cmse_output<'tcx>(
162136
tcx: TyCtxt<'tcx>,
137+
dcx: DiagCtxtHandle<'_>,
163138
fn_sig: ty::PolyFnSig<'tcx>,
164-
) -> Result<bool, &'tcx LayoutError<'tcx>> {
139+
fn_decl: &hir::FnDecl<'tcx>,
140+
abi: ExternAbi,
141+
) -> Result<(), &'tcx LayoutError<'tcx>> {
165142
// this type is only used for layout computation, which does not rely on regions
166143
let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
167144
let fn_sig = tcx.erase_and_anonymize_regions(fn_sig);
@@ -183,7 +160,11 @@ fn is_valid_cmse_output<'tcx>(
183160
let typing_env = ty::TypingEnv::fully_monomorphized();
184161
let layout = tcx.layout_of(typing_env.as_query_input(return_type))?;
185162

186-
Ok(is_valid_cmse_output_layout(layout))
163+
if !is_valid_cmse_output_layout(layout) {
164+
dcx.emit_err(errors::CmseOutputStackSpill { span: fn_decl.output.span(), abi });
165+
}
166+
167+
Ok(())
187168
}
188169

189170
/// Returns whether the output will fit into the available registers

tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers
2-
--> $DIR/params-via-stack.rs:16:61
2+
--> $DIR/params-via-stack.rs:16:64
33
|
44
LL | f1: extern "cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32),
5-
| ^^^^^^^^^^^^^^ these arguments don't fit in the available registers
5+
| ^^^ ^^^ these arguments don't fit in the available registers
6+
| |
7+
| these arguments don't fit in the available registers
68
|
79
= note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
810

tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass
22
--> $DIR/params-via-stack.rs:15:76
33
|
44
LL | pub extern "cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {}
5-
| ^^^^^^^^^^^ these arguments don't fit in the available registers
5+
| ^^^ ^^^ these arguments don't fit in the available registers
6+
| |
7+
| these arguments don't fit in the available registers
68
|
79
= note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers
810

0 commit comments

Comments
 (0)