From 043bd767688281d574ea8cc0c368156021baa61d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?=
Date: Fri, 27 Feb 2026 06:23:06 +0100
Subject: [PATCH 01/38] Make `layout_of` cycles fatal errors
---
compiler/rustc_codegen_llvm/src/context.rs | 6 +-----
.../src/interpret/eval_context.rs | 3 +--
.../src/hir_ty_lowering/cmse.rs | 3 +--
compiler/rustc_middle/src/ty/layout.rs | 6 +-----
.../src/handle_cycle_error.rs | 4 +---
compiler/rustc_transmute/src/layout/tree.rs | 1 -
.../html/templates/type_layout.html | 5 -----
tests/ui/layout/layout-cycle.rs | 1 -
tests/ui/layout/layout-cycle.stderr | 16 ++------------
tests/ui/layout/post-mono-layout-cycle.stderr | 6 ------
...ck-overflow-trait-infer-98842.64bit.stderr | 21 -------------------
.../sized/stack-overflow-trait-infer-98842.rs | 4 +---
...> stack-overflow-trait-infer-98842.stderr} | 13 +++---------
13 files changed, 11 insertions(+), 78 deletions(-)
delete mode 100644 tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr
rename tests/ui/sized/{stack-overflow-trait-infer-98842.32bit.stderr => stack-overflow-trait-infer-98842.stderr} (55%)
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index e02c4ae6ea695..80d939a25701e 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -1134,11 +1134,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
match err {
- FnAbiError::Layout(
- LayoutError::SizeOverflow(_)
- | LayoutError::Cycle(_)
- | LayoutError::InvalidSimd { .. },
- ) => {
+ FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) => {
self.tcx.dcx().emit_fatal(Spanned { span, node: err });
}
_ => match fn_abi_request {
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 0bfe012bfe7a4..04f0e7099d840 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -107,8 +107,7 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> {
| LayoutError::SizeOverflow(_)
| LayoutError::InvalidSimd { .. }
| LayoutError::TooGeneric(_)
- | LayoutError::ReferencesError(_)
- | LayoutError::Cycle(_) => {}
+ | LayoutError::ReferencesError(_) => {}
}
err_inval!(Layout(err))
}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
index 58c296d92c24e..a1b169c6a1661 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -194,8 +194,7 @@ fn should_emit_layout_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError<
| SizeOverflow(..)
| InvalidSimd { .. }
| NormalizationFailure(..)
- | ReferencesError(..)
- | Cycle(..) => {
+ | ReferencesError(..) => {
false // not our job to report these
}
}
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 4ca51c078bef5..46682abc823d8 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -260,8 +260,6 @@ pub enum LayoutError<'tcx> {
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
/// A non-layout error is reported elsewhere.
ReferencesError(ErrorGuaranteed),
- /// A type has cyclic layout, i.e. the type contains itself without indirection.
- Cycle(ErrorGuaranteed),
}
impl<'tcx> fmt::Display for LayoutError<'tcx> {
@@ -286,7 +284,6 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
t,
e.get_type_for_failure()
),
- LayoutError::Cycle(_) => write!(f, "a cycle occurred during layout computation"),
LayoutError::ReferencesError(_) => write!(f, "the type has an unknown layout"),
}
}
@@ -358,8 +355,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
Err(err @ LayoutError::TooGeneric(_)) => err,
// We can't extract SizeSkeleton info from other layout errors
Err(
- e @ LayoutError::Cycle(_)
- | e @ LayoutError::Unknown(_)
+ e @ LayoutError::Unknown(_)
| e @ LayoutError::SizeOverflow(_)
| e @ LayoutError::InvalidSimd { .. }
| e @ LayoutError::NormalizationFailure(..)
diff --git a/compiler/rustc_query_impl/src/handle_cycle_error.rs b/compiler/rustc_query_impl/src/handle_cycle_error.rs
index 5676669bf1c0e..22f8ac9837f6d 100644
--- a/compiler/rustc_query_impl/src/handle_cycle_error.rs
+++ b/compiler/rustc_query_impl/src/handle_cycle_error.rs
@@ -12,7 +12,6 @@ use rustc_middle::bug;
use rustc_middle::queries::{QueryVTables, TaggedQueryKey};
use rustc_middle::query::Cycle;
use rustc_middle::query::erase::erase_val;
-use rustc_middle::ty::layout::LayoutError;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{ErrorGuaranteed, Span};
@@ -203,8 +202,7 @@ fn layout_of<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> &'tcx ty::layout::L
|| create_cycle_error(tcx, &cycle),
);
- let guar = diag.emit();
- tcx.arena.alloc(LayoutError::Cycle(guar))
+ diag.emit().raise_fatal()
}
// item_and_field_ids should form a cycle where each field contains the
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 1202ed2384315..1bfe6e94cc3b6 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -282,7 +282,6 @@ pub(crate) mod rustc {
| LayoutError::InvalidSimd { .. }
| LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
LayoutError::SizeOverflow(..) => Self::SizeOverflow,
- LayoutError::Cycle(err) => Self::TypeError(*err),
}
}
}
diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
index 49153d58fe98c..4d4222a34956a 100644
--- a/src/librustdoc/html/templates/type_layout.html
+++ b/src/librustdoc/html/templates/type_layout.html
@@ -60,11 +60,6 @@
- {% when Err(LayoutError::Cycle(_)) %}
- {# #}
- Note: Encountered an error during type layout; {#+ #}
- the type's layout depended on the type's layout itself. {# #}
-
{% when Err(LayoutError::InvalidSimd {..}) %}
{# #}
Note: Encountered an error during type layout; {#+ #}
diff --git a/tests/ui/layout/layout-cycle.rs b/tests/ui/layout/layout-cycle.rs
index b38bd52c6ade9..846ce0882cad1 100644
--- a/tests/ui/layout/layout-cycle.rs
+++ b/tests/ui/layout/layout-cycle.rs
@@ -1,6 +1,5 @@
//@ build-fail
//~^ ERROR: cycle detected when computing layout of
-//~? ERROR: a cycle occurred during layout computation
// Issue #111176 -- ensure that we do not emit ICE on layout cycles
diff --git a/tests/ui/layout/layout-cycle.stderr b/tests/ui/layout/layout-cycle.stderr
index e05ff614567c4..28c35d431226e 100644
--- a/tests/ui/layout/layout-cycle.stderr
+++ b/tests/ui/layout/layout-cycle.stderr
@@ -6,18 +6,6 @@ note: cycle used when const-evaluating + checking `core::mem::SizedTypePropertie
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-error[E0080]: a cycle occurred during layout computation
- --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
- = note: evaluation of `> as std::mem::SizedTypeProperties>::SIZE` failed here
-
-note: the above error was encountered while instantiating `fn std::mem::size_of::>>`
- --> $DIR/layout-cycle.rs:26:5
- |
-LL | mem::size_of::>()
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
-Some errors have detailed explanations: E0080, E0391.
-For more information about an error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/layout/post-mono-layout-cycle.stderr b/tests/ui/layout/post-mono-layout-cycle.stderr
index 7f246b3d409ad..b9b1b988499e6 100644
--- a/tests/ui/layout/post-mono-layout-cycle.stderr
+++ b/tests/ui/layout/post-mono-layout-cycle.stderr
@@ -5,12 +5,6 @@ error[E0391]: cycle detected when computing layout of `Wrapper<()>`
= note: cycle used when computing layout of `core::option::Option>`
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-note: the above error was encountered while instantiating `fn abi::<()>`
- --> $DIR/post-mono-layout-cycle.rs:19:5
- |
-LL | abi::(None);
- | ^^^^^^^^^^^^^^
-
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr
deleted file mode 100644
index d097b809b5698..0000000000000
--- a/tests/ui/sized/stack-overflow-trait-infer-98842.64bit.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0391]: cycle detected when computing layout of `Foo`
- |
- = note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`...
- = note: ...which again requires computing layout of `Foo`, completing the cycle
-note: cycle used when const-evaluating + checking `_`
- --> $DIR/stack-overflow-trait-infer-98842.rs:14:1
- |
-LL | const _: *const Foo = 0 as _;
- | ^^^^^^^^^^^^^^^^^^^
- = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error[E0080]: a cycle occurred during layout computation
- --> $DIR/stack-overflow-trait-infer-98842.rs:14:1
- |
-LL | const _: *const Foo = 0 as _;
- | ^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0080, E0391.
-For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.rs b/tests/ui/sized/stack-overflow-trait-infer-98842.rs
index 1c9f6c593f447..d6522e3cfb643 100644
--- a/tests/ui/sized/stack-overflow-trait-infer-98842.rs
+++ b/tests/ui/sized/stack-overflow-trait-infer-98842.rs
@@ -2,8 +2,7 @@
// issue: rust-lang/rust#98842
//@ check-fail
//@ edition:2021
-//@ stderr-per-bitwidth
-//~^^^^^ ERROR cycle detected when computing layout of `Foo`
+//~^^^^ ERROR cycle detected when computing layout of `Foo`
// If the inner `Foo` is named through an associated type,
// the "infinite size" error does not occur.
@@ -12,6 +11,5 @@ struct Foo(<&'static Foo as ::core::ops::Deref>::Target);
// and it will infinitely recurse somewhere trying to figure out the
// size of this pointer (is my guess):
const _: *const Foo = 0 as _;
-//~^ ERROR a cycle occurred during layout computation
pub fn main() {}
diff --git a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr b/tests/ui/sized/stack-overflow-trait-infer-98842.stderr
similarity index 55%
rename from tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr
rename to tests/ui/sized/stack-overflow-trait-infer-98842.stderr
index d097b809b5698..5557a6fc45b89 100644
--- a/tests/ui/sized/stack-overflow-trait-infer-98842.32bit.stderr
+++ b/tests/ui/sized/stack-overflow-trait-infer-98842.stderr
@@ -3,19 +3,12 @@ error[E0391]: cycle detected when computing layout of `Foo`
= note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`...
= note: ...which again requires computing layout of `Foo`, completing the cycle
note: cycle used when const-evaluating + checking `_`
- --> $DIR/stack-overflow-trait-infer-98842.rs:14:1
+ --> $DIR/stack-overflow-trait-infer-98842.rs:13:1
|
LL | const _: *const Foo = 0 as _;
| ^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-error[E0080]: a cycle occurred during layout computation
- --> $DIR/stack-overflow-trait-infer-98842.rs:14:1
- |
-LL | const _: *const Foo = 0 as _;
- | ^^^^^^^^^^^^^^^^^^^ evaluation of `_` failed here
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
-Some errors have detailed explanations: E0080, E0391.
-For more information about an error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0391`.
From 4fd1d9713af32df00514bb57e5e888b84d34291d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?=
Date: Mon, 16 Mar 2026 22:18:59 +0100
Subject: [PATCH 02/38] Skip ICE message for fatal errors
---
src/tools/miri/src/eval.rs | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 1e75df7d278fb..cf4f7d689ac22 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -10,6 +10,7 @@ use std::{iter, thread};
use rustc_abi::ExternAbi;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::FatalErrorMarker;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutCx};
@@ -477,7 +478,11 @@ pub fn eval_entry<'tcx>(
let res: thread::Result> =
panic::catch_unwind(AssertUnwindSafe(|| ecx.run_threads()));
let res = res.unwrap_or_else(|panic_payload| {
- ecx.handle_ice();
+ // rustc "handles" some errors by unwinding with FatalErrorMarker
+ // (after emitting suitable diagnostics), so do not treat those as ICEs.
+ if !panic_payload.is::() {
+ ecx.handle_ice();
+ }
panic::resume_unwind(panic_payload)
});
// Obtain the result of the execution. This is always an `Err`, but that doesn't necessarily
From db30a36c8edb360eb16de681ff07972980dfbba1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?=
Date: Mon, 16 Mar 2026 22:19:21 +0100
Subject: [PATCH 03/38] Update tests
---
src/tools/miri/tests/fail/layout_cycle.rs | 3 +--
src/tools/miri/tests/fail/layout_cycle.stderr | 11 ++---------
2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/src/tools/miri/tests/fail/layout_cycle.rs b/src/tools/miri/tests/fail/layout_cycle.rs
index 3e0dd881db84e..8d5f1914d0c32 100644
--- a/src/tools/miri/tests/fail/layout_cycle.rs
+++ b/src/tools/miri/tests/fail/layout_cycle.rs
@@ -1,5 +1,4 @@
-//@error-in-other-file: a cycle occurred during layout computation
-//~^ ERROR: cycle detected when computing layout of
+//~ ERROR: cycle detected when computing layout of
use std::mem;
diff --git a/src/tools/miri/tests/fail/layout_cycle.stderr b/src/tools/miri/tests/fail/layout_cycle.stderr
index dae6934931228..f8d555e5a10b8 100644
--- a/src/tools/miri/tests/fail/layout_cycle.stderr
+++ b/src/tools/miri/tests/fail/layout_cycle.stderr
@@ -9,13 +9,6 @@ LL | const SIZE: usize = intrinsics::size_of::();
| ^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-error[E0080]: a cycle occurred during layout computation
- --> RUSTLIB/core/src/mem/mod.rs:LL:CC
- |
-LL | const SIZE: usize = intrinsics::size_of::();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `> as std::mem::SizedTypeProperties>::SIZE` failed here
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
-Some errors have detailed explanations: E0080, E0391.
-For more information about an error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0391`.
From 7d0577e95815194acf59cb3e876ca521f5638232 Mon Sep 17 00:00:00 2001
From: David Wood
Date: Thu, 19 Feb 2026 11:03:14 +0000
Subject: [PATCH 04/38] ty_utils: lower tuples to `ScalableVector` repr
Instead of just using regular struct lowering for these types, which
results in an incorrect ABI (e.g. returning indirectly), use
`BackendRepr::ScalableVector` which will lower to the correct type and
be passed in registers.
This also enables some simplifications for generating alloca of scalable
vectors and greater re-use of `scalable_vector_parts`.
A LLVM codegen test demonstrating the changed IR this generates is
included in the next commit alongside some intrinsics that make these
tuples usable.
---
compiler/rustc_abi/src/layout.rs | 21 ++++++---
compiler/rustc_abi/src/lib.rs | 33 ++++++++++++--
compiler/rustc_codegen_gcc/src/builder.rs | 7 +--
compiler/rustc_codegen_llvm/src/builder.rs | 18 +++-----
compiler/rustc_codegen_llvm/src/type_of.rs | 44 ++++++++++++++++++-
.../rustc_codegen_ssa/src/mir/debuginfo.rs | 4 +-
compiler/rustc_codegen_ssa/src/mir/place.rs | 15 +++----
.../rustc_codegen_ssa/src/traits/builder.rs | 2 +-
compiler/rustc_middle/src/ty/sty.rs | 24 +++++++---
compiler/rustc_public/src/abi.rs | 5 +++
.../src/unstable/convert/stable/abi.rs | 25 +++++++++--
compiler/rustc_ty_utils/src/layout.rs | 32 ++++++--------
12 files changed, 161 insertions(+), 69 deletions(-)
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index ca6128b6f1be4..cca1d499088f4 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -10,8 +10,8 @@ use tracing::{debug, trace};
use crate::{
AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
- LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
- TargetDataLayout, Variants, WrappingRange,
+ LayoutData, Niche, NonZeroUsize, NumScalableVectors, Primitive, ReprOptions, Scalar, Size,
+ StructKind, TagEncoding, TargetDataLayout, Variants, WrappingRange,
};
mod coroutine;
@@ -204,13 +204,19 @@ impl LayoutCalculator {
&self,
element: F,
count: u64,
+ number_of_vectors: NumScalableVectors,
) -> LayoutCalculatorResult
where
FieldIdx: Idx,
VariantIdx: Idx,
F: AsRef> + fmt::Debug,
{
- vector_type_layout(SimdVectorKind::Scalable, self.cx.data_layout(), element, count)
+ vector_type_layout(
+ SimdVectorKind::Scalable(number_of_vectors),
+ self.cx.data_layout(),
+ element,
+ count,
+ )
}
pub fn simd_type(
@@ -1526,7 +1532,7 @@ impl LayoutCalculator {
enum SimdVectorKind {
/// `#[rustc_scalable_vector]`
- Scalable,
+ Scalable(NumScalableVectors),
/// `#[repr(simd, packed)]`
PackedFixed,
/// `#[repr(simd)]`
@@ -1559,9 +1565,10 @@ where
let size =
elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
let (repr, align) = match kind {
- SimdVectorKind::Scalable => {
- (BackendRepr::SimdScalableVector { element, count }, dl.llvmlike_vector_align(size))
- }
+ SimdVectorKind::Scalable(number_of_vectors) => (
+ BackendRepr::SimdScalableVector { element, count, number_of_vectors },
+ dl.llvmlike_vector_align(size),
+ ),
// Non-power-of-two vectors have padding up to the next power-of-two.
// If we're a packed repr, remove the padding while keeping the alignment as close
// to a vector as possible.
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 253dff6f8e75c..4f3bd6ef208da 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1702,6 +1702,28 @@ impl AddressSpace {
pub const ZERO: Self = AddressSpace(0);
}
+/// How many scalable vectors are in a `BackendRepr::ScalableVector`?
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
+pub struct NumScalableVectors(pub u8);
+
+impl NumScalableVectors {
+ /// Returns a `NumScalableVector` for a non-tuple scalable vector (e.g. a single vector).
+ pub fn for_non_tuple() -> Self {
+ NumScalableVectors(1)
+ }
+
+ // Returns `NumScalableVectors` for values of two through eight, which are a valid number of
+ // fields for a tuple of scalable vectors to have. `1` is a valid value of `NumScalableVectors`
+ // but not for a tuple which would have a field count.
+ pub fn from_field_count(count: usize) -> Option {
+ match count {
+ 2..8 => Some(NumScalableVectors(count as u8)),
+ _ => None,
+ }
+ }
+}
+
/// The way we represent values to the backend
///
/// Previously this was conflated with the "ABI" a type is given, as in the platform-specific ABI.
@@ -1720,6 +1742,7 @@ pub enum BackendRepr {
SimdScalableVector {
element: Scalar,
count: u64,
+ number_of_vectors: NumScalableVectors,
},
SimdVector {
element: Scalar,
@@ -1826,8 +1849,12 @@ impl BackendRepr {
BackendRepr::SimdVector { element: element.to_union(), count }
}
BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true },
- BackendRepr::SimdScalableVector { element, count } => {
- BackendRepr::SimdScalableVector { element: element.to_union(), count }
+ BackendRepr::SimdScalableVector { element, count, number_of_vectors } => {
+ BackendRepr::SimdScalableVector {
+ element: element.to_union(),
+ count,
+ number_of_vectors,
+ }
}
}
}
@@ -2167,7 +2194,7 @@ impl LayoutData {
}
/// Returns `true` if the size of the type is only known at runtime.
- pub fn is_runtime_sized(&self) -> bool {
+ pub fn is_scalable_vector(&self) -> bool {
matches!(self.backend_repr, BackendRepr::SimdScalableVector { .. })
}
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 3eb0fd95284a1..08964113b944a 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -24,7 +24,8 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::ty::layout::{
- FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers,
+ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError,
+ LayoutOfHelpers, TyAndLayout,
};
use rustc_middle::ty::{self, AtomicOrdering, Instance, Ty, TyCtxt};
use rustc_span::Span;
@@ -943,8 +944,8 @@ 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 alloca_with_ty(&mut self, ty: TyAndLayout<'tcx>) -> RValue<'gcc> {
+ self.alloca(ty.layout.size, ty.layout.align.abi)
}
fn load(&mut self, pointee_ty: Type<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index f3508c10d1f61..9e59d7aa7c20a 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -7,8 +7,7 @@ pub(crate) mod autodiff;
pub(crate) mod gpu_offload;
use libc::{c_char, c_uint};
-use rustc_abi as abi;
-use rustc_abi::{Align, Size, WrappingRange};
+use rustc_abi::{self as abi, Align, Size, WrappingRange};
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind};
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
@@ -616,21 +615,14 @@ 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 {
+ fn alloca_with_ty(&mut self, layout: TyAndLayout<'tcx>) -> 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"),
- };
+ let scalable_vector_ty = layout.llvm_type(self.cx);
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);
+ let alloca = llvm::LLVMBuildAlloca(&bx.llbuilder, scalable_vector_ty, UNNAMED);
+ llvm::LLVMSetAlignment(alloca, layout.align.abi.bytes() as c_uint);
alloca
}
}
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index e586ed0dd6b07..6d0490e4a1f79 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -24,14 +24,54 @@ fn uncached_llvm_type<'a, 'tcx>(
let element = layout.scalar_llvm_type_at(cx, element);
return cx.type_vector(element, count);
}
- BackendRepr::SimdScalableVector { ref element, count } => {
+ BackendRepr::SimdScalableVector { ref element, count, number_of_vectors } => {
let element = if element.is_bool() {
cx.type_i1()
} else {
layout.scalar_llvm_type_at(cx, *element)
};
- return cx.type_scalable_vector(element, count);
+ let vector_type = cx.type_scalable_vector(element, count);
+ return match number_of_vectors.0 {
+ 1 => vector_type,
+ 2 => cx.type_struct(&[vector_type, vector_type], false),
+ 3 => cx.type_struct(&[vector_type, vector_type, vector_type], false),
+ 4 => cx.type_struct(&[vector_type, vector_type, vector_type, vector_type], false),
+ 5 => cx.type_struct(
+ &[vector_type, vector_type, vector_type, vector_type, vector_type],
+ false,
+ ),
+ 6 => cx.type_struct(
+ &[vector_type, vector_type, vector_type, vector_type, vector_type, vector_type],
+ false,
+ ),
+ 7 => cx.type_struct(
+ &[
+ vector_type,
+ vector_type,
+ vector_type,
+ vector_type,
+ vector_type,
+ vector_type,
+ vector_type,
+ ],
+ false,
+ ),
+ 8 => cx.type_struct(
+ &[
+ vector_type,
+ vector_type,
+ vector_type,
+ vector_type,
+ vector_type,
+ vector_type,
+ vector_type,
+ vector_type,
+ ],
+ false,
+ ),
+ _ => bug!("`#[rustc_scalable_vector]` tuple struct with too many fields"),
+ };
}
BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {}
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 2f93f688c316d..60ab13dbc6f76 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -438,8 +438,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if operand.layout.ty.is_scalable_vector()
&& bx.sess().target.arch == rustc_target::spec::Arch::AArch64
{
- let (count, element_ty) =
- operand.layout.ty.scalable_vector_element_count_and_type(bx.tcx());
+ let (count, element_ty, _) =
+ operand.layout.ty.scalable_vector_parts(bx.tcx()).unwrap();
// i.e. `` when `N != 16`
if element_ty.is_bool() && count != 16 {
return;
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index d62e622b6fed3..53518fd816f31 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -1,3 +1,5 @@
+use std::ops::Deref as _;
+
use rustc_abi::{
Align, BackendRepr, FieldIdx, FieldsShape, Size, TagEncoding, VariantIdx, Variants,
};
@@ -109,8 +111,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
bx: &mut Bx,
layout: TyAndLayout<'tcx>,
) -> Self {
- if layout.is_runtime_sized() {
- Self::alloca_runtime_sized(bx, layout)
+ if layout.deref().is_scalable_vector() {
+ Self::alloca_scalable(bx, layout)
} else {
Self::alloca_size(bx, layout.size, layout)
}
@@ -151,16 +153,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
}
}
- fn alloca_runtime_sized>(
+ fn alloca_scalable>(
bx: &mut Bx,
layout: TyAndLayout<'tcx>,
) -> Self {
- let (element_count, ty) = layout.ty.scalable_vector_element_count_and_type(bx.tcx());
- PlaceValue::new_sized(
- bx.scalable_alloca(element_count as u64, layout.align.abi, ty),
- layout.align.abi,
- )
- .with_type(layout)
+ PlaceValue::new_sized(bx.alloca_with_ty(layout), layout.align.abi).with_type(layout)
}
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 05e94b8019f49..5092f28a33f7b 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -235,7 +235,7 @@ pub trait BuilderMethods<'a, 'tcx>:
fn to_immediate_scalar(&mut self, val: Self::Value, scalar: Scalar) -> Self::Value;
fn alloca(&mut self, size: Size, align: Align) -> Self::Value;
- fn scalable_alloca(&mut self, elt: u64, align: Align, element_ty: Ty<'_>) -> Self::Value;
+ fn alloca_with_ty(&mut self, layout: TyAndLayout<'tcx>) -> 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_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 0d047b348d9e1..621ceeffac658 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -7,7 +7,7 @@ use std::debug_assert_matches;
use std::ops::{ControlFlow, Range};
use hir::def::{CtorKind, DefKind};
-use rustc_abi::{FIRST_VARIANT, FieldIdx, ScalableElt, VariantIdx};
+use rustc_abi::{FIRST_VARIANT, FieldIdx, NumScalableVectors, ScalableElt, VariantIdx};
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::LangItem;
@@ -1261,17 +1261,27 @@ impl<'tcx> Ty<'tcx> {
}
}
- pub fn scalable_vector_element_count_and_type(self, tcx: TyCtxt<'tcx>) -> (u16, Ty<'tcx>) {
+ pub fn scalable_vector_parts(
+ self,
+ tcx: TyCtxt<'tcx>,
+ ) -> Option<(u16, Ty<'tcx>, NumScalableVectors)> {
let Adt(def, args) = self.kind() else {
- bug!("`scalable_vector_size_and_type` called on invalid type")
+ return None;
};
- let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else {
- bug!("`scalable_vector_size_and_type` called on non-scalable vector type");
+ let (num_vectors, vec_def) = match def.repr().scalable? {
+ ScalableElt::ElementCount(_) => (NumScalableVectors::for_non_tuple(), *def),
+ ScalableElt::Container => (
+ NumScalableVectors::from_field_count(def.non_enum_variant().fields.len())?,
+ def.non_enum_variant().fields[FieldIdx::ZERO].ty(tcx, args).ty_adt_def()?,
+ ),
};
- let variant = def.non_enum_variant();
+ let Some(ScalableElt::ElementCount(element_count)) = vec_def.repr().scalable else {
+ return None;
+ };
+ let variant = vec_def.non_enum_variant();
assert_eq!(variant.fields.len(), 1);
let field_ty = variant.fields[FieldIdx::ZERO].ty(tcx, args);
- (element_count, field_ty)
+ Some((element_count, field_ty, num_vectors))
}
pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs
index 1403e57a7e6a9..4a780d652df81 100644
--- a/compiler/rustc_public/src/abi.rs
+++ b/compiler/rustc_public/src/abi.rs
@@ -232,6 +232,10 @@ pub enum TagEncoding {
},
}
+/// How many scalable vectors are in a `ValueAbi::ScalableVector`?
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
+pub struct NumScalableVectors(pub(crate) u8);
+
/// Describes how values of the type are passed by target ABIs,
/// in terms of categories of C types there are ABI rules for.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
@@ -245,6 +249,7 @@ pub enum ValueAbi {
ScalableVector {
element: Scalar,
count: u64,
+ number_of_vectors: NumScalableVectors,
},
Aggregate {
/// If true, the size is exact, otherwise it's only a lower bound.
diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs
index b3edc6194c307..d8c4cee7abbe4 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs
@@ -10,8 +10,9 @@ use rustc_target::callconv;
use crate::abi::{
AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength,
- IntegerType, Layout, LayoutShape, PassMode, Primitive, ReprFlags, ReprOptions, Scalar,
- TagEncoding, TyAndLayout, ValueAbi, VariantFields, VariantsShape, WrappingRange,
+ IntegerType, Layout, LayoutShape, NumScalableVectors, PassMode, Primitive, ReprFlags,
+ ReprOptions, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantFields, VariantsShape,
+ WrappingRange,
};
use crate::compiler_interface::BridgeTys;
use crate::target::MachineSize as Size;
@@ -249,6 +250,18 @@ impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding {
}
}
+impl<'tcx> Stable<'tcx> for rustc_abi::NumScalableVectors {
+ type T = NumScalableVectors;
+
+ fn stable<'cx>(
+ &self,
+ _tables: &mut Tables<'cx, BridgeTys>,
+ _cx: &CompilerCtxt<'cx, BridgeTys>,
+ ) -> Self::T {
+ NumScalableVectors(self.0)
+ }
+}
+
impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr {
type T = ValueAbi;
@@ -265,8 +278,12 @@ 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::SimdScalableVector { element, count } => {
- ValueAbi::ScalableVector { element: element.stable(tables, cx), count }
+ rustc_abi::BackendRepr::SimdScalableVector { element, count, number_of_vectors } => {
+ ValueAbi::ScalableVector {
+ element: element.stable(tables, cx),
+ count,
+ number_of_vectors: number_of_vectors.stable(tables, cx),
+ }
}
rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized },
}
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 391f50edf23fa..136df923ee47a 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -4,8 +4,8 @@ use rustc_abi::Integer::{I8, I32};
use rustc_abi::Primitive::{self, Float, Int, Pointer};
use rustc_abi::{
AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout,
- LayoutCalculatorError, LayoutData, Niche, ReprOptions, ScalableElt, Scalar, Size, StructKind,
- TagEncoding, VariantIdx, Variants, WrappingRange,
+ LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding,
+ VariantIdx, Variants, WrappingRange,
};
use rustc_hashes::Hash64;
use rustc_hir as hir;
@@ -572,30 +572,26 @@ fn layout_of_uncached<'tcx>(
// ```rust (ignore, example)
// #[rustc_scalable_vector(3)]
// struct svuint32_t(u32);
+ //
+ // #[rustc_scalable_vector]
+ // struct svuint32x2_t(svuint32_t, svuint32_t);
// ```
- ty::Adt(def, args)
- if matches!(def.repr().scalable, Some(ScalableElt::ElementCount(..))) =>
- {
- let Some(element_ty) = def
- .is_struct()
- .then(|| &def.variant(FIRST_VARIANT).fields)
- .filter(|fields| fields.len() == 1)
- .map(|fields| fields[FieldIdx::ZERO].ty(tcx, args))
+ ty::Adt(def, _args) if def.repr().scalable() => {
+ let Some((element_count, element_ty, number_of_vectors)) =
+ ty.scalable_vector_parts(tcx)
else {
let guar = tcx
.dcx()
- .delayed_bug("#[rustc_scalable_vector] was applied to an invalid type");
- return Err(error(cx, LayoutError::ReferencesError(guar)));
- };
- let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else {
- let guar = tcx
- .dcx()
- .delayed_bug("#[rustc_scalable_vector] was applied to an invalid type");
+ .delayed_bug("`#[rustc_scalable_vector]` was applied to an invalid type");
return Err(error(cx, LayoutError::ReferencesError(guar)));
};
let element_layout = cx.layout_of(element_ty)?;
- map_layout(cx.calc.scalable_vector_type(element_layout, element_count as u64))?
+ map_layout(cx.calc.scalable_vector_type(
+ element_layout,
+ element_count as u64,
+ number_of_vectors,
+ ))?
}
// SIMD vector types.
From 93dfff5c9065fffebc1587949235cf4ddb7eabd4 Mon Sep 17 00:00:00 2001
From: David Wood
Date: Thu, 19 Feb 2026 11:03:14 +0000
Subject: [PATCH 05/38] cg_llvm: `sve_tuple_{create,get,set}` intrinsics
Clang changed to representing tuples of scalable vectors as
structs rather than as wide vectors (that is, scalable vector types
where the `N` part of the `` type was multiplied by
the number of vectors). rustc mirrored this in the initial implementation
of scalable vectors.
Earlier versions of our patches used the wide vector representation and
our intrinsic patches used the legacy
`llvm.aarch64.sve.tuple.{create,get,set}{2,3,4}` intrinsics for creating
these tuples/getting/setting the vectors, which were only supported
due to LLVM's `AutoUpgrade` pass converting these intrinsics into
`llvm.vector.insert`. `AutoUpgrade` only supports these legacy intrinsics
with the wide vector representation.
With the current struct representation, Clang has special handling in
codegen for generating `insertvalue`/`extractvalue` instructions for
these operations, which must be replicated by rustc's codegen for our
intrinsics to use. This patch implements new intrinsics in
`core::intrinsics::scalable` (mirroring the structure of
`core::intrinsics::simd`) which rustc lowers to the appropriate
`insertvalue`/`extractvalue` instructions.
---
compiler/rustc_codegen_llvm/src/intrinsic.rs | 112 +++++++++++++++++-
.../rustc_hir_analysis/src/check/intrinsic.rs | 6 +
compiler/rustc_span/src/symbol.rs | 5 +
.../src/intrinsics/{simd.rs => simd/mod.rs} | 2 +
library/core/src/intrinsics/simd/scalable.rs | 76 ++++++++++++
.../scalable-vectors/tuple-intrinsics.rs | 100 ++++++++++++++++
.../simd/masked-load-store-check-fail.stderr | 4 +-
triagebot.toml | 2 +-
8 files changed, 303 insertions(+), 4 deletions(-)
rename library/core/src/intrinsics/{simd.rs => simd/mod.rs} (99%)
create mode 100644 library/core/src/intrinsics/simd/scalable.rs
create mode 100644 tests/codegen-llvm/scalable-vectors/tuple-intrinsics.rs
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 39bf4c10dab18..ad2c23c99820b 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -3,7 +3,8 @@ use std::ffi::c_uint;
use std::{assert_matches, ptr};
use rustc_abi::{
- Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size, WrappingRange,
+ Align, BackendRepr, ExternAbi, Float, HasDataLayout, NumScalableVectors, Primitive, Size,
+ WrappingRange,
};
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
@@ -605,6 +606,115 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
self.pointercast(val, self.type_ptr())
}
+ sym::sve_tuple_create2 => {
+ assert_matches!(
+ self.layout_of(fn_args.type_at(0)).backend_repr,
+ BackendRepr::SimdScalableVector {
+ number_of_vectors: NumScalableVectors(1),
+ ..
+ }
+ );
+ let tuple_ty = self.layout_of(fn_args.type_at(1));
+ assert_matches!(
+ tuple_ty.backend_repr,
+ BackendRepr::SimdScalableVector {
+ number_of_vectors: NumScalableVectors(2),
+ ..
+ }
+ );
+ let ret = self.const_poison(self.backend_type(tuple_ty));
+ let ret = self.insert_value(ret, args[0].immediate(), 0);
+ self.insert_value(ret, args[1].immediate(), 1)
+ }
+
+ sym::sve_tuple_create3 => {
+ assert_matches!(
+ self.layout_of(fn_args.type_at(0)).backend_repr,
+ BackendRepr::SimdScalableVector {
+ number_of_vectors: NumScalableVectors(1),
+ ..
+ }
+ );
+ let tuple_ty = self.layout_of(fn_args.type_at(1));
+ assert_matches!(
+ tuple_ty.backend_repr,
+ BackendRepr::SimdScalableVector {
+ number_of_vectors: NumScalableVectors(3),
+ ..
+ }
+ );
+ let ret = self.const_poison(self.backend_type(tuple_ty));
+ let ret = self.insert_value(ret, args[0].immediate(), 0);
+ let ret = self.insert_value(ret, args[1].immediate(), 1);
+ self.insert_value(ret, args[2].immediate(), 2)
+ }
+
+ sym::sve_tuple_create4 => {
+ assert_matches!(
+ self.layout_of(fn_args.type_at(0)).backend_repr,
+ BackendRepr::SimdScalableVector {
+ number_of_vectors: NumScalableVectors(1),
+ ..
+ }
+ );
+ let tuple_ty = self.layout_of(fn_args.type_at(1));
+ assert_matches!(
+ tuple_ty.backend_repr,
+ BackendRepr::SimdScalableVector {
+ number_of_vectors: NumScalableVectors(4),
+ ..
+ }
+ );
+ let ret = self.const_poison(self.backend_type(tuple_ty));
+ let ret = self.insert_value(ret, args[0].immediate(), 0);
+ let ret = self.insert_value(ret, args[1].immediate(), 1);
+ let ret = self.insert_value(ret, args[2].immediate(), 2);
+ self.insert_value(ret, args[3].immediate(), 3)
+ }
+
+ sym::sve_tuple_get => {
+ assert_matches!(
+ self.layout_of(fn_args.type_at(0)).backend_repr,
+ BackendRepr::SimdScalableVector {
+ number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8),
+ ..
+ }
+ );
+ assert_matches!(
+ self.layout_of(fn_args.type_at(1)).backend_repr,
+ BackendRepr::SimdScalableVector {
+ number_of_vectors: NumScalableVectors(1),
+ ..
+ }
+ );
+ self.extract_value(
+ args[0].immediate(),
+ fn_args.const_at(2).to_leaf().to_i32() as u64,
+ )
+ }
+
+ sym::sve_tuple_set => {
+ assert_matches!(
+ self.layout_of(fn_args.type_at(0)).backend_repr,
+ BackendRepr::SimdScalableVector {
+ number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8),
+ ..
+ }
+ );
+ assert_matches!(
+ self.layout_of(fn_args.type_at(1)).backend_repr,
+ BackendRepr::SimdScalableVector {
+ number_of_vectors: NumScalableVectors(1),
+ ..
+ }
+ );
+ self.insert_value(
+ args[0].immediate(),
+ args[1].immediate(),
+ fn_args.const_at(2).to_leaf().to_i32() as u64,
+ )
+ }
+
_ if name.as_str().starts_with("simd_") => {
// Unpack non-power-of-2 #[repr(packed, simd)] arguments.
// This gives them the expected layout of a regular #[repr(simd)] vector.
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index b1dc593331c6c..ca57921089fae 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -783,6 +783,12 @@ pub(crate) fn check_intrinsic_type(
sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)),
sym::simd_shuffle_const_generic => (2, 1, vec![param(0), param(0)], param(1)),
+ sym::sve_tuple_create2 => (2, 0, vec![param(0), param(0)], param(1)),
+ sym::sve_tuple_create3 => (2, 0, vec![param(0), param(0), param(0)], param(1)),
+ sym::sve_tuple_create4 => (2, 0, vec![param(0), param(0), param(0), param(0)], param(1)),
+ sym::sve_tuple_get => (2, 1, vec![param(0)], param(1)),
+ sym::sve_tuple_set => (2, 1, vec![param(0), param(1)], param(0)),
+
sym::atomic_cxchg | sym::atomic_cxchgweak => (
1,
2,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 7b359dcd6b252..e44e9f4ea1ce7 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1977,6 +1977,11 @@ symbols! {
suggestion,
super_let,
supertrait_item_shadowing,
+ sve_tuple_create2,
+ sve_tuple_create3,
+ sve_tuple_create4,
+ sve_tuple_get,
+ sve_tuple_set,
sym,
sync,
synthetic,
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd/mod.rs
similarity index 99%
rename from library/core/src/intrinsics/simd.rs
rename to library/core/src/intrinsics/simd/mod.rs
index ae86690dc418d..084d8a3f1f247 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd/mod.rs
@@ -2,6 +2,8 @@
//!
//! In this module, a "vector" is any `repr(simd)` type.
+pub mod scalable;
+
use crate::marker::ConstParamTy;
/// Inserts an element into a vector, returning the updated vector.
diff --git a/library/core/src/intrinsics/simd/scalable.rs b/library/core/src/intrinsics/simd/scalable.rs
new file mode 100644
index 0000000000000..a569d1ffbc548
--- /dev/null
+++ b/library/core/src/intrinsics/simd/scalable.rs
@@ -0,0 +1,76 @@
+//! Scalable vector compiler intrinsics.
+//!
+//! In this module, a "vector" is any `#[rustc_scalable_vector]`-annotated type.
+
+/// Create a tuple of two vectors.
+///
+/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a
+/// scalable vector (`#[rustc_scalable_vector(N)]`). `SVecTup` must be a tuple of vectors of
+/// type `SVec`.
+///
+/// Corresponds to Clang's `__builtin_sve_svcreate2*` builtins.
+#[cfg(target_arch = "aarch64")]
+#[rustc_nounwind]
+#[rustc_intrinsic]
+#[target_feature(enable = "sve")]
+pub unsafe fn sve_tuple_create2(x0: SVec, x1: SVec) -> SVecTup;
+
+/// Create a tuple of three vectors.
+///
+/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a
+/// scalable vector (`#[rustc_scalable_vector(N)]`). `SVecTup` must be a tuple of vectors of
+/// type `SVec`.
+///
+/// Corresponds to Clang's `__builtin_sve_svcreate3*` builtins.
+#[cfg(target_arch = "aarch64")]
+#[rustc_intrinsic]
+#[rustc_nounwind]
+#[target_feature(enable = "sve")]
+pub unsafe fn sve_tuple_create3(x0: SVec, x1: SVec, x2: SVec) -> SVecTup;
+
+/// Create a tuple of four vectors.
+///
+/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a
+/// scalable vector (`#[rustc_scalable_vector(N)]`). `SVecTup` must be a tuple of vectors of
+/// type `SVec`.
+///
+/// Corresponds to Clang's `__builtin_sve_svcreate4*` builtins.
+#[cfg(target_arch = "aarch64")]
+#[rustc_intrinsic]
+#[rustc_nounwind]
+#[target_feature(enable = "sve")]
+pub unsafe fn sve_tuple_create4(x0: SVec, x1: SVec, x2: SVec, x3: SVec) -> SVecTup;
+
+/// Get one vector from a tuple of vectors.
+///
+/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a
+/// scalable vector (`#[rustc_scalable_vector(N)]`). `SVecTup` must be a tuple of vectors of
+/// type `SVec`.
+///
+/// Corresponds to Clang's `__builtin_sve_svget*` builtins.
+///
+/// # Safety
+///
+/// `IDX` must be in-bounds of the tuple.
+#[cfg(target_arch = "aarch64")]
+#[rustc_intrinsic]
+#[rustc_nounwind]
+#[target_feature(enable = "sve")]
+pub unsafe fn sve_tuple_get(tuple: SVecTup) -> SVec;
+
+/// Change one vector in a tuple of vectors.
+///
+/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a
+/// scalable vector (`#[rustc_scalable_vector(N)]`). `SVecTup` must be a tuple of vectors of
+/// type `SVec`.
+///
+/// Corresponds to Clang's `__builtin_sve_svset*` builtins.
+///
+/// # Safety
+///
+/// `IDX` must be in-bounds of the tuple.
+#[cfg(target_arch = "aarch64")]
+#[rustc_intrinsic]
+#[rustc_nounwind]
+#[target_feature(enable = "sve")]
+pub unsafe fn sve_tuple_set(tuple: SVecTup, x: SVec) -> SVecTup;
diff --git a/tests/codegen-llvm/scalable-vectors/tuple-intrinsics.rs b/tests/codegen-llvm/scalable-vectors/tuple-intrinsics.rs
new file mode 100644
index 0000000000000..e19fc40cb9d67
--- /dev/null
+++ b/tests/codegen-llvm/scalable-vectors/tuple-intrinsics.rs
@@ -0,0 +1,100 @@
+//@ build-pass
+//@ only-aarch64
+#![crate_type = "lib"]
+#![allow(incomplete_features, internal_features)]
+#![feature(abi_unadjusted, core_intrinsics, link_llvm_intrinsics, rustc_attrs)]
+
+// Tests that tuples of scalable vectors are passed as immediates and that the intrinsics for
+// creating/getting/setting tuples of scalable vectors generate the correct assembly
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+pub struct svfloat32_t(f32);
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+pub struct svfloat32x2_t(svfloat32_t, svfloat32_t);
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+pub struct svfloat32x3_t(svfloat32_t, svfloat32_t, svfloat32_t);
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+pub struct svfloat32x4_t(svfloat32_t, svfloat32_t, svfloat32_t, svfloat32_t);
+
+#[inline(never)]
+#[target_feature(enable = "sve")]
+pub fn svdup_n_f32(op: f32) -> svfloat32_t {
+ extern "C" {
+ #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.dup.x.nxv4f32")]
+ fn _svdup_n_f32(op: f32) -> svfloat32_t;
+ }
+ unsafe { _svdup_n_f32(op) }
+}
+
+// CHECK: define { , } @svcreate2_f32( %x0, %x1)
+#[no_mangle]
+#[target_feature(enable = "sve")]
+pub fn svcreate2_f32(x0: svfloat32_t, x1: svfloat32_t) -> svfloat32x2_t {
+ // CHECK: %1 = insertvalue { , } poison, %x0, 0
+ // CHECK-NEXT: %2 = insertvalue { , } %1, %x1, 1
+ unsafe { std::intrinsics::simd::scalable::sve_tuple_create2(x0, x1) }
+}
+
+// CHECK: define { , , } @svcreate3_f32( %x0, %x1, %x2)
+#[no_mangle]
+#[target_feature(enable = "sve")]
+pub fn svcreate3_f32(x0: svfloat32_t, x1: svfloat32_t, x2: svfloat32_t) -> svfloat32x3_t {
+ // CHECK-LABEL: @_RNvCsk3YxfLN8zWY_6tuples13svcreate3_f32
+ // CHECK: %1 = insertvalue { , , } poison, %x0, 0
+ // CHECK-NEXT: %2 = insertvalue { , , } %1, %x1, 1
+ // CHECK-NEXT: %3 = insertvalue { , , } %2, %x2, 2
+ unsafe { std::intrinsics::simd::scalable::sve_tuple_create3(x0, x1, x2) }
+}
+
+// CHECK: define { , , , } @svcreate4_f32( %x0, %x1, %x2, %x3)
+#[no_mangle]
+#[target_feature(enable = "sve")]
+pub fn svcreate4_f32(
+ x0: svfloat32_t,
+ x1: svfloat32_t,
+ x2: svfloat32_t,
+ x3: svfloat32_t,
+) -> svfloat32x4_t {
+ // CHECK-LABEL: @_RNvCsk3YxfLN8zWY_6tuples13svcreate4_f32
+ // CHECK: %1 = insertvalue { , , , } poison, %x0, 0
+ // CHECK-NEXT: %2 = insertvalue { , , , } %1, %x1, 1
+ // CHECK-NEXT: %3 = insertvalue { , , , } %2, %x2, 2
+ // CHECK-NEXT: %4 = insertvalue { , , , } %3, %x3, 3
+ unsafe { std::intrinsics::simd::scalable::sve_tuple_create4(x0, x1, x2, x3) }
+}
+
+// CHECK: define @svget2_f32({ , } %tup)
+#[no_mangle]
+#[target_feature(enable = "sve")]
+pub fn svget2_f32(tup: svfloat32x2_t) -> svfloat32_t {
+ // CHECK: %1 = extractvalue { , } %tup, 0
+ unsafe { std::intrinsics::simd::scalable::sve_tuple_get::<_, _, { IDX }>(tup) }
+}
+
+// CHECK: define { , } @svset2_f32({ , } %tup, %x)
+#[no_mangle]
+#[target_feature(enable = "sve")]
+pub fn svset2_f32(tup: svfloat32x2_t, x: svfloat32_t) -> svfloat32x2_t {
+ // CHECK: %1 = insertvalue { , } %tup, %x, 0
+ unsafe { std::intrinsics::simd::scalable::sve_tuple_set::<_, _, { IDX }>(tup, x) }
+}
+
+// This function exists only so there are calls to the generic functions
+#[target_feature(enable = "sve")]
+pub fn test() {
+ let x = svdup_n_f32(2f32);
+ let tup = svcreate2_f32(x, x);
+ let x = svget2_f32::<0>(tup);
+ let tup = svset2_f32::<0>(tup, x);
+}
diff --git a/tests/ui/simd/masked-load-store-check-fail.stderr b/tests/ui/simd/masked-load-store-check-fail.stderr
index 4e63d04a3b158..037855c8ec9ca 100644
--- a/tests/ui/simd/masked-load-store-check-fail.stderr
+++ b/tests/ui/simd/masked-load-store-check-fail.stderr
@@ -21,7 +21,7 @@ LL | | Simd::([9; 4]),
LL | | );
| |_________^
note: function defined here
- --> $SRC_DIR/core/src/intrinsics/simd.rs:LL:COL
+ --> $SRC_DIR/core/src/intrinsics/simd/mod.rs:LL:COL
error[E0308]: mismatched types
--> $DIR/masked-load-store-check-fail.rs:25:13
@@ -46,7 +46,7 @@ LL | | default,
LL | | );
| |_________^
note: function defined here
- --> $SRC_DIR/core/src/intrinsics/simd.rs:LL:COL
+ --> $SRC_DIR/core/src/intrinsics/simd/mod.rs:LL:COL
error: aborting due to 2 previous errors
diff --git a/triagebot.toml b/triagebot.toml
index f99d700310dfe..719fe2a75c82b 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1077,7 +1077,7 @@ cc = ["@Amanieu", "@folkertdev", "@sayantn"]
message = "Some changes occurred in `std_detect`"
cc = ["@Amanieu", "@folkertdev", "@sayantn"]
-[mentions."library/core/src/intrinsics/simd.rs"]
+[mentions."library/core/src/intrinsics/simd/mod.rs"]
message = """
Some changes occurred to the platform-builtins intrinsics. Make sure the
LLVM backend as well as portable-simd gets adapted for the changes.
From a05afe5b6750e5324324d8ef69dba89095840eb7 Mon Sep 17 00:00:00 2001
From: David Wood
Date: Thu, 26 Feb 2026 15:35:20 +0000
Subject: [PATCH 06/38] cg_llvm/debuginfo: scalable vectors
Generate debuginfo for scalable vectors, following the structure that
Clang generates for scalable vectors.
---
compiler/rustc_codegen_gcc/src/common.rs | 4 +
compiler/rustc_codegen_llvm/src/common.rs | 4 +
.../src/debuginfo/dwarf_const.rs | 8 +
.../src/debuginfo/metadata.rs | 120 +++++++++++++-
compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 17 ++
.../rustc_codegen_ssa/src/traits/consts.rs | 1 +
.../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 36 ++++-
.../scalable-vectors/debuginfo-tuples-x2.rs | 149 ++++++++++++++++++
.../scalable-vectors/debuginfo-tuples-x3.rs | 149 ++++++++++++++++++
.../scalable-vectors/debuginfo-tuples-x4.rs | 149 ++++++++++++++++++
.../scalable-vectors/debuginfo.rs | 123 +++++++++++++++
11 files changed, 754 insertions(+), 6 deletions(-)
create mode 100644 tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x2.rs
create mode 100644 tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x3.rs
create mode 100644 tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x4.rs
create mode 100644 tests/codegen-llvm/scalable-vectors/debuginfo.rs
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index 9e548ac0a8b01..dd0064d34bc4a 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -145,6 +145,10 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
self.const_int(self.type_i32(), i as i64)
}
+ fn const_i64(&self, i: i64) -> RValue<'gcc> {
+ self.const_int(self.type_i64(), i)
+ }
+
fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> {
self.gcc_int(typ, int)
}
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index a134e97cc8915..dadf8e9e7d5fa 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -159,6 +159,10 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
self.const_int(self.type_i32(), i as i64)
}
+ fn const_i64(&self, i: i64) -> &'ll Value {
+ self.const_int(self.type_i64(), i as i64)
+ }
+
fn const_int(&self, t: &'ll Type, i: i64) -> &'ll Value {
debug_assert!(
self.type_kind(t) == TypeKind::Integer,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs
index 52d04625749b9..1172660af4a29 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs
@@ -35,6 +35,14 @@ declare_constant!(DW_OP_plus_uconst: u64);
/// Double-checked by a static assertion in `RustWrapper.cpp`.
#[allow(non_upper_case_globals)]
pub(crate) const DW_OP_LLVM_fragment: u64 = 0x1000;
+#[allow(non_upper_case_globals)]
+pub(crate) const DW_OP_constu: u64 = 0x10;
+#[allow(non_upper_case_globals)]
+pub(crate) const DW_OP_minus: u64 = 0x1c;
+#[allow(non_upper_case_globals)]
+pub(crate) const DW_OP_mul: u64 = 0x1e;
+#[allow(non_upper_case_globals)]
+pub(crate) const DW_OP_bregx: u64 = 0x92;
// It describes the actual value of a source variable which might not exist in registers or in memory.
#[allow(non_upper_case_globals)]
pub(crate) const DW_OP_stack_value: u64 = 0x9f;
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 04c0b6953290c..25307823b37c7 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -6,7 +6,7 @@ use std::sync::Arc;
use std::{iter, ptr};
use libc::{c_longlong, c_uint};
-use rustc_abi::{Align, Size};
+use rustc_abi::{Align, Layout, NumScalableVectors, Size};
use rustc_codegen_ssa::debuginfo::type_names::{VTableNameKind, cpp_like_debuginfo};
use rustc_codegen_ssa::traits::*;
use rustc_hir::def::{CtorKind, DefKind};
@@ -16,12 +16,12 @@ use rustc_middle::ty::layout::{
HasTypingEnv, LayoutOf, TyAndLayout, WIDE_PTR_ADDR, WIDE_PTR_EXTRA,
};
use rustc_middle::ty::{
- self, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility,
+ self, AdtDef, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility,
};
use rustc_session::config::{self, DebugInfo, Lto};
use rustc_span::{DUMMY_SP, FileName, RemapPathScopeComponents, SourceFile, Span, Symbol, hygiene};
use rustc_symbol_mangling::typeid_for_trait_ref;
-use rustc_target::spec::DebuginfoKind;
+use rustc_target::spec::{Arch, DebuginfoKind};
use smallvec::smallvec;
use tracing::{debug, instrument};
@@ -33,7 +33,7 @@ use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_na
use super::utils::{DIB, debug_context, get_namespace_for_item, is_node_local_to_unit};
use crate::common::{AsCCharPtr, CodegenCx};
use crate::debuginfo::metadata::type_map::build_type_with_children;
-use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
+use crate::debuginfo::utils::{WidePtrKind, create_DIArray, wide_pointer_kind};
use crate::debuginfo::{DIBuilderExt, dwarf_const};
use crate::llvm::debuginfo::{
DIBasicType, DIBuilder, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock,
@@ -1039,6 +1039,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
span: Span,
) -> DINodeCreationResult<'ll> {
let struct_type = unique_type_id.expect_ty();
+
let ty::Adt(adt_def, _) = struct_type.kind() else {
bug!("build_struct_type_di_node() called with non-struct-type: {:?}", struct_type);
};
@@ -1051,6 +1052,21 @@ fn build_struct_type_di_node<'ll, 'tcx>(
} else {
None
};
+ let name = compute_debuginfo_type_name(cx.tcx, struct_type, false);
+
+ if struct_type.is_scalable_vector() {
+ let parts = struct_type.scalable_vector_parts(cx.tcx).unwrap();
+ return build_scalable_vector_di_node(
+ cx,
+ unique_type_id,
+ name,
+ *adt_def,
+ parts,
+ struct_type_and_layout.layout,
+ def_location,
+ containing_scope,
+ );
+ }
type_map::build_type_with_children(
cx,
@@ -1058,7 +1074,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
cx,
Stub::Struct,
unique_type_id,
- &compute_debuginfo_type_name(cx.tcx, struct_type, false),
+ &name,
def_location,
size_and_align_of(struct_type_and_layout),
Some(containing_scope),
@@ -1101,6 +1117,100 @@ fn build_struct_type_di_node<'ll, 'tcx>(
)
}
+/// Generate debuginfo for a `#[rustc_scalable_vector]` type.
+///
+/// Debuginfo for a scalable vector uses a derived type based on a composite type. The composite
+/// type has the `DIFlagVector` flag set and is based on the element type of the scalable vector.
+/// The composite type has a subrange from 0 to an expression that calculates the number of
+/// elements in the vector.
+///
+/// ```text,ignore
+/// !1 = !DIDerivedType(tag: DW_TAG_typedef, name: "svint16_t", ..., baseType: !2, ...)
+/// !2 = !DICompositeType(tag: DW_TAG_array_type, baseType: !3, ..., flags: DIFlagVector, elements: !4)
+/// !3 = !DIBasicType(name: "i16", size: 16, encoding: DW_ATE_signed)
+/// !4 = !{!5}
+/// !5 = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 4, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+/// ```
+///
+/// See the `CodegenType::CreateType(const BuiltinType *BT)` implementation in Clang for how this
+/// is generated for C and C++.
+fn build_scalable_vector_di_node<'ll, 'tcx>(
+ cx: &CodegenCx<'ll, 'tcx>,
+ unique_type_id: UniqueTypeId<'tcx>,
+ name: String,
+ adt_def: AdtDef<'tcx>,
+ (element_count, element_ty, number_of_vectors): (u16, Ty<'tcx>, NumScalableVectors),
+ layout: Layout<'tcx>,
+ def_location: Option>,
+ containing_scope: &'ll DIScope,
+) -> DINodeCreationResult<'ll> {
+ use dwarf_const::{DW_OP_bregx, DW_OP_constu, DW_OP_minus, DW_OP_mul};
+ assert!(adt_def.repr().scalable());
+ // This logic is specific to AArch64 for the moment, but can be extended for other architectures
+ // later.
+ assert_matches!(cx.tcx.sess.target.arch, Arch::AArch64);
+
+ let (file_metadata, line_number) = if let Some(def_location) = def_location {
+ (def_location.0, def_location.1)
+ } else {
+ (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
+ };
+
+ let (bitstride, element_di_node) = if element_ty.is_bool() {
+ (Some(llvm::LLVMValueAsMetadata(cx.const_i64(1))), type_di_node(cx, cx.tcx.types.u8))
+ } else {
+ (None, type_di_node(cx, element_ty))
+ };
+
+ let number_of_elements: u64 = (element_count as u64) * (number_of_vectors.0 as u64);
+ let number_of_elements_per_vg = number_of_elements / 2;
+ let mut expr = smallvec::SmallVec::<[u64; 9]>::new();
+ // `($number_of_elements_per_vector_granule * (value_of_register(AArch64::VG) + 0)) - 1`
+ expr.push(DW_OP_constu); // Push a constant onto the stack
+ expr.push(number_of_elements_per_vg);
+ expr.push(DW_OP_bregx); // Push the value of a register + offset on to the stack
+ expr.push(/* AArch64::VG */ 46u64);
+ expr.push(0u64);
+ expr.push(DW_OP_mul); // Multiply top two values on stack
+ expr.push(DW_OP_constu); // Push a constant onto the stack
+ expr.push(1u64);
+ expr.push(DW_OP_minus); // Subtract top two values on stack
+
+ let di_builder = DIB(cx);
+ let metadata = unsafe {
+ let upper = llvm::LLVMDIBuilderCreateExpression(di_builder, expr.as_ptr(), expr.len());
+ let subrange = llvm::LLVMRustDIGetOrCreateSubrange(
+ di_builder,
+ /* CountNode */ None,
+ llvm::LLVMValueAsMetadata(cx.const_i64(0)),
+ upper,
+ /* Stride */ None,
+ );
+ let subscripts = create_DIArray(di_builder, &[Some(subrange)]);
+ let vector_ty = llvm::LLVMRustDICreateVectorType(
+ di_builder,
+ /* Size */ 0,
+ layout.align.bits() as u32,
+ element_di_node,
+ subscripts,
+ bitstride,
+ );
+ llvm::LLVMDIBuilderCreateTypedef(
+ di_builder,
+ vector_ty,
+ name.as_ptr(),
+ name.len(),
+ file_metadata,
+ line_number,
+ Some(containing_scope),
+ layout.align.bits() as u32,
+ )
+ };
+
+ debug_context(cx).type_map.insert(unique_type_id, metadata);
+ DINodeCreationResult { di_node: metadata, already_stored_in_typemap: true }
+}
+
//=-----------------------------------------------------------------------------
// Tuples
//=-----------------------------------------------------------------------------
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 7355d11367920..0ad74c9ca43a7 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2302,6 +2302,23 @@ unsafe extern "C" {
Params: Option<&'a DIArray>,
);
+ pub(crate) fn LLVMRustDIGetOrCreateSubrange<'a>(
+ Builder: &DIBuilder<'a>,
+ CountNode: Option<&'a Metadata>,
+ LB: &'a Metadata,
+ UB: &'a Metadata,
+ Stride: Option<&'a Metadata>,
+ ) -> &'a Metadata;
+
+ pub(crate) fn LLVMRustDICreateVectorType<'a>(
+ Builder: &DIBuilder<'a>,
+ Size: u64,
+ AlignInBits: u32,
+ Type: &'a DIType,
+ Subscripts: &'a DIArray,
+ BitStride: Option<&'a Metadata>,
+ ) -> &'a Metadata;
+
pub(crate) fn LLVMRustDILocationCloneWithBaseDiscriminator<'a>(
Location: &'a DILocation,
BD: c_uint,
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index 4178a9742e268..22784a8868ab5 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -20,6 +20,7 @@ pub trait ConstCodegenMethods: BackendTypes {
fn const_i8(&self, i: i8) -> Self::Value;
fn const_i16(&self, i: i16) -> Self::Value;
fn const_i32(&self, i: i32) -> Self::Value;
+ fn const_i64(&self, i: i64) -> Self::Value;
fn const_int(&self, t: Self::Type, i: i64) -> Self::Value;
fn const_u8(&self, i: u8) -> Self::Value;
fn const_u32(&self, i: u32) -> Self::Value;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 63ff0b2a0a0df..f0cda4493c851 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -70,6 +70,10 @@ using namespace llvm::object;
// This opcode is an LLVM detail that could hypothetically change (?), so
// verify that the hard-coded value in `dwarf_const.rs` still agrees with LLVM.
static_assert(dwarf::DW_OP_LLVM_fragment == 0x1000);
+static_assert(dwarf::DW_OP_constu == 0x10);
+static_assert(dwarf::DW_OP_minus == 0x1c);
+static_assert(dwarf::DW_OP_mul == 0x1e);
+static_assert(dwarf::DW_OP_bregx == 0x92);
static_assert(dwarf::DW_OP_stack_value == 0x9f);
static LLVM_THREAD_LOCAL char *LastError;
@@ -731,7 +735,7 @@ extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
}
template DIT *unwrapDIPtr(LLVMMetadataRef Ref) {
- return (DIT *)(Ref ? unwrap(Ref) : nullptr);
+ return (DIT *)(Ref ? unwrap(Ref) : nullptr);
}
#define DIDescriptor DIScope
@@ -1207,6 +1211,36 @@ extern "C" void LLVMRustDICompositeTypeReplaceArrays(
DINodeArray(unwrap(Params)));
}
+// LLVM's C FFI bindings don't expose the overload of `GetOrCreateSubrange`
+// which takes a metadata node as the upper bound.
+extern "C" LLVMMetadataRef
+LLVMRustDIGetOrCreateSubrange(LLVMDIBuilderRef Builder,
+ LLVMMetadataRef CountNode, LLVMMetadataRef LB,
+ LLVMMetadataRef UB, LLVMMetadataRef Stride) {
+ return wrap(unwrap(Builder)->getOrCreateSubrange(
+ unwrapDI(CountNode), unwrapDI(LB),
+ unwrapDI(UB), unwrapDI(Stride)));
+}
+
+// LLVM's CI FFI bindings don't expose the `BitStride` parameter of
+// `createVectorType`.
+extern "C" LLVMMetadataRef
+LLVMRustDICreateVectorType(LLVMDIBuilderRef Builder, uint64_t Size,
+ uint32_t AlignInBits, LLVMMetadataRef Type,
+ LLVMMetadataRef Subscripts,
+ LLVMMetadataRef BitStride) {
+#if LLVM_VERSION_GE(22, 0)
+ return wrap(unwrap(Builder)->createVectorType(
+ Size, AlignInBits, unwrapDI(Type),
+ DINodeArray(unwrapDI(Subscripts)),
+ unwrapDI(BitStride)));
+#else
+ return wrap(unwrap(Builder)->createVectorType(
+ Size, AlignInBits, unwrapDI(Type),
+ DINodeArray(unwrapDI(Subscripts))));
+#endif
+}
+
extern "C" LLVMMetadataRef
LLVMRustDILocationCloneWithBaseDiscriminator(LLVMMetadataRef Location,
unsigned BD) {
diff --git a/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x2.rs b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x2.rs
new file mode 100644
index 0000000000000..1aaba621d0e10
--- /dev/null
+++ b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x2.rs
@@ -0,0 +1,149 @@
+//@ only-aarch64
+//@ compile-flags: -Cdebuginfo=2 -Copt-level=0
+
+#![crate_type = "lib"]
+#![allow(incomplete_features, internal_features)]
+#![feature(rustc_attrs)]
+
+// Test that we generate the correct debuginfo for scalable vector types.
+
+#[rustc_scalable_vector(16)]
+#[allow(non_camel_case_types)]
+struct svint8_t(i8);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint8x2_t(svint8_t, svint8_t);
+
+#[rustc_scalable_vector(16)]
+#[allow(non_camel_case_types)]
+struct svuint8_t(u8);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint8x2_t(svuint8_t, svuint8_t);
+
+#[rustc_scalable_vector(8)]
+#[allow(non_camel_case_types)]
+struct svint16_t(i16);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint16x2_t(svint16_t, svint16_t);
+
+#[rustc_scalable_vector(8)]
+#[allow(non_camel_case_types)]
+struct svuint16_t(u16);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint16x2_t(svuint16_t, svuint16_t);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svint32_t(i32);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint32x2_t(svint32_t, svint32_t);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svuint32_t(u32);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint32x2_t(svuint32_t, svuint32_t);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svint64_t(i64);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint64x2_t(svint64_t, svint64_t);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svuint64_t(u64);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint64x2_t(svuint64_t, svuint64_t);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svfloat32_t(f32);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svfloat32x2_t(svfloat32_t, svfloat32_t);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svfloat64_t(f64);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svfloat64x2_t(svfloat64_t, svfloat64_t);
+
+#[target_feature(enable = "sve")]
+pub fn locals() {
+ // CHECK-DAG: name: "svint8x2_t",{{.*}}, baseType: ![[CT8:[0-9]+]]
+ // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x2:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "i8", size: 8, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS8x2]] = !{![[REALELTS8x2:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS8x2]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 16, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s8: svint8x2_t;
+
+ // CHECK-DAG: name: "svuint8x2_t",{{.*}}, baseType: ![[CT8:[0-9]+]]
+ // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x2]])
+ // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned)
+ let u8: svuint8x2_t;
+
+ // CHECK-DAG: name: "svint16x2_t",{{.*}}, baseType: ![[CT16:[0-9]+]]
+ // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x2:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "i16", size: 16, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS16x2]] = !{![[REALELTS16x2:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS16x2]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 8, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s16: svint16x2_t;
+
+ // CHECK-DAG: name: "svuint16x2_t",{{.*}}, baseType: ![[CT16:[0-9]+]]
+ // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x2]])
+ // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "u16", size: 16, encoding: DW_ATE_unsigned)
+ let u16: svuint16x2_t;
+
+ // CHECK-DAG: name: "svint32x2_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x2:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS32x2]] = !{![[REALELTS32x2:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS32x2]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 4, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s32: svint32x2_t;
+
+ // CHECK-DAG: name: "svuint32x2_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x2]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "u32", size: 32, encoding: DW_ATE_unsigned)
+ let u32: svuint32x2_t;
+
+ // CHECK-DAG: name: "svint64x2_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x2_64:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "i64", size: 64, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS1x2_64]] = !{![[REALELTS1x2_64:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS1x2_64]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 2, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s64: svint64x2_t;
+
+ // CHECK-DAG: name: "svuint64x2_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x2_64]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned)
+ let u64: svuint64x2_t;
+
+ // CHECK: name: "svfloat32x2_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x2]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "f32", size: 32, encoding: DW_ATE_float)
+ let f32: svfloat32x2_t;
+
+ // CHECK: name: "svfloat64x2_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x2_64]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "f64", size: 64, encoding: DW_ATE_float)
+ let f64: svfloat64x2_t;
+}
diff --git a/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x3.rs b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x3.rs
new file mode 100644
index 0000000000000..b19051e2c743d
--- /dev/null
+++ b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x3.rs
@@ -0,0 +1,149 @@
+//@ only-aarch64
+//@ compile-flags: -Cdebuginfo=2 -Copt-level=0
+
+#![crate_type = "lib"]
+#![allow(incomplete_features, internal_features)]
+#![feature(rustc_attrs)]
+
+// Test that we generate the correct debuginfo for scalable vector types.
+
+#[rustc_scalable_vector(16)]
+#[allow(non_camel_case_types)]
+struct svint8_t(i8);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint8x3_t(svint8_t, svint8_t, svint8_t);
+
+#[rustc_scalable_vector(16)]
+#[allow(non_camel_case_types)]
+struct svuint8_t(u8);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint8x3_t(svuint8_t, svuint8_t, svuint8_t);
+
+#[rustc_scalable_vector(8)]
+#[allow(non_camel_case_types)]
+struct svint16_t(i16);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint16x3_t(svint16_t, svint16_t, svint16_t);
+
+#[rustc_scalable_vector(8)]
+#[allow(non_camel_case_types)]
+struct svuint16_t(u16);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint16x3_t(svuint16_t, svuint16_t, svuint16_t);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svint32_t(i32);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint32x3_t(svint32_t, svint32_t, svint32_t);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svuint32_t(u32);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint32x3_t(svuint32_t, svuint32_t, svuint32_t);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svint64_t(i64);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint64x3_t(svint64_t, svint64_t, svint64_t);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svuint64_t(u64);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint64x3_t(svuint64_t, svuint64_t, svuint64_t);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svfloat32_t(f32);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svfloat32x3_t(svfloat32_t, svfloat32_t, svfloat32_t);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svfloat64_t(f64);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svfloat64x3_t(svfloat64_t, svfloat64_t, svfloat64_t);
+
+#[target_feature(enable = "sve")]
+pub fn locals() {
+ // CHECK-DAG: name: "svint8x3_t",{{.*}}, baseType: ![[CT8:[0-9]+]]
+ // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x3:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "i8", size: 8, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS8x3]] = !{![[REALELTS8x3:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS8x3]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 24, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s8: svint8x3_t;
+
+ // CHECK-DAG: name: "svuint8x3_t",{{.*}}, baseType: ![[CT8:[0-9]+]]
+ // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x3]])
+ // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned)
+ let u8: svuint8x3_t;
+
+ // CHECK-DAG: name: "svint16x3_t",{{.*}}, baseType: ![[CT16:[0-9]+]]
+ // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x3:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "i16", size: 16, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS16x3]] = !{![[REALELTS16x3:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS16x3]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 12, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s16: svint16x3_t;
+
+ // CHECK-DAG: name: "svuint16x3_t",{{.*}}, baseType: ![[CT16:[0-9]+]]
+ // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x3]])
+ // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "u16", size: 16, encoding: DW_ATE_unsigned)
+ let u16: svuint16x3_t;
+
+ // CHECK-DAG: name: "svint32x3_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x3:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS32x3]] = !{![[REALELTS32x3:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS32x3]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 6, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s32: svint32x3_t;
+
+ // CHECK-DAG: name: "svuint32x3_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x3]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "u32", size: 32, encoding: DW_ATE_unsigned)
+ let u32: svuint32x3_t;
+
+ // CHECK-DAG: name: "svint64x3_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x3_64:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "i64", size: 64, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS1x3_64]] = !{![[REALELTS1x3_64:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS1x3_64]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 3, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s64: svint64x3_t;
+
+ // CHECK-DAG: name: "svuint64x3_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x3_64]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned)
+ let u64: svuint64x3_t;
+
+ // CHECK: name: "svfloat32x3_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x3]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "f32", size: 32, encoding: DW_ATE_float)
+ let f32: svfloat32x3_t;
+
+ // CHECK: name: "svfloat64x3_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x3_64]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "f64", size: 64, encoding: DW_ATE_float)
+ let f64: svfloat64x3_t;
+}
diff --git a/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x4.rs b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x4.rs
new file mode 100644
index 0000000000000..911af76f42ebb
--- /dev/null
+++ b/tests/codegen-llvm/scalable-vectors/debuginfo-tuples-x4.rs
@@ -0,0 +1,149 @@
+//@ only-aarch64
+//@ compile-flags: -Cdebuginfo=2 -Copt-level=0
+
+#![crate_type = "lib"]
+#![allow(incomplete_features, internal_features)]
+#![feature(rustc_attrs)]
+
+// Test that we generate the correct debuginfo for scalable vector types.
+
+#[rustc_scalable_vector(16)]
+#[allow(non_camel_case_types)]
+struct svint8_t(i8);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint8x4_t(svint8_t, svint8_t, svint8_t, svint8_t);
+
+#[rustc_scalable_vector(16)]
+#[allow(non_camel_case_types)]
+struct svuint8_t(u8);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint8x4_t(svuint8_t, svuint8_t, svuint8_t, svuint8_t);
+
+#[rustc_scalable_vector(8)]
+#[allow(non_camel_case_types)]
+struct svint16_t(i16);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint16x4_t(svint16_t, svint16_t, svint16_t, svint16_t);
+
+#[rustc_scalable_vector(8)]
+#[allow(non_camel_case_types)]
+struct svuint16_t(u16);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint16x4_t(svuint16_t, svuint16_t, svuint16_t, svuint16_t);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svint32_t(i32);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint32x4_t(svint32_t, svint32_t, svint32_t, svint32_t);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svuint32_t(u32);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint32x4_t(svuint32_t, svuint32_t, svuint32_t, svuint32_t);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svint64_t(i64);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svint64x4_t(svint64_t, svint64_t, svint64_t, svint64_t);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svuint64_t(u64);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svuint64x4_t(svuint64_t, svuint64_t, svuint64_t, svuint64_t);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svfloat32_t(f32);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svfloat32x4_t(svfloat32_t, svfloat32_t, svfloat32_t, svfloat32_t);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svfloat64_t(f64);
+
+#[rustc_scalable_vector]
+#[allow(non_camel_case_types)]
+struct svfloat64x4_t(svfloat64_t, svfloat64_t, svfloat64_t, svfloat64_t);
+
+#[target_feature(enable = "sve")]
+pub fn locals() {
+ // CHECK-DAG: name: "svint8x4_t",{{.*}}, baseType: ![[CT8:[0-9]+]]
+ // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x4:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "i8", size: 8, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS8x4]] = !{![[REALELTS8x4:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS8x4]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 32, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s8: svint8x4_t;
+
+ // CHECK-DAG: name: "svuint8x4_t",{{.*}}, baseType: ![[CT8:[0-9]+]]
+ // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8x4]])
+ // CHECK-DAG: ![[ELTTY8]] = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned)
+ let u8: svuint8x4_t;
+
+ // CHECK-DAG: name: "svint16x4_t",{{.*}}, baseType: ![[CT16:[0-9]+]]
+ // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x4:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "i16", size: 16, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS16x4]] = !{![[REALELTS16x4:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS16x4]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 16, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s16: svint16x4_t;
+
+ // CHECK-DAG: name: "svuint16x4_t",{{.*}}, baseType: ![[CT16:[0-9]+]]
+ // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16x4]])
+ // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "u16", size: 16, encoding: DW_ATE_unsigned)
+ let u16: svuint16x4_t;
+
+ // CHECK-DAG: name: "svint32x4_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x4:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS32x4]] = !{![[REALELTS32x4:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS32x4]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 8, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s32: svint32x4_t;
+
+ // CHECK-DAG: name: "svuint32x4_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x4]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "u32", size: 32, encoding: DW_ATE_unsigned)
+ let u32: svuint32x4_t;
+
+ // CHECK-DAG: name: "svint64x4_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x4_64:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "i64", size: 64, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS1x4_64]] = !{![[REALELTS1x4_64:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS1x4_64]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 4, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s64: svint64x4_t;
+
+ // CHECK-DAG: name: "svuint64x4_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x4_64]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned)
+ let u64: svuint64x4_t;
+
+ // CHECK: name: "svfloat32x4_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32x4]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "f32", size: 32, encoding: DW_ATE_float)
+ let f32: svfloat32x4_t;
+
+ // CHECK: name: "svfloat64x4_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS1x4_64]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "f64", size: 64, encoding: DW_ATE_float)
+ let f64: svfloat64x4_t;
+}
diff --git a/tests/codegen-llvm/scalable-vectors/debuginfo.rs b/tests/codegen-llvm/scalable-vectors/debuginfo.rs
new file mode 100644
index 0000000000000..f4b34a5e1e7eb
--- /dev/null
+++ b/tests/codegen-llvm/scalable-vectors/debuginfo.rs
@@ -0,0 +1,123 @@
+// ignore-tidy-linelength
+//@ only-aarch64
+//@ compile-flags: -Cdebuginfo=2 -Copt-level=0
+//@ revisions: POST-LLVM-22 PRE-LLVM-22
+//@ [PRE-LLVM-22] max-llvm-major-version: 21
+//@ [POST-LLVM-22] min-llvm-version: 22
+
+#![crate_type = "lib"]
+#![allow(incomplete_features, internal_features)]
+#![feature(rustc_attrs)]
+
+// Test that we generate the correct debuginfo for scalable vector types.
+
+#[rustc_scalable_vector(16)]
+#[allow(non_camel_case_types)]
+struct svbool_t(bool);
+
+#[rustc_scalable_vector(16)]
+#[allow(non_camel_case_types)]
+struct svint8_t(i8);
+
+#[rustc_scalable_vector(16)]
+#[allow(non_camel_case_types)]
+struct svuint8_t(u8);
+
+#[rustc_scalable_vector(8)]
+#[allow(non_camel_case_types)]
+struct svint16_t(i16);
+
+#[rustc_scalable_vector(8)]
+#[allow(non_camel_case_types)]
+struct svuint16_t(u16);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svint32_t(i32);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svuint32_t(u32);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svint64_t(i64);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svuint64_t(u64);
+
+#[rustc_scalable_vector(4)]
+#[allow(non_camel_case_types)]
+struct svfloat32_t(f32);
+
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+struct svfloat64_t(f64);
+
+#[target_feature(enable = "sve")]
+pub fn locals() {
+ // CHECK-DAG: name: "svbool_t",{{.*}}, baseType: ![[CT1:[0-9]+]]
+ // PRE-LLVM-22-DAG: ![[CT1]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTYU8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8:[0-9]+]])
+ // POST-LLVM-22-DAG: ![[CT1]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTYU8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8:[0-9]+]], bitStride: i64 1)
+ // CHECK-DAG: ![[ELTTYU8]] = !DIBasicType(name: "u8", size: 8, encoding: DW_ATE_unsigned)
+ // CHECK-DAG: ![[ELTS8]] = !{![[REALELTS8:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS8]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 8, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let b8: svbool_t;
+
+ // CHECK-DAG: name: "svint8_t",{{.*}}, baseType: ![[CT8:[0-9]+]]
+ // CHECK-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTYS8:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8:[0-9]+]])
+ // CHECK-DAG: ![[ELTTYS8]] = !DIBasicType(name: "i8", size: 8, encoding: DW_ATE_signed)
+ let s8: svint8_t;
+
+ // PRE-LLVM-22-DAG: name: "svuint8_t",{{.*}}, baseType: ![[CT1:[0-9]+]]
+ // POST-LLVM-22-DAG: name: "svuint8_t",{{.*}}, baseType: ![[CT8:[0-9]+]]
+ // POST-LLVM-22-DAG: ![[CT8]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTYU8]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS8]])
+ let u8: svuint8_t;
+
+ // CHECK-DAG: name: "svint16_t",{{.*}}, baseType: ![[CT16:[0-9]+]]
+ // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "i16", size: 16, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS16]] = !{![[REALELTS16:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS16]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 4, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s16: svint16_t;
+
+ // CHECK-DAG: name: "svuint16_t",{{.*}}, baseType: ![[CT16:[0-9]+]]
+ // CHECK-DAG: ![[CT16]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY16:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS16]])
+ // CHECK-DAG: ![[ELTTY16]] = !DIBasicType(name: "u16", size: 16, encoding: DW_ATE_unsigned)
+ let u16: svuint16_t;
+
+ // CHECK-DAG: name: "svint32_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS32]] = !{![[REALELTS32:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS32]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 2, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s32: svint32_t;
+
+ // CHECK-DAG: name: "svuint32_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "u32", size: 32, encoding: DW_ATE_unsigned)
+ let u32: svuint32_t;
+
+ // CHECK-DAG: name: "svint64_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS64:[0-9]+]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "i64", size: 64, encoding: DW_ATE_signed)
+ // CHECK-DAG: ![[ELTS64]] = !{![[REALELTS64:[0-9]+]]}
+ // CHECK-DAG: ![[REALELTS64]] = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 1, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
+ let s64: svint64_t;
+
+ // CHECK-DAG: name: "svuint64_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS64]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "u64", size: 64, encoding: DW_ATE_unsigned)
+ let u64: svuint64_t;
+
+ // CHECK: name: "svfloat32_t",{{.*}}, baseType: ![[CT32:[0-9]+]]
+ // CHECK-DAG: ![[CT32]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY32:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS32]])
+ // CHECK-DAG: ![[ELTTY32]] = !DIBasicType(name: "f32", size: 32, encoding: DW_ATE_float)
+ let f32: svfloat32_t;
+
+ // CHECK: name: "svfloat64_t",{{.*}}, baseType: ![[CT64:[0-9]+]]
+ // CHECK-DAG: ![[CT64]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELTTY64:[0-9]+]],{{.*}}, flags: DIFlagVector, elements: ![[ELTS64]])
+ // CHECK-DAG: ![[ELTTY64]] = !DIBasicType(name: "f64", size: 64, encoding: DW_ATE_float)
+ let f64: svfloat64_t;
+}
From 72f2ace16006d04a7c32d9d92ce9d051f1daf39e Mon Sep 17 00:00:00 2001
From: David Wood
Date: Sat, 28 Feb 2026 16:48:59 +0000
Subject: [PATCH 07/38] cg_llvm: `sve_cast` intrinsic
Abstract over the existing `simd_cast` intrinsic to implement a new
`sve_cast` intrinsic - this is better than allowing scalable vectors to
be used with all of the generic `simd_*` intrinsics.
---
.../src/debuginfo/metadata.rs | 2 +-
compiler/rustc_codegen_llvm/src/intrinsic.rs | 203 ++++++++++--------
.../rustc_hir_analysis/src/check/intrinsic.rs | 1 +
compiler/rustc_span/src/symbol.rs | 1 +
library/core/src/intrinsics/simd/scalable.rs | 23 ++
tests/ui/scalable-vectors/cast-intrinsic.rs | 65 ++++++
6 files changed, 205 insertions(+), 90 deletions(-)
create mode 100644 tests/ui/scalable-vectors/cast-intrinsic.rs
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 25307823b37c7..c91d3ec63a028 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -3,7 +3,7 @@ use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::path::PathBuf;
use std::sync::Arc;
-use std::{iter, ptr};
+use std::{assert_matches, iter, ptr};
use libc::{c_longlong, c_uint};
use rustc_abi::{Align, Layout, NumScalableVectors, Size};
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index ad2c23c99820b..3e600914d6f42 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -606,6 +606,27 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
self.pointercast(val, self.type_ptr())
}
+ sym::sve_cast => {
+ let Some((in_cnt, in_elem, in_num_vecs)) =
+ args[0].layout.ty.scalable_vector_parts(self.cx.tcx)
+ else {
+ bug!("input parameter to `sve_cast` was not scalable vector");
+ };
+ let out_layout = self.layout_of(fn_args.type_at(1));
+ let Some((out_cnt, out_elem, out_num_vecs)) =
+ out_layout.ty.scalable_vector_parts(self.cx.tcx)
+ else {
+ bug!("output parameter to `sve_cast` was not scalable vector");
+ };
+ assert_eq!(in_cnt, out_cnt);
+ assert_eq!(in_num_vecs, out_num_vecs);
+ let out_llty = self.backend_type(out_layout);
+ match simd_cast(self, sym::simd_cast, args, out_llty, in_elem, out_elem) {
+ Some(val) => val,
+ _ => bug!("could not cast scalable vectors"),
+ }
+ }
+
sym::sve_tuple_create2 => {
assert_matches!(
self.layout_of(fn_args.type_at(0)).backend_repr,
@@ -2772,96 +2793,17 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
out_len
}
);
- // casting cares about nominal type, not just structural type
- if in_elem == out_elem {
- return Ok(args[0].immediate());
- }
-
- #[derive(Copy, Clone)]
- enum Sign {
- Unsigned,
- Signed,
- }
- use Sign::*;
-
- enum Style {
- Float,
- Int(Sign),
- Unsupported,
- }
-
- let (in_style, in_width) = match in_elem.kind() {
- // vectors of pointer-sized integers should've been
- // disallowed before here, so this unwrap is safe.
- ty::Int(i) => (
- Style::Int(Signed),
- i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
- ),
- ty::Uint(u) => (
- Style::Int(Unsigned),
- u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
- ),
- ty::Float(f) => (Style::Float, f.bit_width()),
- _ => (Style::Unsupported, 0),
- };
- let (out_style, out_width) = match out_elem.kind() {
- ty::Int(i) => (
- Style::Int(Signed),
- i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
- ),
- ty::Uint(u) => (
- Style::Int(Unsigned),
- u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
- ),
- ty::Float(f) => (Style::Float, f.bit_width()),
- _ => (Style::Unsupported, 0),
- };
-
- match (in_style, out_style) {
- (Style::Int(sign), Style::Int(_)) => {
- return Ok(match in_width.cmp(&out_width) {
- Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty),
- Ordering::Equal => args[0].immediate(),
- Ordering::Less => match sign {
- Sign::Signed => bx.sext(args[0].immediate(), llret_ty),
- Sign::Unsigned => bx.zext(args[0].immediate(), llret_ty),
- },
- });
- }
- (Style::Int(Sign::Signed), Style::Float) => {
- return Ok(bx.sitofp(args[0].immediate(), llret_ty));
- }
- (Style::Int(Sign::Unsigned), Style::Float) => {
- return Ok(bx.uitofp(args[0].immediate(), llret_ty));
- }
- (Style::Float, Style::Int(sign)) => {
- return Ok(match (sign, name == sym::simd_as) {
- (Sign::Unsigned, false) => bx.fptoui(args[0].immediate(), llret_ty),
- (Sign::Signed, false) => bx.fptosi(args[0].immediate(), llret_ty),
- (_, true) => bx.cast_float_to_int(
- matches!(sign, Sign::Signed),
- args[0].immediate(),
- llret_ty,
- ),
- });
- }
- (Style::Float, Style::Float) => {
- return Ok(match in_width.cmp(&out_width) {
- Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty),
- Ordering::Equal => args[0].immediate(),
- Ordering::Less => bx.fpext(args[0].immediate(), llret_ty),
- });
- }
- _ => { /* Unsupported. Fallthrough. */ }
+ match simd_cast(bx, name, args, llret_ty, in_elem, out_elem) {
+ Some(val) => return Ok(val),
+ None => return_error!(InvalidMonomorphization::UnsupportedCast {
+ span,
+ name,
+ in_ty,
+ in_elem,
+ ret_ty,
+ out_elem
+ }),
}
- return_error!(InvalidMonomorphization::UnsupportedCast {
- span,
- name,
- in_ty,
- in_elem,
- ret_ty,
- out_elem
- });
}
macro_rules! arith_binary {
($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
@@ -3035,3 +2977,86 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
span_bug!(span, "unknown SIMD intrinsic");
}
+
+/// Implementation of `core::intrinsics::simd_cast`, re-used by `core::scalable::sve_cast`.
+fn simd_cast<'ll, 'tcx>(
+ bx: &mut Builder<'_, 'll, 'tcx>,
+ name: Symbol,
+ args: &[OperandRef<'tcx, &'ll Value>],
+ llret_ty: &'ll Type,
+ in_elem: Ty<'tcx>,
+ out_elem: Ty<'tcx>,
+) -> Option<&'ll Value> {
+ // Casting cares about nominal type, not just structural type
+ if in_elem == out_elem {
+ return Some(args[0].immediate());
+ }
+
+ #[derive(Copy, Clone)]
+ enum Sign {
+ Unsigned,
+ Signed,
+ }
+ use Sign::*;
+
+ enum Style {
+ Float,
+ Int(Sign),
+ Unsupported,
+ }
+
+ let (in_style, in_width) = match in_elem.kind() {
+ // vectors of pointer-sized integers should've been
+ // disallowed before here, so this unwrap is safe.
+ ty::Int(i) => (
+ Style::Int(Signed),
+ i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+ ),
+ ty::Uint(u) => (
+ Style::Int(Unsigned),
+ u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+ ),
+ ty::Float(f) => (Style::Float, f.bit_width()),
+ _ => (Style::Unsupported, 0),
+ };
+ let (out_style, out_width) = match out_elem.kind() {
+ ty::Int(i) => (
+ Style::Int(Signed),
+ i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+ ),
+ ty::Uint(u) => (
+ Style::Int(Unsigned),
+ u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+ ),
+ ty::Float(f) => (Style::Float, f.bit_width()),
+ _ => (Style::Unsupported, 0),
+ };
+
+ match (in_style, out_style) {
+ (Style::Int(sign), Style::Int(_)) => Some(match in_width.cmp(&out_width) {
+ Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty),
+ Ordering::Equal => args[0].immediate(),
+ Ordering::Less => match sign {
+ Sign::Signed => bx.sext(args[0].immediate(), llret_ty),
+ Sign::Unsigned => bx.zext(args[0].immediate(), llret_ty),
+ },
+ }),
+ (Style::Int(Sign::Signed), Style::Float) => Some(bx.sitofp(args[0].immediate(), llret_ty)),
+ (Style::Int(Sign::Unsigned), Style::Float) => {
+ Some(bx.uitofp(args[0].immediate(), llret_ty))
+ }
+ (Style::Float, Style::Int(sign)) => Some(match (sign, name == sym::simd_as) {
+ (Sign::Unsigned, false) => bx.fptoui(args[0].immediate(), llret_ty),
+ (Sign::Signed, false) => bx.fptosi(args[0].immediate(), llret_ty),
+ (_, true) => {
+ bx.cast_float_to_int(matches!(sign, Sign::Signed), args[0].immediate(), llret_ty)
+ }
+ }),
+ (Style::Float, Style::Float) => Some(match in_width.cmp(&out_width) {
+ Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty),
+ Ordering::Equal => args[0].immediate(),
+ Ordering::Less => bx.fpext(args[0].immediate(), llret_ty),
+ }),
+ _ => None,
+ }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index ca57921089fae..58454cfc489c6 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -783,6 +783,7 @@ pub(crate) fn check_intrinsic_type(
sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)),
sym::simd_shuffle_const_generic => (2, 1, vec![param(0), param(0)], param(1)),
+ sym::sve_cast => (2, 0, vec![param(0)], param(1)),
sym::sve_tuple_create2 => (2, 0, vec![param(0), param(0)], param(1)),
sym::sve_tuple_create3 => (2, 0, vec![param(0), param(0), param(0)], param(1)),
sym::sve_tuple_create4 => (2, 0, vec![param(0), param(0), param(0), param(0)], param(1)),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index e44e9f4ea1ce7..d5c815653b72a 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1977,6 +1977,7 @@ symbols! {
suggestion,
super_let,
supertrait_item_shadowing,
+ sve_cast,
sve_tuple_create2,
sve_tuple_create3,
sve_tuple_create4,
diff --git a/library/core/src/intrinsics/simd/scalable.rs b/library/core/src/intrinsics/simd/scalable.rs
index a569d1ffbc548..1a8e90012bce8 100644
--- a/library/core/src/intrinsics/simd/scalable.rs
+++ b/library/core/src/intrinsics/simd/scalable.rs
@@ -2,6 +2,29 @@
//!
//! In this module, a "vector" is any `#[rustc_scalable_vector]`-annotated type.
+/// Numerically casts a vector, elementwise.
+///
+/// `T` and `U` must be vectors of integers or floats, and must have the same length.
+///
+/// When casting floats to integers, the result is truncated. Out-of-bounds result lead to UB.
+/// When casting integers to floats, the result is rounded.
+/// Otherwise, truncates or extends the value, maintaining the sign for signed integers.
+///
+/// # Safety
+/// Casting from integer types is always safe.
+/// Casting between two float types is also always safe.
+///
+/// Casting floats to integers truncates, following the same rules as `to_int_unchecked`.
+/// Specifically, each element must:
+/// * Not be `NaN`
+/// * Not be infinite
+/// * Be representable in the return type, after truncating off its fractional part
+#[cfg(target_arch = "aarch64")]
+#[rustc_intrinsic]
+#[rustc_nounwind]
+#[target_feature(enable = "sve")]
+pub unsafe fn sve_cast(x: T) -> U;
+
/// Create a tuple of two vectors.
///
/// `SVecTup` must be a scalable vector tuple (`#[rustc_scalable_vector]`) and `SVec` must be a
diff --git a/tests/ui/scalable-vectors/cast-intrinsic.rs b/tests/ui/scalable-vectors/cast-intrinsic.rs
new file mode 100644
index 0000000000000..f2157d8bcc14b
--- /dev/null
+++ b/tests/ui/scalable-vectors/cast-intrinsic.rs
@@ -0,0 +1,65 @@
+//@ check-pass
+//@ only-aarch64
+#![crate_type = "lib"]
+#![allow(incomplete_features, internal_features, improper_ctypes)]
+#![feature(abi_unadjusted, core_intrinsics, link_llvm_intrinsics, rustc_attrs)]
+
+use std::intrinsics::simd::scalable::sve_cast;
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector(16)]
+#[allow(non_camel_case_types)]
+pub struct svbool_t(bool);
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+pub struct svbool2_t(bool);
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+pub struct svint64_t(i64);
+
+#[derive(Copy, Clone)]
+#[rustc_scalable_vector(2)]
+#[allow(non_camel_case_types)]
+pub struct nxv2i16(i16);
+
+pub trait SveInto: Sized {
+ unsafe fn sve_into(self) -> T;
+}
+
+impl SveInto for svbool_t {
+ #[target_feature(enable = "sve")]
+ unsafe fn sve_into(self) -> svbool2_t {
+ unsafe extern "C" {
+ #[cfg_attr(
+ target_arch = "aarch64",
+ link_name = concat!("llvm.aarch64.sve.convert.from.svbool.nxv2i1")
+ )]
+ fn convert_from_svbool(b: svbool_t) -> svbool2_t;
+ }
+ unsafe { convert_from_svbool(self) }
+ }
+}
+
+#[target_feature(enable = "sve")]
+pub unsafe fn svld1sh_gather_s64offset_s64(
+ pg: svbool_t,
+ base: *const i16,
+ offsets: svint64_t,
+) -> svint64_t {
+ unsafe extern "unadjusted" {
+ #[cfg_attr(
+ target_arch = "aarch64",
+ link_name = "llvm.aarch64.sve.ld1.gather.nxv2i16"
+ )]
+ fn _svld1sh_gather_s64offset_s64(
+ pg: svbool2_t,
+ base: *const i16,
+ offsets: svint64_t,
+ ) -> nxv2i16;
+ }
+ sve_cast(_svld1sh_gather_s64offset_s64(pg.sve_into(), base, offsets))
+}
From 9bdf217810e77b7d58e43030dd61a65172ab1354 Mon Sep 17 00:00:00 2001
From: binarycat
Date: Tue, 31 Mar 2026 12:51:12 -0500
Subject: [PATCH 08/38] rustdoc: seperate methods and associated functions in
sidebar
---
src/librustdoc/clean/types.rs | 9 ++
src/librustdoc/html/render/sidebar.rs | 132 ++++++++++++--------
tests/rustdoc-gui/hash-item-expansion.goml | 4 +-
tests/rustdoc-gui/sidebar-mobile.goml | 2 +-
tests/rustdoc-html/sidebar/sidebar-items.rs | 8 ++
tests/rustdoc-html/typedef.rs | 2 +-
6 files changed, 103 insertions(+), 54 deletions(-)
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index ad70fc1096691..7d40bc95ec089 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -465,6 +465,15 @@ impl Item {
.unwrap_or(false)
}
+ /// Returns true if item is an associated function with a `self` parameter.
+ pub(crate) fn has_self_param(&self) -> bool {
+ if let ItemKind::MethodItem(box Function { decl, .. }, _) = &self.inner.kind {
+ decl.receiver_type().is_some()
+ } else {
+ false
+ }
+ }
+
pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option {
let kind = match &self.kind {
ItemKind::StrippedItem(k) => k,
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index a4535792ac3ce..d40c9501cabc1 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -433,6 +433,7 @@ fn sidebar_assoc_items<'a>(
let mut assoc_consts = Vec::new();
let mut assoc_types = Vec::new();
+ let mut assoc_fns = Vec::new();
let mut methods = Vec::new();
if let Some(v) = cache.impls.get(&did) {
let mut used_links = FxHashSet::default();
@@ -443,7 +444,12 @@ fn sidebar_assoc_items<'a>(
for impl_ in v.iter().map(|i| i.inner_impl()).filter(|i| i.trait_.is_none()) {
assoc_consts.extend(get_associated_constants(impl_, used_links_bor));
assoc_types.extend(get_associated_types(impl_, used_links_bor));
- methods.extend(get_methods(impl_, false, used_links_bor, false, cx.tcx()));
+ methods.extend(get_methods(
+ impl_,
+ GetMethodsMode::AlsoCollectAssocFns { assoc_fns: &mut assoc_fns },
+ used_links_bor,
+ cx.tcx(),
+ ));
}
// We want links' order to be reproducible so we don't use unstable sort.
assoc_consts.sort();
@@ -462,6 +468,11 @@ fn sidebar_assoc_items<'a>(
"associatedtype",
assoc_types,
),
+ LinkBlock::new(
+ Link::new("implementations", "Associated Functions"),
+ "method",
+ assoc_fns,
+ ),
LinkBlock::new(Link::new("implementations", "Methods"), "method", methods),
];
@@ -546,7 +557,15 @@ fn sidebar_deref_methods<'a>(
i.inner_impl().trait_.is_none()
&& real_target.is_doc_subtype_of(&i.inner_impl().for_, c)
})
- .flat_map(|i| get_methods(i.inner_impl(), true, used_links, deref_mut, cx.tcx()))
+ .flat_map(|i| {
+ get_methods(
+ i.inner_impl(),
+ GetMethodsMode::Deref { deref_mut },
+ used_links,
+ cx.tcx(),
+ )
+ .collect::>()
+ })
.collect::>();
if !ret.is_empty() {
let id = if let Some(target_def_id) = real_target.def_id(c) {
@@ -734,69 +753,82 @@ fn get_next_url(used_links: &mut FxHashSet, url: String) -> String {
format!("{url}-{add}")
}
+enum GetMethodsMode<'r, 'l> {
+ Deref { deref_mut: bool },
+ AlsoCollectAssocFns { assoc_fns: &'r mut Vec> },
+}
+
fn get_methods<'a>(
i: &'a clean::Impl,
- for_deref: bool,
+ mut mode: GetMethodsMode<'_, 'a>,
used_links: &mut FxHashSet,
- deref_mut: bool,
tcx: TyCtxt<'_>,
-) -> Vec> {
- i.items
- .iter()
- .filter_map(|item| {
- if let Some(ref name) = item.name
- && item.is_method()
- && (!for_deref || super::should_render_item(item, deref_mut, tcx))
- {
- Some(Link::new(
+) -> impl Iterator- > {
+ i.items.iter().filter_map(move |item| {
+ if let Some(ref name) = item.name
+ && item.is_method()
+ {
+ let mut build_link = || {
+ Link::new(
get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::Method)),
name.as_str(),
- ))
- } else {
- None
+ )
+ };
+ match &mut mode {
+ &mut GetMethodsMode::Deref { deref_mut } => {
+ if super::should_render_item(item, deref_mut, tcx) {
+ Some(build_link())
+ } else {
+ None
+ }
+ }
+ GetMethodsMode::AlsoCollectAssocFns { assoc_fns } => {
+ if item.has_self_param() {
+ Some(build_link())
+ } else {
+ assoc_fns.push(build_link());
+ None
+ }
+ }
}
- })
- .collect()
+ } else {
+ None
+ }
+ })
}
fn get_associated_constants<'a>(
i: &'a clean::Impl,
used_links: &mut FxHashSet,
-) -> Vec> {
- i.items
- .iter()
- .filter_map(|item| {
- if let Some(ref name) = item.name
- && item.is_associated_const()
- {
- Some(Link::new(
- get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocConst)),
- name.as_str(),
- ))
- } else {
- None
- }
- })
- .collect()
+) -> impl Iterator
- > {
+ i.items.iter().filter_map(|item| {
+ if let Some(ref name) = item.name
+ && item.is_associated_const()
+ {
+ Some(Link::new(
+ get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocConst)),
+ name.as_str(),
+ ))
+ } else {
+ None
+ }
+ })
}
fn get_associated_types<'a>(
i: &'a clean::Impl,
used_links: &mut FxHashSet,
-) -> Vec> {
- i.items
- .iter()
- .filter_map(|item| {
- if let Some(ref name) = item.name
- && item.is_associated_type()
- {
- Some(Link::new(
- get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocType)),
- name.as_str(),
- ))
- } else {
- None
- }
- })
- .collect()
+) -> impl Iterator
- > {
+ i.items.iter().filter_map(|item| {
+ if let Some(ref name) = item.name
+ && item.is_associated_type()
+ {
+ Some(Link::new(
+ get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocType)),
+ name.as_str(),
+ ))
+ } else {
+ None
+ }
+ })
}
diff --git a/tests/rustdoc-gui/hash-item-expansion.goml b/tests/rustdoc-gui/hash-item-expansion.goml
index a7a5c3cb48345..8661641206685 100644
--- a/tests/rustdoc-gui/hash-item-expansion.goml
+++ b/tests/rustdoc-gui/hash-item-expansion.goml
@@ -5,7 +5,7 @@ assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"ope
// We first check that the impl block is open by default.
assert-attribute: ("#implementations-list details", {"open": ""})
// To ensure that we will click on the currently hidden method.
-assert-text: (".sidebar-elems section .block li > a", "must_use")
-click: ".sidebar-elems section .block li > a"
+assert-text: (".sidebar-elems section ul:nth-of-type(2) li > a", "must_use")
+click: ".sidebar-elems ul:nth-of-type(2) li > a"
// We check that the impl block was opened as expected so that we can see the method.
assert-attribute: ("#implementations-list > details", {"open": ""})
diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml
index 3183650b555a8..61c1555fbc0e3 100644
--- a/tests/rustdoc-gui/sidebar-mobile.goml
+++ b/tests/rustdoc-gui/sidebar-mobile.goml
@@ -48,7 +48,7 @@ assert-property: ("rustdoc-topbar", {"clientHeight": "45"})
// Check that clicking an element from the sidebar scrolls to the right place
// so the target is not obscured by the topbar.
click: ".sidebar-menu-toggle"
-click: ".sidebar-elems section .block li > a"
+click: ".sidebar-elems section ul:nth-of-type(2) li > a"
assert-position: ("#method\.must_use", {"y": 45})
// Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
diff --git a/tests/rustdoc-html/sidebar/sidebar-items.rs b/tests/rustdoc-html/sidebar/sidebar-items.rs
index 6e13457796e5e..bd0893dac3e36 100644
--- a/tests/rustdoc-html/sidebar/sidebar-items.rs
+++ b/tests/rustdoc-html/sidebar/sidebar-items.rs
@@ -42,6 +42,14 @@ pub struct Bar {
waza: u32,
}
+//@ has foo/struct.Bar.html
+//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#implementations"]' 'Associated Functions'
+//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#implementations"]' 'Methods'
+impl Bar {
+ pub fn method(&self) {}
+ pub fn assoc_fn() {}
+}
+
//@ has foo/enum.En.html
//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#variants"]' 'Variants'
//@ has - '//*[@class="sidebar-elems"]//section//a' 'Foo'
diff --git a/tests/rustdoc-html/typedef.rs b/tests/rustdoc-html/typedef.rs
index 3fdc2788bcacf..4eae3c7258213 100644
--- a/tests/rustdoc-html/typedef.rs
+++ b/tests/rustdoc-html/typedef.rs
@@ -13,7 +13,7 @@ impl MyStruct {
//@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias'
//@ hasraw - 'Alias docstring'
//@ has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias'
-//@ has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
+//@ has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Associated Functions'
//@ has - '//*[@class="sidebar"]//a[@href="#trait-implementations"]' 'Trait Implementations'
/// Alias docstring
pub type MyAlias = MyStruct;
From 8277043ea3a47a0279ed166b3d8d95a32a2baece Mon Sep 17 00:00:00 2001
From: mu001999
Date: Wed, 1 Apr 2026 10:48:35 +0800
Subject: [PATCH 09/38] Avoid creating async return opaques for foreign async
fns
---
compiler/rustc_resolve/src/def_collector.rs | 7 +++++--
.../bad-external-async-fn-issue-146754.rs | 8 +++++++
.../bad-external-async-fn-issue-146754.stderr | 21 +++++++++++++++++++
3 files changed, 34 insertions(+), 2 deletions(-)
create mode 100644 tests/ui/extern/bad-external-async-fn-issue-146754.rs
create mode 100644 tests/ui/extern/bad-external-async-fn-issue-146754.stderr
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index de36f01b6d0e5..0acc42a6efbe1 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -209,12 +209,15 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
fn visit_fn(&mut self, fn_kind: FnKind<'a>, _: &AttrVec, span: Span, _: NodeId) {
match fn_kind {
FnKind::Fn(
- _ctxt,
+ ctxt,
_vis,
Fn {
sig: FnSig { header, decl, span: _ }, ident, generics, contract, body, ..
},
- ) if let Some(coroutine_kind) = header.coroutine_kind => {
+ ) if let Some(coroutine_kind) = header.coroutine_kind
+ // Foreign ones are denied, so don't create them here.
+ && ctxt != visit::FnCtxt::Foreign =>
+ {
self.visit_ident(ident);
self.visit_fn_header(header);
self.visit_generics(generics);
diff --git a/tests/ui/extern/bad-external-async-fn-issue-146754.rs b/tests/ui/extern/bad-external-async-fn-issue-146754.rs
new file mode 100644
index 0000000000000..394341c129654
--- /dev/null
+++ b/tests/ui/extern/bad-external-async-fn-issue-146754.rs
@@ -0,0 +1,8 @@
+//@ edition:2024
+#![crate_type = "lib"]
+
+unsafe extern "C" {
+ async fn function() -> [(); || {}];
+ //~^ ERROR functions in `extern` blocks cannot have `async` qualifier
+ //~^^ ERROR mismatched types
+}
diff --git a/tests/ui/extern/bad-external-async-fn-issue-146754.stderr b/tests/ui/extern/bad-external-async-fn-issue-146754.stderr
new file mode 100644
index 0000000000000..2a04b23630430
--- /dev/null
+++ b/tests/ui/extern/bad-external-async-fn-issue-146754.stderr
@@ -0,0 +1,21 @@
+error: functions in `extern` blocks cannot have `async` qualifier
+ --> $DIR/bad-external-async-fn-issue-146754.rs:5:5
+ |
+LL | unsafe extern "C" {
+ | ----------------- in this `extern` block
+LL | async fn function() -> [(); || {}];
+ | ^^^^^ help: remove the `async` qualifier
+
+error[E0308]: mismatched types
+ --> $DIR/bad-external-async-fn-issue-146754.rs:5:33
+ |
+LL | async fn function() -> [(); || {}];
+ | ^^^^^ expected `usize`, found closure
+ |
+ = note: expected type `usize`
+ found closure `{closure@$DIR/bad-external-async-fn-issue-146754.rs:5:33: 5:35}`
+ = note: array length can only be `usize`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
From 910677fcc625fcff770158b4184ff64e4b57320c Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote
Date: Wed, 1 Apr 2026 16:38:30 +1100
Subject: [PATCH 10/38] Rename `HirCtx` as `Hcx`.
PR #154634 recently renamed many type parameters that impl
`HashStableContext` as `Hcx`. It missed a few that are named `HirCtx`.
This commit renames them.
---
compiler/rustc_hir/src/stable_hash_impls.rs | 36 ++++++++++-----------
compiler/rustc_middle/src/hir/mod.rs | 4 +--
2 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 58649a694880b..d2d6529619662 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -13,48 +13,48 @@ use crate::lints::DelayedLints;
/// instead of implementing everything in `rustc_middle`.
pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {}
-impl ToStableHashKey for BodyId {
+impl ToStableHashKey for BodyId {
type KeyType = (DefPathHash, ItemLocalId);
#[inline]
- fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
+ fn to_stable_hash_key(&self, hcx: &Hcx) -> (DefPathHash, ItemLocalId) {
let BodyId { hir_id } = *self;
hir_id.to_stable_hash_key(hcx)
}
}
-impl ToStableHashKey for ItemId {
+impl ToStableHashKey for ItemId {
type KeyType = DefPathHash;
#[inline]
- fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
+ fn to_stable_hash_key(&self, hcx: &Hcx) -> DefPathHash {
self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
-impl ToStableHashKey for TraitItemId {
+impl ToStableHashKey for TraitItemId {
type KeyType = DefPathHash;
#[inline]
- fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
+ fn to_stable_hash_key(&self, hcx: &Hcx) -> DefPathHash {
self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
-impl ToStableHashKey for ImplItemId {
+impl ToStableHashKey for ImplItemId {
type KeyType = DefPathHash;
#[inline]
- fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
+ fn to_stable_hash_key(&self, hcx: &Hcx) -> DefPathHash {
self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
-impl ToStableHashKey for ForeignItemId {
+impl ToStableHashKey for ForeignItemId {
type KeyType = DefPathHash;
#[inline]
- fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
+ fn to_stable_hash_key(&self, hcx: &Hcx) -> DefPathHash {
self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
@@ -66,8 +66,8 @@ impl ToStableHashKey for ForeignItemId
// want to pick up on a reference changing its target, so we hash the NodeIds
// in "DefPath Mode".
-impl<'tcx, HirCtx: crate::HashStableContext> HashStable for OwnerNodes<'tcx> {
- fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+impl<'tcx, Hcx: crate::HashStableContext> HashStable for OwnerNodes<'tcx> {
+ fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
// We ignore the `nodes` and `bodies` fields since these refer to information included in
// `hash` which is hashed in the collector and used for the crate hash.
// `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing
@@ -78,15 +78,15 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable for OwnerNodes<'
}
}
-impl HashStable for DelayedLints {
- fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+impl HashStable for DelayedLints {
+ fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
let DelayedLints { opt_hash, .. } = *self;
opt_hash.unwrap().hash_stable(hcx, hasher);
}
}
-impl<'tcx, HirCtx: crate::HashStableContext> HashStable for AttributeMap<'tcx> {
- fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+impl<'tcx, Hcx: crate::HashStableContext> HashStable for AttributeMap<'tcx> {
+ fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
// We ignore the `map` since it refers to information included in `opt_hash` which is
// hashed in the collector and used for the crate hash.
let AttributeMap { opt_hash, define_opaque: _, map: _ } = *self;
@@ -94,8 +94,8 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable for AttributeMap
}
}
-impl HashStable for HashIgnoredAttrId {
- fn hash_stable(&self, _hcx: &mut HirCtx, _hasher: &mut StableHasher) {
+impl HashStable for HashIgnoredAttrId {
+ fn hash_stable(&self, _hcx: &mut Hcx, _hasher: &mut StableHasher) {
/* we don't hash HashIgnoredAttrId, we ignore them */
}
}
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index ad56e462d2934..dfce7e0917608 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -77,8 +77,8 @@ impl<'hir> Crate<'hir> {
}
}
-impl HashStable for Crate<'_> {
- fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+impl HashStable for Crate<'_> {
+ fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
let Crate { opt_hir_hash, .. } = self;
opt_hir_hash.unwrap().hash_stable(hcx, hasher)
}
From d9a8a553cd601d6c25f7557021a01ea0370738bb Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote
Date: Wed, 1 Apr 2026 16:51:01 +1100
Subject: [PATCH 11/38] Reorder `use`/`mod` items in `rustc_session`.
They're in multiple sections with no rhyme or reason.
---
compiler/rustc_session/src/lib.rs | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 1741dde90f5cf..29192f267ed3a 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -11,28 +11,24 @@
#![recursion_limit = "256"]
// tidy-alphabetical-end
-pub mod errors;
-
-pub mod utils;
+pub use getopts;
pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass};
pub use rustc_lint_defs as lint;
-pub mod parse;
+pub use session::*;
pub mod code_stats;
+pub mod errors;
+pub mod parse;
+pub mod utils;
#[macro_use]
pub mod config;
pub mod cstore;
pub mod filesearch;
mod macros;
mod options;
+pub mod output;
pub mod search_paths;
-
mod session;
-pub use session::*;
-
-pub mod output;
-
-pub use getopts;
/// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro
From 1a9a284ad253fb0fd1d52e880789dc6848599d93 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote
Date: Wed, 1 Apr 2026 16:41:28 +1100
Subject: [PATCH 12/38] Simplify `HashStableContext`.
`derive(HashStable_Generic)` generates impls like this:
```
impl<__CTX> HashStable<__CTX> for ExpnKind
where
__CTX: crate::HashStableContext
{
fn hash_stable(&self, hcx : &mut __CTX, __hasher: &mut StableHasher) {
...
}
}
```
This is used for crates that are upstream of `rustc_middle`.
The `crate::HashStableContext` bound means every crate that uses
`derive(HashStable_Generic)` must provide (or import) a trait
`HashStableContext` which `rustc_middle` then impls. In `rustc_span`
this trait is sensible, with three methods. In other crates, this trait
is empty, and there is the following trait hierarchy:
```
rustc_session::HashStableContext
| |
| rustc_hir::HashStableContext
| / \
rustc_ast::HashStableContext rustc_abi::HashStableContext
|
rustc_span::HashStableContext
```
All very strange and unnecessary. This commit changes
`derive(HashStable_Generic)` to use `rustc_span::HashStableContext`
instead of `crate::HashStableContext`. This eliminates the need for all
the empty `HashStableContext` traits and impls. Much better.
---
compiler/rustc_abi/src/lib.rs | 6 ------
compiler/rustc_ast/src/ast.rs | 5 +++--
compiler/rustc_ast/src/lib.rs | 5 -----
compiler/rustc_ast/src/tokenstream.rs | 4 ++--
compiler/rustc_hir/src/def.rs | 4 ++--
compiler/rustc_hir/src/lib.rs | 1 -
compiler/rustc_hir/src/stable_hash_impls.rs | 24 +++++++++------------
compiler/rustc_hir_id/src/lib.rs | 4 ++--
compiler/rustc_lint_defs/src/lib.rs | 4 ++--
compiler/rustc_macros/src/hash_stable.rs | 2 +-
compiler/rustc_middle/src/hir/mod.rs | 2 +-
compiler/rustc_middle/src/ich/hcx.rs | 9 ++------
compiler/rustc_session/src/config.rs | 5 +++--
compiler/rustc_session/src/lib.rs | 5 -----
compiler/rustc_span/src/lib.rs | 8 +++----
compiler/rustc_target/src/lib.rs | 2 --
16 files changed, 32 insertions(+), 58 deletions(-)
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 253dff6f8e75c..42e272fdafb5d 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -67,12 +67,6 @@ pub use layout::{FIRST_VARIANT, FieldIdx, LayoutCalculator, LayoutCalculatorErro
#[cfg(feature = "nightly")]
pub use layout::{Layout, TyAbiInterface, TyAndLayout};
-/// Requirements for a `StableHashingContext` to be used in this crate.
-/// This is a hack to allow using the `HashStable_Generic` derive macro
-/// instead of implementing everything in `rustc_middle`.
-#[cfg(feature = "nightly")]
-pub trait HashStableContext {}
-
#[derive(Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(
feature = "nightly",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 71ec1c5042fda..87633cade1b6a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -31,7 +31,8 @@ use rustc_data_structures::tagged_ptr::Tag;
use rustc_macros::{Decodable, Encodable, HashStable_Generic, Walkable};
pub use rustc_span::AttrId;
use rustc_span::{
- ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Spanned, Symbol, kw, respan, sym,
+ ByteSymbol, DUMMY_SP, ErrorGuaranteed, HashStableContext, Ident, Span, Spanned, Symbol, kw,
+ respan, sym,
};
use thin_vec::{ThinVec, thin_vec};
@@ -120,7 +121,7 @@ impl PartialEq<&[Symbol]> for Path {
}
}
-impl HashStable for Path {
+impl HashStable for Path {
fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
self.segments.len().hash_stable(hcx, hasher);
for segment in &self.segments {
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index ac3e77b0b5d6f..4178db1bfb09d 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -36,8 +36,3 @@ pub mod visit;
pub use self::ast::*;
pub use self::ast_traits::{AstNodeWrapper, HasAttrs, HasNodeId, HasTokens};
-
-/// Requirements for a `StableHashingContext` to be used in this crate.
-/// This is a hack to allow using the `HashStable_Generic` derive macro
-/// instead of implementing everything in `rustc_middle`.
-pub trait HashStableContext: rustc_span::HashStableContext {}
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 8953391ac58bf..06bd6f03e9350 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -14,7 +14,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync;
use rustc_macros::{Decodable, Encodable, HashStable_Generic, Walkable};
use rustc_serialize::{Decodable, Encodable};
-use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
+use rustc_span::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, Symbol, sym};
use thin_vec::ThinVec;
use crate::ast::AttrStyle;
@@ -826,7 +826,7 @@ impl FromIterator for TokenStream {
impl HashStable for TokenStream
where
- Hcx: crate::HashStableContext,
+ Hcx: HashStableContext,
{
fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
for sub_tt in self.iter() {
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 78bd709dd4844..cae8bb89233b2 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -8,9 +8,9 @@ use rustc_data_structures::stable_hasher::ToStableHashKey;
use rustc_data_structures::unord::UnordMap;
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
-use rustc_span::Symbol;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::hygiene::MacroKind;
+use rustc_span::{HashStableContext, Symbol};
use crate::definitions::DefPathData;
use crate::hir;
@@ -712,7 +712,7 @@ impl IntoDiagArg for Namespace {
}
}
-impl ToStableHashKey for Namespace {
+impl ToStableHashKey for Namespace {
type KeyType = Namespace;
#[inline]
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 9c2fec8677854..c2d9f879cd601 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -43,7 +43,6 @@ pub use hir::*;
pub use lang_items::{LangItem, LanguageItems};
pub use rustc_ast::attr::version::*;
pub use stability::*;
-pub use stable_hash_impls::HashStableContext;
pub use target::{MethodKind, Target};
arena_types!(rustc_arena::declare_arena);
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index d2d6529619662..a157fc0ccbb0c 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -1,4 +1,5 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_span::HashStableContext;
use rustc_span::def_id::DefPathHash;
use crate::HashIgnoredAttrId;
@@ -8,12 +9,7 @@ use crate::hir::{
use crate::hir_id::ItemLocalId;
use crate::lints::DelayedLints;
-/// Requirements for a `StableHashingContext` to be used in this crate.
-/// This is a hack to allow using the `HashStable_Generic` derive macro
-/// instead of implementing everything in `rustc_middle`.
-pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {}
-
-impl ToStableHashKey for BodyId {
+impl ToStableHashKey for BodyId {
type KeyType = (DefPathHash, ItemLocalId);
#[inline]
@@ -23,7 +19,7 @@ impl ToStableHashKey for BodyId {
}
}
-impl ToStableHashKey for ItemId {
+impl ToStableHashKey for ItemId {
type KeyType = DefPathHash;
#[inline]
@@ -32,7 +28,7 @@ impl ToStableHashKey for ItemId {
}
}
-impl ToStableHashKey for TraitItemId {
+impl ToStableHashKey for TraitItemId {
type KeyType = DefPathHash;
#[inline]
@@ -41,7 +37,7 @@ impl ToStableHashKey for TraitItemId {
}
}
-impl ToStableHashKey for ImplItemId {
+impl ToStableHashKey for ImplItemId {
type KeyType = DefPathHash;
#[inline]
@@ -50,7 +46,7 @@ impl ToStableHashKey for ImplItemId {
}
}
-impl ToStableHashKey for ForeignItemId {
+impl ToStableHashKey for ForeignItemId {
type KeyType = DefPathHash;
#[inline]
@@ -66,7 +62,7 @@ impl ToStableHashKey for ForeignItemId {
// want to pick up on a reference changing its target, so we hash the NodeIds
// in "DefPath Mode".
-impl<'tcx, Hcx: crate::HashStableContext> HashStable for OwnerNodes<'tcx> {
+impl<'tcx, Hcx: HashStableContext> HashStable for OwnerNodes<'tcx> {
fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
// We ignore the `nodes` and `bodies` fields since these refer to information included in
// `hash` which is hashed in the collector and used for the crate hash.
@@ -78,14 +74,14 @@ impl<'tcx, Hcx: crate::HashStableContext> HashStable for OwnerNodes<'tcx> {
}
}
-impl HashStable for DelayedLints {
+impl HashStable for DelayedLints {
fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
let DelayedLints { opt_hash, .. } = *self;
opt_hash.unwrap().hash_stable(hcx, hasher);
}
}
-impl<'tcx, Hcx: crate::HashStableContext> HashStable for AttributeMap<'tcx> {
+impl<'tcx, Hcx: HashStableContext> HashStable for AttributeMap<'tcx> {
fn hash_stable(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
// We ignore the `map` since it refers to information included in `opt_hash` which is
// hashed in the collector and used for the crate hash.
@@ -94,7 +90,7 @@ impl<'tcx, Hcx: crate::HashStableContext> HashStable for AttributeMap<'tcx>
}
}
-impl HashStable for HashIgnoredAttrId {
+impl HashStable for HashIgnoredAttrId {
fn hash_stable(&self, _hcx: &mut Hcx, _hasher: &mut StableHasher) {
/* we don't hash HashIgnoredAttrId, we ignore them */
}
diff --git a/compiler/rustc_hir_id/src/lib.rs b/compiler/rustc_hir_id/src/lib.rs
index ffff3f979f9e3..064ce4ed4cafe 100644
--- a/compiler/rustc_hir_id/src/lib.rs
+++ b/compiler/rustc_hir_id/src/lib.rs
@@ -8,7 +8,7 @@ use std::fmt::{self, Debug};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
-pub use rustc_span::HashStableContext;
+use rustc_span::HashStableContext;
use rustc_span::def_id::{CRATE_DEF_ID, DefId, DefIndex, DefPathHash, LocalDefId};
#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
@@ -176,7 +176,7 @@ pub const CRATE_HIR_ID: HirId =
pub const CRATE_OWNER_ID: OwnerId = OwnerId { def_id: CRATE_DEF_ID };
-impl ToStableHashKey for HirId {
+impl ToStableHashKey for HirId {
type KeyType = (DefPathHash, ItemLocalId);
#[inline]
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index af1d1854fa5a0..1c86d553f9b6a 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -8,11 +8,11 @@ use rustc_data_structures::stable_hasher::{
HashStable, StableCompare, StableHasher, ToStableHashKey,
};
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
-use rustc_hir_id::{HashStableContext, HirId, ItemLocalId};
+use rustc_hir_id::{HirId, ItemLocalId};
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::def_id::DefPathHash;
pub use rustc_span::edition::Edition;
-use rustc_span::{Ident, Span, Symbol, sym};
+use rustc_span::{HashStableContext, Ident, Span, Symbol, sym};
use serde::{Deserialize, Serialize};
pub use self::Level::*;
diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs
index fa67adb406ed2..adb93e375c32c 100644
--- a/compiler/rustc_macros/src/hash_stable.rs
+++ b/compiler/rustc_macros/src/hash_stable.rs
@@ -84,7 +84,7 @@ fn hash_stable_derive_with_mode(
match mode {
HashStableMode::Normal => {}
HashStableMode::Generic => {
- s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
+ s.add_where_predicate(parse_quote! { __CTX: ::rustc_span::HashStableContext });
}
HashStableMode::NoContext => {}
}
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index dfce7e0917608..814b333cfb0f8 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -21,7 +21,7 @@ use rustc_hir::lints::DelayedLint;
use rustc_hir::*;
use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, HashStable};
-use rustc_span::{ErrorGuaranteed, ExpnId, Span};
+use rustc_span::{ErrorGuaranteed, ExpnId, HashStableContext, Span};
use crate::query::Providers;
use crate::ty::{ResolverAstLowering, TyCtxt};
diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs
index 2e118dc3359fa..0e1cee2970f71 100644
--- a/compiler/rustc_middle/src/ich/hcx.rs
+++ b/compiler/rustc_middle/src/ich/hcx.rs
@@ -6,7 +6,7 @@ use rustc_hir::definitions::DefPathHash;
use rustc_session::Session;
use rustc_session::cstore::Untracked;
use rustc_span::source_map::SourceMap;
-use rustc_span::{CachingSourceMapView, DUMMY_SP, Pos, Span};
+use rustc_span::{CachingSourceMapView, DUMMY_SP, HashStableContext, Pos, Span};
// Very often, we are hashing something that does not need the `CachingSourceMapView`, so we
// initialize it lazily.
@@ -73,7 +73,7 @@ impl<'a> StableHashingContext<'a> {
}
}
-impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
+impl<'a> HashStableContext for StableHashingContext<'a> {
/// Hashes a span in a stable way. We can't directly hash the span's `BytePos` fields (that
/// would be similar to hashing pointers, since those are just offsets into the `SourceMap`).
/// Instead, we hash the (file name, line, column) triple, which stays the same even if the
@@ -189,8 +189,3 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
);
}
}
-
-impl<'a> rustc_abi::HashStableContext for StableHashingContext<'a> {}
-impl<'a> rustc_ast::HashStableContext for StableHashingContext<'a> {}
-impl<'a> rustc_hir::HashStableContext for StableHashingContext<'a> {}
-impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index e37247d7dd837..1e95482a8c7e6 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -23,7 +23,8 @@ use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic};
use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION};
use rustc_span::source_map::FilePathMapping;
use rustc_span::{
- FileName, RealFileName, RemapPathScopeComponents, SourceFileHashAlgorithm, Symbol, sym,
+ FileName, HashStableContext, RealFileName, RemapPathScopeComponents, SourceFileHashAlgorithm,
+ Symbol, sym,
};
use rustc_target::spec::{
FramePointer, LinkSelfContainedComponents, LinkerFeatures, PanicStrategy, SplitDebuginfo,
@@ -38,7 +39,7 @@ use crate::errors::FileWriteFail;
pub use crate::options::*;
use crate::search_paths::SearchPath;
use crate::utils::CanonicalizedPath;
-use crate::{EarlyDiagCtxt, HashStableContext, Session, filesearch, lint};
+use crate::{EarlyDiagCtxt, Session, filesearch, lint};
mod cfg;
mod externs;
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 29192f267ed3a..04e12f1afce68 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -29,8 +29,3 @@ mod options;
pub mod output;
pub mod search_paths;
mod session;
-
-/// Requirements for a `StableHashingContext` to be used in this crate.
-/// This is a hack to allow using the `HashStable_Generic` derive macro
-/// instead of implementing everything in `rustc_middle`.
-pub trait HashStableContext: rustc_ast::HashStableContext + rustc_hir::HashStableContext {}
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 6794ffb311e32..97de708290fb4 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -2796,10 +2796,10 @@ impl InnerSpan {
}
}
-/// Requirements for a `StableHashingContext` to be used in this crate.
-///
-/// This is a hack to allow using the [`HashStable_Generic`] derive macro
-/// instead of implementing everything in rustc_middle.
+/// This trait lets `HashStable` and `derive(HashStable_Generic)` be used in
+/// this crate (and other crates upstream of `rustc_middle`), while leaving
+/// certain operations to be defined in `rustc_middle` where more things are
+/// visible.
pub trait HashStableContext {
/// The main event: stable hashing of a span.
fn span_hash_stable(&mut self, span: Span, hasher: &mut StableHasher);
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index 1dc62cb3659cc..d46802bf45d1a 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -24,8 +24,6 @@ pub mod target_features;
#[cfg(test)]
mod tests;
-use rustc_abi::HashStableContext;
-
/// The name of rustc's own place to organize libraries.
///
/// Used to be `rustc`, now the default is `rustlib`.
From e18dd4a9925015045bbb54e0291d0bf060cdcf43 Mon Sep 17 00:00:00 2001
From: Makai
Date: Mon, 16 Mar 2026 22:07:03 +0800
Subject: [PATCH 13/38] add `TypeFlags::HAS_NON_REGION_ERROR` and
`TypeFlags::HAS_RE_ERROR`
---
compiler/rustc_middle/src/ty/region.rs | 2 +-
compiler/rustc_type_ir/src/flags.rs | 31 +++++++++++++++-----------
compiler/rustc_type_ir/src/visit.rs | 19 ++++++++++++++++
3 files changed, 38 insertions(+), 14 deletions(-)
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index a497501ef19d5..798b98c5def5c 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -291,7 +291,7 @@ impl<'tcx> Region<'tcx> {
}
ty::ReError(_) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_ERROR;
+ flags = flags | TypeFlags::HAS_RE_ERROR;
}
}
diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs
index 6962a7ab1d727..f311298119649 100644
--- a/compiler/rustc_type_ir/src/flags.rs
+++ b/compiler/rustc_type_ir/src/flags.rs
@@ -91,19 +91,24 @@ bitflags::bitflags! {
| TypeFlags::HAS_TY_INHERENT.bits()
| TypeFlags::HAS_CT_PROJECTION.bits();
+ /// Is a type or const error reachable?
+ const HAS_NON_REGION_ERROR = 1 << 15;
+ /// Is a region error reachable?
+ const HAS_RE_ERROR = 1 << 16;
/// Is an error type/lifetime/const reachable?
- const HAS_ERROR = 1 << 15;
+ const HAS_ERROR = TypeFlags::HAS_NON_REGION_ERROR.bits()
+ | TypeFlags::HAS_RE_ERROR.bits();
/// Does this have any region that "appears free" in the type?
/// Basically anything but `ReBound` and `ReErased`.
- const HAS_FREE_REGIONS = 1 << 16;
+ const HAS_FREE_REGIONS = 1 << 17;
/// Does this have any `ReBound` regions?
- const HAS_RE_BOUND = 1 << 17;
+ const HAS_RE_BOUND = 1 << 18;
/// Does this have any `Bound` types?
- const HAS_TY_BOUND = 1 << 18;
+ const HAS_TY_BOUND = 1 << 19;
/// Does this have any `ConstKind::Bound` consts?
- const HAS_CT_BOUND = 1 << 19;
+ const HAS_CT_BOUND = 1 << 20;
/// Does this have any bound variables?
/// Used to check if a global bound is safe to evaluate.
const HAS_BOUND_VARS = TypeFlags::HAS_RE_BOUND.bits()
@@ -111,7 +116,7 @@ bitflags::bitflags! {
| TypeFlags::HAS_CT_BOUND.bits();
/// Does this have any `ReErased` regions?
- const HAS_RE_ERASED = 1 << 20;
+ const HAS_RE_ERASED = 1 << 21;
/// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization?
@@ -123,19 +128,19 @@ bitflags::bitflags! {
| TypeFlags::HAS_CT_INFER.bits();
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
- const HAS_TY_FRESH = 1 << 21;
+ const HAS_TY_FRESH = 1 << 22;
/// Does this value have `InferConst::Fresh`?
- const HAS_CT_FRESH = 1 << 22;
+ const HAS_CT_FRESH = 1 << 23;
/// Does this have any binders with bound vars (e.g. that need to be anonymized)?
- const HAS_BINDER_VARS = 1 << 23;
+ const HAS_BINDER_VARS = 1 << 24;
/// Does this type have any coroutines in it?
- const HAS_TY_CORO = 1 << 24;
+ const HAS_TY_CORO = 1 << 25;
/// Does this have have a `Bound(BoundVarIndexKind::Canonical, _)`?
- const HAS_CANONICAL_BOUND = 1 << 25;
+ const HAS_CANONICAL_BOUND = 1 << 26;
}
}
@@ -240,7 +245,7 @@ impl FlagComputation {
| ty::Str
| ty::Foreign(..) => {}
- ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
+ ty::Error(_) => self.add_flags(TypeFlags::HAS_NON_REGION_ERROR),
ty::Param(_) => {
self.add_flags(TypeFlags::HAS_TY_PARAM);
@@ -489,7 +494,7 @@ impl FlagComputation {
}
}
ty::ConstKind::Expr(e) => self.add_args(e.args().as_slice()),
- ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
+ ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_NON_REGION_ERROR),
}
}
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index 1ee4bff6b7a11..cfb4588965368 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -279,6 +279,8 @@ pub trait TypeVisitableExt: TypeVisitable {
fn error_reported(&self) -> Result<(), I::ErrorGuaranteed>;
+ fn non_region_error_reported(&self) -> Result<(), I::ErrorGuaranteed>;
+
fn has_non_region_param(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM)
}
@@ -352,6 +354,11 @@ pub trait TypeVisitableExt: TypeVisitable {
fn still_further_specializable(&self) -> bool {
self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
}
+
+ /// True if a type or const error is reachable
+ fn has_non_region_error(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_NON_REGION_ERROR)
+ }
}
impl> TypeVisitableExt for T {
@@ -376,6 +383,18 @@ impl> TypeVisitableExt for T {
Ok(())
}
}
+
+ fn non_region_error_reported(&self) -> Result<(), I::ErrorGuaranteed> {
+ if self.has_non_region_error() {
+ if let ControlFlow::Break(guar) = self.visit_with(&mut HasErrorVisitor) {
+ Err(guar)
+ } else {
+ panic!("type flags said there was an non region error, but now there is not")
+ }
+ } else {
+ Ok(())
+ }
+ }
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
From 339fb64d1c751de5d781f4c8d51ae37b613ba644 Mon Sep 17 00:00:00 2001
From: Makai