@@ -4,6 +4,7 @@ use rustc_hir::{self as hir, HirId};
44use rustc_middle:: bug;
55use rustc_middle:: ty:: layout:: { LayoutError , TyAndLayout } ;
66use rustc_middle:: ty:: { self , TyCtxt , TypeVisitableExt } ;
7+ use rustc_span:: Span ;
78
89use 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
12874fn 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
161115fn 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}" ) ,
0 commit comments