@@ -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