44use crate :: attr:: { AggregatedSpirvAttributes , IntrinsicType } ;
55use crate :: codegen_cx:: CodegenCx ;
66use crate :: spirv_type:: SpirvType ;
7+ use itertools:: Itertools ;
78use rspirv:: spirv:: { Dim , ImageFormat , StorageClass , Word } ;
89use rustc_data_structures:: fx:: FxHashMap ;
910use rustc_errors:: ErrorGuaranteed ;
@@ -22,7 +23,8 @@ use rustc_span::def_id::DefId;
2223use rustc_span:: { Span , Symbol } ;
2324use rustc_target:: abi:: call:: { ArgAbi , ArgAttributes , FnAbi , PassMode } ;
2425use rustc_target:: abi:: {
25- Abi , Align , FieldsShape , LayoutS , Primitive , Scalar , Size , TagEncoding , VariantIdx , Variants ,
26+ Abi , Align , FieldsShape , LayoutS , Primitive , ReprFlags , ReprOptions , Scalar , Size , TagEncoding ,
27+ VariantIdx , Variants ,
2628} ;
2729use rustc_target:: spec:: abi:: Abi as SpecAbi ;
2830use std:: cell:: RefCell ;
@@ -157,6 +159,7 @@ pub(crate) fn provide(providers: &mut Providers) {
157159 unadjusted_abi_align,
158160 }
159161 }
162+
160163 providers. layout_of = |tcx, key| {
161164 let TyAndLayout { ty, mut layout } =
162165 ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . layout_of ) ( tcx, key) ?;
@@ -176,6 +179,90 @@ pub(crate) fn provide(providers: &mut Providers) {
176179
177180 Ok ( TyAndLayout { ty, layout } )
178181 } ;
182+
183+ // HACK(eddyb) work around https://github.com/rust-lang/rust/pull/129403
184+ // banning "struct-style" `#[repr(simd)]` (in favor of "array-newtype-style"),
185+ // by simply bypassing "type definition WF checks" for affected types, which:
186+ // - can only really be sound for types with trivial field types, that are
187+ // either completely non-generic (covering most `#[repr(simd)]` `struct`s),
188+ // or *at most* one generic type parameter with no bounds/where clause
189+ // - relies on upstream `layout_of` not having had the non-array logic removed
190+ //
191+ // FIXME(eddyb) remove this once migrating beyond `#[repr(simd)]` becomes
192+ // an option (may require Rust-GPU distinguishing between "SPIR-V interface"
193+ // and "Rust-facing" types, which is even worse when the `OpTypeVector`s
194+ // may be e.g. nested in `struct`s/arrays/etc. - at least buffers are easy).
195+ providers. check_well_formed = |tcx, def_id| {
196+ let trivial_struct = match tcx. hir_node_by_def_id ( def_id) {
197+ rustc_hir:: Node :: Item ( item) => match item. kind {
198+ rustc_hir:: ItemKind :: Struct (
199+ _,
200+ & rustc_hir:: Generics {
201+ params :
202+ & [ ]
203+ | & [
204+ rustc_hir:: GenericParam {
205+ kind :
206+ rustc_hir:: GenericParamKind :: Type {
207+ default : None ,
208+ synthetic : false ,
209+ } ,
210+ ..
211+ } ,
212+ ] ,
213+ predicates : & [ ] ,
214+ has_where_clause_predicates : false ,
215+ where_clause_span : _,
216+ span : _,
217+ } ,
218+ ) => Some ( tcx. adt_def ( def_id) ) ,
219+ _ => None ,
220+ } ,
221+ _ => None ,
222+ } ;
223+ let valid_non_array_simd_struct = trivial_struct. is_some_and ( |adt_def| {
224+ let ReprOptions {
225+ int : None ,
226+ align : None ,
227+ pack : None ,
228+ flags : ReprFlags :: IS_SIMD ,
229+ field_shuffle_seed : _,
230+ } = adt_def. repr ( )
231+ else {
232+ return false ;
233+ } ;
234+ if adt_def. destructor ( tcx) . is_some ( ) {
235+ return false ;
236+ }
237+
238+ let field_types = adt_def
239+ . non_enum_variant ( )
240+ . fields
241+ . iter ( )
242+ . map ( |f| tcx. type_of ( f. did ) . instantiate_identity ( ) ) ;
243+ field_types. dedup ( ) . exactly_one ( ) . is_ok_and ( |elem_ty| {
244+ matches ! (
245+ elem_ty. kind( ) ,
246+ ty:: Bool | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) | ty:: Param ( _)
247+ )
248+ } )
249+ } ) ;
250+
251+ if valid_non_array_simd_struct {
252+ tcx. dcx ( )
253+ . struct_span_warn (
254+ tcx. def_span ( def_id) ,
255+ "[Rust-GPU] temporarily re-allowing old-style `#[repr(simd)]` (with fields)" ,
256+ )
257+ . with_note ( "removed upstream by https://github.com/rust-lang/rust/pull/129403" )
258+ . with_note ( "in favor of the new `#[repr(simd)] struct TxN([T; N]);` style" )
259+ . with_note ( "(taking effect since `nightly-2024-09-12` / `1.83.0` stable)" )
260+ . emit ( ) ;
261+ return Ok ( ( ) ) ;
262+ }
263+
264+ ( rustc_interface:: DEFAULT_QUERY_PROVIDERS . check_well_formed ) ( tcx, def_id)
265+ } ;
179266}
180267
181268/// If a struct contains a pointer to itself, even indirectly, then doing a naiive recursive walk
@@ -458,7 +545,7 @@ impl<'tcx> ConvSpirvType<'tcx> for TyAndLayout<'tcx> {
458545 }
459546}
460547
461- /// Only pub for `LayoutTypeMethods ::scalar_pair_element_backend_type`. Think about what you're
548+ /// Only pub for `LayoutTypeCodegenMethods ::scalar_pair_element_backend_type`. Think about what you're
462549/// doing before calling this.
463550pub fn scalar_pair_element_backend_type < ' tcx > (
464551 cx : & CodegenCx < ' tcx > ,
0 commit comments