|
1 |
| -use rustc_abi::ExternAbi; |
| 1 | +use rustc_abi::{BackendRepr, ExternAbi, Float, Integer, Primitive, Scalar}; |
2 | 2 | use rustc_errors::{DiagCtxtHandle, E0781, struct_span_code_err};
|
3 | 3 | use rustc_hir::{self as hir, HirId};
|
4 | 4 | use rustc_middle::bug;
|
5 |
| -use rustc_middle::ty::layout::LayoutError; |
6 |
| -use rustc_middle::ty::{self, TyCtxt}; |
| 5 | +use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; |
| 6 | +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; |
7 | 7 |
|
8 | 8 | use crate::errors;
|
9 | 9 |
|
@@ -164,44 +164,48 @@ fn is_valid_cmse_output<'tcx>(
|
164 | 164 | ) -> Result<bool, &'tcx LayoutError<'tcx>> {
|
165 | 165 | // this type is only used for layout computation, which does not rely on regions
|
166 | 166 | let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
|
| 167 | + let fn_sig = tcx.erase_and_anonymize_regions(fn_sig); |
| 168 | + let return_type = fn_sig.output(); |
| 169 | + |
| 170 | + // `impl Trait` is already disallowed with `cmse-nonsecure-call`, because that ABI is only |
| 171 | + // allowed on function pointers, and function pointers cannot contain `impl Trait` in their |
| 172 | + // signature. |
| 173 | + // |
| 174 | + // Here we explicitly disallow `impl Trait` in the `cmse-nonsecure-entry` return type too, to |
| 175 | + // prevent query cycles when calculating the layout. This ABI is meant to be used with |
| 176 | + // `#[no_mangle]` or similar, so generics in the type really don't make sense. |
| 177 | + // |
| 178 | + // 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))); |
| 181 | + } |
167 | 182 |
|
168 | 183 | let typing_env = ty::TypingEnv::fully_monomorphized();
|
| 184 | + let layout = tcx.layout_of(typing_env.as_query_input(return_type))?; |
| 185 | + |
| 186 | + Ok(is_valid_cmse_output_layout(layout)) |
| 187 | +} |
169 | 188 |
|
170 |
| - let mut ret_ty = fn_sig.output(); |
171 |
| - let layout = tcx.layout_of(typing_env.as_query_input(ret_ty))?; |
| 189 | +/// Returns whether the output will fit into the available registers |
| 190 | +fn is_valid_cmse_output_layout<'tcx>(layout: TyAndLayout<'tcx>) -> bool { |
172 | 191 | let size = layout.layout.size().bytes();
|
173 | 192 |
|
174 | 193 | if size <= 4 {
|
175 |
| - return Ok(true); |
| 194 | + return true; |
176 | 195 | } else if size > 8 {
|
177 |
| - return Ok(false); |
| 196 | + return false; |
178 | 197 | }
|
179 | 198 |
|
180 |
| - // next we need to peel any repr(transparent) layers off |
181 |
| - 'outer: loop { |
182 |
| - let ty::Adt(adt_def, args) = ret_ty.kind() else { |
183 |
| - break; |
184 |
| - }; |
185 |
| - |
186 |
| - if !adt_def.repr().transparent() { |
187 |
| - break; |
188 |
| - } |
189 |
| - |
190 |
| - // the first field with non-trivial size and alignment must be the data |
191 |
| - for variant_def in adt_def.variants() { |
192 |
| - for field_def in variant_def.fields.iter() { |
193 |
| - let ty = field_def.ty(tcx, args); |
194 |
| - let layout = tcx.layout_of(typing_env.as_query_input(ty))?; |
| 199 | + // Accept scalar 64-bit types. |
| 200 | + let BackendRepr::Scalar(scalar) = layout.layout.backend_repr else { |
| 201 | + return false; |
| 202 | + }; |
195 | 203 |
|
196 |
| - if !layout.layout.is_1zst() { |
197 |
| - ret_ty = ty; |
198 |
| - continue 'outer; |
199 |
| - } |
200 |
| - } |
201 |
| - } |
202 |
| - } |
| 204 | + let Scalar::Initialized { value, .. } = scalar else { |
| 205 | + return false; |
| 206 | + }; |
203 | 207 |
|
204 |
| - Ok(ret_ty == tcx.types.i64 || ret_ty == tcx.types.u64 || ret_ty == tcx.types.f64) |
| 208 | + matches!(value, Primitive::Int(Integer::I64, _) | Primitive::Float(Float::F64)) |
205 | 209 | }
|
206 | 210 |
|
207 | 211 | fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError<'tcx>) -> bool {
|
|
0 commit comments