Auto merge of #143924 - davidtwco:sve-infrastructure, r=workingjubilee
`rustc_scalable_vector(N)` Supercedes rust-lang/rust#118917. Initial experimental implementation of rust-lang/rfcs#3838. Introduces a `rustc_scalable_vector(N)` attribute that can be applied to types with a single `[$ty]` field (for `u{16,32,64}`, `i{16,32,64}`, `f{32,64}`, `bool`). `rustc_scalable_vector` types are lowered to scalable vectors in the codegen backend. As with any unstable feature, there will necessarily be follow-ups as we experiment and find cases that we've not considered or still need some logic to handle, but this aims to be a decent baseline to start from. See rust-lang/rust#145052 for request for a lang experiment.
This commit is contained in:
commit
95a27adcf9
84 changed files with 2234 additions and 146 deletions
|
|
@ -60,6 +60,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
/// This is public so that it can be used in unit tests, but
|
||||
/// should generally only be relevant to the ABI details of
|
||||
/// specific targets.
|
||||
#[tracing::instrument(skip(cx), level = "debug")]
|
||||
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
|
|
@ -82,6 +83,10 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
}))
|
||||
}
|
||||
|
||||
BackendRepr::ScalableVector { .. } => {
|
||||
unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")
|
||||
}
|
||||
|
||||
BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
|
||||
// Helper for computing `homogeneous_aggregate`, allowing a custom
|
||||
// starting offset (used below for handling variants).
|
||||
|
|
|
|||
|
|
@ -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<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn simd_type<
|
||||
pub fn scalable_vector_type<FieldIdx, VariantIdx, F>(
|
||||
&self,
|
||||
element: F,
|
||||
count: u64,
|
||||
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
|
||||
where
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
>(
|
||||
{
|
||||
vector_type_layout(VectorKind::Scalable, self.cx.data_layout(), element, count)
|
||||
}
|
||||
|
||||
pub fn simd_type<FieldIdx, VariantIdx, F>(
|
||||
&self,
|
||||
element: F,
|
||||
count: u64,
|
||||
repr_packed: bool,
|
||||
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
|
||||
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<FieldIdx, VariantIdx, F>
|
||||
where
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + 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<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
BackendRepr::Scalar(..)
|
||||
| BackendRepr::ScalarPair(..)
|
||||
| BackendRepr::SimdVector { .. }
|
||||
| BackendRepr::ScalableVector { .. }
|
||||
| BackendRepr::Memory { .. } => repr,
|
||||
},
|
||||
};
|
||||
|
|
@ -524,7 +499,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
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<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
s
|
||||
}
|
||||
}
|
||||
|
||||
enum VectorKind {
|
||||
/// `#[rustc_scalable_vector]`
|
||||
Scalable,
|
||||
/// `#[repr(simd, packed)]`
|
||||
PackedFixed,
|
||||
/// `#[repr(simd)]`
|
||||
Fixed,
|
||||
}
|
||||
|
||||
fn vector_type_layout<FieldIdx, VariantIdx, F>(
|
||||
kind: VectorKind,
|
||||
dl: &TargetDataLayout,
|
||||
element: F,
|
||||
count: u64,
|
||||
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F>
|
||||
where
|
||||
FieldIdx: Idx,
|
||||
VariantIdx: Idx,
|
||||
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + 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)),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
|
|||
|
||||
/// Trait that needs to be implemented by the higher-level type representation
|
||||
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
|
||||
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
|
||||
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
|
||||
fn ty_and_layout_for_variant(
|
||||
this: TyAndLayout<'a, Self>,
|
||||
cx: &C,
|
||||
|
|
@ -172,6 +172,7 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
|
|||
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
|
||||
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
|
||||
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
|
||||
fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool;
|
||||
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
|
||||
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
|
||||
}
|
||||
|
|
@ -271,6 +272,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
Ty::is_transparent(self)
|
||||
}
|
||||
|
||||
pub fn is_scalable_vector<C>(self) -> bool
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C>,
|
||||
{
|
||||
Ty::is_scalable_vector(self)
|
||||
}
|
||||
|
||||
/// If this method returns `true`, then this type should always have a `PassMode` of
|
||||
/// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
|
||||
/// non-Rustic ABI (this is true for structs annotated with the
|
||||
|
|
|
|||
|
|
@ -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(u16),
|
||||
/// `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<Align>,
|
||||
pub pack: Option<Align>,
|
||||
pub flags: ReprFlags,
|
||||
/// `#[rustc_scalable_vector]`
|
||||
pub scalable: Option<ScalableElt>,
|
||||
/// 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,12 @@ impl BackendRepr {
|
|||
match *self {
|
||||
BackendRepr::Scalar(_)
|
||||
| BackendRepr::ScalarPair(..)
|
||||
// FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the
|
||||
// `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
|
||||
// fully implemented, scalable vectors will remain `Sized`, they just won't be
|
||||
// `const Sized` - whether `is_unsized` continues to return `false` at that point will
|
||||
// need to be revisited and will depend on what `is_unsized` is used for.
|
||||
| BackendRepr::ScalableVector { .. }
|
||||
| BackendRepr::SimdVector { .. } => false,
|
||||
BackendRepr::Memory { sized } => !sized,
|
||||
}
|
||||
|
|
@ -1794,7 +1826,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 +1850,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 +1867,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 +2110,9 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
/// 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 +2206,19 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
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<u64> {
|
||||
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 +2227,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
match self.backend_repr {
|
||||
BackendRepr::Scalar(_)
|
||||
| BackendRepr::ScalarPair(..)
|
||||
| BackendRepr::ScalableVector { .. }
|
||||
| BackendRepr::SimdVector { .. } => false,
|
||||
BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,6 +270,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
|
||||
|
|
|
|||
|
|
@ -1319,6 +1319,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);
|
||||
|
|
|
|||
|
|
@ -990,3 +990,10 @@ pub(crate) struct AbiX86Interrupt {
|
|||
pub spans: Vec<Span>,
|
||||
pub param_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_scalable_vector_not_tuple_struct)]
|
||||
pub(crate) struct ScalableVectorNotTupleStruct {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,6 +200,9 @@ attr_parsing_rustc_allowed_unstable_pairing =
|
|||
attr_parsing_rustc_promotable_pairing =
|
||||
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
|
||||
|
||||
attr_parsing_rustc_scalable_vector_count_out_of_range = element count in `rustc_scalable_vector` is too large: `{$n}`
|
||||
.note = the value may not exceed `u16::MAX`
|
||||
|
||||
attr_parsing_soft_no_args =
|
||||
`soft` should not have any arguments
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use super::prelude::*;
|
||||
use super::util::parse_single_integer;
|
||||
use crate::session_diagnostics::RustcScalableVectorCountOutOfRange;
|
||||
|
||||
pub(crate) struct RustcMainParser;
|
||||
|
||||
|
|
@ -76,3 +77,29 @@ impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser
|
|||
Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcScalableVectorParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::rustc_scalable_vector];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = 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<AttributeKind> {
|
||||
if args.no_args().is_ok() {
|
||||
return Some(AttributeKind::RustcScalableVector {
|
||||
element_count: None,
|
||||
span: cx.attr_span,
|
||||
});
|
||||
}
|
||||
|
||||
let n = parse_single_integer(cx, args)?;
|
||||
let Ok(n) = n.try_into() else {
|
||||
cx.emit_err(RustcScalableVectorCountOutOfRange { span: cx.attr_span, n });
|
||||
return None;
|
||||
};
|
||||
Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,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::{
|
||||
|
|
@ -209,6 +210,7 @@ attribute_parsers!(
|
|||
Single<RustcLayoutScalarValidRangeEndParser>,
|
||||
Single<RustcLayoutScalarValidRangeStartParser>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<RustcScalableVectorParser>,
|
||||
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
||||
Single<SanitizeParser>,
|
||||
Single<ShouldPanicParser>,
|
||||
|
|
|
|||
|
|
@ -501,6 +501,15 @@ pub(crate) struct LinkOrdinalOutOfRange {
|
|||
pub ordinal: u128,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_rustc_scalable_vector_count_out_of_range)]
|
||||
#[note]
|
||||
pub(crate) struct RustcScalableVectorCountOutOfRange {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub n: u128,
|
||||
}
|
||||
|
||||
pub(crate) enum AttributeParseErrorReason<'a> {
|
||||
ExpectedNoArgs,
|
||||
ExpectedStringLiteral {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -504,7 +504,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`),
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(
|
|||
);
|
||||
}
|
||||
BackendRepr::Memory { .. } => {}
|
||||
BackendRepr::ScalableVector { .. } => todo!(),
|
||||
}
|
||||
|
||||
let name = match *layout.ty.kind() {
|
||||
|
|
@ -179,6 +180,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
fn is_gcc_immediate(&self) -> bool {
|
||||
match self.backend_repr {
|
||||
BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true,
|
||||
// FIXME(rustc_scalable_vector): Not yet implemented in rustc_codegen_gcc.
|
||||
BackendRepr::ScalableVector { .. } => todo!(),
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -480,6 +480,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`),
|
||||
|
|
@ -1679,11 +1687,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()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> 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) }
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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}`
|
||||
|
|
|
|||
|
|
@ -1094,6 +1094,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 {
|
||||
|
|
|
|||
|
|
@ -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 `<vscale x N x i1>` 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 `<vscale x 16 x i8>` vector has a `<vscale x 16 x i1>`
|
||||
// predicate type. `<vscale x 16 x i1>` 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`/`<vscale x 4 x i32>`,
|
||||
// while only a `<vscale x 4 x i1>` predicate type would be strictly necessary,
|
||||
// relevant intrinsics still take a `svbool_t`/`<vscale x 16 x i1>` - this is
|
||||
// because a `<vscale x 4 x i1>` 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 `<vscale x N x i1>`
|
||||
// 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`/`<vscale x 4 x i32>`
|
||||
// (for example), the intrinsic takes the `svbool_t`/`<vscale x 16 x i1>` predicate
|
||||
// and casts it to a `svbool4_t`/`<vscale x 4 x i1>`. Therefore, it's important that
|
||||
// the `<vscale x 4 x i32>` 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. `<vscale x N x i1>` 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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:?}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
||||
|
|
@ -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: BuilderMethods<'a, 'tcx, Value = V>>(
|
||||
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> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1315,7 +1315,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.)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1422,6 +1422,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:
|
||||
|
|
|
|||
|
|
@ -878,6 +878,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<u16>,
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_should_not_be_called_on_const_items]`
|
||||
RustcShouldNotBeCalledOnConstItems(Span),
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,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,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use std::num::NonZero;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_abi::Align;
|
||||
use rustc_ast::token::{CommentKind, DocFragmentKind};
|
||||
|
|
@ -37,6 +38,15 @@ impl<T: PrintAttribute> PrintAttribute for &T {
|
|||
T::print_attribute(self, p)
|
||||
}
|
||||
}
|
||||
impl<T: PrintAttribute> PrintAttribute for Box<T> {
|
||||
fn should_render(&self) -> bool {
|
||||
self.deref().should_render()
|
||||
}
|
||||
|
||||
fn print_attribute(&self, p: &mut Printer) {
|
||||
T::print_attribute(self.deref(), p)
|
||||
}
|
||||
}
|
||||
impl<T: PrintAttribute> PrintAttribute for Option<T> {
|
||||
fn should_render(&self) -> bool {
|
||||
self.as_ref().is_some_and(|x| x.should_render())
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -1426,6 +1428,100 @@ 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*` 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()
|
||||
{
|
||||
match def
|
||||
.repr()
|
||||
.scalable
|
||||
.expect("`repr().scalable.is_some()` != `repr().scalable()`")
|
||||
{
|
||||
ScalableElt::ElementCount(_) => { /* expected field */ }
|
||||
ScalableElt::Container => {
|
||||
tcx.dcx().span_err(
|
||||
tcx.def_span(field.did),
|
||||
"scalable vector structs cannot contain other scalable vector structs",
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tcx.dcx().span_err(
|
||||
tcx.def_span(field.did),
|
||||
"scalable vector structs can only have scalable vector fields",
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
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",
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
|
||||
let repr = def.repr();
|
||||
if repr.packed() {
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
@ -1038,7 +1038,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 a
|
||||
// `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
|
||||
|
|
|
|||
|
|
@ -1178,6 +1178,10 @@ where
|
|||
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
|
||||
}
|
||||
|
||||
fn is_scalable_vector(this: TyAndLayout<'tcx>) -> bool {
|
||||
this.ty.is_scalable_vector()
|
||||
}
|
||||
|
||||
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
|
||||
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'tcx>) -> bool {
|
||||
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS))
|
||||
|
|
|
|||
|
|
@ -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::AttrVec;
|
||||
use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
|
|
@ -1515,6 +1517,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 {
|
||||
|
|
@ -1579,7 +1592,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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -1253,6 +1253,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,
|
||||
|
|
@ -1261,6 +1269,19 @@ impl<'tcx> Ty<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn scalable_vector_element_count_and_type(self, tcx: TyCtxt<'tcx>) -> (u16, 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")
|
||||
|
|
|
|||
|
|
@ -1891,6 +1891,16 @@ fn check_must_not_suspend_ty<'tcx>(
|
|||
SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data },
|
||||
)
|
||||
}
|
||||
// FIXME(sized_hierarchy): This should be replaced with a requirement that types in
|
||||
// coroutines implement `const Sized`. Scalable vectors are temporarily `Sized` while
|
||||
// `feature(sized_hierarchy)` is not fully implemented, but in practice are
|
||||
// non-`const Sized` and so do not have a known size at compilation time. Layout computation
|
||||
// for a coroutine containing scalable vectors would be incorrect.
|
||||
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, .. }) => {
|
||||
|
|
|
|||
|
|
@ -1661,7 +1661,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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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] {""}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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 passes_vectors_by_value(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(..) => matches!(repr, BackendRepr::SimdVector { .. }),
|
||||
PassMode::Direct(..) | PassMode::Pair(..)
|
||||
if matches!(repr, BackendRepr::SimdVector { .. }) =>
|
||||
{
|
||||
UsesVectorRegisters::FixedVector
|
||||
}
|
||||
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 passes_vectors_by_value(&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 !feature.is_empty() && !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,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if !feature.is_empty() && !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::ScalableVector => {
|
||||
let Some(required_feature) =
|
||||
tcx.sess.target.features_for_correct_scalable_vector_abi()
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if !required_feature.is_empty() && !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,
|
||||
});
|
||||
}
|
||||
}
|
||||
UsesVectorRegisters::No => {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::MacroEscape( .. )
|
||||
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
|
||||
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
|
||||
| AttributeKind::RustcScalableVector { .. }
|
||||
| AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
|
||||
| AttributeKind::RustcShouldNotBeCalledOnConstItems(..)
|
||||
| AttributeKind::ExportStable
|
||||
|
|
|
|||
|
|
@ -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,15 @@ 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(rustc_scalable_vector): Scalable vectors are `Sized` while the
|
||||
// `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
|
||||
// fully implemented, scalable vectors will remain `Sized`, they just won't be
|
||||
// `const Sized` - whether `is_unsized` continues to return `false` at that point will
|
||||
// need to be revisited and will depend on what `is_unsized` is used for.
|
||||
| ValueAbi::ScalableVector { .. } => false,
|
||||
ValueAbi::Aggregate { sized } => !sized,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1998,6 +1998,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,
|
||||
|
|
|
|||
|
|
@ -9,13 +9,14 @@ use crate::spec::{Abi, HasTargetSpec, Target};
|
|||
/// Used to accommodate Apple and Microsoft's deviations from the usual AAPCS ABI.
|
||||
///
|
||||
/// Corresponds to Clang's `AArch64ABIInfo::ABIKind`.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub(crate) enum AbiKind {
|
||||
AAPCS,
|
||||
DarwinPCS,
|
||||
Win64,
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(cx), level = "debug")]
|
||||
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
|
|
@ -73,12 +74,13 @@ fn softfloat_float_abi<Ty>(target: &Target, arg: &mut ArgAbi<'_, Ty>) {
|
|||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(cx), level = "debug")]
|
||||
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, kind: AbiKind)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
if !ret.layout.is_sized() {
|
||||
if !ret.layout.is_sized() || ret.layout.is_scalable_vector() {
|
||||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
|
|
@ -105,12 +107,13 @@ where
|
|||
ret.make_indirect();
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(cx), level = "debug")]
|
||||
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, kind: AbiKind)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
if !arg.layout.is_sized() {
|
||||
if !arg.layout.is_sized() || arg.layout.is_scalable_vector() {
|
||||
// Not touching this...
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,10 @@ where
|
|||
}
|
||||
}
|
||||
},
|
||||
BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv),
|
||||
BackendRepr::SimdVector { .. } => {
|
||||
return Err(CannotUseFpConv);
|
||||
}
|
||||
BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"),
|
||||
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields {
|
||||
FieldsShape::Primitive => {
|
||||
unreachable!("aggregates can't have `FieldsShape::Primitive`")
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`")
|
||||
|
|
|
|||
|
|
@ -103,6 +103,9 @@ where
|
|||
}
|
||||
false
|
||||
}
|
||||
BackendRepr::ScalableVector { .. } => {
|
||||
panic!("scalable vectors are unsupported")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ where
|
|||
// FIXME(eddyb) there should be a size cap here
|
||||
// (probably what clang calls "illegal vectors").
|
||||
}
|
||||
BackendRepr::ScalableVector { .. } => panic!("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) {
|
||||
|
|
|
|||
|
|
@ -911,18 +911,24 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
|
|||
// 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 AMDGPU_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(1024, "")];
|
||||
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 AMDGPU_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
|
||||
&[(1024, "")];
|
||||
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"),
|
||||
|
|
@ -937,13 +943,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)]
|
||||
|
|
@ -982,24 +991,26 @@ 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::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => {
|
||||
MIPS_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::AmdGpu => AMDGPU_FEATURES_FOR_CORRECT_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_FIXED_LENGTH_VECTOR_ABI
|
||||
}
|
||||
Arch::AmdGpu => AMDGPU_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::Avr
|
||||
|
|
@ -1011,6 +1022,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,
|
||||
|
|
|
|||
|
|
@ -771,9 +771,25 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -412,7 +412,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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
49
tests/codegen-llvm/scalable-vectors/simple.rs
Normal file
49
tests/codegen-llvm/scalable-vectors/simple.rs
Normal file
|
|
@ -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<const IMM3: i32>(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 <vscale x 4 x i32> @pass_as_ref(ptr {{.*}}align 16{{.*}} %a, <vscale x 4 x i32> %b)
|
||||
pub unsafe fn pass_as_ref(a: &svint32_t, b: svint32_t) -> svint32_t {
|
||||
// CHECK: load <vscale x 4 x i32>, ptr %a, align 16
|
||||
svxar_n_s32::<1>(*a, b)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[target_feature(enable = "sve,sve2")]
|
||||
// CHECK: define <vscale x 4 x i32> @test()
|
||||
pub unsafe fn test() -> svint32_t {
|
||||
let a = svdup_n_s32(1);
|
||||
let b = svdup_n_s32(2);
|
||||
// CHECK: %_0 = call <vscale x 4 x i32> @pass_as_ref(ptr {{.*}}align 16{{.*}} %a, <vscale x 4 x i32> %b)
|
||||
pass_as_ref(&a, b)
|
||||
}
|
||||
44
tests/ui/scalable-vectors/async.rs
Normal file
44
tests/ui/scalable-vectors/async.rs
Normal file
|
|
@ -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::transmute_unchecked;
|
||||
|
||||
#[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 = transmute_unchecked(x);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = unsafe { test_function() };
|
||||
}
|
||||
8
tests/ui/scalable-vectors/async.stderr
Normal file
8
tests/ui/scalable-vectors/async.stderr
Normal file
|
|
@ -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
|
||||
|
||||
51
tests/ui/scalable-vectors/closure-capture.rs
Normal file
51
tests/ui/scalable-vectors/closure-capture.rs
Normal file
|
|
@ -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<const IMM3: i32>(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);
|
||||
});
|
||||
}
|
||||
}
|
||||
8
tests/ui/scalable-vectors/closure-capture.stderr
Normal file
8
tests/ui/scalable-vectors/closure-capture.stderr
Normal file
|
|
@ -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
|
||||
|
||||
31
tests/ui/scalable-vectors/copy-clone.rs
Normal file
31
tests/ui/scalable-vectors/copy-clone.rs
Normal file
|
|
@ -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: Copy>(t: T) {}
|
||||
|
||||
#[target_feature(enable = "sve")]
|
||||
fn test() {
|
||||
unsafe {
|
||||
let a = svdup_n_s32(1);
|
||||
require_copy(a);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
17
tests/ui/scalable-vectors/copy-clone.stderr
Normal file
17
tests/ui/scalable-vectors/copy-clone.stderr
Normal file
|
|
@ -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
|
||||
|
||||
13
tests/ui/scalable-vectors/fn-trait.rs
Normal file
13
tests/ui/scalable-vectors/fn-trait.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_scalable_vector(4)]
|
||||
pub struct ScalableSimdFloat(f32);
|
||||
|
||||
unsafe fn test<T>(f: T)
|
||||
where
|
||||
T: Fn(ScalableSimdFloat), //~ ERROR: scalable vectors cannot be tuple fields
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
8
tests/ui/scalable-vectors/fn-trait.stderr
Normal file
8
tests/ui/scalable-vectors/fn-trait.stderr
Normal file
|
|
@ -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
|
||||
|
||||
93
tests/ui/scalable-vectors/illformed-element-type.rs
Normal file
93
tests/ui/scalable-vectors/illformed-element-type.rs
Normal file
|
|
@ -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
|
||||
122
tests/ui/scalable-vectors/illformed-element-type.stderr
Normal file
122
tests/ui/scalable-vectors/illformed-element-type.stderr
Normal file
|
|
@ -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*` 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*` 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*` 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*` 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*` 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*` 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*` 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*` 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*` 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*` 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*` 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*` 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*` 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*` 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*` and `bool` types are accepted
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
//@ 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 ValidTuple(ValidI32, ValidI32, ValidI32);
|
||||
|
||||
#[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: scalable vector structs can only have scalable vector fields
|
||||
|
||||
#[rustc_scalable_vector]
|
||||
struct DifferentNonVectorTypes(u32, u64);
|
||||
//~^ ERROR: scalable vector structs can only have scalable vector fields
|
||||
|
||||
#[rustc_scalable_vector]
|
||||
struct SomeVectorTypes(ValidI64, u64);
|
||||
//~^ ERROR: scalable vector structs can only have scalable vector fields
|
||||
|
||||
#[rustc_scalable_vector]
|
||||
struct NestedTuple(ValidTuple, ValidTuple);
|
||||
//~^ ERROR: scalable vector structs cannot contain other scalable vector structs
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
error: scalable vectors must be tuple structs
|
||||
--> $DIR/illformed-tuples-of-scalable-vectors.rs:15: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:19:39
|
||||
|
|
||||
LL | struct DifferentVectorTypes(ValidI64, ValidI32);
|
||||
| ^^^^^^^^
|
||||
|
||||
error: scalable vector structs can only have scalable vector fields
|
||||
--> $DIR/illformed-tuples-of-scalable-vectors.rs:23:23
|
||||
|
|
||||
LL | struct NonVectorTypes(u32, u64);
|
||||
| ^^^
|
||||
|
||||
error: scalable vector structs can only have scalable vector fields
|
||||
--> $DIR/illformed-tuples-of-scalable-vectors.rs:27:32
|
||||
|
|
||||
LL | struct DifferentNonVectorTypes(u32, u64);
|
||||
| ^^^
|
||||
|
||||
error: scalable vector structs can only have scalable vector fields
|
||||
--> $DIR/illformed-tuples-of-scalable-vectors.rs:31:34
|
||||
|
|
||||
LL | struct SomeVectorTypes(ValidI64, u64);
|
||||
| ^^^
|
||||
|
||||
error: scalable vector structs cannot contain other scalable vector structs
|
||||
--> $DIR/illformed-tuples-of-scalable-vectors.rs:35:20
|
||||
|
|
||||
LL | struct NestedTuple(ValidTuple, ValidTuple);
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
23
tests/ui/scalable-vectors/illformed-within-types.rs
Normal file
23
tests/ui/scalable-vectors/illformed-within-types.rs
Normal file
|
|
@ -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
|
||||
}
|
||||
32
tests/ui/scalable-vectors/illformed-within-types.stderr
Normal file
32
tests/ui/scalable-vectors/illformed-within-types.stderr
Normal file
|
|
@ -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
|
||||
|
||||
59
tests/ui/scalable-vectors/illformed.rs
Normal file
59
tests/ui/scalable-vectors/illformed.rs
Normal file
|
|
@ -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,
|
||||
//~^ ERROR: scalable vector structs can only have scalable vector fields
|
||||
other: u32,
|
||||
}
|
||||
|
||||
#[rustc_scalable_vector]
|
||||
struct MultipleFieldsTupleWithoutElementCount(f32, u32);
|
||||
//~^ ERROR: scalable vector structs can only have scalable vector fields
|
||||
|
||||
#[rustc_scalable_vector(2)]
|
||||
struct SingleFieldStruct { _ty: f64 }
|
||||
//~^ ERROR: scalable vectors must be tuple structs
|
||||
125
tests/ui/scalable-vectors/illformed.stderr
Normal file
125
tests/ui/scalable-vectors/illformed.stderr
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
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 | | }
|
||||
| |_^
|
||||
|
||||
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: scalable vector structs can only have scalable vector fields
|
||||
--> $DIR/illformed.rs:48:5
|
||||
|
|
||||
LL | _ty: f32,
|
||||
| ^^^^^^^^
|
||||
|
||||
error: scalable vector structs can only have scalable vector fields
|
||||
--> $DIR/illformed.rs:54:47
|
||||
|
|
||||
LL | struct MultipleFieldsTupleWithoutElementCount(f32, u32);
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
163
tests/ui/scalable-vectors/invalid.rs
Normal file
163
tests/ui/scalable-vectors/invalid.rs
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
//@ 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<T>),
|
||||
}
|
||||
|
||||
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<T> Bar<T> {
|
||||
#[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<T> FooBaz for Bar<T> {
|
||||
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(65536)]
|
||||
//~^ ERROR: element count in `rustc_scalable_vector` is too large: `65536`
|
||||
struct CountTooLarge(f32);
|
||||
|
||||
#[rustc_scalable_vector(4)]
|
||||
struct Okay(f32);
|
||||
|
||||
#[rustc_scalable_vector]
|
||||
struct OkayNoArg(f32);
|
||||
//~^ ERROR: scalable vector structs can only have scalable vector fields
|
||||
339
tests/ui/scalable-vectors/invalid.stderr
Normal file
339
tests/ui/scalable-vectors/invalid.stderr
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
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: element count in `rustc_scalable_vector` is too large: `65536`
|
||||
--> $DIR/invalid.rs:154:1
|
||||
|
|
||||
LL | #[rustc_scalable_vector(65536)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the value may not exceed `u16::MAX`
|
||||
|
||||
error: scalable vector structs can only have scalable vector fields
|
||||
--> $DIR/invalid.rs:162:18
|
||||
|
|
||||
LL | struct OkayNoArg(f32);
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 39 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0539, E0805.
|
||||
For more information about an error, try `rustc --explain E0539`.
|
||||
40
tests/ui/scalable-vectors/require-target-feature.rs
Normal file
40
tests/ui/scalable-vectors/require-target-feature.rs
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
25
tests/ui/scalable-vectors/require-target-feature.stderr
Normal file
25
tests/ui/scalable-vectors/require-target-feature.stderr
Normal file
|
|
@ -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
|
||||
|
||||
37
tests/ui/scalable-vectors/value-type.rs
Normal file
37
tests/ui/scalable-vectors/value-type.rs
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
17
tests/ui/scalable-vectors/value-type.stderr
Normal file
17
tests/ui/scalable-vectors/value-type.stderr
Normal file
|
|
@ -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
|
||||
|
||||
10
tests/ui/scalable-vectors/wellformed-arrays.rs
Normal file
10
tests/ui/scalable-vectors/wellformed-arrays.rs
Normal file
|
|
@ -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!();
|
||||
}
|
||||
48
tests/ui/scalable-vectors/wellformed.rs
Normal file
48
tests/ui/scalable-vectors/wellformed.rs
Normal file
|
|
@ -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);
|
||||
|
|
@ -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: []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue