diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index a21e1aee9b08a..360f5689cee40 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -82,6 +82,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { })) } + BackendRepr::ScalableVector { .. } => Err(Heterogeneous), + BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { // Helper for computing `homogeneous_aggregate`, allowing a custom // starting offset (used below for handling variants). diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index b078fc92482fb..b852d71b80082 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -11,7 +11,7 @@ use tracing::{debug, trace}; use crate::{ AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, - Variants, WrappingRange, + TargetDataLayout, Variants, WrappingRange, }; mod coroutine; @@ -143,58 +143,32 @@ impl LayoutCalculator { }) } - pub fn simd_type< + pub fn scalable_vector_type( + &self, + element: F, + count: u64, + ) -> LayoutCalculatorResult + where FieldIdx: Idx, VariantIdx: Idx, F: AsRef> + fmt::Debug, - >( + { + vector_type_layout(VectorKind::Scalable, self.cx.data_layout(), element, count) + } + + pub fn simd_type( &self, element: F, count: u64, repr_packed: bool, - ) -> LayoutCalculatorResult { - let elt = element.as_ref(); - if count == 0 { - return Err(LayoutCalculatorError::ZeroLengthSimdType); - } else if count > crate::MAX_SIMD_LANES { - return Err(LayoutCalculatorError::OversizedSimdType { - max_lanes: crate::MAX_SIMD_LANES, - }); - } - - let BackendRepr::Scalar(e_repr) = elt.backend_repr else { - return Err(LayoutCalculatorError::NonPrimitiveSimdType(element)); - }; - - // Compute the size and alignment of the vector - let dl = self.cx.data_layout(); - let size = - elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; - let (repr, align) = if repr_packed && !count.is_power_of_two() { - // Non-power-of-two vectors have padding up to the next power-of-two. - // If we're a packed repr, remove the padding while keeping the alignment as close - // to a vector as possible. - (BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size)) - } else { - (BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size)) - }; - let size = size.align_to(align); - - Ok(LayoutData { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Arbitrary { - offsets: [Size::ZERO].into(), - memory_index: [0].into(), - }, - backend_repr: repr, - largest_niche: elt.largest_niche, - uninhabited: false, - size, - align: AbiAlign::new(align), - max_repr_align: None, - unadjusted_abi_align: elt.align.abi, - randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)), - }) + ) -> LayoutCalculatorResult + where + FieldIdx: Idx, + VariantIdx: Idx, + F: AsRef> + fmt::Debug, + { + let kind = if repr_packed { VectorKind::PackedFixed } else { VectorKind::Fixed }; + vector_type_layout(kind, self.cx.data_layout(), element, count) } /// Compute the layout for a coroutine. @@ -453,6 +427,7 @@ impl LayoutCalculator { BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } | BackendRepr::Memory { .. } => repr, }, }; @@ -524,7 +499,8 @@ impl LayoutCalculator { hide_niches(a); hide_niches(b); } - BackendRepr::SimdVector { element, count: _ } => hide_niches(element), + BackendRepr::SimdVector { element, .. } + | BackendRepr::ScalableVector { element, .. } => hide_niches(element), BackendRepr::Memory { sized: _ } => {} } st.largest_niche = None; @@ -1501,3 +1477,67 @@ impl LayoutCalculator { s } } + +enum VectorKind { + /// `#[rustc_scalable_vector]` + Scalable, + /// `#[repr(simd, packed)]` + PackedFixed, + /// `#[repr(simd)]` + Fixed, +} + +fn vector_type_layout( + kind: VectorKind, + dl: &TargetDataLayout, + element: F, + count: u64, +) -> LayoutCalculatorResult +where + FieldIdx: Idx, + VariantIdx: Idx, + F: AsRef> + fmt::Debug, +{ + let elt = element.as_ref(); + if count == 0 { + return Err(LayoutCalculatorError::ZeroLengthSimdType); + } else if count > crate::MAX_SIMD_LANES { + return Err(LayoutCalculatorError::OversizedSimdType { max_lanes: crate::MAX_SIMD_LANES }); + } + + let BackendRepr::Scalar(element) = elt.backend_repr else { + return Err(LayoutCalculatorError::NonPrimitiveSimdType(element)); + }; + + // Compute the size and alignment of the vector + let size = + elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; + let (repr, align) = match kind { + VectorKind::Scalable => { + (BackendRepr::ScalableVector { element, count }, dl.llvmlike_vector_align(size)) + } + // Non-power-of-two vectors have padding up to the next power-of-two. + // If we're a packed repr, remove the padding while keeping the alignment as close + // to a vector as possible. + VectorKind::PackedFixed if !count.is_power_of_two() => { + (BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size)) + } + VectorKind::PackedFixed | VectorKind::Fixed => { + (BackendRepr::SimdVector { element, count }, dl.llvmlike_vector_align(size)) + } + }; + let size = size.align_to(align); + + Ok(LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() }, + backend_repr: repr, + largest_niche: elt.largest_niche, + uninhabited: false, + size, + align: AbiAlign::new(align), + max_repr_align: None, + unadjusted_abi_align: elt.align.abi, + randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)), + }) +} diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index cd85efb2753ae..43010ed2b9daf 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -96,9 +96,11 @@ bitflags! { /// If true, the type is always passed indirectly by non-Rustic ABIs. /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. const PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS = 1 << 5; - /// Any of these flags being set prevent field reordering optimisation. - const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits() + const IS_SCALABLE = 1 << 6; + // Any of these flags being set prevent field reordering optimisation. + const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits() + | ReprFlags::IS_SCALABLE.bits() | ReprFlags::IS_LINEAR.bits(); const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits(); } @@ -135,6 +137,19 @@ impl IntegerType { } } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] +pub enum ScalableElt { + /// `N` in `rustc_scalable_vector(N)` - the element count of the scalable vector + ElementCount(u128), + /// `rustc_scalable_vector` w/out `N`, used for tuple types of scalable vectors that only + /// contain other scalable vectors + Container, +} + /// Represents the repr options provided by the user. #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] #[cfg_attr( @@ -146,6 +161,8 @@ pub struct ReprOptions { pub align: Option, pub pack: Option, pub flags: ReprFlags, + /// `#[rustc_scalable_vector]` + pub scalable: Option, /// The seed to be used for randomizing a type's layout /// /// Note: This could technically be a `u128` which would @@ -162,6 +179,11 @@ impl ReprOptions { self.flags.contains(ReprFlags::IS_SIMD) } + #[inline] + pub fn scalable(&self) -> bool { + self.flags.contains(ReprFlags::IS_SCALABLE) + } + #[inline] pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) @@ -1736,6 +1758,10 @@ impl AddressSpace { pub enum BackendRepr { Scalar(Scalar), ScalarPair(Scalar, Scalar), + ScalableVector { + element: Scalar, + count: u64, + }, SimdVector { element: Scalar, count: u64, @@ -1754,6 +1780,9 @@ impl BackendRepr { match *self { BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) + // FIXME(repr_scalable): Scalable vectors are `Sized` while the `sized_hierarchy` + // feature is not yet fully implemented + | BackendRepr::ScalableVector { .. } | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => !sized, } @@ -1794,7 +1823,9 @@ impl BackendRepr { BackendRepr::Scalar(s) => Some(s.align(cx).abi), BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi), // The align of a Vector can vary in surprising ways - BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None, + BackendRepr::SimdVector { .. } + | BackendRepr::Memory { .. } + | BackendRepr::ScalableVector { .. } => None, } } @@ -1816,7 +1847,9 @@ impl BackendRepr { Some(size) } // The size of a Vector can vary in surprising ways - BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None, + BackendRepr::SimdVector { .. } + | BackendRepr::Memory { .. } + | BackendRepr::ScalableVector { .. } => None, } } @@ -1831,6 +1864,9 @@ impl BackendRepr { BackendRepr::SimdVector { element: element.to_union(), count } } BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true }, + BackendRepr::ScalableVector { element, count } => { + BackendRepr::ScalableVector { element: element.to_union(), count } + } } } @@ -2071,7 +2107,9 @@ impl LayoutData { /// Returns `true` if this is an aggregate type (including a ScalarPair!) pub fn is_aggregate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => false, + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => false, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, } } @@ -2165,6 +2203,19 @@ impl LayoutData { self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1 } + /// Returns `true` if the size of the type is only known at runtime. + pub fn is_runtime_sized(&self) -> bool { + matches!(self.backend_repr, BackendRepr::ScalableVector { .. }) + } + + /// Returns the elements count of a scalable vector. + pub fn scalable_vector_element_count(&self) -> Option { + match self.backend_repr { + BackendRepr::ScalableVector { count, .. } => Some(count), + _ => None, + } + } + /// Returns `true` if the type is a ZST and not unsized. /// /// Note that this does *not* imply that the type is irrelevant for layout! It can still have @@ -2173,6 +2224,7 @@ impl LayoutData { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) + | BackendRepr::ScalableVector { .. } | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 9bdbcf6ab9071..e40e35534905f 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -265,6 +265,8 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc} +ast_passes_scalable_vector_not_tuple_struct = scalable vectors must be tuple structs + ast_passes_static_without_body = free static item without body .suggestion = provide a definition for the static diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 163dbc3350ba2..30051b5e30c2b 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1298,6 +1298,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Struct(ident, generics, vdata) => { self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| { + // Scalable vectors can only be tuple structs + let is_scalable_vector = + item.attrs.iter().any(|attr| attr.has_name(sym::rustc_scalable_vector)); + if is_scalable_vector && !matches!(vdata, VariantData::Tuple(..)) { + this.dcx() + .emit_err(errors::ScalableVectorNotTupleStruct { span: item.span }); + } + match vdata { VariantData::Struct { fields, .. } => { this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 02e6ecfbaee74..0087167090c4d 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -974,3 +974,10 @@ pub(crate) struct AbiX86Interrupt { pub spans: Vec, pub param_count: usize, } + +#[derive(Diagnostic)] +#[diag(ast_passes_scalable_vector_not_tuple_struct)] +pub(crate) struct ScalableVectorNotTupleStruct { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 455c61097d78d..50300d655d615 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -76,3 +76,27 @@ impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?)) } } + +pub(crate) struct RustcScalableVectorParser; + +impl SingleAttributeParser for RustcScalableVectorParser { + const PATH: &[rustc_span::Symbol] = &[sym::rustc_scalable_vector]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); + const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if args.no_args().is_ok() { + return Some(AttributeKind::RustcScalableVector { + element_count: None, + span: cx.attr_span, + }); + } + + parse_single_integer(cx, args).map(|n| AttributeKind::RustcScalableVector { + element_count: Some(n), + span: cx.attr_span, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 99e6c748dbe90..890a70b9ab8b5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -57,7 +57,8 @@ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcMainParser, - RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser, + RustcObjectLifetimeDefaultParser, RustcScalableVectorParser, + RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ @@ -205,6 +206,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 132c43ef3cdad..87ef2680fda13 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -943,6 +943,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { .get_address(self.location) } + fn scalable_alloca(&mut self, _elt: u64, _align: Align, _element_ty: Ty<'_>) -> RValue<'gcc> { + todo!() + } + fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { let block = self.llbb(); let function = block.get_function(); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 8225df5686417..dc5254a401cef 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -531,7 +531,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, - SimdVector { .. } => false, + SimdVector { .. } | ScalableVector { .. } => false, Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 93202483eed81..034101b70da89 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -85,6 +85,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( ); } BackendRepr::Memory { .. } => {} + BackendRepr::ScalableVector { .. } => todo!(), } let name = match *layout.ty.kind() { @@ -178,7 +179,9 @@ pub trait LayoutGccExt<'tcx> { impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => true, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -188,6 +191,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::ScalarPair(..) => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index b10a1282f4dd0..7ac58c5b26f9b 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -613,6 +613,25 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } + fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value { + let mut bx = Builder::with_cx(self.cx); + bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) }); + let llvm_ty = match element_ty.kind() { + ty::Bool => bx.type_i1(), + ty::Int(int_ty) => self.cx.type_int_from_ty(*int_ty), + ty::Uint(uint_ty) => self.cx.type_uint_from_ty(*uint_ty), + ty::Float(float_ty) => self.cx.type_float_from_ty(*float_ty), + _ => unreachable!("scalable vectors can only contain a bool, int, uint or float"), + }; + + unsafe { + let ty = llvm::LLVMScalableVectorType(llvm_ty, elt.try_into().unwrap()); + let alloca = llvm::LLVMBuildAlloca(&bx.llbuilder, ty, UNNAMED); + llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); + alloca + } + } + fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value { unsafe { let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 029c43e0ba82e..22cde2bca2347 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -458,6 +458,14 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, SimdVector { .. } => false, + ScalableVector { .. } => { + tcx.dcx().emit_err(InvalidMonomorphization::NonScalableType { + span, + name: sym::raw_eq, + ty: tp_ty, + }); + return Ok(()); + } Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), @@ -1406,6 +1414,20 @@ fn generic_simd_intrinsic<'ll, 'tcx>( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } + if name == sym::simd_reinterpret { + require_simd!(ret_ty, SimdReturn); + + return Ok(match args[0].val { + OperandValue::Ref(PlaceValue { llval: val, .. }) | OperandValue::Immediate(val) => { + bx.bitcast(val, llret_ty) + } + OperandValue::ZeroSized => bx.const_undef(llret_ty), + OperandValue::Pair(_, _) => { + return_error!(InvalidMonomorphization::NonScalableType { span, name, ty: ret_ty }) + } + }); + } + // every intrinsic below takes a SIMD vector as its first argument let (in_len, in_elem) = require_simd!(args[0].layout.ty, SimdInput); let in_ty = args[0].layout.ty; @@ -1601,11 +1623,27 @@ fn generic_simd_intrinsic<'ll, 'tcx>( m_len == v_len, InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len } ); - let in_elem_bitwidth = require_int_or_uint_ty!( - m_elem_ty.kind(), - InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty } - ); - let m_i1s = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len); + + let m_i1s = if args[1].layout.ty.is_scalable_vector() { + match m_elem_ty.kind() { + ty::Bool => {} + _ => return_error!(InvalidMonomorphization::MaskWrongElementType { + span, + name, + ty: m_elem_ty + }), + }; + let i1 = bx.type_i1(); + let i1xn = bx.type_scalable_vector(i1, m_len as u64); + bx.trunc(args[0].immediate(), i1xn) + } else { + let in_elem_bitwidth = require_int_or_uint_ty!( + m_elem_ty.kind(), + InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty } + ); + vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len) + }; + return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 09978dc6f873d..40b523d5faf64 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -998,6 +998,7 @@ unsafe extern "C" { // Operations on array, pointer, and vector types (sequence types) pub(crate) safe fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type; pub(crate) fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; + pub(crate) fn LLVMScalableVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; pub(crate) fn LLVMGetElementType(Ty: &Type) -> &Type; pub(crate) fn LLVMGetVectorSize(VectorTy: &Type) -> c_uint; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 55f053f4fad3f..83d7fa0c91535 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -68,6 +68,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { unsafe { llvm::LLVMVectorType(ty, len as c_uint) } } + pub(crate) fn type_scalable_vector(&self, ty: &'ll Type, count: u64) -> &'ll Type { + unsafe { llvm::LLVMScalableVectorType(ty, count as c_uint) } + } + pub(crate) fn add_func(&self, name: &str, ty: &'ll Type) -> &'ll Value { let name = SmallCStr::new(name); unsafe { llvm::LLVMAddFunction(self.llmod(), name.as_ptr(), ty) } diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 2b2ac1c6eb29f..1ed06fbd28219 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -24,6 +24,15 @@ fn uncached_llvm_type<'a, 'tcx>( let element = layout.scalar_llvm_type_at(cx, element); return cx.type_vector(element, count); } + BackendRepr::ScalableVector { ref element, count } => { + let element = if element.is_bool() { + cx.type_i1() + } else { + layout.scalar_llvm_type_at(cx, *element) + }; + + return cx.type_scalable_vector(element, count); + } BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {} } @@ -176,7 +185,9 @@ pub(crate) trait LayoutLlvmExt<'tcx> { impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => true, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -186,6 +197,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::ScalarPair(..) => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index add25da025b2d..8d77c25bbf907 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -549,7 +549,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( registers_for_primitive(scalar1.primitive()); registers_for_primitive(scalar2.primitive()); } - BackendRepr::SimdVector { .. } => { + BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { // Because no instance of VaArgSafe uses a non-scalar `BackendRepr`. unreachable!( "No x86-64 SysV va_arg implementation for {:?}", @@ -689,7 +689,9 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( } } // The Previous match on `BackendRepr` means control flow already escaped. - BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => unreachable!(), + BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } + | BackendRepr::Memory { .. } => unreachable!(), }; // AMD64-ABI 3.5.7p5: Step 5. Set: diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index e321b0773ec39..6375f47f87b6e 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -129,6 +129,7 @@ codegen_ssa_invalid_monomorphization_mask_wrong_element_type = invalid monomorph codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` +codegen_ssa_invalid_monomorphization_non_scalable_type = invalid monomorphization of `{$name}` intrinsic: expected non-scalable type, found scalable type `{$ty}` codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 2dd7c6fa7c080..e1bcfb42d06d5 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1100,6 +1100,14 @@ pub enum InvalidMonomorphization<'tcx> { expected_element: Ty<'tcx>, vector_type: Ty<'tcx>, }, + + #[diag(codegen_ssa_invalid_monomorphization_non_scalable_type, code = E0511)] + NonScalableType { + #[primary_span] + span: Span, + name: Symbol, + ty: Ty<'tcx>, + }, } pub enum ExpectedPointerMutability { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 0c9acf087f9f3..f068a51f7d4a1 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -2,7 +2,7 @@ use std::collections::hash_map::Entry; use std::marker::PhantomData; use std::ops::Range; -use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, Size, VariantIdx}; +use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, ScalableElt, Size, VariantIdx}; use rustc_data_structures::fx::FxHashMap; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -408,6 +408,49 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } + // Don't spill `` for `N != 16`: + // + // SVE predicates are only one bit for each byte in an SVE vector (which makes + // sense, the predicate only needs to keep track of whether a lane is + // enabled/disabled). i.e. a `` vector has a `` + // predicate type. `` corresponds to two bytes of storage, + // multiplied by the `vscale`, with one bit for each of the sixteen lanes. + // + // For a vector with fewer elements, such as `svint32_t`/``, + // while only a `` predicate type would be strictly necessary, + // relevant intrinsics still take a `svbool_t`/`` - this is + // because a `` is only half of a byte (for `vscale=1`), and with + // memory being byte-addressable, it's unclear how to store that. + // + // Due to this, LLVM ultimately decided not to support stores of `` + // for `N != 16`. As for `vscale=1` and `N` fewer than sixteen, partial bytes would + // need to be stored (except for `N=8`, but that also isn't supported). `N` can + // never be greater than sixteen as that ends up larger than the 128-bit increment + // size. + // + // Internally, with an intrinsic operating on a `svint32_t`/`` + // (for example), the intrinsic takes the `svbool_t`/`` predicate + // and casts it to a `svbool4_t`/``. Therefore, it's important that + // the `` never spills because that'll cause errors during + // instruction selection. Spilling to the stack to create debuginfo for these + // intermediate values must be avoided and won't degrade the debugging experience + // anyway. + if operand.layout.ty.is_scalable_vector() + && bx.sess().target.arch == rustc_target::spec::Arch::AArch64 + && let ty::Adt(adt, args) = &operand.layout.ty.kind() + && let Some(marker_type_field) = + adt.non_enum_variant().fields.get(FieldIdx::from_u32(0)) + { + let marker_type = marker_type_field.ty(bx.tcx(), args); + // i.e. `` when `N != 16` + if let ty::Slice(element_ty) = marker_type.kind() + && element_ty.is_bool() + && adt.repr().scalable != Some(ScalableElt::ElementCount(16)) + { + return; + } + } + Self::spill_operand_to_stack(*operand, name, bx) } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 5a139702f81d9..6fd118a60d4d9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -405,7 +405,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { imm } } - BackendRepr::ScalarPair(_, _) | BackendRepr::Memory { .. } => bug!(), + BackendRepr::ScalarPair(_, _) + | BackendRepr::Memory { .. } + | BackendRepr::ScalableVector { .. } => bug!(), }) }; @@ -692,7 +694,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> { BackendRepr::ScalarPair(a, b) => { OperandValueBuilder::Pair(Either::Right(a), Either::Right(b)) } - BackendRepr::SimdVector { .. } => OperandValueBuilder::Vector(Either::Right(())), + BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { + OperandValueBuilder::Vector(Either::Right(())) + } BackendRepr::Memory { .. } => { bug!("Cannot use non-ZST Memory-ABI type in operand builder: {layout:?}"); } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 50f56f913a51e..d62e622b6fed3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -109,7 +109,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, layout: TyAndLayout<'tcx>, ) -> Self { - Self::alloca_size(bx, layout.size, layout) + if layout.is_runtime_sized() { + Self::alloca_runtime_sized(bx, layout) + } else { + Self::alloca_size(bx, layout.size, layout) + } } pub fn alloca_size>( @@ -146,6 +150,18 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bug!("unexpected layout `{:#?}` in PlaceRef::len", self.layout) } } + + fn alloca_runtime_sized>( + bx: &mut Bx, + layout: TyAndLayout<'tcx>, + ) -> Self { + let (element_count, ty) = layout.ty.scalable_vector_element_count_and_type(bx.tcx()); + PlaceValue::new_sized( + bx.scalable_alloca(element_count as u64, layout.align.abi, ty), + layout.align.abi, + ) + .with_type(layout) + } } impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index f57f9108f744b..4f45c614e0030 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -235,6 +235,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value; fn alloca(&mut self, size: Size, align: Align) -> Self::Value; + fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value; fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value; fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 89a3303eb3902..a2c75068ac672 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1321,7 +1321,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, self.visit_scalar(b, b_layout)?; } } - BackendRepr::SimdVector { .. } => { + BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { // No checks here, we assume layout computation gets this right. // (This is harder to check since Miri does not represent these as `Immediate`. We // also cannot use field projections since this might be a newtype around a vector.) diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 34bd8423e8e15..939f9151680bb 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -119,7 +119,9 @@ fn check_validity_requirement_lax<'tcx>( } BackendRepr::SimdVector { element: s, count } => count == 0 || scalar_allows_raw_init(s), BackendRepr::Memory { .. } => true, // Fields are checked below. + BackendRepr::ScalableVector { element, .. } => scalar_allows_raw_init(element), }; + if !valid { // This is definitely not okay. return Ok(false); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c1e947720452c..325add3c1169c 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1412,6 +1412,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes, "`#[rustc_force_inline]` forces a free function to be inlined" ), + rustc_attr!( + rustc_scalable_vector, Normal, template!(List: &["count"]), WarnFollowing, EncodeCrossCrate::Yes, + "`#[rustc_scalable_vector]` defines a scalable vector type" + ), // ========================================================================== // Internal attributes, Testing: diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 708210ac6c6e4..562e51f72df9f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -701,6 +701,14 @@ pub enum AttributeKind { /// Represents `#[rustc_pass_indirectly_in_non_rustic_abis]` RustcPassIndirectlyInNonRusticAbis(Span), + /// Represents `#[rustc_scalable_vector(N)]` + RustcScalableVector { + /// The base multiple of lanes that are in a scalable vector, if provided. `element_count` + /// is not provided for representing tuple types. + element_count: Option, + span: Span, + }, + /// Represents `#[rustc_should_not_be_called_on_const_items]` RustcShouldNotBeCalledOnConstItems(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 74fc6c6af009e..39513b82f371d 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -91,6 +91,7 @@ impl AttributeKind { RustcMain => No, RustcObjectLifetimeDefault => No, RustcPassIndirectlyInNonRusticAbis(..) => No, + RustcScalableVector { .. } => Yes, RustcShouldNotBeCalledOnConstItems(..) => Yes, RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate Sanitize { .. } => No, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index e124dfeb72840..33d2621ef2e47 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1,7 +1,7 @@ use std::cell::LazyCell; use std::ops::ControlFlow; -use rustc_abi::{ExternAbi, FieldIdx}; +use rustc_abi::{ExternAbi, FieldIdx, ScalableElt}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{EmissionGuarantee, MultiSpan}; @@ -92,7 +92,9 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { let span = tcx.def_span(def_id); def.destructor(tcx); // force the destructor to be evaluated - if def.repr().simd() { + if let Some(scalable) = def.repr().scalable { + check_scalable_vector(tcx, span, def_id, scalable); + } else if def.repr().simd() { check_simd(tcx, span, def_id); } @@ -1425,6 +1427,83 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { } } +#[tracing::instrument(skip(tcx), level = "debug")] +fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalable: ScalableElt) { + let ty = tcx.type_of(def_id).instantiate_identity(); + let ty::Adt(def, args) = ty.kind() else { return }; + if !def.is_struct() { + tcx.dcx().delayed_bug("`rustc_scalable_vector` applied to non-struct"); + return; + } + + let fields = &def.non_enum_variant().fields; + match scalable { + ScalableElt::ElementCount(..) if fields.is_empty() => { + let mut err = + tcx.dcx().struct_span_err(span, "scalable vectors must have a single field"); + err.help("scalable vector types' only field must be a primitive scalar type"); + err.emit(); + return; + } + ScalableElt::ElementCount(..) if fields.len() >= 2 => { + tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit(); + return; + } + ScalableElt::Container if fields.is_empty() => { + let mut err = + tcx.dcx().struct_span_err(span, "scalable vectors must have a single field"); + err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type"); + err.emit(); + return; + } + _ => {} + } + + match scalable { + ScalableElt::ElementCount(..) => { + let element_ty = &fields[FieldIdx::ZERO].ty(tcx, args); + + // Check that `element_ty` only uses types valid in the lanes of a scalable vector + // register: scalar types which directly match a "machine" type - integers, floats and + // bools + match element_ty.kind() { + ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Bool => (), + _ => { + let mut err = tcx.dcx().struct_span_err( + span, + "element type of a scalable vector must be a primitive scalar", + ); + err.help( + "only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted", + ); + err.emit(); + } + } + } + ScalableElt::Container => { + let mut prev_field_ty = None; + for field in fields.iter() { + let element_ty = field.ty(tcx, args); + if let ty::Adt(def, _) = element_ty.kind() + && !def.repr().scalable() + { + tcx.dcx().span_err( + tcx.def_span(field.did), + "scalable vector structs can only have scalable vector fields", + ); + } else if let Some(prev_ty) = prev_field_ty.replace(element_ty) + && prev_ty != element_ty + { + tcx.dcx().span_err( + tcx.def_span(field.did), + "all fields in a scalable vector struct must be the same type", + ); + } + } + } + } +} + pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 8a505668d0dad..96b4b6fa5e9ff 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -709,6 +709,7 @@ pub(crate) fn check_intrinsic_type( } sym::simd_cast | sym::simd_as + | sym::simd_reinterpret | sym::simd_cast_ptr | sym::simd_expose_provenance | sym::simd_with_exposed_provenance => (2, 0, vec![param(0)], param(1)), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index ccae524352a59..6c849095f0ea7 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2,7 +2,7 @@ use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; -use rustc_abi::ExternAbi; +use rustc_abi::{ExternAbi, ScalableElt}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; @@ -1037,7 +1037,21 @@ fn check_type_defn<'tcx>( hir_ty.span, Some(WellFormedLoc::Ty(field_id)), ty.into(), - ) + ); + + if matches!(ty.kind(), ty::Adt(def, _) if def.repr().scalable()) + && !matches!(adt_def.repr().scalable, Some(ScalableElt::Container)) + { + // Scalable vectors can only be fields of structs if the type has an + // `rustc_scalable_vector` attribute w/out specifying an element count + tcx.dcx().span_err( + hir_ty.span, + format!( + "scalable vectors cannot be fields of a {}", + adt_def.variant_descr() + ), + ); + } } // For DST, or when drop needs to copy things around, all diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d3914d2aee74c..d121b1c145562 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -24,7 +24,9 @@ pub use assoc::*; pub use generic_args::{GenericArgKind, TermKind, *}; pub use generics::*; pub use intrinsic::IntrinsicDef; -use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; +use rustc_abi::{ + Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, ScalableElt, VariantIdx, +}; use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; @@ -1512,6 +1514,17 @@ impl<'tcx> TyCtxt<'tcx> { } let attributes = self.get_all_attrs(did); + let elt = find_attr!( + attributes, + AttributeKind::RustcScalableVector { element_count, .. } => element_count + ) + .map(|elt| match elt { + Some(n) => ScalableElt::ElementCount(*n), + None => ScalableElt::Container, + }); + if elt.is_some() { + flags.insert(ReprFlags::IS_SCALABLE); + } if let Some(reprs) = find_attr!(attributes, AttributeKind::Repr { reprs, .. } => reprs) { for (r, _) in reprs { flags.insert(match *r { @@ -1576,7 +1589,14 @@ impl<'tcx> TyCtxt<'tcx> { flags.insert(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS); } - ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed } + ReprOptions { + int: size, + align: max_align, + pack: min_pack, + flags, + field_shuffle_seed, + scalable: elt, + } } /// Look up the name of a definition across crates. This does not look at HIR. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d8f16ef5561db..55e87a3071719 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -7,7 +7,7 @@ use std::borrow::Cow; use std::ops::{ControlFlow, Range}; use hir::def::{CtorKind, DefKind}; -use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx}; +use rustc_abi::{FIRST_VARIANT, FieldIdx, ScalableElt, VariantIdx}; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::LangItem; @@ -1257,6 +1257,14 @@ impl<'tcx> Ty<'tcx> { } } + #[inline] + pub fn is_scalable_vector(self) -> bool { + match self.kind() { + Adt(def, _) => def.repr().scalable(), + _ => false, + } + } + pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { Array(ty, _) | Slice(ty) => *ty, @@ -1265,6 +1273,19 @@ impl<'tcx> Ty<'tcx> { } } + pub fn scalable_vector_element_count_and_type(self, tcx: TyCtxt<'tcx>) -> (u128, Ty<'tcx>) { + let Adt(def, args) = self.kind() else { + bug!("`scalable_vector_size_and_type` called on invalid type") + }; + let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else { + bug!("`scalable_vector_size_and_type` called on non-scalable vector type"); + }; + let variant = def.non_enum_variant(); + assert_eq!(variant.fields.len(), 1); + let field_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args); + (element_count, field_ty) + } + pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { let Adt(def, args) = self.kind() else { bug!("`simd_size_and_type` called on invalid type") diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 072733c97efb1..c4739a8d37e90 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1891,6 +1891,11 @@ fn check_must_not_suspend_ty<'tcx>( SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data }, ) } + ty::Adt(def, _) if def.repr().scalable() => { + tcx.dcx() + .span_err(data.source_span, "scalable vectors cannot be held over await points"); + true + } ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data), // FIXME: support adding the attribute to TAITs ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index d9c26faaf4455..532024ed6343d 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1662,7 +1662,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { BackendRepr::ScalarPair(a, b) => { !a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx) } - BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => false, + BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } + | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index bfb2edf286a20..edb91d8f2eda1 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -2,7 +2,10 @@ monomorphize_abi_error_disabled_vector_type = this function {$is_call -> [true] call *[false] definition - } uses SIMD vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call -> + } uses {$is_scalable -> + [true] scalable + *[false] SIMD + } vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call -> [true] {" "}in the caller *[false] {""} } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index a5040ef22dd03..4949d9ae3922d 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -78,6 +78,8 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> { pub ty: Ty<'a>, /// Whether this is a problem at a call site or at a declaration. pub is_call: bool, + /// Whether this is a problem with a fixed length vector or a scalable vector + pub is_scalable: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 2ee77e9deb0d3..66255a942ec73 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -10,14 +10,37 @@ use rustc_target::callconv::{FnAbi, PassMode}; use crate::errors; -fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool { +/// Are vector registers used? +enum UsesVectorRegisters { + /// e.g. `neon` + FixedVector, + /// e.g. `sve` + ScalableVector, + No, +} + +/// Determines whether the combination of `mode` and `repr` will use fixed vector registers, +/// scalable vector registers or no vector registers. +fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters { match mode { - PassMode::Ignore | PassMode::Indirect { .. } => false, - PassMode::Cast { pad_i32: _, cast } => { - cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector)) - || cast.rest.unit.kind == RegKind::Vector + PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No, + PassMode::Cast { pad_i32: _, cast } + if cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector)) + || cast.rest.unit.kind == RegKind::Vector => + { + UsesVectorRegisters::FixedVector + } + PassMode::Direct(..) | PassMode::Pair(..) + if matches!(repr, BackendRepr::SimdVector { .. }) => + { + UsesVectorRegisters::FixedVector } - PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::SimdVector { .. }), + PassMode::Direct(..) | PassMode::Pair(..) + if matches!(repr, BackendRepr::ScalableVector { .. }) => + { + UsesVectorRegisters::ScalableVector + } + _ => UsesVectorRegisters::No, } } @@ -32,37 +55,60 @@ fn do_check_simd_vector_abi<'tcx>( is_call: bool, loc: impl Fn() -> (Span, HirId), ) { - let feature_def = tcx.sess.target.features_for_correct_vector_abi(); let codegen_attrs = tcx.codegen_fn_attrs(def_id); let have_feature = |feat: Symbol| { - tcx.sess.unstable_target_features.contains(&feat) - || codegen_attrs.target_features.iter().any(|x| x.name == feat) + let target_feats = tcx.sess.unstable_target_features.contains(&feat); + let fn_feats = codegen_attrs.target_features.iter().any(|x| x.name == feat); + target_feats || fn_feats }; for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) { let size = arg_abi.layout.size; - if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) { - // Find the first feature that provides at least this vector size. - let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { - Some((_, feature)) => feature, - None => { + match uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) { + UsesVectorRegisters::FixedVector => { + let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi(); + // Find the first feature that provides at least this vector size. + let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { + Some((_, feature)) => feature, + None => { + let (span, _hir_id) = loc(); + tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType { + span, + ty: arg_abi.layout.ty, + is_call, + }); + continue; + } + }; + if !have_feature(Symbol::intern(feature)) { let (span, _hir_id) = loc(); - tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType { + tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType { span, + required_feature: feature, ty: arg_abi.layout.ty, is_call, + is_scalable: false, }); + } + } + UsesVectorRegisters::ScalableVector => { + let Some(required_feature) = + tcx.sess.target.features_for_correct_scalable_vector_abi() + else { continue; + }; + if !have_feature(Symbol::intern(required_feature)) { + let (span, _) = loc(); + tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType { + span, + required_feature, + ty: arg_abi.layout.ty, + is_call, + is_scalable: true, + }); } - }; - if !have_feature(Symbol::intern(feature)) { - // Emit error. - let (span, _hir_id) = loc(); - tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType { - span, - required_feature: feature, - ty: arg_abi.layout.ty, - is_call, - }); + } + UsesVectorRegisters::No => { + continue; } } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 58e55211c671c..e5524f13445c4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -253,6 +253,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::MacroEscape( .. ) | AttributeKind::RustcLayoutScalarValidRangeStart(..) | AttributeKind::RustcLayoutScalarValidRangeEnd(..) + | AttributeKind::RustcScalableVector { .. } | AttributeKind::RustcSimdMonomorphizeLaneLimit(..) | AttributeKind::RustcShouldNotBeCalledOnConstItems(..) | AttributeKind::ExportStable diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index 820c41acf5b23..7afd7231924a3 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -225,6 +225,10 @@ pub enum ValueAbi { element: Scalar, count: u64, }, + ScalableVector { + element: Scalar, + count: u64, + }, Aggregate { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, @@ -235,7 +239,12 @@ impl ValueAbi { /// Returns `true` if the layout corresponds to an unsized type. pub fn is_unsized(&self) -> bool { match *self { - ValueAbi::Scalar(_) | ValueAbi::ScalarPair(..) | ValueAbi::Vector { .. } => false, + ValueAbi::Scalar(_) + | ValueAbi::ScalarPair(..) + | ValueAbi::Vector { .. } + // FIXME(repr_scalable): Scalable vectors are `Sized` while the `sized_hierarchy` + // feature is not yet fully implemented + | ValueAbi::ScalableVector { .. } => false, ValueAbi::Aggregate { sized } => !sized, } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index 782e75a930e07..03328d084ee94 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -256,6 +256,9 @@ impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { rustc_abi::BackendRepr::SimdVector { element, count } => { ValueAbi::Vector { element: element.stable(tables, cx), count } } + rustc_abi::BackendRepr::ScalableVector { element, count } => { + ValueAbi::ScalableVector { element: element.stable(tables, cx), count } + } rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized }, } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cd730ede4ba1f..78297a47423f3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1985,6 +1985,7 @@ symbols! { rustc_reallocator, rustc_regions, rustc_reservation_impl, + rustc_scalable_vector, rustc_serialize, rustc_should_not_be_called_on_const_items, rustc_simd_monomorphize_lane_limit, @@ -2097,6 +2098,7 @@ symbols! { simd_reduce_mul_unordered, simd_reduce_or, simd_reduce_xor, + simd_reinterpret, simd_relaxed_fma, simd_rem, simd_round, diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index bbea841b41069..3f0c61ff8df4e 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -85,7 +85,10 @@ where } } }, - BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv), + BackendRepr::SimdVector { .. } => { + return Err(CannotUseFpConv); + } + BackendRepr::ScalableVector { .. } => unreachable!(), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 8783401435827..092d99e911188 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -393,6 +393,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { ), BackendRepr::SimdVector { .. } => PassMode::Direct(ArgAttributes::new()), BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout), + BackendRepr::ScalableVector { .. } => PassMode::Direct(ArgAttributes::new()), }; ArgAbi { layout, mode } } diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index c4310bf6ccfb0..f166b83305165 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -91,7 +91,9 @@ where } } }, - BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv), + BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { + return Err(CannotUseFpConv); + } BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 93dc60dc1593e..63df9bb8c4ed6 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -103,6 +103,9 @@ where } false } + BackendRepr::ScalableVector { .. } => { + unreachable!("scalable vectors are unsupported") + } } } diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 04eecbfbc8dd6..8fab4e444228c 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -59,6 +59,8 @@ where BackendRepr::SimdVector { .. } => Class::Sse, + BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"), + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { let field_off = off + layout.fields.offset(i); diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index 85ee59eabc7c4..23ce394426e64 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -25,6 +25,7 @@ where // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } + BackendRepr::ScalableVector { .. } => unreachable!("scalable vectors are unsupported"), BackendRepr::Scalar(scalar) => { if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) { if cx.target_spec().rustc_abi == Some(RustcAbi::X86Softfloat) { diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 990928774731c..cefe288c3dc7c 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -911,17 +911,22 @@ pub fn all_rust_features() -> impl Iterator { // These arrays represent the least-constraining feature that is required for vector types up to a // certain size to have their "proper" ABI on each architecture. // Note that they must be kept sorted by vector size. -const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = +const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10. -const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")]; +const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "neon")]; // We might want to add "helium" too. -const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")]; +const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "neon")]; -const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")]; -const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")]; -const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")]; -const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[ +const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "altivec")]; +const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "simd128")]; +const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "vector")]; +const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[ (32, "zvl32b"), (64, "zvl64b"), (128, "zvl128b"), @@ -936,13 +941,16 @@ const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[ (65536, "zvl65536b"), ]; // Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment. -const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/]; +const SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[/*(64, "vis")*/]; -const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = +const HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")]; -const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")]; -const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")]; -const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = +const MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "msa")]; +const CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "vdspv1")]; +const LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "lsx"), (256, "lasx")]; #[derive(Copy, Clone, Debug)] @@ -981,23 +989,25 @@ impl Target { } } - pub fn features_for_correct_vector_abi(&self) -> &'static [(u64, &'static str)] { + pub fn features_for_correct_fixed_length_vector_abi(&self) -> &'static [(u64, &'static str)] { match &self.arch { - Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_VECTOR_ABI, - Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI, - Arch::Arm => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI, - Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI, - Arch::LoongArch32 | Arch::LoongArch64 => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI, - Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI, - Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI, - Arch::S390x => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI, - Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI, - Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI, + Arch::X86 | Arch::X86_64 => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + Arch::AArch64 | Arch::Arm64EC => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + Arch::Arm => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + Arch::PowerPC | Arch::PowerPC64 => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + Arch::LoongArch32 | Arch::LoongArch64 => { + LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI + } + Arch::RiscV32 | Arch::RiscV64 => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + Arch::Wasm32 | Arch::Wasm64 => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + Arch::S390x => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + Arch::Sparc | Arch::Sparc64 => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + Arch::Hexagon => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => { - MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI + MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI } Arch::Nvptx64 | Arch::Bpf | Arch::M68k => &[], // no vector ABI - Arch::CSky => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI, + Arch::CSky => CSKY_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, // FIXME: for some tier3 targets, we are overly cautious and always give warnings // when passing args in vector registers. Arch::AmdGpu @@ -1010,6 +1020,14 @@ impl Target { } } + pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> { + match &self.arch { + Arch::AArch64 | Arch::Arm64EC => Some("sve"), + // Other targets have no scalable vectors or they are unimplemented. + _ => None, + } + } + pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] { match &self.arch { Arch::AArch64 | Arch::Arm64EC => AARCH64_TIED_FEATURES, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index db7bd635f32e6..394095508393c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -771,9 +771,25 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } ty::Tuple(tys) => { - if let Some((_last, rest)) = tys.split_last() { + if let Some((last, rest)) = tys.split_last() { for &elem in rest { self.require_sized(elem, ObligationCauseCode::TupleElem); + if elem.is_scalable_vector() && !self.span.is_dummy() { + self.tcx() + .dcx() + .struct_span_err( + self.span, + "scalable vectors cannot be tuple fields", + ) + .emit(); + } + } + + if last.is_scalable_vector() && !self.span.is_dummy() { + self.tcx() + .dcx() + .struct_span_err(self.span, "scalable vectors cannot be tuple fields") + .emit(); } } } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index f98f161e80938..78deee92bba5e 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -407,7 +407,9 @@ fn fn_abi_sanity_check<'tcx>( // `layout.backend_repr` and ignore everything else. We should just reject //`Aggregate` entirely here, but some targets need to be fixed first. match arg.layout.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => {} + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => {} BackendRepr::ScalarPair(..) => { panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty) } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 3a935b917ea2d..6962eeddf1370 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -3,8 +3,8 @@ use rustc_abi::Integer::{I8, I32}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout, - LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, - VariantIdx, Variants, WrappingRange, + LayoutCalculatorError, LayoutData, Niche, ReprOptions, ScalableElt, Scalar, Size, StructKind, + TagEncoding, VariantIdx, Variants, WrappingRange, }; use rustc_hashes::Hash64; use rustc_hir::attrs::AttributeKind; @@ -567,6 +567,37 @@ fn layout_of_uncached<'tcx>( univariant(tys, kind)? } + // Scalable vector types + // + // ```rust (ignore, example) + // #[rustc_scalable_vector(3)] + // struct svuint32_t(u32); + // ``` + ty::Adt(def, args) + if matches!(def.repr().scalable, Some(ScalableElt::ElementCount(..))) => + { + let Some(element_ty) = def + .is_struct() + .then(|| &def.variant(FIRST_VARIANT).fields) + .filter(|fields| fields.len() == 1) + .map(|fields| fields[FieldIdx::ZERO].ty(tcx, args)) + else { + let guar = tcx + .dcx() + .delayed_bug("#[rustc_scalable_vector] was applied to an invalid type"); + return Err(error(cx, LayoutError::ReferencesError(guar))); + }; + let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else { + let guar = tcx + .dcx() + .delayed_bug("#[rustc_scalable_vector] was applied to an invalid type"); + return Err(error(cx, LayoutError::ReferencesError(guar))); + }; + + let element_layout = cx.layout_of(element_ty)?; + map_layout(cx.calc.scalable_vector_type(element_layout, element_count as u64))? + } + // SIMD vector types. ty::Adt(def, args) if def.repr().simd() => { // Supported SIMD vectors are ADTs with a single array field: diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index d1484aed16718..a7c5e4c22f3e9 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -250,7 +250,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou // And the size has to be element * count plus alignment padding, of course assert!(size == (element_size * count).align_to(align)); } - BackendRepr::Memory { .. } => {} // Nothing to check. + BackendRepr::Memory { .. } | BackendRepr::ScalableVector { .. } => {} // Nothing to check. } } diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 722a765cd01ee..c3da654be7f3c 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -218,6 +218,11 @@ pub const unsafe fn simd_cast(x: T) -> U; #[rustc_nounwind] pub const unsafe fn simd_as(x: T) -> U; +/// Replacement for `transmute`, specifically for use with scalable SIMD types. +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn simd_reinterpret(src: Src) -> Dst; + /// Negates a vector elementwise. /// /// `T` must be a vector of integers or floats. diff --git a/tests/codegen-llvm/scalable-vectors/simple.rs b/tests/codegen-llvm/scalable-vectors/simple.rs new file mode 100644 index 0000000000000..04ef911d44e63 --- /dev/null +++ b/tests/codegen-llvm/scalable-vectors/simple.rs @@ -0,0 +1,49 @@ +//@ edition: 2021 +//@ only-aarch64 +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features)] +#![feature(simd_ffi, rustc_attrs, link_llvm_intrinsics)] + +#[derive(Copy, Clone)] +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +pub struct svint32_t(i32); + +#[inline(never)] +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; + } + unsafe { _svdup_n_s32(op) } +} + +#[inline] +#[target_feature(enable = "sve,sve2")] +pub unsafe fn svxar_n_s32(op1: svint32_t, op2: svint32_t) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.xar.nxv4i32")] + fn _svxar_n_s32(op1: svint32_t, op2: svint32_t, imm3: i32) -> svint32_t; + } + unsafe { _svxar_n_s32(op1, op2, IMM3) } +} + +#[inline(never)] +#[no_mangle] +#[target_feature(enable = "sve,sve2")] +// CHECK: define @pass_as_ref(ptr {{.*}}align 16{{.*}} %a, %b) +pub unsafe fn pass_as_ref(a: &svint32_t, b: svint32_t) -> svint32_t { + // CHECK: load , ptr %a, align 16 + svxar_n_s32::<1>(*a, b) +} + +#[no_mangle] +#[target_feature(enable = "sve,sve2")] +// CHECK: define @test() +pub unsafe fn test() -> svint32_t { + let a = svdup_n_s32(1); + let b = svdup_n_s32(2); + // CHECK: %_0 = call @pass_as_ref(ptr {{.*}}align 16{{.*}} %a, splat (i32 2)) + pass_as_ref(&a, b) +} diff --git a/tests/ui/scalable-vectors/async.rs b/tests/ui/scalable-vectors/async.rs new file mode 100644 index 0000000000000..44970fc86a2ff --- /dev/null +++ b/tests/ui/scalable-vectors/async.rs @@ -0,0 +1,44 @@ +//@ only-aarch64 +//@ edition:2021 + +#![allow(incomplete_features, internal_features)] +#![feature( + core_intrinsics, + simd_ffi, + rustc_attrs, + link_llvm_intrinsics +)] + +use core::intrinsics::simd::simd_reinterpret; + +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +pub struct svint32_t(i32); + +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; + } + unsafe { _svdup_n_s32(op) } +} + +#[target_feature(enable = "sve")] +async fn another() -> i32 { + 42 +} + +#[no_mangle] +#[target_feature(enable = "sve")] +pub async fn test_function() { + unsafe { + let x = svdup_n_s32(1); //~ ERROR: scalable vectors cannot be held over await points + let temp = another().await; + let y: svint32_t = simd_reinterpret(x); + } +} + +fn main() { + let _ = unsafe { test_function() }; +} diff --git a/tests/ui/scalable-vectors/async.stderr b/tests/ui/scalable-vectors/async.stderr new file mode 100644 index 0000000000000..fa81c7b8ed4d1 --- /dev/null +++ b/tests/ui/scalable-vectors/async.stderr @@ -0,0 +1,8 @@ +error: scalable vectors cannot be held over await points + --> $DIR/async.rs:36:13 + | +LL | let x = svdup_n_s32(1); + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/scalable-vectors/closure-capture.rs b/tests/ui/scalable-vectors/closure-capture.rs new file mode 100644 index 0000000000000..d6a45f76e214d --- /dev/null +++ b/tests/ui/scalable-vectors/closure-capture.rs @@ -0,0 +1,51 @@ +//@ compile-flags: --crate-type=lib +//@ only-aarch64 + +#![allow(incomplete_features, internal_features)] +#![feature( + link_llvm_intrinsics, + rustc_attrs, + simd_ffi +)] + +#[derive(Copy, Clone)] +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +pub struct svint32_t(i32); + +#[inline(never)] +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; + } + unsafe { _svdup_n_s32(op) } +} + +#[inline] +#[target_feature(enable = "sve,sve2")] +pub unsafe fn svxar_n_s32(op1: svint32_t, op2: svint32_t) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.xar.nxv4i32")] + fn _svxar_n_s32(op1: svint32_t, op2: svint32_t, imm3: i32) -> svint32_t; + } + unsafe { _svxar_n_s32(op1, op2, IMM3) } +} + +#[inline(never)] +#[target_feature(enable = "sve,sve2")] +fn run(f: impl Fn() -> ()) { + f(); +} + +#[target_feature(enable = "sve,sve2")] +fn foo() { + unsafe { + let a = svdup_n_s32(42); + run(move || { +//~^ ERROR: scalable vectors cannot be tuple fields + svxar_n_s32::<2>(a, a); + }); + } +} diff --git a/tests/ui/scalable-vectors/closure-capture.stderr b/tests/ui/scalable-vectors/closure-capture.stderr new file mode 100644 index 0000000000000..ea53066988e56 --- /dev/null +++ b/tests/ui/scalable-vectors/closure-capture.stderr @@ -0,0 +1,8 @@ +error: scalable vectors cannot be tuple fields + --> $DIR/closure-capture.rs:46:9 + | +LL | run(move || { + | ^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/scalable-vectors/copy-clone.rs b/tests/ui/scalable-vectors/copy-clone.rs new file mode 100644 index 0000000000000..7576b6ec18dcb --- /dev/null +++ b/tests/ui/scalable-vectors/copy-clone.rs @@ -0,0 +1,31 @@ +//@ build-pass +//@ only-aarch64 +#![feature(simd_ffi, rustc_attrs, link_llvm_intrinsics)] + +#[derive(Copy, Clone)] +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +pub struct svint32_t(i32); + +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; +//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe + } + unsafe { _svdup_n_s32(op) } +} + +#[target_feature(enable = "sve")] +fn require_copy(t: T) {} + +#[target_feature(enable = "sve")] +fn test() { + unsafe { + let a = svdup_n_s32(1); + require_copy(a); + } +} + +fn main() {} diff --git a/tests/ui/scalable-vectors/copy-clone.stderr b/tests/ui/scalable-vectors/copy-clone.stderr new file mode 100644 index 0000000000000..8b07aba8e1c07 --- /dev/null +++ b/tests/ui/scalable-vectors/copy-clone.stderr @@ -0,0 +1,17 @@ +warning: `extern` block uses type `svint32_t`, which is not FFI-safe + --> $DIR/copy-clone.rs:14:37 + | +LL | fn _svdup_n_s32(op: i32) -> svint32_t; + | ^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/copy-clone.rs:8:1 + | +LL | pub struct svint32_t(i32); + | ^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(improper_ctypes)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/scalable-vectors/fn-trait.rs b/tests/ui/scalable-vectors/fn-trait.rs new file mode 100644 index 0000000000000..5203b5fa0efd7 --- /dev/null +++ b/tests/ui/scalable-vectors/fn-trait.rs @@ -0,0 +1,13 @@ +#![allow(internal_features)] +#![feature(rustc_attrs)] + +#[rustc_scalable_vector(4)] +pub struct ScalableSimdFloat(f32); + +unsafe fn test(f: T) +where + T: Fn(ScalableSimdFloat), //~ ERROR: scalable vectors cannot be tuple fields +{ +} + +fn main() {} diff --git a/tests/ui/scalable-vectors/fn-trait.stderr b/tests/ui/scalable-vectors/fn-trait.stderr new file mode 100644 index 0000000000000..4d00272dd1b5a --- /dev/null +++ b/tests/ui/scalable-vectors/fn-trait.stderr @@ -0,0 +1,8 @@ +error: scalable vectors cannot be tuple fields + --> $DIR/fn-trait.rs:9:8 + | +LL | T: Fn(ScalableSimdFloat), + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/scalable-vectors/illformed-element-type.rs b/tests/ui/scalable-vectors/illformed-element-type.rs new file mode 100644 index 0000000000000..469ca006f5e9b --- /dev/null +++ b/tests/ui/scalable-vectors/illformed-element-type.rs @@ -0,0 +1,93 @@ +//@ compile-flags: --crate-type=lib +#![allow(internal_features)] +#![feature(extern_types)] +#![feature(never_type)] +#![feature(rustc_attrs)] + +struct Foo; +enum Bar {} +union Baz { x: u16 } +extern "C" { + type Qux; +} + +#[rustc_scalable_vector(4)] +struct TyChar(char); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(2)] +struct TyConstPtr(*const u8); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(2)] +struct TyMutPtr(*mut u8); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TyStruct(Foo); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TyEnum(Bar); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TyUnion(Baz); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TyForeign(Qux); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TyArray([u32; 4]); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TySlice([u32]); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TyRef<'a>(&'a u32); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TyFnPtr(fn(u32) -> u32); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TyDyn(dyn std::io::Write); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TyNever(!); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +#[rustc_scalable_vector(4)] +struct TyTuple((u32, u32)); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +type ValidAlias = u32; +type InvalidAlias = String; + +#[rustc_scalable_vector(4)] +struct TyValidAlias(ValidAlias); + +#[rustc_scalable_vector(4)] +struct TyInvalidAlias(InvalidAlias); +//~^ ERROR: element type of a scalable vector must be a primitive scalar + +trait Tr { + type Valid; + type Invalid; +} + +impl Tr for () { + type Valid = u32; + type Invalid = String; +} + +struct TyValidProjection(<() as Tr>::Valid); + +struct TyInvalidProjection(<() as Tr>::Invalid); +// FIXME: element type of a scalable vector must be a primitive scalar diff --git a/tests/ui/scalable-vectors/illformed-element-type.stderr b/tests/ui/scalable-vectors/illformed-element-type.stderr new file mode 100644 index 0000000000000..2d059ed2e7a8c --- /dev/null +++ b/tests/ui/scalable-vectors/illformed-element-type.stderr @@ -0,0 +1,122 @@ +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:15:1 + | +LL | struct TyChar(char); + | ^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:19:1 + | +LL | struct TyConstPtr(*const u8); + | ^^^^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:23:1 + | +LL | struct TyMutPtr(*mut u8); + | ^^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:27:1 + | +LL | struct TyStruct(Foo); + | ^^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:31:1 + | +LL | struct TyEnum(Bar); + | ^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:35:1 + | +LL | struct TyUnion(Baz); + | ^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:39:1 + | +LL | struct TyForeign(Qux); + | ^^^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:43:1 + | +LL | struct TyArray([u32; 4]); + | ^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:47:1 + | +LL | struct TySlice([u32]); + | ^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:51:1 + | +LL | struct TyRef<'a>(&'a u32); + | ^^^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:55:1 + | +LL | struct TyFnPtr(fn(u32) -> u32); + | ^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:59:1 + | +LL | struct TyDyn(dyn std::io::Write); + | ^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:63:1 + | +LL | struct TyNever(!); + | ^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:67:1 + | +LL | struct TyTuple((u32, u32)); + | ^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed-element-type.rs:77:1 + | +LL | struct TyInvalidAlias(InvalidAlias); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: aborting due to 15 previous errors + diff --git a/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.rs b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.rs new file mode 100644 index 0000000000000..ef5a1f0a4f3ff --- /dev/null +++ b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.rs @@ -0,0 +1,25 @@ +//@ compile-flags: --crate-type=lib +#![allow(internal_features)] +#![feature(rustc_attrs)] + +#[rustc_scalable_vector(2)] +struct ValidI64(i64); + +#[rustc_scalable_vector(4)] +struct ValidI32(i32); + +#[rustc_scalable_vector] +struct Struct { x: ValidI64, y: ValidI64 } +//~^ ERROR: scalable vectors must be tuple structs + +#[rustc_scalable_vector] +struct DifferentVectorTypes(ValidI64, ValidI32); +//~^ ERROR: all fields in a scalable vector struct must be the same type + +#[rustc_scalable_vector] +struct NonVectorTypes(u32, u64); +//~^ ERROR: all fields in a scalable vector struct must be the same type + +#[rustc_scalable_vector] +struct SomeVectorTypes(ValidI64, u64); +//~^ ERROR: all fields in a scalable vector struct must be the same type diff --git a/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.stderr b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.stderr new file mode 100644 index 0000000000000..973cc024bc0dc --- /dev/null +++ b/tests/ui/scalable-vectors/illformed-tuples-of-scalable-vectors.stderr @@ -0,0 +1,26 @@ +error: scalable vectors must be tuple structs + --> $DIR/illformed-tuples-of-scalable-vectors.rs:12:1 + | +LL | struct Struct { x: ValidI64, y: ValidI64 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: all fields in a scalable vector struct must be the same type + --> $DIR/illformed-tuples-of-scalable-vectors.rs:16:39 + | +LL | struct DifferentVectorTypes(ValidI64, ValidI32); + | ^^^^^^^^ + +error: all fields in a scalable vector struct must be the same type + --> $DIR/illformed-tuples-of-scalable-vectors.rs:20:28 + | +LL | struct NonVectorTypes(u32, u64); + | ^^^ + +error: all fields in a scalable vector struct must be the same type + --> $DIR/illformed-tuples-of-scalable-vectors.rs:24:34 + | +LL | struct SomeVectorTypes(ValidI64, u64); + | ^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/scalable-vectors/illformed-within-types.rs b/tests/ui/scalable-vectors/illformed-within-types.rs new file mode 100644 index 0000000000000..81d960e4d4e1a --- /dev/null +++ b/tests/ui/scalable-vectors/illformed-within-types.rs @@ -0,0 +1,23 @@ +//@ compile-flags: --crate-type=lib +#![allow(internal_features)] +#![feature(rustc_attrs)] + +#[rustc_scalable_vector(2)] +struct ValidI64(i64); + +struct Struct { + x: ValidI64, +//~^ ERROR: scalable vectors cannot be fields of a struct + in_tuple: (ValidI64,), +//~^ ERROR: scalable vectors cannot be tuple fields +} + +struct TupleStruct(ValidI64); +//~^ ERROR: scalable vectors cannot be fields of a struct + +enum Enum { + StructVariant { _ty: ValidI64 }, +//~^ ERROR: scalable vectors cannot be fields of a variant + TupleVariant(ValidI64), +//~^ ERROR: scalable vectors cannot be fields of a variant +} diff --git a/tests/ui/scalable-vectors/illformed-within-types.stderr b/tests/ui/scalable-vectors/illformed-within-types.stderr new file mode 100644 index 0000000000000..e76ef26f2aa4b --- /dev/null +++ b/tests/ui/scalable-vectors/illformed-within-types.stderr @@ -0,0 +1,32 @@ +error: scalable vectors cannot be fields of a struct + --> $DIR/illformed-within-types.rs:9:8 + | +LL | x: ValidI64, + | ^^^^^^^^ + +error: scalable vectors cannot be tuple fields + --> $DIR/illformed-within-types.rs:11:15 + | +LL | in_tuple: (ValidI64,), + | ^^^^^^^^^^^ + +error: scalable vectors cannot be fields of a struct + --> $DIR/illformed-within-types.rs:15:20 + | +LL | struct TupleStruct(ValidI64); + | ^^^^^^^^ + +error: scalable vectors cannot be fields of a variant + --> $DIR/illformed-within-types.rs:19:26 + | +LL | StructVariant { _ty: ValidI64 }, + | ^^^^^^^^ + +error: scalable vectors cannot be fields of a variant + --> $DIR/illformed-within-types.rs:21:18 + | +LL | TupleVariant(ValidI64), + | ^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/scalable-vectors/illformed.rs b/tests/ui/scalable-vectors/illformed.rs new file mode 100644 index 0000000000000..5af66ad6c7390 --- /dev/null +++ b/tests/ui/scalable-vectors/illformed.rs @@ -0,0 +1,59 @@ +//@ compile-flags: --crate-type=lib +#![allow(internal_features)] +#![feature(rustc_attrs)] + +#[rustc_scalable_vector(4)] +struct NoFieldsStructWithElementCount {} +//~^ ERROR: scalable vectors must have a single field +//~^^ ERROR: scalable vectors must be tuple structs + +#[rustc_scalable_vector(4)] +struct NoFieldsTupleWithElementCount(); +//~^ ERROR: scalable vectors must have a single field + +#[rustc_scalable_vector(4)] +struct NoFieldsUnitWithElementCount; +//~^ ERROR: scalable vectors must have a single field +//~^^ ERROR: scalable vectors must be tuple structs + +#[rustc_scalable_vector] +struct NoFieldsStructWithoutElementCount {} +//~^ ERROR: scalable vectors must have a single field +//~^^ ERROR: scalable vectors must be tuple structs + +#[rustc_scalable_vector] +struct NoFieldsTupleWithoutElementCount(); +//~^ ERROR: scalable vectors must have a single field + +#[rustc_scalable_vector] +struct NoFieldsUnitWithoutElementCount; +//~^ ERROR: scalable vectors must have a single field +//~^^ ERROR: scalable vectors must be tuple structs + +#[rustc_scalable_vector(4)] +struct MultipleFieldsStructWithElementCount { +//~^ ERROR: scalable vectors cannot have multiple fields +//~^^ ERROR: scalable vectors must be tuple structs + _ty: f32, + other: u32, +} + +#[rustc_scalable_vector(4)] +struct MultipleFieldsTupleWithElementCount(f32, u32); +//~^ ERROR: scalable vectors cannot have multiple fields + +#[rustc_scalable_vector] +struct MultipleFieldsStructWithoutElementCount { +//~^ ERROR: scalable vectors must be tuple structs + _ty: f32, + other: u32, +//~^ ERROR: all fields in a scalable vector struct must be the same type +} + +#[rustc_scalable_vector] +struct MultipleFieldsTupleWithoutElementCount(f32, u32); +//~^ ERROR: all fields in a scalable vector struct must be the same type + +#[rustc_scalable_vector(2)] +struct SingleFieldStruct { _ty: f64 } +//~^ ERROR: scalable vectors must be tuple structs diff --git a/tests/ui/scalable-vectors/illformed.stderr b/tests/ui/scalable-vectors/illformed.stderr new file mode 100644 index 0000000000000..92b115664d1c9 --- /dev/null +++ b/tests/ui/scalable-vectors/illformed.stderr @@ -0,0 +1,126 @@ +error: scalable vectors must be tuple structs + --> $DIR/illformed.rs:6:1 + | +LL | struct NoFieldsStructWithElementCount {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors must be tuple structs + --> $DIR/illformed.rs:15:1 + | +LL | struct NoFieldsUnitWithElementCount; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors must be tuple structs + --> $DIR/illformed.rs:20:1 + | +LL | struct NoFieldsStructWithoutElementCount {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors must be tuple structs + --> $DIR/illformed.rs:29:1 + | +LL | struct NoFieldsUnitWithoutElementCount; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors must be tuple structs + --> $DIR/illformed.rs:34:1 + | +LL | / struct MultipleFieldsStructWithElementCount { +LL | | +LL | | +LL | | _ty: f32, +LL | | other: u32, +LL | | } + | |_^ + +error: scalable vectors must be tuple structs + --> $DIR/illformed.rs:46:1 + | +LL | / struct MultipleFieldsStructWithoutElementCount { +LL | | +LL | | _ty: f32, +LL | | other: u32, +LL | | +LL | | } + | |_^ + +error: scalable vectors must be tuple structs + --> $DIR/illformed.rs:58:1 + | +LL | struct SingleFieldStruct { _ty: f64 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors must have a single field + --> $DIR/illformed.rs:6:1 + | +LL | struct NoFieldsStructWithElementCount {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: scalable vector types' only field must be a primitive scalar type + +error: scalable vectors must have a single field + --> $DIR/illformed.rs:11:1 + | +LL | struct NoFieldsTupleWithElementCount(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: scalable vector types' only field must be a primitive scalar type + +error: scalable vectors must have a single field + --> $DIR/illformed.rs:15:1 + | +LL | struct NoFieldsUnitWithElementCount; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: scalable vector types' only field must be a primitive scalar type + +error: scalable vectors must have a single field + --> $DIR/illformed.rs:20:1 + | +LL | struct NoFieldsStructWithoutElementCount {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: tuples of scalable vectors can only contain multiple of the same scalable vector type + +error: scalable vectors must have a single field + --> $DIR/illformed.rs:25:1 + | +LL | struct NoFieldsTupleWithoutElementCount(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: tuples of scalable vectors can only contain multiple of the same scalable vector type + +error: scalable vectors must have a single field + --> $DIR/illformed.rs:29:1 + | +LL | struct NoFieldsUnitWithoutElementCount; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: tuples of scalable vectors can only contain multiple of the same scalable vector type + +error: scalable vectors cannot have multiple fields + --> $DIR/illformed.rs:34:1 + | +LL | struct MultipleFieldsStructWithElementCount { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors cannot have multiple fields + --> $DIR/illformed.rs:42:1 + | +LL | struct MultipleFieldsTupleWithElementCount(f32, u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: all fields in a scalable vector struct must be the same type + --> $DIR/illformed.rs:49:5 + | +LL | other: u32, + | ^^^^^^^^^^ + +error: all fields in a scalable vector struct must be the same type + --> $DIR/illformed.rs:54:52 + | +LL | struct MultipleFieldsTupleWithoutElementCount(f32, u32); + | ^^^ + +error: aborting due to 17 previous errors + diff --git a/tests/ui/scalable-vectors/invalid.rs b/tests/ui/scalable-vectors/invalid.rs new file mode 100644 index 0000000000000..dd58fa93feae3 --- /dev/null +++ b/tests/ui/scalable-vectors/invalid.rs @@ -0,0 +1,158 @@ +//@ edition: 2024 +#![allow(internal_features, unused_imports, unused_macros)] +#![feature(extern_types)] +#![feature(gen_blocks)] +#![feature(rustc_attrs)] +#![feature(stmt_expr_attributes)] +#![feature(trait_alias)] + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on extern crates +extern crate std as other_std; + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on use statements +use std::vec::Vec; + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on statics +static _X: u32 = 0; + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on constants +const _Y: u32 = 0; + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on modules +mod bar { +} + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign modules +unsafe extern "C" { + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign statics + static X: &'static u32; + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign types + type Y; + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on foreign functions + fn foo(); +} + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on type aliases +type Foo = u32; + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on enums +enum Bar<#[rustc_scalable_vector(4)] T> { +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on function params + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on enum variants + Baz(std::marker::PhantomData), +} + +struct Qux { + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on struct fields + field: u32, +} + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on unions +union FooBar { + x: u32, + y: u32, +} + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on traits +trait FooBaz { + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on associated types + type Foo; + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on associated consts + const Bar: i32; + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on provided trait methods + fn foo() {} +} + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on trait aliases +trait FooQux = FooBaz; + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on inherent impl blocks +impl Bar { + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on inherent methods + fn foo() {} +} + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on trait impl blocks +impl FooBaz for Bar { + type Foo = u32; + const Bar: i32 = 3; +} + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on macro defs +macro_rules! barqux { ($foo:tt) => { $foo }; } + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions +fn barqux(#[rustc_scalable_vector(4)] _x: u32) {} +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on function params +//~^^ ERROR: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions +async fn async_foo() {} + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions +gen fn gen_foo() {} + +#[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on functions +async gen fn async_gen_foo() {} + +fn main() { + let _x = #[rustc_scalable_vector(4)] || { }; +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on closures + let _y = #[rustc_scalable_vector(4)] 3 + 4; +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on expressions + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on statements + let _z = 3; + + match _z { + #[rustc_scalable_vector(4)] +//~^ ERROR: `#[rustc_scalable_vector]` attribute cannot be used on match arms + 1 => (), + _ => (), + } +} + +#[rustc_scalable_vector("4")] +//~^ ERROR: malformed `rustc_scalable_vector` attribute input +struct ArgNotLit(f32); + +#[rustc_scalable_vector(4, 2)] +//~^ ERROR: malformed `rustc_scalable_vector` attribute input +struct ArgMultipleLits(f32); + +#[rustc_scalable_vector(count = "4")] +//~^ ERROR: malformed `rustc_scalable_vector` attribute input +struct ArgKind(f32); + +#[rustc_scalable_vector(4)] +struct Okay(f32); + +#[rustc_scalable_vector] +struct OkayNoArg(f32); diff --git a/tests/ui/scalable-vectors/invalid.stderr b/tests/ui/scalable-vectors/invalid.stderr new file mode 100644 index 0000000000000..b802d93901d80 --- /dev/null +++ b/tests/ui/scalable-vectors/invalid.stderr @@ -0,0 +1,325 @@ +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/invalid.rs:109:11 + | +LL | fn barqux(#[rustc_scalable_vector(4)] _x: u32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[rustc_scalable_vector]` attribute cannot be used on extern crates + --> $DIR/invalid.rs:9:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on use statements + --> $DIR/invalid.rs:13:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on statics + --> $DIR/invalid.rs:17:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on constants + --> $DIR/invalid.rs:21:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on modules + --> $DIR/invalid.rs:25:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on foreign modules + --> $DIR/invalid.rs:30:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on foreign statics + --> $DIR/invalid.rs:33:5 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on foreign types + --> $DIR/invalid.rs:36:5 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on foreign functions + --> $DIR/invalid.rs:39:5 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on type aliases + --> $DIR/invalid.rs:44:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on enums + --> $DIR/invalid.rs:48:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on function params + --> $DIR/invalid.rs:50:10 + | +LL | enum Bar<#[rustc_scalable_vector(4)] T> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on enum variants + --> $DIR/invalid.rs:52:5 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on struct fields + --> $DIR/invalid.rs:58:5 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on unions + --> $DIR/invalid.rs:63:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on traits + --> $DIR/invalid.rs:70:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on associated types + --> $DIR/invalid.rs:73:5 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on associated consts + --> $DIR/invalid.rs:76:5 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on provided trait methods + --> $DIR/invalid.rs:79:5 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on trait aliases + --> $DIR/invalid.rs:84:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on inherent impl blocks + --> $DIR/invalid.rs:88:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on inherent methods + --> $DIR/invalid.rs:91:5 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on trait impl blocks + --> $DIR/invalid.rs:96:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on macro defs + --> $DIR/invalid.rs:103:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on functions + --> $DIR/invalid.rs:107:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on function params + --> $DIR/invalid.rs:109:11 + | +LL | fn barqux(#[rustc_scalable_vector(4)] _x: u32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on functions + --> $DIR/invalid.rs:113:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on functions + --> $DIR/invalid.rs:117:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on functions + --> $DIR/invalid.rs:121:1 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on closures + --> $DIR/invalid.rs:126:14 + | +LL | let _x = #[rustc_scalable_vector(4)] || { }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on expressions + --> $DIR/invalid.rs:128:14 + | +LL | let _y = #[rustc_scalable_vector(4)] 3 + 4; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on statements + --> $DIR/invalid.rs:130:5 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error: `#[rustc_scalable_vector]` attribute cannot be used on match arms + --> $DIR/invalid.rs:135:9 + | +LL | #[rustc_scalable_vector(4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_scalable_vector]` can only be applied to structs + +error[E0539]: malformed `rustc_scalable_vector` attribute input + --> $DIR/invalid.rs:142:1 + | +LL | #[rustc_scalable_vector("4")] + | ^^^^^^^^^^^^^^^^^^^^^^^^---^^ + | | + | expected an integer literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[rustc_scalable_vector("4")] +LL + #[rustc_scalable_vector(count)] + | +LL - #[rustc_scalable_vector("4")] +LL + #[rustc_scalable_vector] + | + +error[E0805]: malformed `rustc_scalable_vector` attribute input + --> $DIR/invalid.rs:146:1 + | +LL | #[rustc_scalable_vector(4, 2)] + | ^^^^^^^^^^^^^^^^^^^^^^^------^ + | | + | expected a single argument here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[rustc_scalable_vector(4, 2)] +LL + #[rustc_scalable_vector(count)] + | +LL - #[rustc_scalable_vector(4, 2)] +LL + #[rustc_scalable_vector] + | + +error[E0539]: malformed `rustc_scalable_vector` attribute input + --> $DIR/invalid.rs:150:1 + | +LL | #[rustc_scalable_vector(count = "4")] + | ^^^^^^^^^^^^^^^^^^^^^^^^-----------^^ + | | + | expected an integer literal here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[rustc_scalable_vector(count = "4")] +LL + #[rustc_scalable_vector(count)] + | +LL - #[rustc_scalable_vector(count = "4")] +LL + #[rustc_scalable_vector] + | + +error: aborting due to 37 previous errors + +Some errors have detailed explanations: E0539, E0805. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/scalable-vectors/require-target-feature.rs b/tests/ui/scalable-vectors/require-target-feature.rs new file mode 100644 index 0000000000000..b3c1d3e510077 --- /dev/null +++ b/tests/ui/scalable-vectors/require-target-feature.rs @@ -0,0 +1,40 @@ +//@ build-fail +//@ compile-flags: --crate-type=lib +//@ only-aarch64 +#![allow(incomplete_features, internal_features)] +#![feature( + simd_ffi, + rustc_attrs, + link_llvm_intrinsics +)] + +#[derive(Copy, Clone)] +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +pub struct svint32_t(i32); + +#[inline(never)] +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; +//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe + } + unsafe { _svdup_n_s32(op) } +} + +pub fn non_annotated_callee(x: svint32_t) {} +//~^ ERROR: this function definition uses scalable vector type `svint32_t` + +#[target_feature(enable = "sve")] +pub fn annotated_callee(x: svint32_t) {} // okay! + +#[target_feature(enable = "sve")] +pub fn caller() { + unsafe { + let a = svdup_n_s32(42); + non_annotated_callee(a); + annotated_callee(a); + } +} diff --git a/tests/ui/scalable-vectors/require-target-feature.stderr b/tests/ui/scalable-vectors/require-target-feature.stderr new file mode 100644 index 0000000000000..85b9e5b6579ce --- /dev/null +++ b/tests/ui/scalable-vectors/require-target-feature.stderr @@ -0,0 +1,25 @@ +warning: `extern` block uses type `svint32_t`, which is not FFI-safe + --> $DIR/require-target-feature.rs:21:37 + | +LL | fn _svdup_n_s32(op: i32) -> svint32_t; + | ^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/require-target-feature.rs:14:1 + | +LL | pub struct svint32_t(i32); + | ^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(improper_ctypes)]` on by default + +error: this function definition uses scalable vector type `svint32_t` which (with the chosen ABI) requires the `sve` target feature, which is not enabled + --> $DIR/require-target-feature.rs:27:1 + | +LL | pub fn non_annotated_callee(x: svint32_t) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = help: consider enabling it globally (`-C target-feature=+sve`) or locally (`#[target_feature(enable="sve")]`) + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/ui/scalable-vectors/value-type.rs b/tests/ui/scalable-vectors/value-type.rs new file mode 100644 index 0000000000000..31a9ee8344eb5 --- /dev/null +++ b/tests/ui/scalable-vectors/value-type.rs @@ -0,0 +1,37 @@ +//@ build-pass +//@ compile-flags: --crate-type=lib +//@ only-aarch64 +#![allow(internal_features)] +#![feature( + link_llvm_intrinsics, + rustc_attrs, + simd_ffi, +)] + +#[derive(Copy, Clone)] +#[rustc_scalable_vector(4)] +#[allow(non_camel_case_types)] +pub struct svint32_t(i32); + +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; +//~^ WARN: `extern` block uses type `svint32_t`, which is not FFI-safe + } + unsafe { _svdup_n_s32(op) } +} + +// Tests that scalable vectors can be locals, arguments and return types. + +#[target_feature(enable = "sve")] +fn id(v: svint32_t) -> svint32_t { v } + +#[target_feature(enable = "sve")] +fn foo() { + unsafe { + let v = svdup_n_s32(1); + let v = id(v); + } +} diff --git a/tests/ui/scalable-vectors/value-type.stderr b/tests/ui/scalable-vectors/value-type.stderr new file mode 100644 index 0000000000000..3fc90ebd874e6 --- /dev/null +++ b/tests/ui/scalable-vectors/value-type.stderr @@ -0,0 +1,17 @@ +warning: `extern` block uses type `svint32_t`, which is not FFI-safe + --> $DIR/value-type.rs:20:37 + | +LL | fn _svdup_n_s32(op: i32) -> svint32_t; + | ^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/value-type.rs:14:1 + | +LL | pub struct svint32_t(i32); + | ^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(improper_ctypes)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/scalable-vectors/wellformed-arrays.rs b/tests/ui/scalable-vectors/wellformed-arrays.rs new file mode 100644 index 0000000000000..b8f0bf291eea4 --- /dev/null +++ b/tests/ui/scalable-vectors/wellformed-arrays.rs @@ -0,0 +1,10 @@ +//@ check-pass +//@ compile-flags: --crate-type=lib +#![feature(rustc_attrs)] + +#[rustc_scalable_vector(16)] +struct ScalableU8(u8); + +fn main() { + let x: [ScalableU8; 4] = todo!(); +} diff --git a/tests/ui/scalable-vectors/wellformed.rs b/tests/ui/scalable-vectors/wellformed.rs new file mode 100644 index 0000000000000..cb6a22d6c4338 --- /dev/null +++ b/tests/ui/scalable-vectors/wellformed.rs @@ -0,0 +1,48 @@ +//@ check-pass +//@ compile-flags: --crate-type=lib +#![feature(rustc_attrs)] + +#[rustc_scalable_vector(16)] +struct ScalableU8(u8); + +#[rustc_scalable_vector(8)] +struct ScalableU16(u16); + +#[rustc_scalable_vector(4)] +struct ScalableU32(u32); + +#[rustc_scalable_vector(2)] +struct ScalableU64(u64); + +#[rustc_scalable_vector(1)] +struct ScalableU128(u128); + +#[rustc_scalable_vector(16)] +struct ScalableI8(i8); + +#[rustc_scalable_vector(8)] +struct ScalableI16(i16); + +#[rustc_scalable_vector(4)] +struct ScalableI32(i32); + +#[rustc_scalable_vector(2)] +struct ScalableI64(i64); + +#[rustc_scalable_vector(1)] +struct ScalableI128(i128); + +#[rustc_scalable_vector(8)] +struct ScalableF16(f32); + +#[rustc_scalable_vector(4)] +struct ScalableF32(f32); + +#[rustc_scalable_vector(2)] +struct ScalableF64(f64); + +#[rustc_scalable_vector(16)] +struct ScalableBool(bool); + +#[rustc_scalable_vector] +struct ScalableTuple(ScalableU8, ScalableU8, ScalableU8); diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index f2fcb98cb6a95..9c1da58872e2e 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -93,7 +93,7 @@ hir-stats GenericParam 400 (NN.N%) 5 80 hir-stats Block 288 (NN.N%) 6 48 hir-stats GenericBound 256 (NN.N%) 4 64 hir-stats - Trait 256 (NN.N%) 4 -hir-stats Attribute 200 (NN.N%) 5 40 +hir-stats Attribute 240 (NN.N%) 5 48 hir-stats Variant 144 (NN.N%) 2 72 hir-stats GenericArgs 144 (NN.N%) 3 48 hir-stats FieldDef 128 (NN.N%) 2 64 @@ -119,5 +119,5 @@ hir-stats TraitItemId 8 (NN.N%) 2 4 hir-stats ImplItemId 8 (NN.N%) 2 4 hir-stats ForeignItemId 4 (NN.N%) 1 4 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_616 173 +hir-stats Total 8_656 173 hir-stats ================================================================ diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 8a2bad56c126a..ecc5fb21435f8 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -95,7 +95,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 } args: [] variant_index: 0 subpatterns: [ @@ -109,7 +109,7 @@ body: did: DefId(0:3 ~ thir_tree_match[fcf8]::Bar) variants: [VariantDef { def_id: DefId(0:4 ~ thir_tree_match[fcf8]::Bar::First), ctor: Some((Const, DefId(0:5 ~ thir_tree_match[fcf8]::Bar::First::{constructor#0}))), name: "First", discr: Relative(0), fields: [], tainted: None, flags: }, VariantDef { def_id: DefId(0:6 ~ thir_tree_match[fcf8]::Bar::Second), ctor: Some((Const, DefId(0:7 ~ thir_tree_match[fcf8]::Bar::Second::{constructor#0}))), name: "Second", discr: Relative(1), fields: [], tainted: None, flags: }, VariantDef { def_id: DefId(0:8 ~ thir_tree_match[fcf8]::Bar::Third), ctor: Some((Const, DefId(0:9 ~ thir_tree_match[fcf8]::Bar::Third::{constructor#0}))), name: "Third", discr: Relative(2), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 7908585036048874241 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 7908585036048874241 } args: [] variant_index: 0 subpatterns: [] @@ -157,7 +157,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 } args: [] variant_index: 0 subpatterns: [ @@ -209,7 +209,7 @@ body: did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM - repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 13397682652773712997 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 13397682652773712997 } args: [] variant_index: 1 subpatterns: []