@@ -4,6 +4,7 @@ use rustc_hir::{self as hir, HirId};
4
4
use rustc_middle:: bug;
5
5
use rustc_middle:: ty:: layout:: { LayoutError , TyAndLayout } ;
6
6
use rustc_middle:: ty:: { self , TyCtxt , TypeVisitableExt } ;
7
+ use rustc_span:: Span ;
7
8
8
9
use crate :: errors;
9
10
@@ -17,15 +18,10 @@ pub(crate) fn validate_cmse_abi<'tcx>(
17
18
abi : ExternAbi ,
18
19
fn_sig : ty:: PolyFnSig < ' tcx > ,
19
20
) {
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
+ _ => {
29
25
let span = match tcx. parent_hir_node ( hir_id) {
30
26
hir:: Node :: Item ( hir:: Item {
31
27
kind : hir:: ItemKind :: ForeignMod { .. } ,
@@ -42,45 +38,10 @@ pub(crate) fn validate_cmse_abi<'tcx>(
42
38
)
43
39
. emit ( ) ;
44
40
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
- }
66
41
}
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
+ } ,
81
43
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 {
84
45
// might happen when this ABI is used incorrectly. That will be handled elsewhere
85
46
return ;
86
47
} ;
@@ -91,53 +52,43 @@ pub(crate) fn validate_cmse_abi<'tcx>(
91
52
return ;
92
53
}
93
54
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
+ } ;
109
59
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 } ) ;
122
69
}
123
- _ => ( ) ,
124
70
}
125
71
}
126
72
127
73
/// Returns whether the inputs will fit into the available registers
128
74
fn is_valid_cmse_inputs < ' tcx > (
129
75
tcx : TyCtxt < ' tcx > ,
76
+ dcx : DiagCtxtHandle < ' _ > ,
130
77
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 > ) > {
133
81
let mut accum = 0u64 ;
82
+ let mut excess_argument_spans = Vec :: new ( ) ;
134
83
135
84
// this type is only used for layout computation, which does not rely on regions
136
85
let fn_sig = tcx. instantiate_bound_regions_with_erased ( fn_sig) ;
137
86
let fn_sig = tcx. erase_and_anonymize_regions ( fn_sig) ;
138
87
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) ) ?;
141
92
142
93
let align = layout. layout . align ( ) . bytes ( ) ;
143
94
let size = layout. layout . size ( ) . bytes ( ) ;
@@ -147,21 +98,27 @@ fn is_valid_cmse_inputs<'tcx>(
147
98
148
99
// i.e. exceeds 4 32-bit registers
149
100
if accum > 16 {
150
- span = span . or ( Some ( index ) ) ;
101
+ excess_argument_spans . push ( hir_ty . span ) ;
151
102
}
152
103
}
153
104
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 } ) ;
157
109
}
110
+
111
+ Ok ( ( ) )
158
112
}
159
113
160
114
/// Returns whether the output will fit into the available registers
161
115
fn is_valid_cmse_output < ' tcx > (
162
116
tcx : TyCtxt < ' tcx > ,
117
+ dcx : DiagCtxtHandle < ' _ > ,
163
118
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 > > {
165
122
// this type is only used for layout computation, which does not rely on regions
166
123
let fn_sig = tcx. instantiate_bound_regions_with_erased ( fn_sig) ;
167
124
let fn_sig = tcx. erase_and_anonymize_regions ( fn_sig) ;
@@ -176,14 +133,19 @@ fn is_valid_cmse_output<'tcx>(
176
133
// `#[no_mangle]` or similar, so generics in the type really don't make sense.
177
134
//
178
135
// 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 ( ( ) ) ;
181
139
}
182
140
183
141
let typing_env = ty:: TypingEnv :: fully_monomorphized ( ) ;
184
142
let layout = tcx. layout_of ( typing_env. as_query_input ( return_type) ) ?;
185
143
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 ( ( ) )
187
149
}
188
150
189
151
/// 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 {
208
170
matches ! ( value, Primitive :: Int ( Integer :: I64 , _) | Primitive :: Float ( Float :: F64 ) )
209
171
}
210
172
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 {
212
174
use LayoutError :: * ;
213
175
214
176
match layout_err {
215
177
TooGeneric ( ty) => {
216
178
match abi {
217
179
ExternAbi :: CmseNonSecureCall => {
218
180
// prevent double reporting of this error
219
- !ty. is_impl_trait ( )
181
+ !ty. has_opaque_types ( )
220
182
}
221
183
ExternAbi :: CmseNonSecureEntry => true ,
222
184
_ => bug ! ( "invalid ABI: {abi}" ) ,
0 commit comments