From b3494b4cf0d3cda31861fd4e42aa74ddf8c105d9 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 8 Jul 2025 08:29:46 +0000 Subject: [PATCH 01/12] attr: parse `repr(simd, scalable(N))` Extend parsing of `ReprOptions` with `repr(scalable(N))` which always accepts a single literal integral value - the base multiple of lanes that are in a scalable vector. Can only be applied to structs and must be used with `repr(simd)`. Co-authored-by: Jamie Cunliffe --- compiler/rustc_abi/src/lib.rs | 8 + .../src/attributes.rs | 8 + compiler/rustc_attr_parsing/messages.ftl | 4 + .../rustc_attr_parsing/src/attributes/repr.rs | 22 +- .../src/session_diagnostics.rs | 8 + compiler/rustc_middle/src/ty/mod.rs | 14 +- compiler/rustc_middle/src/ty/sty.rs | 8 + compiler/rustc_passes/messages.ftl | 3 + compiler/rustc_passes/src/check_attr.rs | 23 +- compiler/rustc_passes/src/errors.rs | 7 + compiler/rustc_span/src/symbol.rs | 1 + tests/ui/simd/scalable/invalid.rs | 228 ++++++ tests/ui/simd/scalable/invalid.stderr | 765 ++++++++++++++++++ tests/ui/thir-print/thir-tree-match.stdout | 8 +- 14 files changed, 1099 insertions(+), 8 deletions(-) create mode 100644 tests/ui/simd/scalable/invalid.rs create mode 100644 tests/ui/simd/scalable/invalid.stderr diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index de4b5a46c81aa..1f87d461a2bbc 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -93,9 +93,11 @@ bitflags! { // Other flags can still inhibit reordering and thus randomization. // The seed stored in `ReprOptions.field_shuffle_seed`. const RANDOMIZE_LAYOUT = 1 << 4; + const IS_SCALABLE = 1 << 5; // 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(); } @@ -143,6 +145,7 @@ pub struct ReprOptions { pub align: Option, pub pack: Option, pub flags: ReprFlags, + pub scalable: Option, /// The seed to be used for randomizing a type's layout /// /// Note: This could technically be a `u128` which would @@ -159,6 +162,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) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 41a9e8feaafab..b7524c3c27eef 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -65,6 +65,7 @@ pub enum ReprAttr { ReprC, ReprPacked(Align), ReprSimd, + ReprScalable(ScalableElt), ReprTransparent, ReprAlign(Align), } @@ -82,6 +83,13 @@ pub enum IntType { UnsignedInt(ast::UintTy), } +/// The base multiple of lanes that are in a scalable vector. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)] +pub struct ScalableElt { + pub elt: u16, +} + #[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] pub struct Deprecation { pub since: DeprecatedSince, diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index bec3a1e8a599b..8fd05029e71b9 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -114,6 +114,10 @@ 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_scalable_missing_n = + invalid `scalable(num)` attribute: `scalable` needs an argument + .suggestion = supply an argument here + attr_parsing_soft_no_args = `soft` should not have any arguments diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 6a45832ed7fda..cd81c9e04e5d7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,6 +1,6 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; -use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; +use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr, ScalableElt}; use rustc_feature::{AttributeTemplate, template}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; @@ -144,6 +144,11 @@ fn parse_repr( (Some(sym::Rust), ArgParser::NoArgs) => Some(ReprRust), (Some(sym::C), ArgParser::NoArgs) => Some(ReprC), (Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd), + (Some(sym::scalable), ArgParser::List(l)) => parse_repr_scalable(cx, l, param.span()), + (Some(sym::scalable), ArgParser::NoArgs) => { + cx.emit_err(session_diagnostics::ScalableAttrMissingN { span: param.span() }); + None + } (Some(sym::transparent), ArgParser::NoArgs) => Some(ReprTransparent), (Some(name @ int_pat!()), ArgParser::NoArgs) => { // int_pat!() should make sure it always parses @@ -322,3 +327,18 @@ impl AttributeParser for AlignParser { Some(AttributeKind::Align { align, span }) } } + +fn parse_repr_scalable( + cx: &AcceptContext<'_, '_, S>, + list: &MetaItemListParser<'_>, + span: Span, +) -> Option { + let Some(LitKind::Int(literal, LitIntType::Unsuffixed)) = + list.single().and_then(|elt| elt.lit()).map(|lit| lit.kind) + else { + cx.emit_err(session_diagnostics::ScalableAttrMissingN { span }); + return None; + }; + + literal.get().try_into().ok().map(|elt| ReprAttr::ReprScalable(ScalableElt { elt })) +} diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 28f6786f37fae..255c318fbc71b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -635,3 +635,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag } } + +#[derive(Diagnostic)] +#[diag(attr_parsing_scalable_missing_n)] +pub(crate) struct ScalableAttrMissingN { + #[primary_span] + #[suggestion(applicability = "has-placeholders", code = "scalable(...)")] + pub span: Span, +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a352ab3fd08a1..05c6343f4428d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1513,6 +1513,7 @@ impl<'tcx> TyCtxt<'tcx> { let mut size = None; let mut max_align: Option = None; let mut min_pack: Option = None; + let mut elt: Option = None; // Generate a deterministically-derived seed from the item's path hash // to allow for cross-crate compilation to actually work @@ -1542,6 +1543,10 @@ impl<'tcx> TyCtxt<'tcx> { } attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, attr::ReprSimd => ReprFlags::IS_SIMD, + attr::ReprScalable(e) => { + elt = Some(e.elt as u32); + ReprFlags::IS_SCALABLE + } attr::ReprInt(i) => { size = Some(match i { attr::IntType::SignedInt(x) => match x { @@ -1586,7 +1591,14 @@ impl<'tcx> TyCtxt<'tcx> { flags.insert(ReprFlags::IS_LINEAR); } - ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed } + ReprOptions { + int: size, + align: max_align, + pack: min_pack, + flags, + field_shuffle_seed, + scalable: elt, + } } /// Look up the name of a definition across crates. This does not look at HIR. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8bb3b3f1263fa..899ceb40c3063 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1194,6 +1194,14 @@ impl<'tcx> Ty<'tcx> { } } + #[inline] + pub fn is_scalable_simd(self) -> bool { + match self.kind() { + Adt(def, _) => def.repr().simd() && def.repr().scalable(), + _ => false, + } + } + pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { Array(ty, _) | Slice(ty) => *ty, diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 46c21dcf67b19..854c76a4455b8 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -605,6 +605,9 @@ passes_repr_align_should_be_align = passes_repr_conflicting = conflicting representation hints +passes_repr_scalable_without_simd = + `scalable` representation hint without `simd` representation hint + passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn` .label = not a `const fn` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7a73dd17e0c63..43e30e5c321ca 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1987,6 +1987,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut is_explicit_rust = false; let mut is_c = false; let mut is_simd = false; + let mut is_scalable = false; let mut is_transparent = false; for (repr, repr_span) in reprs { @@ -2055,6 +2056,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { continue; } } + ReprAttr::ReprScalable(..) => { + is_scalable = true; + if target != Target::Struct { + self.dcx().emit_err(errors::AttrApplication::Struct { + hint_span: *repr_span, + span, + }); + } else { + continue; + } + } ReprAttr::ReprTransparent => { is_transparent = true; match target { @@ -2116,13 +2128,20 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: target.to_string(), }); } - if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) { + if is_explicit_rust && (int_reprs > 0 || is_c || is_simd || is_scalable) { let hint_spans = hint_spans.clone().collect(); self.dcx().emit_err(errors::ReprConflicting { hint_spans }); } - // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8) + // Warn on `repr(scalable(N))` w/out `repr(simd)` + // i.e. only `repr(simd, scalable(N))` permitted + if is_scalable && !is_simd { + let hint_spans = hint_spans.clone().collect(); + self.dcx().emit_err(errors::ReprScalableWithoutSimd { hint_spans }); + } + // Warn on repr(u8, u16), repr(C, simd), repr(C, scalable), and c-like-enum-repr(C, u8) if (int_reprs > 1) || (is_simd && is_c) + || (is_scalable && is_c) || (int_reprs == 1 && is_c && item.is_some_and(|item| { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4ad615a2abfc8..f4c5c2941e086 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -611,6 +611,13 @@ pub(crate) struct ReprConflicting { pub hint_spans: Vec, } +#[derive(Diagnostic)] +#[diag(passes_repr_scalable_without_simd)] +pub(crate) struct ReprScalableWithoutSimd { + #[primary_span] + pub hint_spans: Vec, +} + #[derive(Diagnostic)] #[diag(passes_repr_align_greater_than_target_max, code = E0589)] #[note] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b12edf426c1b..a5eecdd7e6f8d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1923,6 +1923,7 @@ symbols! { saturating_add, saturating_div, saturating_sub, + scalable, sdylib, search_unbox, select_unpredictable, diff --git a/tests/ui/simd/scalable/invalid.rs b/tests/ui/simd/scalable/invalid.rs new file mode 100644 index 0000000000000..f98d5fe620719 --- /dev/null +++ b/tests/ui/simd/scalable/invalid.rs @@ -0,0 +1,228 @@ +//@ edition: 2024 +#![allow(internal_features, unused_imports, unused_macros)] +#![feature(extern_types)] +#![feature(gen_blocks)] +#![feature(repr_simd)] +#![feature(stmt_expr_attributes)] +#![feature(trait_alias)] + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +extern crate std as other_std; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +use std::vec::Vec; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +static _X: u32 = 0; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +const _Y: u32 = 0; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +mod bar { +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +unsafe extern "C" { + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + static X: &'static u32; + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + type Y; + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + fn foo(); +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +type Foo = u32; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +enum Bar<#[repr(simd, scalable(4))] T> { +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + Baz(std::marker::PhantomData), +} + +struct Qux { + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + field: u32, +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +union FooBar { + x: u32, + y: u32, +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +trait FooBaz { + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + type Foo; + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + const Bar: i32; + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + fn foo() {} +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +trait FooQux = FooBaz; + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +impl Bar { + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + fn foo() {} +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +impl FooBaz for Bar { + type Foo = u32; + const Bar: i32 = 3; +} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +macro_rules! barqux { ($foo:tt) => { $foo }; } + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +fn barqux(#[repr(simd, scalable(4))] _x: u32) {} +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +//~^^^ ERROR: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +async fn async_foo() {} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +gen fn gen_foo() {} + +#[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct +async gen fn async_gen_foo() {} + +fn main() { + let _x = #[repr(simd, scalable(4))] || { }; +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + let _y = #[repr(simd, scalable(4))] 3 + 4; +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + let _z = 3; + + match _z { + #[repr(simd, scalable(4))] +//~^ ERROR: attribute should be applied to a struct +//~^^ ERROR: attribute should be applied to a struct + 1 => (), + _ => (), + } +} + +#[repr(transparent, simd, scalable(4))] //~ ERROR: transparent struct cannot have other repr hints +struct CombinedWithReprTransparent { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(Rust, simd, scalable(4))] //~ ERROR: conflicting representation hints +struct CombinedWithReprRust { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(C, simd, scalable(4))] +//~^ ERROR: conflicting representation hints +//~^^ WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +struct CombinedWithReprC { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(scalable(4))] //~ ERROR: `scalable` representation hint without `simd` representation hint +struct WithoutReprSimd { + _ty: [f64], +} + +#[repr(simd, scalable)] //~ ERROR: invalid `scalable(num)` attribute: `scalable` needs an argument +struct MissingArg { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(simd, scalable("4"))] //~ ERROR: invalid `scalable(num)` attribute: `scalable` needs an argument +struct ArgNotLit { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(simd, scalable(4, 2))] //~ ERROR: invalid `scalable(num)` attribute: `scalable` needs an argument +struct ArgMultipleLits { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(simd, scalable = "4")] //~ ERROR: unrecognized representation hint +struct ArgKind { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} + +#[repr(simd, scalable(4))] +struct Okay { +//~^ ERROR: SIMD vector's only field must be an array + _ty: [f64], +} diff --git a/tests/ui/simd/scalable/invalid.stderr b/tests/ui/simd/scalable/invalid.stderr new file mode 100644 index 0000000000000..b7cb0d9d8f12e --- /dev/null +++ b/tests/ui/simd/scalable/invalid.stderr @@ -0,0 +1,765 @@ +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/invalid.rs:134:11 + | +LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: invalid `scalable(num)` attribute: `scalable` needs an argument + --> $DIR/invalid.rs:200:14 + | +LL | #[repr(simd, scalable)] + | ^^^^^^^^ help: supply an argument here: `scalable(...)` + +error: invalid `scalable(num)` attribute: `scalable` needs an argument + --> $DIR/invalid.rs:206:14 + | +LL | #[repr(simd, scalable("4"))] + | ^^^^^^^^^^^^^ help: supply an argument here: `scalable(...)` + +error: invalid `scalable(num)` attribute: `scalable` needs an argument + --> $DIR/invalid.rs:212:14 + | +LL | #[repr(simd, scalable(4, 2))] + | ^^^^^^^^^^^^^^ help: supply an argument here: `scalable(...)` + +error[E0552]: unrecognized representation hint + --> $DIR/invalid.rs:218:14 + | +LL | #[repr(simd, scalable = "4")] + | ^^^^^^^^^^^^^^ + | + = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:9:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | extern crate std as other_std; + | ------------------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:9:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | extern crate std as other_std; + | ------------------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:14:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | use std::vec::Vec; + | ------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:14:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | use std::vec::Vec; + | ------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:19:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | static _X: u32 = 0; + | ------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:19:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | static _X: u32 = 0; + | ------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:24:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | const _Y: u32 = 0; + | ------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:24:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | const _Y: u32 = 0; + | ------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:29:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / mod bar { +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:29:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / mod bar { +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:35:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / unsafe extern "C" { +LL | | #[repr(simd, scalable(4))] +... | +LL | | fn foo(); +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:35:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / unsafe extern "C" { +LL | | #[repr(simd, scalable(4))] +... | +LL | | fn foo(); +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:53:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | type Foo = u32; + | --------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:53:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | type Foo = u32; + | --------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:58:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / enum Bar<#[repr(simd, scalable(4))] T> { +LL | | +LL | | +LL | | #[repr(simd, scalable(4))] +... | +LL | | Baz(std::marker::PhantomData), +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:58:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / enum Bar<#[repr(simd, scalable(4))] T> { +LL | | +LL | | +LL | | #[repr(simd, scalable(4))] +... | +LL | | Baz(std::marker::PhantomData), +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:61:17 + | +LL | enum Bar<#[repr(simd, scalable(4))] T> { + | ^^^^ - not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:61:23 + | +LL | enum Bar<#[repr(simd, scalable(4))] T> { + | ^^^^^^^^^^^ - not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:64:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | Baz(std::marker::PhantomData), + | -------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:64:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | Baz(std::marker::PhantomData), + | -------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:71:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | field: u32, + | ---------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:71:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | field: u32, + | ---------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:77:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / union FooBar { +LL | | x: u32, +LL | | y: u32, +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:77:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / union FooBar { +LL | | x: u32, +LL | | y: u32, +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:85:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / trait FooBaz { +LL | | #[repr(simd, scalable(4))] +... | +LL | | fn foo() {} +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:85:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / trait FooBaz { +LL | | #[repr(simd, scalable(4))] +... | +LL | | fn foo() {} +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:103:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | trait FooQux = FooBaz; + | ---------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:103:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | trait FooQux = FooBaz; + | ---------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:108:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / impl Bar { +LL | | #[repr(simd, scalable(4))] +... | +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:108:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / impl Bar { +LL | | #[repr(simd, scalable(4))] +... | +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:118:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | / impl FooBaz for Bar { +LL | | type Foo = u32; +LL | | const Bar: i32 = 3; +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:118:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | / impl FooBaz for Bar { +LL | | type Foo = u32; +LL | | const Bar: i32 = 3; +LL | | } + | |_- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:126:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | macro_rules! barqux { ($foo:tt) => { $foo }; } + | ---------------------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:126:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | macro_rules! barqux { ($foo:tt) => { $foo }; } + | ---------------------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:131:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} + | ------------------------------------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:131:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} + | ------------------------------------------------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:134:18 + | +LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} + | -------^^^^----------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:134:24 + | +LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} + | -------------^^^^^^^^^^^---------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:139:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | async fn async_foo() {} + | ----------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:139:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | async fn async_foo() {} + | ----------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:144:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | gen fn gen_foo() {} + | ------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:144:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | gen fn gen_foo() {} + | ------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:149:8 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | async gen fn async_gen_foo() {} + | ------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:149:14 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | async gen fn async_gen_foo() {} + | ------------------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:155:21 + | +LL | let _x = #[repr(simd, scalable(4))] || { }; + | ^^^^ ------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:155:27 + | +LL | let _x = #[repr(simd, scalable(4))] || { }; + | ^^^^^^^^^^^ ------ not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:158:21 + | +LL | let _y = #[repr(simd, scalable(4))] 3 + 4; + | ^^^^ - not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:158:27 + | +LL | let _y = #[repr(simd, scalable(4))] 3 + 4; + | ^^^^^^^^^^^ - not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:161:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | let _z = 3; + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:161:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | let _z = 3; + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:167:16 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | 1 => (), + | ------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:167:22 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | 1 => (), + | ------- not a struct + +error[E0692]: transparent struct cannot have other repr hints + --> $DIR/invalid.rs:175:8 + | +LL | #[repr(transparent, simd, scalable(4))] + | ^^^^^^^^^^^ ^^^^ ^^^^^^^^^^^ + +error[E0566]: conflicting representation hints + --> $DIR/invalid.rs:181:8 + | +LL | #[repr(Rust, simd, scalable(4))] + | ^^^^ ^^^^ ^^^^^^^^^^^ + +error[E0566]: conflicting representation hints + --> $DIR/invalid.rs:187:8 + | +LL | #[repr(C, simd, scalable(4))] + | ^ ^^^^ ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 + = note: `#[deny(conflicting_repr_hints)]` on by default + +error: `scalable` representation hint without `simd` representation hint + --> $DIR/invalid.rs:195:8 + | +LL | #[repr(scalable(4))] + | ^^^^^^^^^^^ + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:89:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | type Foo; + | --------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:89:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | type Foo; + | --------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:93:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | const Bar: i32; + | --------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:93:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | const Bar: i32; + | --------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:97:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | fn foo() {} + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:97:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | fn foo() {} + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:112:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | fn foo() {} + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:112:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | fn foo() {} + | ----------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:39:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | static X: &'static u32; + | ----------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:39:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | static X: &'static u32; + | ----------------------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:43:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | type Y; + | ------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:43:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | type Y; + | ------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:47:12 + | +LL | #[repr(simd, scalable(4))] + | ^^^^ +... +LL | fn foo(); + | --------- not a struct + +error[E0517]: attribute should be applied to a struct + --> $DIR/invalid.rs:47:18 + | +LL | #[repr(simd, scalable(4))] + | ^^^^^^^^^^^ +... +LL | fn foo(); + | --------- not a struct + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:176:1 + | +LL | struct CombinedWithReprTransparent { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:182:1 + | +LL | struct CombinedWithReprRust { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:190:1 + | +LL | struct CombinedWithReprC { + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:201:1 + | +LL | struct MissingArg { + | ^^^^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:207:1 + | +LL | struct ArgNotLit { + | ^^^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:213:1 + | +LL | struct ArgMultipleLits { + | ^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:219:1 + | +LL | struct ArgKind { + | ^^^^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/invalid.rs:225:1 + | +LL | struct Okay { + | ^^^^^^^^^^^ +LL | +LL | _ty: [f64], + | ---------- not an array + +error: aborting due to 83 previous errors + +Some errors have detailed explanations: E0076, E0517, E0552, E0566, E0692. +For more information about an error, try `rustc --explain E0076`. +Future incompatibility report: Future breakage diagnostic: +error[E0566]: conflicting representation hints + --> $DIR/invalid.rs:187:8 + | +LL | #[repr(C, simd, scalable(4))] + | ^ ^^^^ ^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #68585 + = note: `#[deny(conflicting_repr_hints)]` on by default + diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index 910582ae4d9e9..88ca75c9b98dc 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -94,7 +94,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: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 3477539199540094892 } args: [] variant_index: 0 subpatterns: [ @@ -108,7 +108,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: 10333377570083945360 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 10333377570083945360 } args: [] variant_index: 0 subpatterns: [] @@ -156,7 +156,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: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 3477539199540094892 } args: [] variant_index: 0 subpatterns: [ @@ -208,7 +208,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: 3477539199540094892 } + repr: ReprOptions { int: None, align: None, pack: None, flags: , scalable: None, field_shuffle_seed: 3477539199540094892 } args: [] variant_index: 1 subpatterns: [] From c8b340ea75ec5e67f372af05ce481bdfa4825c26 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 8 Jul 2025 08:36:47 +0000 Subject: [PATCH 02/12] feature: gate `repr(scalable)` with `repr_scalable` Add a `repr_scalable` feature gate and require its use for the `repr(scalable(N)` attribute. Co-authored-by: Jamie Cunliffe --- compiler/rustc_ast_passes/src/feature_gate.rs | 9 + compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + .../feature-gate-repr-scalable.rs | 8 + .../feature-gate-repr-scalable.stderr | 21 +++ tests/ui/simd/scalable/invalid.rs | 1 + tests/ui/simd/scalable/invalid.stderr | 168 +++++++++--------- 7 files changed, 126 insertions(+), 84 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-repr-scalable.rs create mode 100644 tests/ui/feature-gates/feature-gate-repr-scalable.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 8114733f40670..7cf1b5fa20cf5 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -213,6 +213,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "SIMD types are experimental and possibly buggy" ); } + + if item.has_name(sym::scalable) { + gate!( + &self, + repr_scalable, + attr.span, + "scalable vector types are experimental" + ); + } } } } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index efd8bde71d76d..c3f30b7f7cc38 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -235,6 +235,8 @@ declare_features! ( (internal, prelude_import, "1.2.0", None), /// Used to identify crates that contain the profiler runtime. (internal, profiler_runtime, "1.18.0", None), + /// Allows the use of `repr(scalable)`. + (unstable, repr_scalable, "CURRENT_RUSTC_VERSION", None), /// Allows using `rustc_*` attributes (RFC 572). (internal, rustc_attrs, "1.0.0", None), /// Introduces a hierarchy of `Sized` traits (RFC 3729). diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a5eecdd7e6f8d..1a0e3427979eb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1764,6 +1764,7 @@ symbols! { repr_align, repr_align_enum, repr_packed, + repr_scalable, repr_simd, repr_transparent, require, diff --git a/tests/ui/feature-gates/feature-gate-repr-scalable.rs b/tests/ui/feature-gates/feature-gate-repr-scalable.rs new file mode 100644 index 0000000000000..dfa8729a7f6ab --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-repr-scalable.rs @@ -0,0 +1,8 @@ +#![feature(repr_simd)] + +#[repr(simd, scalable(16))] //~ ERROR: scalable vector types are experimental +struct Foo { //~ ERROR: SIMD vector's only field must be an array + _ty: [i8], +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-repr-scalable.stderr b/tests/ui/feature-gates/feature-gate-repr-scalable.stderr new file mode 100644 index 0000000000000..61a8c73f9ffbb --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-repr-scalable.stderr @@ -0,0 +1,21 @@ +error[E0658]: scalable vector types are experimental + --> $DIR/feature-gate-repr-scalable.rs:3:1 + | +LL | #[repr(simd, scalable(16))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(repr_scalable)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0076]: SIMD vector's only field must be an array + --> $DIR/feature-gate-repr-scalable.rs:4:1 + | +LL | struct Foo { + | ^^^^^^^^^^ +LL | _ty: [i8], + | --------- not an array + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0076, E0658. +For more information about an error, try `rustc --explain E0076`. diff --git a/tests/ui/simd/scalable/invalid.rs b/tests/ui/simd/scalable/invalid.rs index f98d5fe620719..06f7aaeb75119 100644 --- a/tests/ui/simd/scalable/invalid.rs +++ b/tests/ui/simd/scalable/invalid.rs @@ -2,6 +2,7 @@ #![allow(internal_features, unused_imports, unused_macros)] #![feature(extern_types)] #![feature(gen_blocks)] +#![feature(repr_scalable)] #![feature(repr_simd)] #![feature(stmt_expr_attributes)] #![feature(trait_alias)] diff --git a/tests/ui/simd/scalable/invalid.stderr b/tests/ui/simd/scalable/invalid.stderr index b7cb0d9d8f12e..2ec7bbd8326f5 100644 --- a/tests/ui/simd/scalable/invalid.stderr +++ b/tests/ui/simd/scalable/invalid.stderr @@ -1,29 +1,29 @@ error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters - --> $DIR/invalid.rs:134:11 + --> $DIR/invalid.rs:135:11 | LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid `scalable(num)` attribute: `scalable` needs an argument - --> $DIR/invalid.rs:200:14 + --> $DIR/invalid.rs:201:14 | LL | #[repr(simd, scalable)] | ^^^^^^^^ help: supply an argument here: `scalable(...)` error: invalid `scalable(num)` attribute: `scalable` needs an argument - --> $DIR/invalid.rs:206:14 + --> $DIR/invalid.rs:207:14 | LL | #[repr(simd, scalable("4"))] | ^^^^^^^^^^^^^ help: supply an argument here: `scalable(...)` error: invalid `scalable(num)` attribute: `scalable` needs an argument - --> $DIR/invalid.rs:212:14 + --> $DIR/invalid.rs:213:14 | LL | #[repr(simd, scalable(4, 2))] | ^^^^^^^^^^^^^^ help: supply an argument here: `scalable(...)` error[E0552]: unrecognized representation hint - --> $DIR/invalid.rs:218:14 + --> $DIR/invalid.rs:219:14 | LL | #[repr(simd, scalable = "4")] | ^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | #[repr(simd, scalable = "4")] = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:9:8 + --> $DIR/invalid.rs:10:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -40,7 +40,7 @@ LL | extern crate std as other_std; | ------------------------------ not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:9:14 + --> $DIR/invalid.rs:10:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | extern crate std as other_std; | ------------------------------ not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:14:8 + --> $DIR/invalid.rs:15:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -58,7 +58,7 @@ LL | use std::vec::Vec; | ------------------ not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:14:14 + --> $DIR/invalid.rs:15:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -67,7 +67,7 @@ LL | use std::vec::Vec; | ------------------ not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:19:8 + --> $DIR/invalid.rs:20:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -76,7 +76,7 @@ LL | static _X: u32 = 0; | ------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:19:14 + --> $DIR/invalid.rs:20:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | static _X: u32 = 0; | ------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:24:8 + --> $DIR/invalid.rs:25:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -94,7 +94,7 @@ LL | const _Y: u32 = 0; | ------------------ not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:24:14 + --> $DIR/invalid.rs:25:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | const _Y: u32 = 0; | ------------------ not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:29:8 + --> $DIR/invalid.rs:30:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -113,7 +113,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:29:14 + --> $DIR/invalid.rs:30:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -123,7 +123,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:35:8 + --> $DIR/invalid.rs:36:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -136,7 +136,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:35:14 + --> $DIR/invalid.rs:36:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:53:8 + --> $DIR/invalid.rs:54:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -158,7 +158,7 @@ LL | type Foo = u32; | --------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:53:14 + --> $DIR/invalid.rs:54:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | type Foo = u32; | --------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:58:8 + --> $DIR/invalid.rs:59:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -182,7 +182,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:58:14 + --> $DIR/invalid.rs:59:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -197,19 +197,19 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:61:17 + --> $DIR/invalid.rs:62:17 | LL | enum Bar<#[repr(simd, scalable(4))] T> { | ^^^^ - not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:61:23 + --> $DIR/invalid.rs:62:23 | LL | enum Bar<#[repr(simd, scalable(4))] T> { | ^^^^^^^^^^^ - not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:64:12 + --> $DIR/invalid.rs:65:12 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -218,7 +218,7 @@ LL | Baz(std::marker::PhantomData), | -------------------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:64:18 + --> $DIR/invalid.rs:65:18 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -227,7 +227,7 @@ LL | Baz(std::marker::PhantomData), | -------------------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:71:12 + --> $DIR/invalid.rs:72:12 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -236,7 +236,7 @@ LL | field: u32, | ---------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:71:18 + --> $DIR/invalid.rs:72:18 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -245,7 +245,7 @@ LL | field: u32, | ---------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:77:8 + --> $DIR/invalid.rs:78:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -257,7 +257,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:77:14 + --> $DIR/invalid.rs:78:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -269,7 +269,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:85:8 + --> $DIR/invalid.rs:86:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -282,7 +282,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:85:14 + --> $DIR/invalid.rs:86:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -295,7 +295,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:103:8 + --> $DIR/invalid.rs:104:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -304,7 +304,7 @@ LL | trait FooQux = FooBaz; | ---------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:103:14 + --> $DIR/invalid.rs:104:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL | trait FooQux = FooBaz; | ---------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:108:8 + --> $DIR/invalid.rs:109:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -325,7 +325,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:108:14 + --> $DIR/invalid.rs:109:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:118:8 + --> $DIR/invalid.rs:119:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -349,7 +349,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:118:14 + --> $DIR/invalid.rs:119:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -361,7 +361,7 @@ LL | | } | |_- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:126:8 + --> $DIR/invalid.rs:127:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -370,7 +370,7 @@ LL | macro_rules! barqux { ($foo:tt) => { $foo }; } | ---------------------------------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:126:14 + --> $DIR/invalid.rs:127:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -379,7 +379,7 @@ LL | macro_rules! barqux { ($foo:tt) => { $foo }; } | ---------------------------------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:131:8 + --> $DIR/invalid.rs:132:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -388,7 +388,7 @@ LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} | ------------------------------------------------ not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:131:14 + --> $DIR/invalid.rs:132:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -397,19 +397,19 @@ LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} | ------------------------------------------------ not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:134:18 + --> $DIR/invalid.rs:135:18 | LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} | -------^^^^----------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:134:24 + --> $DIR/invalid.rs:135:24 | LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} | -------------^^^^^^^^^^^---------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:139:8 + --> $DIR/invalid.rs:140:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -418,7 +418,7 @@ LL | async fn async_foo() {} | ----------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:139:14 + --> $DIR/invalid.rs:140:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | async fn async_foo() {} | ----------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:144:8 + --> $DIR/invalid.rs:145:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -436,7 +436,7 @@ LL | gen fn gen_foo() {} | ------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:144:14 + --> $DIR/invalid.rs:145:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -445,7 +445,7 @@ LL | gen fn gen_foo() {} | ------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:149:8 + --> $DIR/invalid.rs:150:8 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -454,7 +454,7 @@ LL | async gen fn async_gen_foo() {} | ------------------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:149:14 + --> $DIR/invalid.rs:150:14 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -463,31 +463,31 @@ LL | async gen fn async_gen_foo() {} | ------------------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:155:21 + --> $DIR/invalid.rs:156:21 | LL | let _x = #[repr(simd, scalable(4))] || { }; | ^^^^ ------ not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:155:27 + --> $DIR/invalid.rs:156:27 | LL | let _x = #[repr(simd, scalable(4))] || { }; | ^^^^^^^^^^^ ------ not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:158:21 + --> $DIR/invalid.rs:159:21 | LL | let _y = #[repr(simd, scalable(4))] 3 + 4; | ^^^^ - not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:158:27 + --> $DIR/invalid.rs:159:27 | LL | let _y = #[repr(simd, scalable(4))] 3 + 4; | ^^^^^^^^^^^ - not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:161:12 + --> $DIR/invalid.rs:162:12 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -496,7 +496,7 @@ LL | let _z = 3; | ----------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:161:18 + --> $DIR/invalid.rs:162:18 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -505,7 +505,7 @@ LL | let _z = 3; | ----------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:167:16 + --> $DIR/invalid.rs:168:16 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -514,7 +514,7 @@ LL | 1 => (), | ------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:167:22 + --> $DIR/invalid.rs:168:22 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -523,19 +523,19 @@ LL | 1 => (), | ------- not a struct error[E0692]: transparent struct cannot have other repr hints - --> $DIR/invalid.rs:175:8 + --> $DIR/invalid.rs:176:8 | LL | #[repr(transparent, simd, scalable(4))] | ^^^^^^^^^^^ ^^^^ ^^^^^^^^^^^ error[E0566]: conflicting representation hints - --> $DIR/invalid.rs:181:8 + --> $DIR/invalid.rs:182:8 | LL | #[repr(Rust, simd, scalable(4))] | ^^^^ ^^^^ ^^^^^^^^^^^ error[E0566]: conflicting representation hints - --> $DIR/invalid.rs:187:8 + --> $DIR/invalid.rs:188:8 | LL | #[repr(C, simd, scalable(4))] | ^ ^^^^ ^^^^^^^^^^^ @@ -545,13 +545,13 @@ LL | #[repr(C, simd, scalable(4))] = note: `#[deny(conflicting_repr_hints)]` on by default error: `scalable` representation hint without `simd` representation hint - --> $DIR/invalid.rs:195:8 + --> $DIR/invalid.rs:196:8 | LL | #[repr(scalable(4))] | ^^^^^^^^^^^ error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:89:12 + --> $DIR/invalid.rs:90:12 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -560,7 +560,7 @@ LL | type Foo; | --------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:89:18 + --> $DIR/invalid.rs:90:18 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -569,7 +569,7 @@ LL | type Foo; | --------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:93:12 + --> $DIR/invalid.rs:94:12 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -578,7 +578,7 @@ LL | const Bar: i32; | --------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:93:18 + --> $DIR/invalid.rs:94:18 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -587,7 +587,7 @@ LL | const Bar: i32; | --------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:97:12 + --> $DIR/invalid.rs:98:12 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -596,7 +596,7 @@ LL | fn foo() {} | ----------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:97:18 + --> $DIR/invalid.rs:98:18 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -605,7 +605,7 @@ LL | fn foo() {} | ----------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:112:12 + --> $DIR/invalid.rs:113:12 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -614,7 +614,7 @@ LL | fn foo() {} | ----------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:112:18 + --> $DIR/invalid.rs:113:18 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -623,7 +623,7 @@ LL | fn foo() {} | ----------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:39:12 + --> $DIR/invalid.rs:40:12 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -632,7 +632,7 @@ LL | static X: &'static u32; | ----------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:39:18 + --> $DIR/invalid.rs:40:18 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -641,7 +641,7 @@ LL | static X: &'static u32; | ----------------------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:43:12 + --> $DIR/invalid.rs:44:12 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -650,7 +650,7 @@ LL | type Y; | ------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:43:18 + --> $DIR/invalid.rs:44:18 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -659,7 +659,7 @@ LL | type Y; | ------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:47:12 + --> $DIR/invalid.rs:48:12 | LL | #[repr(simd, scalable(4))] | ^^^^ @@ -668,7 +668,7 @@ LL | fn foo(); | --------- not a struct error[E0517]: attribute should be applied to a struct - --> $DIR/invalid.rs:47:18 + --> $DIR/invalid.rs:48:18 | LL | #[repr(simd, scalable(4))] | ^^^^^^^^^^^ @@ -677,7 +677,7 @@ LL | fn foo(); | --------- not a struct error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:176:1 + --> $DIR/invalid.rs:177:1 | LL | struct CombinedWithReprTransparent { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -686,7 +686,7 @@ LL | _ty: [f64], | ---------- not an array error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:182:1 + --> $DIR/invalid.rs:183:1 | LL | struct CombinedWithReprRust { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -695,7 +695,7 @@ LL | _ty: [f64], | ---------- not an array error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:190:1 + --> $DIR/invalid.rs:191:1 | LL | struct CombinedWithReprC { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -704,7 +704,7 @@ LL | _ty: [f64], | ---------- not an array error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:201:1 + --> $DIR/invalid.rs:202:1 | LL | struct MissingArg { | ^^^^^^^^^^^^^^^^^ @@ -713,7 +713,7 @@ LL | _ty: [f64], | ---------- not an array error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:207:1 + --> $DIR/invalid.rs:208:1 | LL | struct ArgNotLit { | ^^^^^^^^^^^^^^^^ @@ -722,7 +722,7 @@ LL | _ty: [f64], | ---------- not an array error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:213:1 + --> $DIR/invalid.rs:214:1 | LL | struct ArgMultipleLits { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -731,7 +731,7 @@ LL | _ty: [f64], | ---------- not an array error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:219:1 + --> $DIR/invalid.rs:220:1 | LL | struct ArgKind { | ^^^^^^^^^^^^^^ @@ -740,7 +740,7 @@ LL | _ty: [f64], | ---------- not an array error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:225:1 + --> $DIR/invalid.rs:226:1 | LL | struct Okay { | ^^^^^^^^^^^ @@ -754,7 +754,7 @@ Some errors have detailed explanations: E0076, E0517, E0552, E0566, E0692. For more information about an error, try `rustc --explain E0076`. Future incompatibility report: Future breakage diagnostic: error[E0566]: conflicting representation hints - --> $DIR/invalid.rs:187:8 + --> $DIR/invalid.rs:188:8 | LL | #[repr(C, simd, scalable(4))] | ^ ^^^^ ^^^^^^^^^^^ From 5d39638f84bc38df48490b86f4aa2bd2ada6042e Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 9 Jul 2025 16:25:29 +0000 Subject: [PATCH 03/12] hir/trait_sel: prohibit scalable vectors in types Extend well-formedness checking and HIR analysis to prohibit the use of scalable vectors in structs, enums, unions, tuples and arrays. LLVM does not support scalable vectors being members of other types, so these restrictions are necessary. Co-authored-by: Jamie Cunliffe --- .../rustc_hir_analysis/src/check/check.rs | 54 ++++++++++++++- .../rustc_hir_analysis/src/check/wfcheck.rs | 60 +++++++++------- .../rustc_trait_selection/src/traits/wf.rs | 25 ++++++- .../feature-gate-repr-scalable.rs | 2 +- .../feature-gate-repr-scalable.stderr | 13 +--- tests/ui/simd/scalable/illformed.rs | 21 ++++++ tests/ui/simd/scalable/illformed.stderr | 51 ++++++++++++++ tests/ui/simd/scalable/invalid.rs | 4 -- tests/ui/simd/scalable/invalid.stderr | 62 ++++------------- tests/ui/simd/scalable/wellformed.rs | 68 +++++++++++++++++++ 10 files changed, 269 insertions(+), 91 deletions(-) create mode 100644 tests/ui/simd/scalable/illformed.rs create mode 100644 tests/ui/simd/scalable/illformed.stderr create mode 100644 tests/ui/simd/scalable/wellformed.rs diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 70fbb8a543e2a..6782e11b54433 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -95,7 +95,11 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { def.destructor(tcx); // force the destructor to be evaluated if def.repr().simd() { - check_simd(tcx, span, def_id); + if def.repr().scalable() { + check_scalable_simd(tcx, span, def_id); + } else { + check_simd(tcx, span, def_id); + } } check_transparent(tcx, def); @@ -1393,6 +1397,54 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { } } +fn check_scalable_simd(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId) { + 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("`repr(scalable)` applied to non-struct"); + return; + } + + let fields = &def.non_enum_variant().fields; + match fields.len() { + 0 => { + 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 slice of a primitive scalar type"); + err.emit(); + return; + } + 1 => {} + 2.. => { + tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit(); + } + } + + let array_field = &fields[FieldIdx::ZERO]; + let array_ty = array_field.ty(tcx, args); + let ty::Slice(element_ty) = array_ty.kind() else { + let mut err = + tcx.dcx().struct_span_err(span, "the field of a scalable vector type must be a slice"); + err.span_label(tcx.def_span(array_field.did), "not a slice"); + err.emit(); + return; + }; + + // Check that `element_ty` only uses types valid in the lanes of a scalable vector register: + // scalar types which directly match a "machine" type - e.g. integers, floats, bools, thin ptrs. + match element_ty.kind() { + ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) | ty::Bool => (), + _ => { + let mut err = tcx.dcx().struct_span_err( + span, + "element type of a scalable vector must be a primitive scalar", + ); + err.help("only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted"); + err.emit(); + } + } +} + pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 607028f4d9aef..d67d5a9273c8c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1054,10 +1054,9 @@ fn check_type_defn<'tcx>( }; // All fields (except for possibly the last) should be sized. let all_sized = all_sized || variant.fields.is_empty() || needs_drop_copy(); - let unsized_len = if all_sized { 0 } else { 1 }; - for (idx, field) in - variant.fields.raw[..variant.fields.len() - unsized_len].iter().enumerate() - { + let unsized_len = + if all_sized { variant.fields.len() } else { variant.fields.len() - 1 }; + for (idx, field) in variant.fields.raw.iter().enumerate() { let last = idx == variant.fields.len() - 1; let field_id = field.did.expect_local(); let hir::FieldDef { ty: hir_ty, .. } = @@ -1067,28 +1066,41 @@ fn check_type_defn<'tcx>( None, tcx.type_of(field.did).instantiate_identity(), ); - wfcx.register_bound( - traits::ObligationCause::new( + + if matches!(ty.kind(), ty::Adt(def, _) if def.repr().scalable()) { + tcx.dcx().span_err( hir_ty.span, - wfcx.body_def_id, - ObligationCauseCode::FieldSized { - adt_kind: match &item.kind { - ItemKind::Struct(..) => AdtKind::Struct, - ItemKind::Union(..) => AdtKind::Union, - ItemKind::Enum(..) => AdtKind::Enum, - kind => span_bug!( - item.span, - "should be wfchecking an ADT, got {kind:?}" - ), + format!( + "scalable vectors cannot be fields of a {}", + adt_def.variant_descr() + ), + ); + } + + if idx < unsized_len { + wfcx.register_bound( + traits::ObligationCause::new( + hir_ty.span, + wfcx.body_def_id, + ObligationCauseCode::FieldSized { + adt_kind: match &item.kind { + ItemKind::Struct(..) => AdtKind::Struct, + ItemKind::Union(..) => AdtKind::Union, + ItemKind::Enum(..) => AdtKind::Enum, + kind => span_bug!( + item.span, + "should be wfchecking an ADT, got {kind:?}" + ), + }, + span: hir_ty.span, + last, }, - span: hir_ty.span, - last, - }, - ), - wfcx.param_env, - ty, - tcx.require_lang_item(LangItem::Sized, hir_ty.span), - ); + ), + wfcx.param_env, + ty, + tcx.require_lang_item(LangItem::Sized, hir_ty.span), + ); + } } // Explicit `enum` discriminant values must const-evaluate successfully. diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fed9f254cdf83..28323a14410f8 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -748,6 +748,13 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::Array(subty, len) => { self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem); + if subty.is_scalable_simd() && !self.span.is_dummy() { + self.tcx() + .dcx() + .struct_span_err(self.span, "scalable vectors cannot be array elements") + .emit(); + } + // Note that the len being WF is implicitly checked while visiting. // Here we just check that it's of type usize. let cause = self.cause(ObligationCauseCode::ArrayLen(t)); @@ -769,9 +776,25 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } ty::Tuple(tys) => { - if let Some((_last, rest)) = tys.split_last() { + if let Some((last, rest)) = tys.split_last() { for &elem in rest { self.require_sized(elem, ObligationCauseCode::TupleElem); + if elem.is_scalable_simd() && !self.span.is_dummy() { + self.tcx() + .dcx() + .struct_span_err( + self.span, + "scalable vectors cannot be tuple fields", + ) + .emit(); + } + } + + if last.is_scalable_simd() && !self.span.is_dummy() { + self.tcx() + .dcx() + .struct_span_err(self.span, "scalable vectors cannot be tuple fields") + .emit(); } } } diff --git a/tests/ui/feature-gates/feature-gate-repr-scalable.rs b/tests/ui/feature-gates/feature-gate-repr-scalable.rs index dfa8729a7f6ab..3dc10e3fb9f0c 100644 --- a/tests/ui/feature-gates/feature-gate-repr-scalable.rs +++ b/tests/ui/feature-gates/feature-gate-repr-scalable.rs @@ -1,7 +1,7 @@ #![feature(repr_simd)] #[repr(simd, scalable(16))] //~ ERROR: scalable vector types are experimental -struct Foo { //~ ERROR: SIMD vector's only field must be an array +struct Foo { _ty: [i8], } diff --git a/tests/ui/feature-gates/feature-gate-repr-scalable.stderr b/tests/ui/feature-gates/feature-gate-repr-scalable.stderr index 61a8c73f9ffbb..53240662ca27c 100644 --- a/tests/ui/feature-gates/feature-gate-repr-scalable.stderr +++ b/tests/ui/feature-gates/feature-gate-repr-scalable.stderr @@ -7,15 +7,6 @@ LL | #[repr(simd, scalable(16))] = help: add `#![feature(repr_scalable)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0076]: SIMD vector's only field must be an array - --> $DIR/feature-gate-repr-scalable.rs:4:1 - | -LL | struct Foo { - | ^^^^^^^^^^ -LL | _ty: [i8], - | --------- not an array - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0076, E0658. -For more information about an error, try `rustc --explain E0076`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/simd/scalable/illformed.rs b/tests/ui/simd/scalable/illformed.rs new file mode 100644 index 0000000000000..dfa0ce85546fe --- /dev/null +++ b/tests/ui/simd/scalable/illformed.rs @@ -0,0 +1,21 @@ +//@ compile-flags: --crate-type=lib +#![feature(repr_scalable, repr_simd)] + +#[repr(simd, scalable(4))] +struct NoFields {} //~ ERROR: scalable vectors must have a single field + +#[repr(simd, scalable(4))] +struct MultipleFields { //~ ERROR: scalable vectors cannot have multiple fields + _ty: [f32], //~ ERROR: the size for values of type `[f32]` cannot be known at compilation time + other: u32, +} + +#[repr(simd, scalable(4))] +struct WrongFieldType { //~ ERROR: the field of a scalable vector type must be a slice + _ty: String, +} + +#[repr(simd, scalable(4))] +struct WrongElementTy { //~ ERROR: element type of a scalable vector must be a primitive scalar + _ty: [String], +} diff --git a/tests/ui/simd/scalable/illformed.stderr b/tests/ui/simd/scalable/illformed.stderr new file mode 100644 index 0000000000000..a2eeec8ad62f8 --- /dev/null +++ b/tests/ui/simd/scalable/illformed.stderr @@ -0,0 +1,51 @@ +error: scalable vectors must have a single field + --> $DIR/illformed.rs:5:1 + | +LL | struct NoFields {} + | ^^^^^^^^^^^^^^^ + | + = help: scalable vector types' only field must be slice of a primitive scalar type + +error: scalable vectors cannot have multiple fields + --> $DIR/illformed.rs:8:1 + | +LL | struct MultipleFields { + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type `[f32]` cannot be known at compilation time + --> $DIR/illformed.rs:9:10 + | +LL | _ty: [f32], + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[f32]` + = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | _ty: &[f32], + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | _ty: Box<[f32]>, + | ++++ + + +error: the field of a scalable vector type must be a slice + --> $DIR/illformed.rs:14:1 + | +LL | struct WrongFieldType { + | ^^^^^^^^^^^^^^^^^^^^^ +LL | _ty: String, + | ----------- not a slice + +error: element type of a scalable vector must be a primitive scalar + --> $DIR/illformed.rs:19:1 + | +LL | struct WrongElementTy { + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: only `u*`, `i*`, `f*`, `*const`, `*mut` and `bool` types are accepted + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/simd/scalable/invalid.rs b/tests/ui/simd/scalable/invalid.rs index 06f7aaeb75119..38e9c3456e016 100644 --- a/tests/ui/simd/scalable/invalid.rs +++ b/tests/ui/simd/scalable/invalid.rs @@ -175,13 +175,11 @@ fn main() { #[repr(transparent, simd, scalable(4))] //~ ERROR: transparent struct cannot have other repr hints struct CombinedWithReprTransparent { -//~^ ERROR: SIMD vector's only field must be an array _ty: [f64], } #[repr(Rust, simd, scalable(4))] //~ ERROR: conflicting representation hints struct CombinedWithReprRust { -//~^ ERROR: SIMD vector's only field must be an array _ty: [f64], } @@ -189,7 +187,6 @@ struct CombinedWithReprRust { //~^ ERROR: conflicting representation hints //~^^ WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! struct CombinedWithReprC { -//~^ ERROR: SIMD vector's only field must be an array _ty: [f64], } @@ -224,6 +221,5 @@ struct ArgKind { #[repr(simd, scalable(4))] struct Okay { -//~^ ERROR: SIMD vector's only field must be an array _ty: [f64], } diff --git a/tests/ui/simd/scalable/invalid.stderr b/tests/ui/simd/scalable/invalid.stderr index 2ec7bbd8326f5..ddbf805b42b1f 100644 --- a/tests/ui/simd/scalable/invalid.stderr +++ b/tests/ui/simd/scalable/invalid.stderr @@ -5,25 +5,25 @@ LL | fn barqux(#[repr(simd, scalable(4))] _x: u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid `scalable(num)` attribute: `scalable` needs an argument - --> $DIR/invalid.rs:201:14 + --> $DIR/invalid.rs:198:14 | LL | #[repr(simd, scalable)] | ^^^^^^^^ help: supply an argument here: `scalable(...)` error: invalid `scalable(num)` attribute: `scalable` needs an argument - --> $DIR/invalid.rs:207:14 + --> $DIR/invalid.rs:204:14 | LL | #[repr(simd, scalable("4"))] | ^^^^^^^^^^^^^ help: supply an argument here: `scalable(...)` error: invalid `scalable(num)` attribute: `scalable` needs an argument - --> $DIR/invalid.rs:213:14 + --> $DIR/invalid.rs:210:14 | LL | #[repr(simd, scalable(4, 2))] | ^^^^^^^^^^^^^^ help: supply an argument here: `scalable(...)` error[E0552]: unrecognized representation hint - --> $DIR/invalid.rs:219:14 + --> $DIR/invalid.rs:216:14 | LL | #[repr(simd, scalable = "4")] | ^^^^^^^^^^^^^^ @@ -529,13 +529,13 @@ LL | #[repr(transparent, simd, scalable(4))] | ^^^^^^^^^^^ ^^^^ ^^^^^^^^^^^ error[E0566]: conflicting representation hints - --> $DIR/invalid.rs:182:8 + --> $DIR/invalid.rs:181:8 | LL | #[repr(Rust, simd, scalable(4))] | ^^^^ ^^^^ ^^^^^^^^^^^ error[E0566]: conflicting representation hints - --> $DIR/invalid.rs:188:8 + --> $DIR/invalid.rs:186:8 | LL | #[repr(C, simd, scalable(4))] | ^ ^^^^ ^^^^^^^^^^^ @@ -545,7 +545,7 @@ LL | #[repr(C, simd, scalable(4))] = note: `#[deny(conflicting_repr_hints)]` on by default error: `scalable` representation hint without `simd` representation hint - --> $DIR/invalid.rs:196:8 + --> $DIR/invalid.rs:193:8 | LL | #[repr(scalable(4))] | ^^^^^^^^^^^ @@ -677,34 +677,7 @@ LL | fn foo(); | --------- not a struct error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:177:1 - | -LL | struct CombinedWithReprTransparent { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | _ty: [f64], - | ---------- not an array - -error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:183:1 - | -LL | struct CombinedWithReprRust { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | _ty: [f64], - | ---------- not an array - -error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:191:1 - | -LL | struct CombinedWithReprC { - | ^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | _ty: [f64], - | ---------- not an array - -error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:202:1 + --> $DIR/invalid.rs:199:1 | LL | struct MissingArg { | ^^^^^^^^^^^^^^^^^ @@ -713,7 +686,7 @@ LL | _ty: [f64], | ---------- not an array error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:208:1 + --> $DIR/invalid.rs:205:1 | LL | struct ArgNotLit { | ^^^^^^^^^^^^^^^^ @@ -722,7 +695,7 @@ LL | _ty: [f64], | ---------- not an array error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:214:1 + --> $DIR/invalid.rs:211:1 | LL | struct ArgMultipleLits { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -731,7 +704,7 @@ LL | _ty: [f64], | ---------- not an array error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:220:1 + --> $DIR/invalid.rs:217:1 | LL | struct ArgKind { | ^^^^^^^^^^^^^^ @@ -739,22 +712,13 @@ LL | LL | _ty: [f64], | ---------- not an array -error[E0076]: SIMD vector's only field must be an array - --> $DIR/invalid.rs:226:1 - | -LL | struct Okay { - | ^^^^^^^^^^^ -LL | -LL | _ty: [f64], - | ---------- not an array - -error: aborting due to 83 previous errors +error: aborting due to 79 previous errors Some errors have detailed explanations: E0076, E0517, E0552, E0566, E0692. For more information about an error, try `rustc --explain E0076`. Future incompatibility report: Future breakage diagnostic: error[E0566]: conflicting representation hints - --> $DIR/invalid.rs:188:8 + --> $DIR/invalid.rs:186:8 | LL | #[repr(C, simd, scalable(4))] | ^ ^^^^ ^^^^^^^^^^^ diff --git a/tests/ui/simd/scalable/wellformed.rs b/tests/ui/simd/scalable/wellformed.rs new file mode 100644 index 0000000000000..2237174df40f0 --- /dev/null +++ b/tests/ui/simd/scalable/wellformed.rs @@ -0,0 +1,68 @@ +//@ check-pass +//@ compile-flags: --crate-type=lib +#![feature(repr_scalable, repr_simd)] + +#[repr(simd, scalable(4))] +struct ScalableU8 { + _ty: [u8], +} + +#[repr(simd, scalable(4))] +struct ScalableU16 { + _ty: [u16], +} + +#[repr(simd, scalable(4))] +struct ScalableU32 { + _ty: [u32], +} + +#[repr(simd, scalable(4))] +struct ScalableU64 { + _ty: [u64], +} + +#[repr(simd, scalable(4))] +struct ScalableI8 { + _ty: [i8], +} + +#[repr(simd, scalable(4))] +struct ScalableI16 { + _ty: [i16], +} + +#[repr(simd, scalable(4))] +struct ScalableI32 { + _ty: [i32], +} + +#[repr(simd, scalable(4))] +struct ScalableI64 { + _ty: [i64], +} + +#[repr(simd, scalable(4))] +struct ScalableF32 { + _ty: [f32], +} + +#[repr(simd, scalable(4))] +struct ScalableF64 { + _ty: [f64], +} + +#[repr(simd, scalable(4))] +struct ScalableBool { + _ty: [bool], +} + +#[repr(simd, scalable(4))] +struct ScalableConstPtr { + _ty: [*const u8], +} + +#[repr(simd, scalable(4))] +struct ScalableMutPtr { + _ty: [*mut u8], +} From 5305c164d928283d0e9e01bf436a66ac7da4364e Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 9 Jul 2025 15:22:42 +0000 Subject: [PATCH 04/12] lint: scalable vectors are ffi-safe Scalable vectors can be passed by register over the FFI boundary to C code, so they shouldn't be linted by `improper_ctypes`. --- compiler/rustc_lint/src/types.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fc9d795cb2315..a4640ccb23e48 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1191,6 +1191,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } } + // Scalable vectors are passed to C in their vector registers. + if def.repr().scalable() { + return FfiSafe; + } if def.is_phantom_data() { return FfiPhantom(ty); } From 5f644fc0f416e0b28abfd5b8278d91f702adfdce Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 9 Jul 2025 16:47:32 +0000 Subject: [PATCH 05/12] trait_sel: temporary impl `Sized` for scalable vecs Scalable vectors should behave like other value types - being permitted as arguments, locals, return types, etc. This requires that these types be `Sized`, despite not meeting the definition and requirements of `Sized`. `feature(sized_hierarchy)` is being implemented to enable scalable vectors to be non-`const Sized`, but in the mean time, add a builtin impl for scalable vectors. This must be addressed prior to stabilisation. --- compiler/rustc_middle/src/ty/adt.rs | 4 ++++ compiler/rustc_middle/src/ty/sty.rs | 9 ++++++--- .../src/solve/assembly/structural_traits.rs | 13 +++++++++++++ .../rustc_trait_selection/src/traits/select/mod.rs | 13 +++++++++++++ compiler/rustc_type_ir/src/inherent.rs | 2 ++ 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 275458fc85f8d..f6dadb3d0e591 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -208,6 +208,10 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { self.is_struct() } + fn is_scalable_vector(self) -> bool { + self.repr().scalable() + } + fn struct_tail_ty(self, interner: TyCtxt<'tcx>) -> Option>> { Some(interner.type_of(self.non_enum_variant().tail_opt()?.did)) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 899ceb40c3063..56abe94e5952b 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1834,9 +1834,12 @@ impl<'tcx> Ty<'tcx> { ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.has_trivial_sizedness(tcx, sizedness)), - ty::Adt(def, args) => def - .sizedness_constraint(tcx, sizedness) - .is_none_or(|ty| ty.instantiate(tcx, args).has_trivial_sizedness(tcx, sizedness)), + ty::Adt(def, args) => { + def.repr().scalable() // see comment on `sizedness_conditions` + || def.sizedness_constraint(tcx, sizedness).is_none_or(|ty| { + ty.instantiate(tcx, args).has_trivial_sizedness(tcx, sizedness) + }) + } ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index c0bebdf6fb639..1361e410a58ad 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -174,6 +174,19 @@ where // "best effort" optimization and `{meta,pointee,}sized_constraint` may return `Some`, // even if the ADT is {meta,pointee,}sized for all possible args. ty::Adt(def, args) => { + // FIXME(repr_scalable): Scalable vectors aren't actually `Sized`. They will be + // non-const `Sized` after the `sized_hierarchy` feature is implemented, but until + // then need to act like `Sized` types - either by forcing it in the trait solver, + // as below, or by omitting the `Sized` constraints in the first place. Omitting the + // constraints would require many small changes throughout the compiler and in some + // cases would not be trivially limited to only the `repr(scalable)` types due + // to inference variables, etc. When `sized_hierarchy` is fully implemented, this + // line will be required anyway and will be correct, just that in the host effect + // builtin impl for sizedness, it won't be `const Sized`. + if def.is_scalable_vector() { + return Ok(ty::Binder::dummy(vec![])); + } + if let Some(crit) = def.sizedness_constraint(ecx.cx(), sizedness) { Ok(ty::Binder::dummy(vec![crit.instantiate(ecx.cx(), args)])) } else { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2e65750db25de..7da8ba5d2edd0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2128,6 +2128,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Pat(ty, _) => ty::Binder::dummy(vec![*ty]), ty::Adt(def, args) => { + // FIXME(repr_scalable): Scalable vectors aren't actually `Sized`. They will be + // non-const `Sized` after the `sized_hierarchy` feature is implemented, but until + // then need to act like `Sized` types - either by forcing it in the trait solver, + // as below, or by omitting the `Sized` constraints in the first place. Omitting the + // constraints would require many small changes throughout the compiler and in some + // cases would not be trivially limited to only the `repr(scalable)` types due + // to inference variables, etc. When `sized_hierarchy` is fully implemented, this + // line will be required anyway and will be correct, just that in the host effect + // builtin impl for sizedness, it won't be `const Sized`. + if def.repr().scalable() { + return ty::Binder::dummy(vec![]); + } + if let Some(crit) = def.sizedness_constraint(self.tcx(), sizedness) { ty::Binder::dummy(vec![crit.instantiate(self.tcx(), args)]) } else { diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 2754d40fd36ce..180ea7295977e 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -597,6 +597,8 @@ pub trait AdtDef: Copy + Debug + Hash + Eq { fn is_struct(self) -> bool; + fn is_scalable_vector(self) -> bool; + /// Returns the type of the struct tail. /// /// Expects the `AdtDef` to be a struct. If it is not, then this will panic. From 16d90b251818fb43922b76e5c372117e52cc9add Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 8 Jul 2025 09:12:26 +0000 Subject: [PATCH 06/12] core: add `simd_reinterpret` `simd_reinterpret` is a replacement for `transmute`, specifically for use with scalable SIMD types. It is used in the tests for scalable vectors and in stdarch. Co-authored-by: Jamie Cunliffe --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 12 ++++++++++++ compiler/rustc_hir_analysis/src/check/intrinsic.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/simd.rs | 5 +++++ 4 files changed, 19 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index fcc0d378f0686..88309050c2f82 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1246,6 +1246,18 @@ fn generic_simd_intrinsic<'ll, 'tcx>( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } + if name == sym::simd_reinterpret { + require_simd!(ret_ty, SimdReturn); + + return Ok(match args[0].val { + OperandValue::Ref(PlaceValue { llval: val, .. }) | OperandValue::Immediate(val) => { + bx.bitcast(val, llret_ty) + } + OperandValue::ZeroSized => bx.const_undef(llret_ty), + OperandValue::Pair(_, _) => todo!(), + }); + } + // every intrinsic below takes a SIMD vector as its first argument let (in_len, in_elem) = require_simd!(args[0].layout.ty, SimdInput); let in_ty = args[0].layout.ty; diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index dcab6ef1c5a5f..589d678327a58 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -618,6 +618,7 @@ pub(crate) fn check_intrinsic_type( } sym::simd_cast | sym::simd_as + | sym::simd_reinterpret | sym::simd_cast_ptr | sym::simd_expose_provenance | sym::simd_with_exposed_provenance => (2, 0, vec![param(0)], param(1)), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1a0e3427979eb..9b04d6b5a6a41 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2004,6 +2004,7 @@ symbols! { simd_reduce_mul_unordered, simd_reduce_or, simd_reduce_xor, + simd_reinterpret, simd_relaxed_fma, simd_rem, simd_round, diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 19488082cc33d..d36283f81bc7e 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -216,6 +216,11 @@ pub unsafe fn simd_cast(x: T) -> U; #[rustc_nounwind] pub unsafe fn simd_as(x: T) -> U; +/// Replacement for `transmute`, specifically for use with scalable SIMD types. +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn simd_reinterpret(src: Src) -> Dst; + /// Negates a vector elementwise. /// /// `T` must be a vector of integers or floats. From faf5684fe95f8b9932c5730f485605944ceaee43 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 10 Jul 2025 10:17:44 +0000 Subject: [PATCH 07/12] codegen: implement `repr(scalable)` Introduces `BackendRepr::ScalableVector` corresponding to scalable vector types annotated with `repr(scalable)` which lowers to a scalable vector type in LLVM. Co-authored-by: Jamie Cunliffe --- compiler/rustc_abi/src/callconv.rs | 2 + compiler/rustc_abi/src/layout.rs | 12 ++- compiler/rustc_abi/src/lib.rs | 36 ++++++++- compiler/rustc_codegen_gcc/src/builder.rs | 4 + .../rustc_codegen_gcc/src/intrinsic/mod.rs | 2 +- compiler/rustc_codegen_gcc/src/type_of.rs | 6 +- compiler/rustc_codegen_llvm/src/builder.rs | 19 +++++ compiler/rustc_codegen_llvm/src/intrinsic.rs | 38 +++++++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_codegen_llvm/src/type_.rs | 4 + compiler/rustc_codegen_llvm/src/type_of.rs | 14 +++- compiler/rustc_codegen_llvm/src/va_arg.rs | 6 +- compiler/rustc_codegen_ssa/messages.ftl | 1 + compiler/rustc_codegen_ssa/src/errors.rs | 8 ++ compiler/rustc_codegen_ssa/src/mir/operand.rs | 8 +- compiler/rustc_codegen_ssa/src/mir/place.rs | 15 +++- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 1 + .../rustc_codegen_ssa/src/traits/builder.rs | 1 + .../src/interpret/validity.rs | 2 +- .../src/util/check_validity_requirement.rs | 2 + compiler/rustc_middle/src/ty/sty.rs | 32 +++++--- compiler/rustc_mir_transform/src/gvn.rs | 4 +- .../rustc_target/src/callconv/loongarch.rs | 5 +- compiler/rustc_target/src/callconv/mod.rs | 1 + compiler/rustc_target/src/callconv/riscv.rs | 4 +- compiler/rustc_target/src/callconv/x86.rs | 3 + compiler/rustc_target/src/callconv/x86_64.rs | 2 + .../rustc_target/src/callconv/x86_win64.rs | 1 + compiler/rustc_ty_utils/src/abi.rs | 4 +- compiler/rustc_ty_utils/src/layout.rs | 22 +++-- .../rustc_ty_utils/src/layout/invariant.rs | 2 +- compiler/stable_mir/src/abi.rs | 11 ++- .../src/unstable/convert/stable/abi.rs | 3 + tests/ui/simd/scalable/closure-capture.rs | 51 ++++++++++++ tests/ui/simd/scalable/closure-capture.stderr | 29 +++++++ tests/ui/simd/scalable/fn-trait.rs | 14 ++++ tests/ui/simd/scalable/fn-trait.stderr | 8 ++ tests/ui/simd/scalable/illformed-in-types.rs | 54 +++++++++++++ .../simd/scalable/illformed-in-types.stderr | 81 +++++++++++++++++++ tests/ui/simd/scalable/value-type.rs | 30 +++++++ 40 files changed, 496 insertions(+), 47 deletions(-) create mode 100644 tests/ui/simd/scalable/closure-capture.rs create mode 100644 tests/ui/simd/scalable/closure-capture.stderr create mode 100644 tests/ui/simd/scalable/fn-trait.rs create mode 100644 tests/ui/simd/scalable/fn-trait.stderr create mode 100644 tests/ui/simd/scalable/illformed-in-types.rs create mode 100644 tests/ui/simd/scalable/illformed-in-types.stderr create mode 100644 tests/ui/simd/scalable/value-type.rs diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index a21e1aee9b08a..360f5689cee40 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -82,6 +82,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { })) } + BackendRepr::ScalableVector { .. } => Err(Heterogeneous), + BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { // Helper for computing `homogeneous_aggregate`, allowing a custom // starting offset (used below for handling variants). diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 80b44e432eeb0..0964c13ec6594 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -151,6 +151,7 @@ impl LayoutCalculator { element: F, count: u64, repr_packed: bool, + scalable: Option, ) -> LayoutCalculatorResult { let elt = element.as_ref(); if count == 0 { @@ -169,7 +170,12 @@ impl LayoutCalculator { 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() { + let (repr, align) = if let Some(elt) = scalable { + ( + BackendRepr::ScalableVector { element: e_repr, count: elt as u64 }, + dl.llvmlike_vector_align(size), + ) + } else 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. @@ -461,6 +467,7 @@ impl LayoutCalculator { BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } | BackendRepr::Memory { .. } => repr, }, }; @@ -532,7 +539,8 @@ impl LayoutCalculator { hide_niches(a); hide_niches(b); } - BackendRepr::SimdVector { element, count: _ } => hide_niches(element), + BackendRepr::SimdVector { element, .. } + | BackendRepr::ScalableVector { element, .. } => hide_niches(element), BackendRepr::Memory { sized: _ } => {} } st.largest_niche = None; diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 1f87d461a2bbc..0240a4107755d 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1671,6 +1671,10 @@ impl AddressSpace { pub enum BackendRepr { Scalar(Scalar), ScalarPair(Scalar, Scalar), + ScalableVector { + element: Scalar, + count: u64, + }, SimdVector { element: Scalar, count: u64, @@ -1689,6 +1693,9 @@ impl BackendRepr { match *self { BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) + // FIXME(repr_scalable): Scalable vectors are forced to be `Sized` while the + // `sized_hierarchy` feature is not yet fully implemented + | BackendRepr::ScalableVector { .. } | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => !sized, } @@ -1729,7 +1736,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, } } @@ -1751,7 +1760,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, } } @@ -1766,6 +1777,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 } + } } } @@ -2006,7 +2020,9 @@ impl LayoutData { /// Returns `true` if this is an aggregate type (including a ScalarPair!) pub fn is_aggregate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => false, + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => false, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, } } @@ -2100,6 +2116,19 @@ impl LayoutData { self.is_sized() && self.size.bytes() == 0 && self.align.abi.bytes() == 1 } + /// Returns `true` if the size of the type is only known at runtime. + pub fn is_runtime_sized(&self) -> bool { + matches!(self.backend_repr, BackendRepr::ScalableVector { .. }) + } + + /// Returns the elements count of a scalable vector. + pub fn scalable_vector_element_count(&self) -> Option { + match self.backend_repr { + BackendRepr::ScalableVector { count, .. } => Some(count), + _ => None, + } + } + /// Returns `true` if the type is a ZST and not unsized. /// /// Note that this does *not* imply that the type is irrelevant for layout! It can still have @@ -2108,6 +2137,7 @@ impl LayoutData { match self.backend_repr { BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) + | BackendRepr::ScalableVector { .. } | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 28d1ec7d89564..322be5ba08335 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -926,6 +926,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { .get_address(self.location) } + fn scalable_alloca(&mut self, _elt: u64, _align: Align, _element_ty: Ty<'_>) -> RValue<'gcc> { + todo!() + } + fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { let block = self.llbb(); let function = block.get_function(); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 0753ac1aeb84e..d09b9e53a32c7 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -536,7 +536,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, - SimdVector { .. } => false, + SimdVector { .. } | ScalableVector { .. } => false, Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 093f902bc3d86..aeb0b7c08cedd 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -85,6 +85,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( ); } BackendRepr::Memory { .. } => {} + BackendRepr::ScalableVector { .. } => todo!(), } let name = match *layout.ty.kind() { @@ -178,7 +179,9 @@ pub trait LayoutGccExt<'tcx> { impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => true, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -188,6 +191,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::ScalarPair(..) => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 9c3b866aa3c6f..92655e17328c0 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -538,6 +538,25 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } + fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value { + let mut bx = Builder::with_cx(self.cx); + bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) }); + let llvm_ty = match element_ty.kind() { + ty::Bool => bx.type_i1(), + ty::Int(int_ty) => self.cx.type_int_from_ty(*int_ty), + ty::Uint(uint_ty) => self.cx.type_uint_from_ty(*uint_ty), + ty::Float(float_ty) => self.cx.type_float_from_ty(*float_ty), + _ => unreachable!("scalable vectors can only contain a bool, int, uint or float"), + }; + + unsafe { + let ty = llvm::LLVMScalableVectorType(llvm_ty, elt.try_into().unwrap()); + let alloca = llvm::LLVMBuildAlloca(&bx.llbuilder, ty, UNNAMED); + llvm::LLVMSetAlignment(alloca, align.bytes() as c_uint); + alloca + } + } + fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value { unsafe { let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 88309050c2f82..8c83b1690fc39 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -454,6 +454,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`), @@ -1254,7 +1262,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>( bx.bitcast(val, llret_ty) } OperandValue::ZeroSized => bx.const_undef(llret_ty), - OperandValue::Pair(_, _) => todo!(), + OperandValue::Pair(_, _) => { + return_error!(InvalidMonomorphization::NonScalableType { span, name, ty: ret_ty }) + } }); } @@ -1453,11 +1463,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_simd() { + match m_elem_ty.kind() { + ty::Bool => {} + _ => return_error!(InvalidMonomorphization::MaskWrongElementType { + span, + name, + ty: m_elem_ty + }), + }; + let i1 = bx.type_i1(); + let i1xn = bx.type_scalable_vector(i1, m_len as u64); + bx.trunc(args[0].immediate(), i1xn) + } else { + let in_elem_bitwidth = require_int_or_uint_ty!( + m_elem_ty.kind(), + InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty } + ); + vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len) + }; + return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 5c34ab2e3040d..8843b6fac9e4b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1072,6 +1072,7 @@ unsafe extern "C" { // Operations on array, pointer, and vector types (sequence types) pub(crate) fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type; pub(crate) fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; + pub(crate) fn LLVMScalableVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type; pub(crate) fn LLVMGetElementType(Ty: &Type) -> &Type; pub(crate) fn LLVMGetVectorSize(VectorTy: &Type) -> c_uint; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index ee472e75ed41e..c91c6a8d7fcdf 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -68,6 +68,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { unsafe { llvm::LLVMVectorType(ty, len as c_uint) } } + pub(crate) fn type_scalable_vector(&self, ty: &'ll Type, count: u64) -> &'ll Type { + unsafe { llvm::LLVMScalableVectorType(ty, count as c_uint) } + } + pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> { unsafe { let n_args = llvm::LLVMCountParamTypes(ty) as usize; diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 4e7096da502d0..1ae926ed9ee1b 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -23,6 +23,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(..) => {} } @@ -171,7 +180,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, } } @@ -181,6 +192,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::ScalarPair(..) => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index ce079f3cb0af1..74787d20dfcef 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -546,7 +546,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 {:?}", @@ -686,7 +686,9 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( } } // The Previous match on `BackendRepr` means control flow already escaped. - BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => unreachable!(), + BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } + | BackendRepr::Memory { .. } => unreachable!(), }; // AMD64-ABI 3.5.7p5: Step 5. Set: diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 63e9005da45c2..133883b81e33b 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -131,6 +131,7 @@ codegen_ssa_invalid_monomorphization_mask_wrong_element_type = invalid monomorph codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` +codegen_ssa_invalid_monomorphization_non_scalable_type = invalid monomorphization of `{$name}` intrinsic: expected non-scalable type, found scalable type `{$ty}` codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}` codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}` diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index e042fe1f81966..645f2c70f4f62 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1084,6 +1084,14 @@ pub enum InvalidMonomorphization<'tcx> { expected_element: Ty<'tcx>, vector_type: Ty<'tcx>, }, + + #[diag(codegen_ssa_invalid_monomorphization_non_scalable_type, code = E0511)] + NonScalableType { + #[primary_span] + span: Span, + name: Symbol, + ty: Ty<'tcx>, + }, } pub enum ExpectedPointerMutability { diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index b0d191528a891..dc002c93aca49 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -396,7 +396,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { imm } } - BackendRepr::ScalarPair(_, _) | BackendRepr::Memory { .. } => bug!(), + BackendRepr::ScalarPair(_, _) + | BackendRepr::Memory { .. } + | BackendRepr::ScalableVector { .. } => bug!(), }) }; @@ -601,7 +603,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> { BackendRepr::ScalarPair(a, b) => { OperandValueBuilder::Pair(Either::Right(a), Either::Right(b)) } - BackendRepr::SimdVector { .. } => OperandValueBuilder::Vector(Either::Right(())), + BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { + OperandValueBuilder::Vector(Either::Right(())) + } BackendRepr::Memory { .. } => { bug!("Cannot use non-ZST Memory-ABI type in operand builder: {layout:?}"); } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 0090be9fdef06..a6c6e99d337d5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -109,7 +109,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx: &mut Bx, layout: TyAndLayout<'tcx>, ) -> Self { - Self::alloca_size(bx, layout.size, layout) + if layout.is_runtime_sized() { + Self::alloca_runtime_sized(bx, layout) + } else { + Self::alloca_size(bx, layout.size, layout) + } } pub fn alloca_size>( @@ -146,6 +150,15 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bug!("unexpected layout `{:#?}` in PlaceRef::len", self.layout) } } + + fn alloca_runtime_sized>( + bx: &mut Bx, + layout: TyAndLayout<'tcx>, + ) -> Self { + let (elt, ty) = layout.ty.simd_size_and_type(bx.tcx()); + PlaceValue::new_sized(bx.scalable_alloca(elt, layout.align.abi, ty), layout.align.abi) + .with_type(layout) + } } impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e90463aacc8a1..5182c182fdd57 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -978,6 +978,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // cases like from vectors of f32 to vectors of pointers or // from fat pointers to vectors of u16. (See #143194 #110021 ...) (abi::BackendRepr::SimdVector { .. }, _) | (_, abi::BackendRepr::SimdVector { .. }) => false, + (abi::BackendRepr::ScalableVector { .. }, _) | (_, abi::BackendRepr::ScalableVector { .. }) => false, } } mir::Rvalue::Ref(..) | diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 979456a6ba70f..72d956f80e699 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -234,6 +234,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value; fn alloca(&mut self, size: Size, align: Align) -> Self::Value; + fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value; fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value; fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index fc44490c96d37..19a99830c9b0e 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1310,7 +1310,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, self.visit_scalar(b, b_layout)?; } } - BackendRepr::SimdVector { .. } => { + BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { // No checks here, we assume layout computation gets this right. // (This is harder to check since Miri does not represent these as `Immediate`. We // also cannot use field projections since this might be a newtype around a vector.) diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 4ca39bbc68ec2..b07480e27cc1a 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -119,7 +119,9 @@ fn check_validity_requirement_lax<'tcx>( } BackendRepr::SimdVector { element: s, count } => count == 0 || scalar_allows_raw_init(s), BackendRepr::Memory { .. } => true, // Fields are checked below. + BackendRepr::ScalableVector { element, .. } => scalar_allows_raw_init(element), }; + if !valid { // This is definitely not okay. return Ok(false); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 56abe94e5952b..bb9a0d7db986a 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1218,19 +1218,25 @@ impl<'tcx> Ty<'tcx> { let variant = def.non_enum_variant(); assert_eq!(variant.fields.len(), 1); let field_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args); - let Array(f0_elem_ty, f0_len) = field_ty.kind() else { - bug!("Simd type has non-array field type {field_ty:?}") - }; - // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112 - // The way we evaluate the `N` in `[T; N]` here only works since we use - // `simd_size_and_type` post-monomorphization. It will probably start to ICE - // if we use it in generic code. See the `simd-array-trait` ui test. - ( - f0_len - .try_to_target_usize(tcx) - .expect("expected SIMD field to have definite array size"), - *f0_elem_ty, - ) + + match field_ty.kind() { + Array(f0_elem_ty, f0_len) => { + // FIXME(repr_simd): https://github.com/rust-lang/rust/pull/78863#discussion_r522784112 + // The way we evaluate the `N` in `[T; N]` here only works since we use + // `simd_size_and_type` post-monomorphization. It will probably start to ICE + // if we use it in generic code. See the `simd-array-trait` ui test. + ( + f0_len + .try_to_target_usize(tcx) + .expect("expected SIMD field to have definite array size"), + *f0_elem_ty, + ) + } + Slice(f0_elem_ty) if def.repr().scalable() => { + (def.repr().scalable.unwrap_or(0) as u64, *f0_elem_ty) + } + _ => bug!("Simd type has non-array field type {field_ty:?}"), + } } #[inline] diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 6b11706d2b55f..7ab6f22b7fb44 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1558,7 +1558,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { BackendRepr::ScalarPair(a, b) => { !a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx) } - BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => false, + BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } + | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 27b41cc09ed0c..e9dc4dbf063f4 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -80,7 +80,10 @@ where } } }, - BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv), + BackendRepr::SimdVector { .. } => { + return Err(CannotUseFpConv); + } + BackendRepr::ScalableVector { .. } => unreachable!(), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index ab3271220eb47..a1c73b46d800c 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -391,6 +391,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { ), BackendRepr::SimdVector { .. } => PassMode::Direct(ArgAttributes::new()), BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout), + BackendRepr::ScalableVector { .. } => PassMode::Direct(ArgAttributes::new()), }; ArgAbi { layout, mode } } diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index a06f54d60e7b0..2efb3d870069b 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -91,7 +91,9 @@ where } } }, - BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv), + BackendRepr::SimdVector { .. } | BackendRepr::ScalableVector { .. } => { + return Err(CannotUseFpConv); + } BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 918b71c80c4f0..ce173d84c8d56 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -98,6 +98,9 @@ where } false } + BackendRepr::ScalableVector { .. } => { + unreachable!("scalable vectors are unsupported") + } } } diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index d8db7ed6e4c0f..494c590dc63d3 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -59,6 +59,8 @@ where BackendRepr::SimdVector { .. } => Class::Sse, + BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"), + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { let field_off = off + layout.fields.offset(i); diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index 8f8597ea662a8..828eef7d04157 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -22,6 +22,7 @@ pub(crate) fn compute_abi_info(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<' // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } + BackendRepr::ScalableVector { .. } => unreachable!("scalable vectors are unsupported"), BackendRepr::Scalar(scalar) => { if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) { if cx.target_spec().rustc_abi == Some(RustcAbi::X86Softfloat) { diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index f0ff50318abc8..2ff11368d2fe9 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -395,7 +395,9 @@ fn fn_abi_sanity_check<'tcx>( // `layout.backend_repr` and ignore everything else. We should just reject //`Aggregate` entirely here, but some targets need to be fixed first. match arg.layout.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => {} + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::ScalableVector { .. } => {} BackendRepr::ScalarPair(..) => { panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty) } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 163e2b3088374..0c39ad58a21aa 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -544,24 +544,30 @@ fn layout_of_uncached<'tcx>( // * #[repr(simd)] struct S([T; 4]) // // where T is a primitive scalar (integer/float/pointer). - let Some(ty::Array(e_ty, e_len)) = def + let f0_ty = def .is_struct() .then(|| &def.variant(FIRST_VARIANT).fields) .filter(|fields| fields.len() == 1) - .map(|fields| *fields[FieldIdx::ZERO].ty(tcx, args).kind()) - else { + .map(|fields| *fields[FieldIdx::ZERO].ty(tcx, args).kind()); + + let (e_ty, e_len) = if let Some(ty::Array(e_ty, e_len)) = f0_ty { + let e_len = extract_const_value(cx, ty, e_len)? + .try_to_target_usize(tcx) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; + (e_ty, e_len) + } else if let Some(ty::Slice(e_ty)) = f0_ty + && def.repr().scalable() + { + (e_ty, 1) + } else { // Invalid SIMD types should have been caught by typeck by now. let guar = tcx.dcx().delayed_bug("#[repr(simd)] was applied to an invalid ADT"); return Err(error(cx, LayoutError::ReferencesError(guar))); }; - let e_len = extract_const_value(cx, ty, e_len)? - .try_to_target_usize(tcx) - .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; - let e_ly = cx.layout_of(e_ty)?; - map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))? + map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed(), def.repr().scalable))? } // ADTs. diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 1311ee31182c6..85dbe3273594c 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -248,7 +248,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou // And the size has to be element * count plus alignment padding, of course assert!(size == (element_size * count).align_to(align)); } - BackendRepr::Memory { .. } => {} // Nothing to check. + BackendRepr::Memory { .. } | BackendRepr::ScalableVector { .. } => {} // Nothing to check. } } diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index 7b0882caf1b3e..d7a9b5c84e907 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -233,6 +233,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, @@ -243,7 +247,12 @@ impl ValueAbi { /// Returns `true` if the layout corresponds to an unsized type. pub fn is_unsized(&self) -> bool { match *self { - ValueAbi::Scalar(_) | ValueAbi::ScalarPair(..) | ValueAbi::Vector { .. } => false, + ValueAbi::Scalar(_) + | ValueAbi::ScalarPair(..) + | ValueAbi::Vector { .. } + // FIXME(repr_scalable): Scalable vectors are forced to be `Sized` while the + // `sized_hierarchy` feature is not yet fully implemented + | ValueAbi::ScalableVector { .. } => false, ValueAbi::Aggregate { sized } => !sized, } } diff --git a/compiler/stable_mir/src/unstable/convert/stable/abi.rs b/compiler/stable_mir/src/unstable/convert/stable/abi.rs index 8fdaa69c30526..8917303a7f158 100644 --- a/compiler/stable_mir/src/unstable/convert/stable/abi.rs +++ b/compiler/stable_mir/src/unstable/convert/stable/abi.rs @@ -256,6 +256,9 @@ impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { rustc_abi::BackendRepr::SimdVector { element, count } => { ValueAbi::Vector { element: element.stable(tables, cx), count } } + rustc_abi::BackendRepr::ScalableVector { element, count } => { + ValueAbi::ScalableVector { element: element.stable(tables, cx), count } + } rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized }, } } diff --git a/tests/ui/simd/scalable/closure-capture.rs b/tests/ui/simd/scalable/closure-capture.rs new file mode 100644 index 0000000000000..925d7a05335df --- /dev/null +++ b/tests/ui/simd/scalable/closure-capture.rs @@ -0,0 +1,51 @@ +//@ only-aarch64 + +#![allow(incomplete_features, internal_features)] +#![feature( + repr_simd, + repr_scalable, + simd_ffi, + link_llvm_intrinsics +)] + +#[repr(simd, scalable(4))] +#[allow(non_camel_case_types)] +pub struct svint32_t { + _ty: [i32], +} + +#[inline(never)] +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; + } + unsafe { _svdup_n_s32(op) } +} + +#[inline] +#[target_feature(enable = "sve,sve2")] +pub unsafe fn svxar_n_s32(op1: svint32_t, op2: svint32_t) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.xar.nxv4i32")] + fn _svxar_n_s32(op1: svint32_t, op2: svint32_t, imm3: i32) -> svint32_t; + } + unsafe { _svxar_n_s32(op1, op2, IMM3) } +} + +#[inline(never)] +fn run(f: impl Fn() -> ()) { + f(); +} + +fn main() { + unsafe { + let a = svdup_n_s32(42); + run(move || { //~ ERROR: scalable vectors cannot be tuple fields + svxar_n_s32::<2>(a, a); + //~^ ERROR: cannot move out of `a` + //~| ERROR: cannot move out of `a` + }); + } +} diff --git a/tests/ui/simd/scalable/closure-capture.stderr b/tests/ui/simd/scalable/closure-capture.stderr new file mode 100644 index 0000000000000..cd513d84c73eb --- /dev/null +++ b/tests/ui/simd/scalable/closure-capture.stderr @@ -0,0 +1,29 @@ +error: scalable vectors cannot be tuple fields + --> $DIR/closure-capture.rs:45:9 + | +LL | run(move || { + | ^^^ + +error[E0507]: cannot move out of `a`, a captured variable in an `Fn` closure + --> $DIR/closure-capture.rs:46:30 + | +LL | let a = svdup_n_s32(42); + | - captured outer variable +LL | run(move || { + | ------- captured by this `Fn` closure +LL | svxar_n_s32::<2>(a, a); + | ^ move occurs because `a` has type `svint32_t`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `a`, a captured variable in an `Fn` closure + --> $DIR/closure-capture.rs:46:33 + | +LL | let a = svdup_n_s32(42); + | - captured outer variable +LL | run(move || { + | ------- captured by this `Fn` closure +LL | svxar_n_s32::<2>(a, a); + | ^ move occurs because `a` has type `svint32_t`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/simd/scalable/fn-trait.rs b/tests/ui/simd/scalable/fn-trait.rs new file mode 100644 index 0000000000000..924799c749314 --- /dev/null +++ b/tests/ui/simd/scalable/fn-trait.rs @@ -0,0 +1,14 @@ +#![feature(repr_simd, repr_scalable)] + +#[repr(simd, scalable(4))] +pub struct ScalableSimdFloat { + _ty: [f32], +} + +unsafe fn test(f: T) +where + T: Fn(ScalableSimdFloat), //~ ERROR: scalable vectors cannot be tuple fields +{ +} + +fn main() {} diff --git a/tests/ui/simd/scalable/fn-trait.stderr b/tests/ui/simd/scalable/fn-trait.stderr new file mode 100644 index 0000000000000..8945069b10f8c --- /dev/null +++ b/tests/ui/simd/scalable/fn-trait.stderr @@ -0,0 +1,8 @@ +error: scalable vectors cannot be tuple fields + --> $DIR/fn-trait.rs:10:8 + | +LL | T: Fn(ScalableSimdFloat), + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/simd/scalable/illformed-in-types.rs b/tests/ui/simd/scalable/illformed-in-types.rs new file mode 100644 index 0000000000000..89a1a13b42ecf --- /dev/null +++ b/tests/ui/simd/scalable/illformed-in-types.rs @@ -0,0 +1,54 @@ +//@ compile-flags: --crate-type=lib +#![feature(repr_simd, repr_scalable)] + +#[repr(simd, scalable(4))] +pub struct ScalableFloat { + _ty: [f32] +} + +trait WithAssocTy { + type Ty; +} + +impl WithAssocTy for ScalableFloat { + type Ty = Self; +} + +pub enum AsEnumField { + Scalable(ScalableFloat), //~ ERROR: scalable vectors cannot be fields of a variant +} + +pub struct AsStructField { + v: ScalableFloat, //~ ERROR: scalable vectors cannot be fields of a struct +} + +pub union AsUnionField { + v: ScalableFloat, +//~^ ERROR: scalable vectors cannot be fields of a union +//~^^ ERROR: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union +} + +pub enum IndirectAsEnumField { + Scalable(::Ty), //~ ERROR: scalable vectors cannot be fields of a variant +} + +pub struct IndirectAsStructField { + v: ::Ty, //~ ERROR: scalable vectors cannot be fields of a struct +} + +pub union IndirectAsUnionField { + v: ::Ty, +//~^ ERROR: scalable vectors cannot be fields of a union +//~^^ ERROR: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union +} + +fn foo() { + let x: [ScalableFloat; 2]; //~ ERROR: scalable vectors cannot be array elements + let y: (ScalableFloat, u32); //~ ERROR: scalable vectors cannot be tuple fields + let z: (u32, ScalableFloat); //~ ERROR: scalable vectors cannot be tuple fields + + // FIXME(repr-scalable): these should error too + let indirect_x: [::Ty; 2]; + let indirect_y: (::Ty, u32); + let indirect_z: (u32, ::Ty); +} diff --git a/tests/ui/simd/scalable/illformed-in-types.stderr b/tests/ui/simd/scalable/illformed-in-types.stderr new file mode 100644 index 0000000000000..486a521e3934f --- /dev/null +++ b/tests/ui/simd/scalable/illformed-in-types.stderr @@ -0,0 +1,81 @@ +error: scalable vectors cannot be fields of a variant + --> $DIR/illformed-in-types.rs:18:14 + | +LL | Scalable(ScalableFloat), + | ^^^^^^^^^^^^^ + +error: scalable vectors cannot be fields of a struct + --> $DIR/illformed-in-types.rs:22:8 + | +LL | v: ScalableFloat, + | ^^^^^^^^^^^^^ + +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/illformed-in-types.rs:26:5 + | +LL | v: ScalableFloat, + | ^^^^^^^^^^^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | v: std::mem::ManuallyDrop, + | +++++++++++++++++++++++ + + +error: scalable vectors cannot be fields of a union + --> $DIR/illformed-in-types.rs:26:8 + | +LL | v: ScalableFloat, + | ^^^^^^^^^^^^^ + +error: scalable vectors cannot be fields of a variant + --> $DIR/illformed-in-types.rs:32:14 + | +LL | Scalable(::Ty), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors cannot be fields of a struct + --> $DIR/illformed-in-types.rs:36:8 + | +LL | v: ::Ty, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/illformed-in-types.rs:40:5 + | +LL | v: ::Ty, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | v: std::mem::ManuallyDrop<::Ty>, + | +++++++++++++++++++++++ + + +error: scalable vectors cannot be fields of a union + --> $DIR/illformed-in-types.rs:40:8 + | +LL | v: ::Ty, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors cannot be array elements + --> $DIR/illformed-in-types.rs:46:12 + | +LL | let x: [ScalableFloat; 2]; + | ^^^^^^^^^^^^^^^^^^ + +error: scalable vectors cannot be tuple fields + --> $DIR/illformed-in-types.rs:47:12 + | +LL | let y: (ScalableFloat, u32); + | ^^^^^^^^^^^^^^^^^^^^ + +error: scalable vectors cannot be tuple fields + --> $DIR/illformed-in-types.rs:48:12 + | +LL | let z: (u32, ScalableFloat); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0740`. diff --git a/tests/ui/simd/scalable/value-type.rs b/tests/ui/simd/scalable/value-type.rs new file mode 100644 index 0000000000000..a4c0f24f4d71a --- /dev/null +++ b/tests/ui/simd/scalable/value-type.rs @@ -0,0 +1,30 @@ +//@ build-pass +//@ compile-flags: --crate-type=lib +//@ only-aarch64 +#![feature(link_llvm_intrinsics, simd_ffi, repr_scalable, repr_simd)] + +#[repr(simd, scalable(4))] +#[allow(non_camel_case_types)] +pub struct svint32_t { + _ty: [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) } +} + +// Tests that scalable vectors can be locals, arguments and return types. + +fn id(v: svint32_t) -> svint32_t { v } + +fn foo() { + unsafe { + let v = svdup_n_s32(1); + let v = id(v); + } +} From 661d29fe3808cae57771b5585e6150852f807919 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 10 Jul 2025 10:17:53 +0000 Subject: [PATCH 08/12] debuginfo: no spill `` for `N!=16` LLVM doesn't handle stores on `` for `N != 16`, a type used internally in SVE intrinsics. Spilling to the stack to create debuginfo will cause errors during instruction selection. These types that are an internal implementation detail to the intrinsic, so users should never see them types and won't need any debuginfo. Co-authored-by: Jamie Cunliffe --- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 025f5fb54f428..84e636ed47a34 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -361,6 +361,49 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } + // Don't spill `` for `N != 16`: + // + // SVE predicates are only one bit for each byte in an SVE vector (which makes + // sense, the predicate only needs to keep track of whether a lane is + // enabled/disabled). i.e. a `` vector has a `` + // predicate type. `` corresponds to two bytes of storage, + // multiplied by the `vscale`, with one bit for each of the sixteen lanes. + // + // For a vector with fewer elements, such as `svint32_t`/``, + // while only a `` predicate type would be strictly necessary, + // relevant intrinsics still take a `svbool_t`/`` - this is + // because a `` is only half of a byte (for `vscale=1`), and with + // memory being byte-addressable, it's unclear how to store that. + // + // Due to this, LLVM ultimately decided not to support stores of `` + // for `N != 16`. As for `vscale=1` and `N` fewer than sixteen, partial bytes would + // need to be stored (except for `N=8`, but that also isn't supported). `N` can + // never be greater than sixteen as that ends up larger than the 128-bit increment + // size. + // + // Internally, with an intrinsic operating on a `svint32_t`/`` + // (for example), the intrinsic takes the `svbool_t`/`` predicate + // and casts it to a `svbool4_t`/``. Therefore, it's important that + // the `` never spills because that'll cause errors during + // instruction selection. Spilling to the stack to create debuginfo for these + // intermediate values must be avoided and won't degrade the debugging experience + // anyway. + if operand.layout.ty.is_scalable_simd() + && bx.sess().target.arch == "aarch64" + && let ty::Adt(adt, args) = &operand.layout.ty.kind() + && let Some(marker_type_field) = + adt.non_enum_variant().fields.get(FieldIdx::from_u32(0)) + { + let marker_type = marker_type_field.ty(bx.tcx(), args); + // i.e. `` when `N != 16` + if let ty::Slice(element_ty) = marker_type.kind() + && element_ty.is_bool() + && adt.repr().scalable != Some(16) + { + return; + } + } + Self::spill_operand_to_stack(*operand, name, bx) } From 4ee1999966deb06a4d0be7be6e124e27c75546c9 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 10 Jul 2025 06:18:13 +0000 Subject: [PATCH 09/12] mir_transform: prohibit scalable vectors in async Scalable vectors cannot be members of ADTs and thus cannot be kept over await points in async functions. --- compiler/rustc_mir_transform/src/coroutine.rs | 5 +++ tests/ui/simd/scalable/async.rs | 45 +++++++++++++++++++ tests/ui/simd/scalable/async.stderr | 8 ++++ 3 files changed, 58 insertions(+) create mode 100644 tests/ui/simd/scalable/async.rs create mode 100644 tests/ui/simd/scalable/async.stderr diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 761d5461a996f..25d697e23b58b 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1856,6 +1856,11 @@ fn check_must_not_suspend_ty<'tcx>( SuspendCheckData { descr_pre: &format!("{}allocator ", data.descr_pre), ..data }, ) } + ty::Adt(def, _) if def.repr().scalable() => { + tcx.dcx() + .span_err(data.source_span, "scalable vectors cannot be held over await points"); + true + } ty::Adt(def, _) => check_must_not_suspend_def(tcx, def.did(), hir_id, data), // FIXME: support adding the attribute to TAITs ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { diff --git a/tests/ui/simd/scalable/async.rs b/tests/ui/simd/scalable/async.rs new file mode 100644 index 0000000000000..2dbbded5547c3 --- /dev/null +++ b/tests/ui/simd/scalable/async.rs @@ -0,0 +1,45 @@ +//@ only-aarch64 +//@ edition:2021 + +#![allow(incomplete_features, internal_features)] +#![feature( + core_intrinsics, + repr_simd, + repr_scalable, + simd_ffi, + link_llvm_intrinsics +)] + +use core::intrinsics::simd::simd_reinterpret; + +#[repr(simd, scalable(4))] +#[allow(non_camel_case_types)] +pub struct svint32_t { + _ty: [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) } +} + +async fn another() -> i32 { + 42 +} + +#[no_mangle] +pub async fn test_function() { + unsafe { + let x = svdup_n_s32(1); //~ ERROR: scalable vectors cannot be held over await points + let temp = another().await; + let y: svint32_t = simd_reinterpret(x); + } +} + +fn main() { + let _ = test_function(); +} diff --git a/tests/ui/simd/scalable/async.stderr b/tests/ui/simd/scalable/async.stderr new file mode 100644 index 0000000000000..b7ba6171a234b --- /dev/null +++ b/tests/ui/simd/scalable/async.stderr @@ -0,0 +1,8 @@ +error: scalable vectors cannot be held over await points + --> $DIR/async.rs:37:13 + | +LL | let x = svdup_n_s32(1); + | ^ + +error: aborting due to 1 previous error + From 911b435111560d16e99cf5c52a3cf59ac407173a Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 10 Jul 2025 07:30:12 +0000 Subject: [PATCH 10/12] builtin_macros/trait_sel: `Copy`/`Clone` derives As scalable vectors are ultimately just registers, they should be able to implement `Copy` and `Clone`, which require some small special-casing in the compiler to ignore the field within the scalable vector types. --- .../src/deriving/clone.rs | 69 +++++++++++-------- .../rustc_trait_selection/src/traits/misc.rs | 7 ++ tests/codegen/simd/scalable.rs | 53 ++++++++++++++ tests/ui/simd/scalable/copy-clone.rs | 32 +++++++++ 4 files changed, 134 insertions(+), 27 deletions(-) create mode 100644 tests/codegen/simd/scalable.rs create mode 100644 tests/ui/simd/scalable/copy-clone.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 69f8c273797e4..83a3ee3c3009f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -33,37 +33,48 @@ pub(crate) fn expand_deriving_clone( let substructure; let is_simple; match item { - Annotatable::Item(annitem) => match &annitem.kind { - ItemKind::Struct(_, Generics { params, .. }, _) - | ItemKind::Enum(_, Generics { params, .. }, _) => { - let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); - let has_derive_copy = cx.resolver.has_derive_copy(container_id); - if has_derive_copy - && !params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) - { - bounds = vec![]; + Annotatable::Item(annitem) => { + let has_repr_scalable = annitem.attrs.iter().any(|attr| { + attr.has_name(sym::repr) + && attr + .meta_item_list() + .map(|list| list.iter().any(|inner| inner.has_name(sym::scalable))) + .unwrap_or(false) + }); + + match &annitem.kind { + ItemKind::Struct(_, Generics { params, .. }, _) + | ItemKind::Enum(_, Generics { params, .. }, _) => { + let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); + let has_derive_copy = cx.resolver.has_derive_copy(container_id); + if has_derive_copy + && !params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) + { + bounds = vec![]; + is_simple = true; + substructure = combine_substructure(Box::new(move |c, s, sub| { + cs_clone_simple("Clone", c, s, sub, false, has_repr_scalable) + })); + } else { + bounds = vec![]; + is_simple = false; + substructure = combine_substructure(Box::new(|c, s, sub| { + cs_clone("Clone", c, s, sub) + })); + } + } + ItemKind::Union(..) => { + bounds = vec![Path(path_std!(marker::Copy))]; is_simple = true; - substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_simple("Clone", c, s, sub, false) + substructure = combine_substructure(Box::new(move |c, s, sub| { + cs_clone_simple("Clone", c, s, sub, true, has_repr_scalable) })); - } else { - bounds = vec![]; - is_simple = false; - substructure = - combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub))); } + _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), } - ItemKind::Union(..) => { - bounds = vec![Path(path_std!(marker::Copy))]; - is_simple = true; - substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone_simple("Clone", c, s, sub, true) - })); - } - _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), - }, + } _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"), } @@ -98,6 +109,7 @@ fn cs_clone_simple( trait_span: Span, substr: &Substructure<'_>, is_union: bool, + has_repr_scalable: bool, ) -> BlockOrExpr { let mut stmts = ThinVec::new(); let mut seen_type_names = FxHashSet::default(); @@ -112,6 +124,9 @@ fn cs_clone_simple( // Already produced an assertion for this type. // Anonymous structs or unions must be eliminated as they cannot be // type parameters. + } else if has_repr_scalable { + // Fields of scalable vector types are just markers for codegen, don't assert they + // implement `Clone` } else { // let _: AssertParamIsClone; super::assert_ty_bounds( diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 393f458bea273..8c6e6ae0637e4 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -66,6 +66,13 @@ pub fn type_allowed_to_implement_copy<'tcx>( _ => return Err(CopyImplementationError::NotAnAdt), }; + // Scalable vectors have an unsized field that would normally disallow a `Copy` impl on the + // type, but that type doesn't actually exist, it's just a marker to know the element type of + // the vector. After codegen, scalable vectors are just a register that can be trivially copied. + if adt.repr().scalable() { + return Ok(()); + } + all_fields_implement_trait( tcx, param_env, diff --git a/tests/codegen/simd/scalable.rs b/tests/codegen/simd/scalable.rs new file mode 100644 index 0000000000000..f10a7f7f42965 --- /dev/null +++ b/tests/codegen/simd/scalable.rs @@ -0,0 +1,53 @@ +//@ compile-flags: -C opt-level=2 +//@ edition: 2021 +//@ only-aarch64 + +#![crate_type = "lib"] +#![allow(incomplete_features, internal_features)] +#![feature(repr_simd, repr_scalable, simd_ffi, link_llvm_intrinsics)] + +#[derive(Copy, Clone)] +#[repr(simd, scalable(4))] +#[allow(non_camel_case_types)] +pub struct svint32_t { + _ty: [i32], +} + +#[inline(never)] +#[target_feature(enable = "sve")] +pub unsafe fn svdup_n_s32(op: i32) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4i32")] + fn _svdup_n_s32(op: i32) -> svint32_t; + } + unsafe { _svdup_n_s32(op) } +} + +#[inline] +#[target_feature(enable = "sve,sve2")] +pub unsafe fn svxar_n_s32(op1: svint32_t, op2: svint32_t) -> svint32_t { + extern "C" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.xar.nxv4i32")] + fn _svxar_n_s32(op1: svint32_t, op2: svint32_t, imm3: i32) -> svint32_t; + } + unsafe { _svxar_n_s32(op1, op2, IMM3) } +} + +#[inline(never)] +#[no_mangle] +#[target_feature(enable = "sve,sve2")] +// CHECK: define @pass_as_ref(ptr noalias nocapture noundef readonly align 4 dereferenceable(4) %a, %b) +pub unsafe fn pass_as_ref(a: &svint32_t, b: svint32_t) -> svint32_t { + // CHECK: load , ptr %a, align 4 + svxar_n_s32::<1>(*a, b) +} + +#[no_mangle] +#[target_feature(enable = "sve,sve2")] +// CHECK: define @test() +pub unsafe fn test() -> svint32_t { + let a = svdup_n_s32(1); + let b = svdup_n_s32(2); + // CHECK: call @pass_as_ref(ptr noalias noundef nonnull readonly align 4 dereferenceable(4) %a, %b) + pass_as_ref(&a, b) +} diff --git a/tests/ui/simd/scalable/copy-clone.rs b/tests/ui/simd/scalable/copy-clone.rs new file mode 100644 index 0000000000000..816c73a9e6246 --- /dev/null +++ b/tests/ui/simd/scalable/copy-clone.rs @@ -0,0 +1,32 @@ +//@ build-pass +//@ only-aarch64 +#![feature(link_llvm_intrinsics, repr_simd, repr_scalable, simd_ffi)] + +#[derive(Copy, Clone)] +#[repr(simd, scalable(4))] +#[allow(non_camel_case_types)] +pub struct svint32_t { + _ty: [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")] +fn require_copy(t: T) {} + +#[target_feature(enable = "sve")] +fn test() { + unsafe { + let a = svdup_n_s32(1); + require_copy(a); + } +} + +fn main() {} From 51a115e2287da7b5605329a61678f622389e9f3d Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 10 Jul 2025 08:46:19 +0000 Subject: [PATCH 11/12] mono: require target feature for scalable vectors Scalable vector types only work with the relevant target features enabled, so require this for any function with the types in its signature. --- compiler/rustc_monomorphize/messages.ftl | 5 +- compiler/rustc_monomorphize/src/errors.rs | 2 + .../src/mono_checks/abi_check.rs | 100 +++++++++++++----- compiler/rustc_target/src/target_features.rs | 69 +++++++----- .../simd/scalable/require-target-feature.rs | 42 ++++++++ .../scalable/require-target-feature.stderr | 10 ++ 6 files changed, 177 insertions(+), 51 deletions(-) create mode 100644 tests/ui/simd/scalable/require-target-feature.rs create mode 100644 tests/ui/simd/scalable/require-target-feature.stderr diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 2bd19e81b01c2..6591ac3cd758c 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -2,7 +2,10 @@ monomorphize_abi_error_disabled_vector_type = this function {$is_call -> [true] call *[false] definition - } uses SIMD vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call -> + } uses {$is_scalable -> + [true] scalable + *[false] SIMD + } vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call -> [true] {" "}in the caller *[false] {""} } diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 938c427b56c8f..2bf40ebf03bf4 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -75,6 +75,8 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> { pub ty: Ty<'a>, /// Whether this is a problem at a call site or at a declaration. pub is_call: bool, + /// Whether this is a problem with a fixed length vector or a scalable vector + pub is_scalable: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index b8c001d357e6c..a63296f36fd40 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -10,14 +10,37 @@ use rustc_target::callconv::{FnAbi, PassMode}; use crate::errors; -fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool { +/// Are vector registers used? +enum UsesVectorRegisters { + /// e.g. `neon` + FixedVector, + /// e.g. `sve` + ScalableVector, + No, +} + +/// Determines whether the combination of `mode` and `repr` will use fixed vector registers, +/// scalable vector registers or no vector registers. +fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> UsesVectorRegisters { match mode { - PassMode::Ignore | PassMode::Indirect { .. } => false, - PassMode::Cast { pad_i32: _, cast } => { - cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector)) - || cast.rest.unit.kind == RegKind::Vector + PassMode::Ignore | PassMode::Indirect { .. } => UsesVectorRegisters::No, + PassMode::Cast { pad_i32: _, cast } + if cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector)) + || cast.rest.unit.kind == RegKind::Vector => + { + UsesVectorRegisters::FixedVector + } + PassMode::Direct(..) | PassMode::Pair(..) + if matches!(repr, BackendRepr::SimdVector { .. }) => + { + UsesVectorRegisters::FixedVector } - PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::SimdVector { .. }), + PassMode::Direct(..) | PassMode::Pair(..) + if matches!(repr, BackendRepr::ScalableVector { .. }) => + { + UsesVectorRegisters::ScalableVector + } + _ => UsesVectorRegisters::No, } } @@ -32,37 +55,64 @@ 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(); + tracing::debug!(?def_id); 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); + tracing::debug!(?target_feats, ?fn_feats); + target_feats || fn_feats }; for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) { + tracing::debug!(?arg_abi); let size = arg_abi.layout.size; - if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) { - // Find the first feature that provides at least this vector size. - let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { - Some((_, feature)) => feature, - None => { + match uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) { + UsesVectorRegisters::FixedVector => { + let feature_def = tcx.sess.target.features_for_correct_fixed_length_vector_abi(); + // Find the first feature that provides at least this vector size. + let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { + Some((_, feature)) => feature, + None => { + let (span, _hir_id) = loc(); + tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType { + span, + ty: arg_abi.layout.ty, + is_call, + }); + continue; + } + }; + if !have_feature(Symbol::intern(feature)) { let (span, _hir_id) = loc(); - tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType { + tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType { span, + required_feature: feature, ty: arg_abi.layout.ty, is_call, + is_scalable: false, }); + } + } + UsesVectorRegisters::ScalableVector => { + let Some(required_feature) = + tcx.sess.target.features_for_correct_scalable_vector_abi() + else { continue; + }; + tracing::debug!(?required_feature); + if !have_feature(Symbol::intern(required_feature)) { + let (span, _) = loc(); + tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType { + span, + required_feature, + ty: arg_abi.layout.ty, + is_call, + is_scalable: true, + }); } - }; - if !have_feature(Symbol::intern(feature)) { - // Emit error. - let (span, _hir_id) = loc(); - tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType { - span, - required_feature: feature, - ty: arg_abi.layout.ty, - is_call, - }); + } + UsesVectorRegisters::No => { + continue; } } } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b2af99228fe6d..63046c5b2fb86 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -797,17 +797,22 @@ pub fn all_rust_features() -> impl Iterator { // These arrays represent the least-constraining feature that is required for vector types up to a // certain size to have their "proper" ABI on each architecture. // Note that they must be kept sorted by vector size. -const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = +const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10. -const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")]; +const AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "neon")]; // We might want to add "helium" too. -const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")]; +const ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "neon")]; -const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")]; -const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")]; -const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")]; -const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[ +const POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "altivec")]; +const WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "simd128")]; +const S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "vector")]; +const RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] = &[ (32, "zvl32b"), (64, "zvl64b"), (128, "zvl128b"), @@ -822,13 +827,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)] @@ -860,27 +868,38 @@ 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 { - "x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_VECTOR_ABI, - "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI, - "arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI, - "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI, - "loongarch32" | "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI, - "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI, - "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI, - "s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI, - "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI, - "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI, - "mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI, + "x86" | "x86_64" => X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "arm" => ARM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "loongarch32" | "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "s390x" => S390X_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "sparc" | "sparc64" => SPARC_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "hexagon" => HEXAGON_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI, + "mips" | "mips32r6" | "mips64" | "mips64r6" => { + MIPS_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI + } "bpf" | "m68k" => &[], // no vector ABI - "csky" => CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI, + "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. _ => &[], } } + pub fn features_for_correct_scalable_vector_abi(&self) -> Option<&'static str> { + match &*self.arch { + "aarch64" | "arm64ec" => Some("sve"), + "riscv32" | "riscv64" => todo!(), + // Other targets have no scalable vectors. + _ => None, + } + } + pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] { match &*self.arch { "aarch64" | "arm64ec" => AARCH64_TIED_FEATURES, diff --git a/tests/ui/simd/scalable/require-target-feature.rs b/tests/ui/simd/scalable/require-target-feature.rs new file mode 100644 index 0000000000000..74e1f2709de56 --- /dev/null +++ b/tests/ui/simd/scalable/require-target-feature.rs @@ -0,0 +1,42 @@ +//@ build-fail +//@ compile-flags: --crate-type=lib +//@ only-aarch64 +#![allow(incomplete_features, internal_features)] +#![feature( + repr_simd, + repr_scalable, + simd_ffi, + link_llvm_intrinsics +)] + +#[derive(Copy, Clone)] +#[repr(simd, scalable(4))] +#[allow(non_camel_case_types)] +pub struct svint32_t { + _ty: [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) } +} + +pub fn non_annotated_callee(x: svint32_t) {} +//~^ ERROR: this function definition uses scalable vector type `svint32_t` + +#[target_feature(enable = "sve")] +pub fn annotated_callee(x: svint32_t) {} // okay! + +#[target_feature(enable = "sve")] +pub fn caller() { + unsafe { + let a = svdup_n_s32(42); + non_annotated_callee(a); + annotated_callee(a); + } +} diff --git a/tests/ui/simd/scalable/require-target-feature.stderr b/tests/ui/simd/scalable/require-target-feature.stderr new file mode 100644 index 0000000000000..3df33dcf30832 --- /dev/null +++ b/tests/ui/simd/scalable/require-target-feature.stderr @@ -0,0 +1,10 @@ +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:29: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 + From 4f6b823f22f8af2d98e5ff51f3589ac69bae1419 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 14 Jul 2025 12:30:36 +0000 Subject: [PATCH 12/12] rust-analyzer: `repr(scalable)` Trivial changes to rust-analyzer to keep it compiling with changes to `ReprOptions`. --- .../rust-analyzer/crates/hir-def/src/attr.rs | 27 ++++++++++++------- .../rust-analyzer/crates/hir-ty/src/layout.rs | 17 +++++++++--- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index b509e69b0d37b..02afebf65be9a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -6,30 +6,30 @@ use base_db::Crate; use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ - HirFileId, InFile, - attrs::{Attr, AttrId, RawAttrs, collect_attrs}, + attrs::{collect_attrs, Attr, AttrId, RawAttrs}, span_map::SpanMapRef, + HirFileId, InFile, }; -use intern::{Symbol, sym}; +use intern::{sym, Symbol}; use la_arena::{ArenaMap, Idx, RawIdx}; use mbe::DelimiterKind; use rustc_abi::ReprOptions; use span::AstIdNode; use syntax::{ - AstPtr, ast::{self, HasAttrs}, + AstPtr, }; use triomphe::Arc; use tt::iter::{TtElement, TtIter}; use crate::{ - AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId, - VariantId, db::DefDatabase, item_tree::block_item_tree_query, lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, + AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId, + VariantId, }; /// Desugared attributes of an item post `cfg_attr` expansion. @@ -199,7 +199,11 @@ impl Attrs { #[inline] pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Result<(), CfgExpr> { self.cfgs().try_for_each(|cfg| { - if cfg_options.check(&cfg) != Some(false) { Ok(()) } else { Err(cfg) } + if cfg_options.check(&cfg) != Some(false) { + Ok(()) + } else { + Err(cfg) + } }) } @@ -331,7 +335,7 @@ fn parse_rustc_legacy_const_generics(tt: &crate::tt::TopSubtree) -> Box<[u32]> { } fn merge_repr(this: &mut ReprOptions, other: ReprOptions) { - let ReprOptions { int, align, pack, flags, field_shuffle_seed: _ } = this; + let ReprOptions { int, align, pack, flags, scalable, field_shuffle_seed: _ } = this; flags.insert(other.flags); *align = (*align).max(other.align); *pack = match (*pack, other.pack) { @@ -341,6 +345,9 @@ fn merge_repr(this: &mut ReprOptions, other: ReprOptions) { if other.int.is_some() { *int = other.int; } + if other.scalable.is_some() { + *scalable = other.scalable; + } } fn parse_repr_tt(tt: &crate::tt::TopSubtree) -> Option { @@ -852,8 +859,8 @@ mod tests { use hir_expand::span_map::{RealSpanMap, SpanMap}; use span::FileId; - use syntax::{AstNode, TextRange, ast}; - use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree}; + use syntax::{ast, AstNode, TextRange}; + use syntax_bridge::{syntax_node_to_token_tree, DocCommentDesugarMode}; use crate::attr::{DocAtom, DocExpr}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 107da6a5af6d6..e7f8cd971c211 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -4,11 +4,11 @@ use std::fmt; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ - LocalFieldId, StructId, layout::{ Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData, Primitive, ReprOptions, Scalar, StructKind, TargetDataLayout, WrappingRange, }, + LocalFieldId, StructId, }; use la_arena::{Idx, RawIdx}; use rustc_abi::AddressSpace; @@ -17,11 +17,11 @@ use rustc_index::IndexVec; use triomphe::Arc; use crate::{ - Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, consteval::try_const_usize, db::{HirDatabase, InternedClosure}, infer::normalize, utils::ClosureSubst, + Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, }; pub(crate) use self::adt::layout_of_adt_cycle_result; @@ -123,6 +123,7 @@ fn layout_of_simd_ty( db: &dyn HirDatabase, id: StructId, repr_packed: bool, + repr_scalable: Option, subst: &Substitution, env: Arc, dl: &TargetDataLayout, @@ -146,7 +147,7 @@ fn layout_of_simd_ty( let e_ly = db.layout_of_ty(e_ty, env)?; let cx = LayoutCx::new(dl); - Ok(Arc::new(cx.calc.simd_type(e_ly, e_len, repr_packed)?)) + Ok(Arc::new(cx.calc.simd_type(e_ly, e_len, repr_packed, repr_scalable)?)) } pub fn layout_of_ty_query( @@ -168,7 +169,15 @@ pub fn layout_of_ty_query( let data = db.struct_signature(*s); let repr = data.repr.unwrap_or_default(); if repr.simd() { - return layout_of_simd_ty(db, *s, repr.packed(), subst, trait_env, &target); + return layout_of_simd_ty( + db, + *s, + repr.packed(), + repr.scalable, + subst, + trait_env, + &target, + ); } }; return db.layout_of_adt(*def, subst.clone(), trait_env);