diff --git a/Cargo.lock b/Cargo.lock
index 873182dde9102..9d5d0f2d403f9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6213,9 +6213,9 @@ dependencies = [
[[package]]
name = "wasi-preview1-component-adapter-provider"
-version = "44.0.2"
+version = "46.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2211ca2d69a88055eefb06bad741dde3180c9d4020f7e42fea72caba83f9c10c"
+checksum = "1b6c48003fe59c201c97a7786ff55feabe6b6f83b598aa9ff5bcc4f94d940bf3"
[[package]]
name = "wasip2"
@@ -6282,9 +6282,9 @@ dependencies = [
[[package]]
name = "wasm-component-ld"
-version = "0.5.25"
+version = "0.5.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee72c06c556db23aca2d29e1e183d96efdffa7110b24915629a5091de600a894"
+checksum = "51a12709376d4ce64f472699500db3b0e5902cc2bef16fb6ca3098bfdac032fa"
dependencies = [
"anyhow",
"clap",
@@ -6293,12 +6293,12 @@ dependencies = [
"libc",
"tempfile",
"wasi-preview1-component-adapter-provider",
- "wasmparser 0.252.0",
+ "wasmparser 0.253.0",
"wat",
"windows-sys 0.61.2",
"winsplit",
- "wit-component 0.252.0",
- "wit-parser 0.252.0",
+ "wit-component 0.253.0",
+ "wit-parser 0.253.0",
]
[[package]]
@@ -6330,12 +6330,12 @@ dependencies = [
[[package]]
name = "wasm-encoder"
-version = "0.252.0"
+version = "0.253.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8185ae345fa5687c054626ff9a50e7089797a343d9904d1dc9820eb4c4d3196f"
+checksum = "59972d6cd272259de647b7c1f1912e45e289c75ffd4be04e10695507cd7e1b59"
dependencies = [
"leb128fmt",
- "wasmparser 0.252.0",
+ "wasmparser 0.253.0",
]
[[package]]
@@ -6352,14 +6352,14 @@ dependencies = [
[[package]]
name = "wasm-metadata"
-version = "0.252.0"
+version = "0.253.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b7e08e02a3cd55bf778009d4cd6faae50da011f293644daf78a531a32d6d142"
+checksum = "b3f45816ef616806f48498bcd831377de578c4fa51db0c83ab8ceb78cc13523b"
dependencies = [
"anyhow",
"indexmap",
- "wasm-encoder 0.252.0",
- "wasmparser 0.252.0",
+ "wasm-encoder 0.253.0",
+ "wasmparser 0.253.0",
]
[[package]]
@@ -6396,9 +6396,9 @@ dependencies = [
[[package]]
name = "wasmparser"
-version = "0.252.0"
+version = "0.253.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3eb099dcadcde5be9eef55e3a337128efd4e44b4c93122487e4d2e4e1c6627c"
+checksum = "19db11f87d2486580e1e8b6f494c54df7e0566b87d0b599db843c24019667339"
dependencies = [
"bitflags",
"hashbrown 0.17.0",
@@ -6409,22 +6409,22 @@ dependencies = [
[[package]]
name = "wast"
-version = "252.0.0"
+version = "253.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "942a3449d6a593fccc111a6241c8df52bda168af30e40bf9580d4394d7374c65"
+checksum = "d3264542f8965c5d84fb1085d924bfba9a6314bb228eff13a2de14d7627664d0"
dependencies = [
"bumpalo",
"leb128fmt",
"memchr",
"unicode-width 0.2.2",
- "wasm-encoder 0.252.0",
+ "wasm-encoder 0.253.0",
]
[[package]]
name = "wat"
-version = "1.252.0"
+version = "1.253.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c72a4ba7088f7bac94cf516e49882bdf97068904a563768cf249efc839ec42cb"
+checksum = "4bfc5ce906144200c972ec617470aa35bd847472e170b26dde3e80541c674055"
dependencies = [
"wast",
]
@@ -6872,9 +6872,9 @@ dependencies = [
[[package]]
name = "wit-component"
-version = "0.252.0"
+version = "0.253.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76db0662b590f45d33d0e363fa13539a5a1eecd35d5a12fe208c335461c1053d"
+checksum = "dbbd2500ac3488489ee8c6e59b79d7e47e6da5bfb019efd35d5dca57b78af624"
dependencies = [
"anyhow",
"bitflags",
@@ -6883,10 +6883,10 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
- "wasm-encoder 0.252.0",
- "wasm-metadata 0.252.0",
- "wasmparser 0.252.0",
- "wit-parser 0.252.0",
+ "wasm-encoder 0.253.0",
+ "wasm-metadata 0.253.0",
+ "wasmparser 0.253.0",
+ "wit-parser 0.253.0",
]
[[package]]
@@ -6909,9 +6909,9 @@ dependencies = [
[[package]]
name = "wit-parser"
-version = "0.252.0"
+version = "0.253.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4266bea110371c620ccf3201c5023676046bc4556e5c7cfb5d500bda5ebc162d"
+checksum = "4d997b8e5920fcbeec742b58e583325d6419a6aca617ae8075c406a61c65ba8a"
dependencies = [
"anyhow",
"hashbrown 0.17.0",
@@ -6923,7 +6923,7 @@ dependencies = [
"serde_derive",
"serde_json",
"unicode-ident",
- "wasmparser 0.252.0",
+ "wasmparser 0.253.0",
]
[[package]]
diff --git a/RELEASES.md b/RELEASES.md
index 2fa271401fbb3..3146bdeb1b118 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,93 @@
+Version 1.97.0 (2026-07-09)
+==========================
+
+
+
+Language
+--------
+- [Consider `Result` and `ControlFlow` to be equivalent to `T` for must use lint](https://github.com/rust-lang/rust/pull/148214)
+- [Add allow-by-default `dead_code_pub_in_binary` lint for unused pub items in binary crates](https://github.com/rust-lang/rust/pull/149509)
+- [Stabilize the `div32`, `lam-bh`, `lamcas`, `ld-seq-sa` and `scq` target features](https://github.com/rust-lang/rust/pull/154510)
+- [Stabilize `cfg(target_has_atomic_primitive_alignment)`](https://github.com/rust-lang/rust/pull/155006)
+- [Allow trailing `self` in imports in more cases](https://github.com/rust-lang/rust/pull/155137)
+
+
+
+
+Platform Support
+----------------
+- [nvptx64-nvidia-cuda: drop support for old architectures and old ISAs](https://github.com/rust-lang/rust/pull/152443)
+
+
+Refer to Rust's [platform support page][platform-support-doc]
+for more information on Rust's tiered platform support.
+
+[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
+
+
+
+
+Stabilized APIs
+---------------
+
+- [`Default for RepeatN`](https://doc.rust-lang.org/stable/std/iter/struct.RepeatN.html#impl-Default-for-RepeatN%3CA%3E)
+- [`Copy for ffi::FromBytesUntilNulError`](https://doc.rust-lang.org/stable/std/ffi/struct.FromBytesUntilNulError.html#impl-Copy-for-FromBytesUntilNulError)
+- [`Send for std::fs::File` on UEFI](https://github.com/rust-lang/rust/pull/154003)
+- [`<{integer}>::isolate_highest_one`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.isolate_highest_one)
+- [`<{integer}>::isolate_lowest_one`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.isolate_lowest_one)
+- [`<{integer}>::highest_one`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.highest_one)
+- [`<{integer}>::lowest_one`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.lowest_one)
+- [`<{integer}>::bit_width`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.bit_width)
+- [`NonZero<{integer}>::isolate_highest_one`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.isolate_highest_one)
+- [`NonZero<{integer}>::isolate_lowest_one`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.isolate_lowest_one)
+- [`NonZero<{integer}>::highest_one`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.highest_one)
+- [`NonZero<{integer}>::lowest_one`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.lowest_one)
+- [`NonZero<{integer}>::bit_width`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.bit_width)
+
+
+These previously stable APIs are now stable in const contexts:
+
+- [`char::is_control`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_control)
+
+
+
+
+Cargo
+-----
+- [Stabilize `build.warnings` config.](https://github.com/rust-lang/cargo/pull/16796) This controls how lint warnings from local packages are treated. Useful for enforcing a warning-free build in CI, replacing `-Dwarnings`. [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#buildwarnings)
+- [Stabilize `resolver.lockfile-path` config.](https://github.com/rust-lang/cargo/pull/16694) This allows specifying the path to the lockfile to use when resolving dependencies. Useful when working with read-only source directories. [docs](https://doc.rust-lang.org/nightly/cargo/reference/config.html#resolverlockfile-path)
+- [cargo-clean: Error when `--target-dir` doesn't look like a Cargo target directory.](https://github.com/rust-lang/cargo/pull/16712) This prevents accidental deletion of non-target directories.
+- [Add `-m` shorthand for `--manifest-path`](https://github.com/rust-lang/cargo/pull/16858)
+- [Remove `curl` dependency from `crates-io` crate](https://github.com/rust-lang/cargo/pull/16936)
+
+
+
+Rustdoc
+-----
+- [Stabilize `--emit` flag](https://github.com/rust-lang/rust/pull/146220)
+- [Stabilize `--remap-path-prefix`](https://github.com/rust-lang/rust/pull/155307)
+
+
+
+
+Compatibility Notes
+-------------------
+- [Emit a future-compatibility warning when relying on `f32: From<{float}>` to constrain `{float}`](https://github.com/rust-lang/rust/pull/139087)
+- [Rust will use the v0 symbol mangling scheme by default.](https://github.com/rust-lang/rust/pull/151994) This may cause some tools (such as debuggers or profilers, especially with old versions) to fail to demangle symbols emitted by Rust. It may also cause the formatting of text in backtraces to change.
+- [Prevent deref coercions in `pin!`, in order to prevent unsoundness.](https://github.com/rust-lang/rust/pull/153457) The most likely case where this might impact users is: writing `pin!(x)` where `x` has type `&mut T` will now always correctly produce a value of type `Pin<&mut &mut T>`, instead of sometimes allowing a coercion that produces a value of type `Pin<&mut T>`. This coercion was previously incorrectly allowed since Rust 1.88.0.
+- [Deprecate `std::char` constants and functions](https://github.com/rust-lang/rust/pull/153873)
+- [Warn on linker output by default](https://github.com/rust-lang/rust/pull/153968)
+- [Remove hidden `f64` methods which have been deprecated since 1.0](https://github.com/rust-lang/rust/pull/153975)
+- [report the `varargs_without_pattern` lint in deps](https://github.com/rust-lang/rust/pull/154599)
+- [Forbid passing generic arguments to module path segments even if the module reexports a generic enum variant](https://github.com/rust-lang/rust/pull/154971)
+- [Error on invalid macho `link_section` specifier](https://github.com/rust-lang/rust/pull/155065)
+- The encoding of certain `enum`s [have changed](https://github.com/rust-lang/rust/pull/155473). This is not a breaking change, as it only applies to `enum`s without layout guarantees, but is noted here as we've seen people impacted from having made assumptions about the layout algorithm.
+- [Error on `#[export_name = "..."]` where the name is empty](https://github.com/rust-lang/rust/pull/155515)
+- [Syntactically reject tuple index shorthands in struct patterns](https://github.com/rust-lang/rust/pull/155698)
+- [validate `#[link_name = "..."]` & `#[link(name = "...")]` parameters](https://github.com/rust-lang/rust/pull/155817)
+- On Windows, after calling `shutdown` on a socket to shut down the write side, attempting to write to the socket will now produce a `BrokenPipe` error rather than `Other`. [Map `WSAESHUTDOWN` to `io::ErrorKind::BrokenPipe`](https://github.com/rust-lang/rust/pull/156063)
+
+
Version 1.96.1 (2026-06-30)
===========================
diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs
index 41e87caf40c7d..4fda4735b613c 100644
--- a/compiler/rustc_abi/src/callconv.rs
+++ b/compiler/rustc_abi/src/callconv.rs
@@ -89,7 +89,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")
}
- BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
+ BackendRepr::ScalarPair { .. } | BackendRepr::Memory { sized: true } => {
// Helper for computing `homogeneous_aggregate`, allowing a custom
// starting offset (used below for handling variants).
let from_fields_at =
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 003e811dc7855..ad48e14430952 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -476,7 +476,7 @@ impl LayoutCalculator {
Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true },
Ok(Some((repr, _))) => match repr {
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
- BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _)
+ BackendRepr::Scalar(_) | BackendRepr::ScalarPair { .. }
if repr.scalar_platform_align(dl).unwrap() != align =>
{
BackendRepr::Memory { sized: true }
@@ -489,7 +489,7 @@ impl LayoutCalculator {
}
// the alignment tests passed and we can use this
BackendRepr::Scalar(..)
- | BackendRepr::ScalarPair(..)
+ | BackendRepr::ScalarPair { .. }
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. }
| BackendRepr::Memory { .. } => repr,
@@ -558,7 +558,7 @@ impl LayoutCalculator {
};
match &mut st.backend_repr {
BackendRepr::Scalar(scalar) => hide_niches(scalar),
- BackendRepr::ScalarPair(a, b) => {
+ BackendRepr::ScalarPair { a, b, b_offset: _ } => {
hide_niches(a);
hide_niches(b);
}
@@ -701,13 +701,21 @@ impl LayoutCalculator {
// When the total alignment and size match, we can use the
// same ABI as the scalar variant with the reserved niche.
BackendRepr::Scalar(_) => BackendRepr::Scalar(niche_scalar),
- BackendRepr::ScalarPair(first, second) => {
+ BackendRepr::ScalarPair { a: first, b: second, b_offset } => {
// Only the niche is guaranteed to be initialised,
// so use union layouts for the other primitive.
if niche_offset == Size::ZERO {
- BackendRepr::ScalarPair(niche_scalar, second.to_union())
+ BackendRepr::ScalarPair {
+ a: niche_scalar,
+ b: second.to_union(),
+ b_offset,
+ }
} else {
- BackendRepr::ScalarPair(first.to_union(), niche_scalar)
+ BackendRepr::ScalarPair {
+ a: first.to_union(),
+ b: niche_scalar,
+ b_offset,
+ }
}
}
_ => BackendRepr::Memory { sized: true },
@@ -1037,7 +1045,7 @@ impl LayoutCalculator {
// If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the
// variants to ensure they are consistent. This is because a downcast is
// semantically a NOP, and thus should not affect layout.
- if matches!(abi, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) {
+ if matches!(abi, BackendRepr::Scalar(..) | BackendRepr::ScalarPair { .. }) {
for variant in &mut layout_variants {
// We only do this for variants with fields; the others are not accessed anyway.
// Also do not overwrite any already existing "clever" ABIs.
@@ -1354,7 +1362,7 @@ impl LayoutCalculator {
}
// But scalar pairs are Rust-specific and get
// treated as aggregates by C ABIs anyway.
- BackendRepr::ScalarPair(..) => {
+ BackendRepr::ScalarPair { .. } => {
abi = field.backend_repr;
}
_ => {}
diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs
index 5fd504def384a..1fffb84ec21cb 100644
--- a/compiler/rustc_abi/src/layout/simple.rs
+++ b/compiler/rustc_abi/src/layout/simple.rs
@@ -110,7 +110,7 @@ impl LayoutData {
offsets: [Size::ZERO, b_offset].into(),
in_memory_order: [FieldIdx::new(0), FieldIdx::new(1)].into(),
},
- backend_repr: BackendRepr::ScalarPair(a, b),
+ backend_repr: BackendRepr::ScalarPair { a, b, b_offset },
largest_niche,
uninhabited: false,
align: AbiAlign::new(align),
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index c2069432e6f8e..b8cd152e30288 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1796,14 +1796,18 @@ impl IntoDiagArg for NumScalableVectors {
pub enum BackendRepr {
Scalar(Scalar),
/// The data contained in this type can be entirely represented by two scalars.
- /// The two scalars are listed in *memory* order, so the first is at offset zero
- /// and the second at a non-zero offset.
+ /// The two scalars are listed in *memory* order, so `a` is at offset zero
+ /// and `b` is at non-zero offset `b_offset`.
/// These need not be `FieldIdx(0)` and `FieldIdx(1)`.
///
- /// As of June 2026 the offset to the second scalar is the size of the first
- /// scalar rounded up to the platform alignment of the second scalar.
+ /// As of June 2026 the `b_offset` is always the size of the `a`
+ /// scalar rounded up to the platform alignment of the `b` scalar.
/// That may soon change, however; see MCP#1007.
- ScalarPair(Scalar, Scalar),
+ ScalarPair {
+ a: Scalar,
+ b: Scalar,
+ b_offset: Size,
+ },
SimdScalableVector {
element: Scalar,
count: u64,
@@ -1826,7 +1830,7 @@ impl BackendRepr {
pub fn is_unsized(&self) -> bool {
match *self {
BackendRepr::Scalar(_)
- | BackendRepr::ScalarPair(..)
+ | BackendRepr::ScalarPair { .. }
// FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the
// `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
// fully implemented, scalable vectors will remain `Sized`, they just won't be
@@ -1875,7 +1879,7 @@ impl BackendRepr {
pub fn scalar_platform_align(&self, cx: &C) -> Option {
match *self {
BackendRepr::Scalar(s) => Some(s.default_align(cx).abi),
- BackendRepr::ScalarPair(s1, s2) => {
+ BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } => {
Some(s1.default_align(cx).max(s2.default_align(cx)).abi)
}
// The align of a Vector can vary in surprising ways
@@ -1893,8 +1897,7 @@ impl BackendRepr {
// No padding in scalars.
BackendRepr::Scalar(s) => Some(s.size(cx)),
// May have some padding between the pair.
- BackendRepr::ScalarPair(s1, s2) => {
- let field2_offset = s1.size(cx).align_to(s2.default_align(cx).abi);
+ BackendRepr::ScalarPair { a: _, b: s2, b_offset: field2_offset } => {
let size = (field2_offset + s2.size(cx)).align_to(
self.scalar_platform_align(cx)
// We absolutely must have an answer here or everything is FUBAR.
@@ -1913,8 +1916,8 @@ impl BackendRepr {
pub fn to_union(&self) -> Self {
match *self {
BackendRepr::Scalar(s) => BackendRepr::Scalar(s.to_union()),
- BackendRepr::ScalarPair(s1, s2) => {
- BackendRepr::ScalarPair(s1.to_union(), s2.to_union())
+ BackendRepr::ScalarPair { a: s1, b: s2, b_offset } => {
+ BackendRepr::ScalarPair { a: s1.to_union(), b: s2.to_union(), b_offset }
}
BackendRepr::SimdVector { element, count } => {
BackendRepr::SimdVector { element: element.to_union(), count }
@@ -1939,8 +1942,13 @@ impl BackendRepr {
BackendRepr::SimdVector { element: element_l, count: count_l },
BackendRepr::SimdVector { element: element_r, count: count_r },
) => element_l.primitive() == element_r.primitive() && count_l == count_r,
- (BackendRepr::ScalarPair(l1, l2), BackendRepr::ScalarPair(r1, r2)) => {
- l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive()
+ (
+ BackendRepr::ScalarPair { a: l1, b: l2, b_offset: l_offset },
+ BackendRepr::ScalarPair { a: r1, b: r2, b_offset: r_offset },
+ ) => {
+ l1.primitive() == r1.primitive()
+ && l2.primitive() == r2.primitive()
+ && l_offset == r_offset
}
// Everything else must be strictly identical.
_ => self == other,
@@ -2180,7 +2188,7 @@ impl LayoutData {
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. } => false,
- BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true,
+ BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => true,
}
}
@@ -2294,7 +2302,7 @@ impl LayoutData {
pub fn is_zst(&self) -> bool {
match self.backend_repr {
BackendRepr::Scalar(_)
- | BackendRepr::ScalarPair(..)
+ | BackendRepr::ScalarPair { .. }
| BackendRepr::SimdScalableVector { .. }
| BackendRepr::SimdVector { .. } => false,
BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 632f138a4c798..bde6614b48548 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1378,15 +1378,6 @@ pub enum UnsafeSource {
UserProvided,
}
-/// Track whether under `feature(min_generic_const_args)` this anon const
-/// was explicitly disambiguated as an anon const or not through the use of
-/// `const { ... }` syntax.
-#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Walkable)]
-pub enum MgcaDisambiguation {
- AnonConst,
- Direct,
-}
-
/// A constant (expression) that's not an item or associated item,
/// but needs its own `DefId` for type-checking, const-eval, etc.
/// These are usually found nested inside types (e.g., array lengths)
@@ -1396,7 +1387,6 @@ pub enum MgcaDisambiguation {
pub struct AnonConst {
pub id: NodeId,
pub value: Box,
- pub mgca_disambiguation: MgcaDisambiguation,
}
/// An expression.
@@ -1627,6 +1617,7 @@ impl Expr {
| ExprKind::UnsafeBinderCast(..)
| ExprKind::While(..)
| ExprKind::Yield(YieldKind::Postfix(..))
+ | ExprKind::DirectConstArg(..)
| ExprKind::Err(_)
| ExprKind::Dummy => prefix_attrs_precedence(&self.attrs),
}
@@ -1920,6 +1911,9 @@ pub enum ExprKind {
UnsafeBinderCast(UnsafeBinderCastKind, Box, Option>),
+ /// An mGCA `direct_const_arg!()` expression.
+ DirectConstArg(Box),
+
/// Placeholder for an expression that wasn't syntactically well formed in some way.
Err(ErrorGuaranteed),
@@ -2566,6 +2560,8 @@ pub enum TyKind {
FieldOf(Box, Option, Ident),
/// A view of a type. `T.{ field_1, field_2 }`.
View(Box, #[visitable(ignore)] ThinVec),
+ /// An mGCA `direct_const_arg!()` expression.
+ DirectConstArg(Box),
/// Sometimes we need a dummy value when no error has occurred.
Dummy,
/// Placeholder for a kind that has failed to be defined.
@@ -3066,6 +3062,9 @@ impl FnDecl {
/// Must have the same value as `FnSigKind::NO_SPLATTED_ARG_INDEX` and `FnDeclFlags::NO_SPLATTED_ARG_INDEX`.
pub const NO_SPLATTED_ARG_INDEX: u8 = u8::MAX;
+ /// The maximum valid splatted argument index.
+ pub const MAX_VALID_SPLATTED_ARG_INDEX: u8 = Self::NO_SPLATTED_ARG_INDEX - 1;
+
/// Returns a splatted argument index, if any are present.
pub fn splatted(&self) -> Option {
self.inputs.iter().enumerate().find_map(|(index, arg)| {
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
index 56f96f9a8a279..0c2218e557f23 100644
--- a/compiler/rustc_ast/src/util/classify.rs
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -155,6 +155,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
| Yeet(..)
| Yield(..)
| UnsafeBinderCast(..)
+ | DirectConstArg(..)
| Err(..)
| Dummy => return false,
}
@@ -240,6 +241,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option> {
| Try(_)
| Yeet(None)
| UnsafeBinderCast(..)
+ | DirectConstArg(..)
| Err(_)
| Dummy => {
break None;
@@ -301,9 +303,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
| ast::TyKind::CVarArgs
| ast::TyKind::Pat(..)
| ast::TyKind::FieldOf(..)
+ | ast::TyKind::View(..)
+ | ast::TyKind::DirectConstArg(..)
| ast::TyKind::Dummy
- | ast::TyKind::Err(..)
- | ast::TyKind::View(..) => break None,
+ | ast::TyKind::Err(..) => break None,
}
}
}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index fb4e76321d150..e25c1a0b31937 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -418,7 +418,6 @@ macro_rules! common_visitor_and_walkers {
UnsafeBinderCastKind,
BinOpKind,
BlockCheckMode,
- MgcaDisambiguation,
BorrowKind,
BoundAsyncness,
BoundConstness,
@@ -1074,6 +1073,8 @@ macro_rules! common_visitor_and_walkers {
visit_visitable!($($mut)? vis, bytes),
ExprKind::UnsafeBinderCast(kind, expr, ty) =>
visit_visitable!($($mut)? vis, kind, expr, ty),
+ ExprKind::DirectConstArg(expr) =>
+ visit_visitable!($($mut)? vis, expr),
ExprKind::Err(_guar) => {}
ExprKind::Dummy => {}
}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index f66d1ac16c907..4ed23e032d234 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -498,6 +498,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
+
+ ExprKind::DirectConstArg(_) => {
+ let e = self
+ .tcx
+ .dcx()
+ .struct_span_err(
+ e.span,
+ "expected expression, found `direct_const_arg!()` constant",
+ )
+ .emit();
+ hir::ExprKind::Err(e)
+ }
};
hir::Expr { hir_id: expr_hir_id, kind, span }
@@ -599,11 +611,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
arg
};
- let anon_const = AnonConst {
- id: node_id,
- value: const_value,
- mgca_disambiguation: MgcaDisambiguation::AnonConst,
- };
+ let anon_const = AnonConst { id: node_id, value: const_value };
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
} else {
real_args.push(arg);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index dc1acade85ed5..4963a38ddfd45 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1478,6 +1478,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
}
+ TyKind::DirectConstArg(expr)
+ if self.tcx.features().min_generic_const_args() =>
+ {
+ let ct = match self.can_lower_expr_to_const_arg_direct(expr) {
+ Ok(()) => self.lower_expr_to_const_arg_direct(expr, None),
+ Err(e) => e.emit(self),
+ };
+ let ct = self.arena.alloc(ct);
+ return GenericArg::Const(ct.try_as_ambig_ct().unwrap());
+ }
_ => {}
}
GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap())
@@ -1754,6 +1764,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
// FIXME(scrabsha): lower view types to HIR.
return self.lower_ty(ty, itctx);
}
+ TyKind::DirectConstArg(_) => {
+ let e = self
+ .tcx
+ .dcx()
+ .struct_span_err(t.span, "expected type, found `direct_const_arg!()` constant")
+ .emit();
+ hir::TyKind::Err(e)
+ }
TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"),
};
@@ -2672,23 +2690,86 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
#[instrument(level = "debug", skip(self), ret)]
- fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> {
- let span = self.lower_span(expr.span);
-
- let overly_complex_const = |this: &mut Self| {
- let msg = "complex const arguments must be placed inside of a `const` block";
- let e = if expr::WillCreateDefIdsVisitor.visit_expr(expr).is_break() {
- // FIXME(mgca): make this non-fatal once we have a better way to handle
- // nested items in const args
- // Issue: https://github.com/rust-lang/rust/issues/154539
- this.dcx().struct_span_fatal(expr.span, msg).emit()
- } else {
- this.dcx().struct_span_err(expr.span, msg).emit()
- };
+ fn can_lower_expr_to_const_arg_direct(
+ &mut self,
+ expr: &Expr,
+ ) -> Result<(), UnrepresentableConstArgError> {
+ let is_mgca = self.tcx.features().min_generic_const_args();
+ // Note the only stable case is currently ExprKind::Path. All others have an is_mgca guard.
+ match &expr.kind {
+ ExprKind::Call(func, args)
+ if is_mgca && let ExprKind::Path(_qself, _path) = &func.kind =>
+ {
+ for arg in args {
+ self.can_lower_expr_to_const_arg_direct(arg)?;
+ }
+ Ok(())
+ }
+ ExprKind::Tup(exprs) if is_mgca => {
+ for expr in exprs {
+ self.can_lower_expr_to_const_arg_direct(expr)?;
+ }
+ Ok(())
+ }
+ ExprKind::Path(qself, path)
+ if is_mgca
+ || path.is_potential_trivial_const_arg()
+ && matches!(
+ self.get_partial_res(expr.id)
+ .and_then(|partial_res| partial_res.full_res()),
+ Some(Res::Def(DefKind::ConstParam, _))
+ ) =>
+ {
+ Ok(())
+ }
+ ExprKind::Struct(se) if is_mgca => {
+ for f in &se.fields {
+ self.can_lower_expr_to_const_arg_direct(&f.expr)?;
+ }
+ Ok(())
+ }
+ ExprKind::Array(elements) if is_mgca => {
+ for element in elements {
+ self.can_lower_expr_to_const_arg_direct(element)?;
+ }
+ Ok(())
+ }
+ ExprKind::Underscore if is_mgca => Ok(()),
+ ExprKind::Block(block, _)
+ if is_mgca
+ && let [stmt] = block.stmts.as_slice()
+ && let StmtKind::Expr(expr) = &stmt.kind =>
+ {
+ self.can_lower_expr_to_const_arg_direct(expr)
+ }
+ ExprKind::Lit(literal) if is_mgca => Ok(()),
+ ExprKind::Unary(UnOp::Neg, inner_expr)
+ if is_mgca && let ExprKind::Lit(_) = &inner_expr.kind =>
+ {
+ Ok(())
+ }
+ ExprKind::ConstBlock(anon) if is_mgca => Ok(()),
+ ExprKind::DirectConstArg(expr) if is_mgca => {
+ // Always report this as able to be represented directly. If it turns out not to be,
+ // `lower_expr_to_const_arg_direct` will report an error.
+ Ok(())
+ }
+ _ => Err(UnrepresentableConstArgError::new(expr)),
+ }
+ }
- ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e), span }
- };
+ /// It is not allowed to call this function without checking can_lower_expr_to_const_arg_direct
+ /// first, as we assume all feature gates/etc. have been checked already.
+ #[instrument(level = "debug", skip(self), ret)]
+ fn lower_expr_to_const_arg_direct(
+ &mut self,
+ expr: &Expr,
+ id_override: Option,
+ ) -> hir::ConstArg<'hir> {
+ debug_assert!(self.can_lower_expr_to_const_arg_direct(expr).is_ok());
+ let span = self.lower_span(expr.span);
+ let node_id = id_override.unwrap_or(expr.id);
match &expr.kind {
ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => {
let qpath = self.lower_qpath(
@@ -2702,23 +2783,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
- let const_arg = self.lower_expr_to_const_arg_direct(arg);
+ let const_arg = self.lower_expr_to_const_arg_direct(arg, None);
&*self.arena.alloc(const_arg)
}));
ConstArg {
- hir_id: self.next_id(),
+ hir_id: self.lower_node_id(node_id),
kind: hir::ConstArgKind::TupleCall(qpath, lowered_args),
span,
}
}
ExprKind::Tup(exprs) => {
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
- let expr = self.lower_expr_to_const_arg_direct(&expr);
+ let expr = self.lower_expr_to_const_arg_direct(expr, None);
&*self.arena.alloc(expr)
}));
- ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(exprs), span }
+ ConstArg {
+ hir_id: self.lower_node_id(node_id),
+ kind: hir::ConstArgKind::Tup(exprs),
+ span,
+ }
}
ExprKind::Path(qself, path) => {
let qpath = self.lower_qpath(
@@ -2732,7 +2817,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
None,
);
- ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath), span }
+ ConstArg {
+ hir_id: self.lower_node_id(node_id),
+ kind: hir::ConstArgKind::Path(qpath),
+ span,
+ }
}
ExprKind::Struct(se) => {
let path = self.lower_qpath(
@@ -2754,7 +2843,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// then go unused as the `Target::ExprField` is not actually
// corresponding to `Node::ExprField`.
self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);
- let expr = self.lower_expr_to_const_arg_direct(&f.expr);
+ let expr = self.lower_expr_to_const_arg_direct(&f.expr, None);
&*self.arena.alloc(hir::ConstArgExprField {
hir_id,
@@ -2765,14 +2854,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
}));
ConstArg {
- hir_id: self.next_id(),
+ hir_id: self.lower_node_id(node_id),
kind: hir::ConstArgKind::Struct(path, fields),
span,
}
}
ExprKind::Array(elements) => {
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
- let const_arg = self.lower_expr_to_const_arg_direct(element);
+ let const_arg = self.lower_expr_to_const_arg_direct(element, None);
&*self.arena.alloc(const_arg)
}));
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
@@ -2781,31 +2870,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
});
ConstArg {
- hir_id: self.next_id(),
+ hir_id: self.lower_node_id(node_id),
kind: hir::ConstArgKind::Array(array_expr),
span,
}
}
ExprKind::Underscore => ConstArg {
- hir_id: self.lower_node_id(expr.id),
+ hir_id: self.lower_node_id(node_id),
kind: hir::ConstArgKind::Infer(()),
span,
},
- ExprKind::Block(block, _) => {
+ ExprKind::Block(block, _)
if let [stmt] = block.stmts.as_slice()
- && let StmtKind::Expr(expr) = &stmt.kind
- {
- return self.lower_expr_to_const_arg_direct(expr);
- }
-
- overly_complex_const(self)
+ && let StmtKind::Expr(expr) = &stmt.kind =>
+ {
+ return self.lower_expr_to_const_arg_direct(expr, id_override);
}
ExprKind::Lit(literal) => {
let span = self.lower_span(expr.span);
let literal = self.lower_lit(literal, span);
ConstArg {
- hir_id: self.lower_node_id(expr.id),
+ hir_id: self.lower_node_id(node_id),
kind: hir::ConstArgKind::Literal { lit: literal.node, negated: false },
span,
}
@@ -2816,29 +2902,45 @@ impl<'hir> LoweringContext<'_, 'hir> {
let span = self.lower_span(expr.span);
let literal = self.lower_lit(literal, span);
- if !matches!(literal.node, LitKind::Int(..)) {
+ let kind = if !matches!(literal.node, LitKind::Int(..)) {
let err =
self.dcx().struct_span_err(expr.span, "negated literal must be an integer");
-
- return ConstArg {
- hir_id: self.next_id(),
- kind: hir::ConstArgKind::Error(err.emit()),
- span,
- };
- }
-
- ConstArg {
- hir_id: self.lower_node_id(expr.id),
- kind: hir::ConstArgKind::Literal { lit: literal.node, negated: true },
- span,
- }
+ hir::ConstArgKind::Error(err.emit())
+ } else {
+ hir::ConstArgKind::Literal { lit: literal.node, negated: true }
+ };
+ ConstArg { hir_id: self.lower_node_id(node_id), kind, span }
}
ExprKind::ConstBlock(anon_const) => {
+ // Do not use lower_anon_const_to_const_arg, as that attempts to represent the body
+ // directly. Instead, force an anon const.
let def_id = self.local_def_id(anon_const.id);
assert_eq!(DefKind::InlineConst, self.tcx.def_kind(def_id));
- self.lower_anon_const_to_const_arg(anon_const, span)
+ let lowered_anon = self.lower_anon_const_to_anon_const(anon_const, span);
+ ConstArg {
+ hir_id: self.lower_node_id(node_id),
+ kind: hir::ConstArgKind::Anon(lowered_anon),
+ span,
+ }
+ }
+ ExprKind::DirectConstArg(expr) => {
+ // `can_lower_expr_to_const_arg_direct` always returns success upon encountering a
+ // ExprKind::DirectConstArg, which effectively forces the expression to be lowered
+ // as a direct arg. If it actually turns out to not be possible, emit an error
+ // instead.
+ match self.can_lower_expr_to_const_arg_direct(expr) {
+ Ok(()) => self.lower_expr_to_const_arg_direct(expr, id_override),
+ Err(err) => err.emit(self),
+ }
+ }
+ _ => {
+ span_bug!(
+ expr.span,
+ "lower_expr_to_const_arg_direct encountered an unlowerable expression, either \
+ can_lower_expr_to_const_arg_direct returned Ok() on something it shouldn't \
+ have, or you forgot to check can_lower_expr_to_const_arg_direct first"
+ );
}
- _ => overly_complex_const(self),
}
}
@@ -2857,67 +2959,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
anon: &AnonConst,
span: Span,
) -> hir::ConstArg<'hir> {
- let tcx = self.tcx;
-
- // We cannot change parsing depending on feature gates available,
- // we can only require feature gates to be active as a delayed check.
- // Thus we just parse anon consts generally and make the real decision
- // making in ast lowering.
- // FIXME(min_generic_const_args): revisit once stable
- if tcx.features().min_generic_const_args() {
- return match anon.mgca_disambiguation {
- MgcaDisambiguation::AnonConst => {
- let lowered_anon = self.lower_anon_const_to_anon_const(anon, span);
- ConstArg {
- hir_id: self.next_id(),
- kind: hir::ConstArgKind::Anon(lowered_anon),
- span: lowered_anon.span,
- }
- }
- MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value),
- };
- }
-
- // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
- // currently have to be wrapped in curly brackets, so it's necessary to special-case.
- let expr = if let ExprKind::Block(block, _) = &anon.value.kind
- && let [stmt] = block.stmts.as_slice()
- && let StmtKind::Expr(expr) = &stmt.kind
- && let ExprKind::Path(..) = &expr.kind
- {
- expr
- } else {
+ // Stable only allows one nesting of blocks for directly represented paths. mGCA allows
+ // arbitrarily many, and are handled inside lower_expr_to_const_arg_direct for consistency.
+ let expr = if self.tcx.features().min_generic_const_args() {
&anon.value
+ } else {
+ anon.value.maybe_unwrap_block()
};
- let maybe_res =
- self.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
- if let ExprKind::Path(qself, path) = &expr.kind
- && path.is_potential_trivial_const_arg()
- && matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))
- {
- let qpath = self.lower_qpath(
- expr.id,
- qself,
- path,
- ParamMode::Explicit,
- AllowReturnTypeNotation::No,
- ImplTraitContext::Disallowed(ImplTraitPosition::Path),
- None,
- );
-
- return ConstArg {
- hir_id: self.lower_node_id(anon.id),
- kind: hir::ConstArgKind::Path(qpath),
- span: self.lower_span(expr.span),
- };
+ if self.can_lower_expr_to_const_arg_direct(expr).is_ok() {
+ return self.lower_expr_to_const_arg_direct(expr, Some(anon.id));
}
let lowered_anon = self.lower_anon_const_to_anon_const(anon, anon.value.span);
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(lowered_anon),
- span: self.lower_span(expr.span),
+ span: self.lower_span(anon.value.span),
}
}
@@ -3213,3 +3271,36 @@ impl<'hir> GenericArgsCtor<'hir> {
this.arena.alloc(ga)
}
}
+
+#[derive(Debug)]
+struct UnrepresentableConstArgError {
+ span: Span,
+ will_create_def_ids: bool,
+}
+
+impl UnrepresentableConstArgError {
+ fn new(expr: &Expr) -> Self {
+ Self {
+ span: expr.span,
+ will_create_def_ids: expr::WillCreateDefIdsVisitor.visit_expr(expr).is_break(),
+ }
+ }
+
+ fn emit<'hir>(self, lowering_context: &mut LoweringContext<'_, 'hir>) -> ConstArg<'hir> {
+ let msg = "complex const arguments must be placed inside of a `const` block";
+ let e = if self.will_create_def_ids {
+ // FIXME(mgca): make this non-fatal once we have a better way to handle
+ // nested items in const args
+ // Issue: https://github.com/rust-lang/rust/issues/154539
+ lowering_context.dcx().struct_span_fatal(self.span, msg).emit()
+ } else {
+ lowering_context.dcx().struct_span_err(self.span, msg).emit()
+ };
+
+ ConstArg {
+ hir_id: lowering_context.next_id(),
+ kind: hir::ConstArgKind::Error(e),
+ span: self.span,
+ }
+ }
+}
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 06925994b052c..281f417500c55 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -16,6 +16,7 @@
//! constructions produced by proc macros. This pass is only intended for simple checks that do not
//! require name resolution or type checking, or other kinds of complex analysis.
+use std::collections::BTreeMap;
use std::mem;
use std::str::FromStr;
@@ -34,7 +35,7 @@ use rustc_session::lint::builtin::{
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
PATTERNS_IN_FNS_WITHOUT_BODY, UNUSED_VISIBILITIES,
};
-use rustc_span::{Ident, Span, kw, sym};
+use rustc_span::{Ident, Span, Symbol, kw, sym};
use rustc_target::spec::{AbiMap, AbiMapping};
use crate::diagnostics::{self, TildeConstReason};
@@ -45,6 +46,41 @@ enum SelfSemantic {
No,
}
+/// Is `#[splat]` allowed semantically in a function or closure?
+/// Only applies to the function kind and header, the parameters are checked elsewhere.
+enum SplatSemantic {
+ Yes,
+ NoClosures(Span),
+ NoAbiCall { span: Span, abi: Symbol },
+}
+
+impl SplatSemantic {
+ /// Returns if splatting is semantically allowed for the given `FnKind`,
+ /// Only checks the function kind and header, not the parameters.
+ fn from_fn_kind(fk: &FnKind<'_>) -> Self {
+ match fk {
+ FnKind::Fn(_, _, f) => Self::from_extern(f.sig.header.ext),
+ // Splatting closures is banned, because closure arguments are already de-tupled.
+ FnKind::Closure(_, _, _, expr) => SplatSemantic::NoClosures(expr.span),
+ }
+ }
+
+ fn from_extern(ext: Extern) -> Self {
+ match ext {
+ Extern::None => SplatSemantic::Yes,
+ // FIXME(splat): should splatting extern "C" or other ABIs be allowed?
+ Extern::Implicit(_) => SplatSemantic::Yes,
+ // For now, splatting rust-call is banned, because it already de-tuples args.
+ Extern::Explicit(abi_str, span) => match abi_str.symbol_unescaped {
+ sym::rust_dash_call => {
+ SplatSemantic::NoAbiCall { span, abi: abi_str.symbol_unescaped }
+ }
+ _ => SplatSemantic::Yes,
+ },
+ }
+ }
+}
+
enum TraitOrImpl {
Trait { vis: Span, constness: Const },
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
@@ -350,10 +386,15 @@ impl<'a> AstValidator<'a> {
});
}
- fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
+ fn check_fn_decl(
+ &self,
+ fn_decl: &FnDecl,
+ self_semantic: SelfSemantic,
+ splat_semantic: SplatSemantic,
+ ) {
self.check_decl_num_args(fn_decl);
let c_variadic_span = self.check_decl_cvariadic_pos(fn_decl);
- self.check_decl_splatting(fn_decl, c_variadic_span);
+ self.check_decl_splatting(fn_decl, c_variadic_span, splat_semantic);
self.check_decl_attrs(fn_decl);
self.check_decl_self_param(fn_decl, self_semantic);
}
@@ -399,42 +440,76 @@ impl<'a> AstValidator<'a> {
/// Emits an error if a function declaration has more than one splatted argument, with a
/// C-variadic parameter, or a splat at an unsupported index (for performance).
/// Example: `fn foo(#[splat] x: (), #[splat] y: ())` will emit an error.
- fn check_decl_splatting(&self, fn_decl: &FnDecl, c_variadic_span: Option) {
- let (splatted_arg_indexes, mut splatted_spans): (Vec, Vec) = fn_decl
+ fn check_decl_splatting(
+ &self,
+ fn_decl: &FnDecl,
+ c_variadic_span: Option,
+ splat_semantic: SplatSemantic,
+ ) {
+ let mut splatted_arg_spans: BTreeMap> = fn_decl
.inputs
.iter()
.enumerate()
.filter_map(|(index, arg)| {
- arg.attrs
+ let splat_arg_spans: Vec = arg
+ .attrs
.iter()
- .any(|attr| attr.has_name(sym::splat))
- .then_some((u16::try_from(index).unwrap(), arg.span))
+ .filter_map(|attr| attr.has_name(sym::splat).then_some(attr.span))
+ .collect();
+ if splat_arg_spans.is_empty() {
+ None
+ } else {
+ Some((u16::try_from(index).unwrap(), splat_arg_spans))
+ }
})
- .unzip();
+ .collect();
// A splatted argument greater than or equal to the "no splatted" marker index is not
- // supported.
- if let (Some(&splatted_arg_index), Some(&splatted_span)) =
- (splatted_arg_indexes.last(), splatted_spans.last())
- && splatted_arg_index >= u16::from(FnDecl::NO_SPLATTED_ARG_INDEX)
- {
- self.dcx().emit_err(diagnostics::InvalidSplattedArg {
- splatted_arg_index,
- span: splatted_span,
+ // supported. It is ok to drop these spans after issuing this error, because they are
+ // always invalid.
+ let out_of_range_spans =
+ splatted_arg_spans.split_off(&u16::from(FnDecl::NO_SPLATTED_ARG_INDEX));
+ if !out_of_range_spans.is_empty() {
+ self.dcx().emit_err(diagnostics::InvalidSplattedArgs {
+ max_valid_splatted_arg_index: u16::from(FnDecl::MAX_VALID_SPLATTED_ARG_INDEX),
+ first_invalid_splatted_arg_index: *out_of_range_spans.keys().next().unwrap(),
+ spans: out_of_range_spans.values().flatten().copied().collect(),
});
}
- // Multiple splatted arguments are invalid: we can't know which arguments go in each splat.
- if splatted_arg_indexes.len() > 1 {
- self.dcx()
- .emit_err(diagnostics::DuplicateSplattedArgs { spans: splatted_spans.clone() });
- }
+ if !splatted_arg_spans.is_empty() {
+ let splatted_spans = || splatted_arg_spans.values().flatten().copied().collect();
- if let Some(c_variadic_span) = c_variadic_span
- && !splatted_spans.is_empty()
- {
- splatted_spans.push(c_variadic_span);
- self.dcx().emit_err(diagnostics::CVarArgsAndSplat { spans: splatted_spans });
+ // Multiple splatted arguments are invalid: we can't know which arguments go in each splat.
+ if splatted_arg_spans.len() > 1 {
+ self.dcx().emit_err(diagnostics::DuplicateSplattedArgs { spans: splatted_spans() });
+ }
+
+ // C-variadic parameters and splats are not allowed together.
+ if let Some(c_variadic_span) = c_variadic_span {
+ let mut splatted_spans = splatted_spans();
+ splatted_spans.push(c_variadic_span);
+ self.dcx().emit_err(diagnostics::CVarArgsAndSplat { spans: splatted_spans });
+ }
+
+ // Splatting is not allowed on closures, or some function ABIs.
+ match splat_semantic {
+ SplatSemantic::NoClosures(closure_span) => {
+ let mut splatted_spans = splatted_spans();
+ splatted_spans.push(closure_span);
+ self.dcx()
+ .emit_err(diagnostics::SplatNotAllowedOnClosures { spans: splatted_spans });
+ }
+ SplatSemantic::NoAbiCall { span, abi } => {
+ let mut splatted_spans = splatted_spans();
+ splatted_spans.push(span);
+ self.dcx().emit_err(diagnostics::SplatNotAllowedOnAbiCall {
+ spans: splatted_spans,
+ abi,
+ });
+ }
+ SplatSemantic::Yes => {}
+ }
}
}
@@ -1055,7 +1130,11 @@ impl<'a> AstValidator<'a> {
match &ty.kind {
TyKind::FnPtr(bfty) => {
self.check_fn_ptr_safety(bfty.decl_span, bfty.safety);
- self.check_fn_decl(&bfty.decl, SelfSemantic::No);
+ self.check_fn_decl(
+ &bfty.decl,
+ SelfSemantic::No,
+ SplatSemantic::from_extern(bfty.ext),
+ );
Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
self.dcx().emit_err(diagnostics::PatternFnPointer { span });
});
@@ -1746,7 +1825,8 @@ impl Visitor<'_> for AstValidator<'_> {
Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
_ => SelfSemantic::No,
};
- self.check_fn_decl(fk.decl(), self_semantic);
+ let splat_semantic = SplatSemantic::from_fn_kind(&fk);
+ self.check_fn_decl(fk.decl(), self_semantic, splat_semantic);
if let Some(&FnHeader { safety, .. }) = fk.header() {
self.check_item_safety(span, safety);
diff --git a/compiler/rustc_ast_passes/src/diagnostics.rs b/compiler/rustc_ast_passes/src/diagnostics.rs
index 7a78e8e6213a5..0b610431cadd8 100644
--- a/compiler/rustc_ast_passes/src/diagnostics.rs
+++ b/compiler/rustc_ast_passes/src/diagnostics.rs
@@ -124,18 +124,22 @@ pub(crate) struct FnParamCVarArgsNotLast {
}
#[derive(Diagnostic)]
-#[diag("`#[splat]` is not supported on argument index {$splatted_arg_index}")]
+#[diag(
+ "`#[splat]` is only supported on argument index {$max_valid_splatted_arg_index} or less, this `#[splat]` is on index {$first_invalid_splatted_arg_index}"
+)]
#[help("remove `#[splat]`, or use it on an argument closer to the start of the argument list")]
-pub(crate) struct InvalidSplattedArg {
- pub splatted_arg_index: u16,
+pub(crate) struct InvalidSplattedArgs {
+ pub max_valid_splatted_arg_index: u16,
+
+ pub first_invalid_splatted_arg_index: u16,
#[primary_span]
#[label("`#[splat]` is not supported here")]
- pub span: Span,
+ pub spans: Vec,
}
#[derive(Diagnostic)]
-#[diag("multiple `#[splat]`s are not allowed in the same function")]
+#[diag("multiple `#[splat]`s are not allowed in the same function argument list")]
#[help("remove `#[splat]` from all but one argument")]
pub(crate) struct DuplicateSplattedArgs {
#[primary_span]
@@ -143,13 +147,30 @@ pub(crate) struct DuplicateSplattedArgs {
}
#[derive(Diagnostic)]
-#[diag("`...` and `#[splat]` are not allowed in the same function")]
+#[diag("`...` and `#[splat]` are not allowed in the same function argument list")]
#[help("remove `#[splat]` or remove `...`")]
pub(crate) struct CVarArgsAndSplat {
#[primary_span]
pub spans: Vec,
}
+#[derive(Diagnostic)]
+#[diag("`#[splat]` is not allowed on closure arguments")]
+#[help("remove `#[splat]` or turn the closure into a function")]
+pub(crate) struct SplatNotAllowedOnClosures {
+ #[primary_span]
+ pub spans: Vec,
+}
+
+#[derive(Diagnostic)]
+#[diag("`#[splat]` is not allowed in the arguments of functions with the `{$abi}` ABI")]
+#[help("remove `#[splat]` or change the ABI")]
+pub(crate) struct SplatNotAllowedOnAbiCall {
+ #[primary_span]
+ pub spans: Vec,
+ pub abi: Symbol,
+}
+
#[derive(Diagnostic)]
#[diag("documentation comments cannot be applied to function parameters")]
pub(crate) struct FnParamDocComment {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 106606877e110..bfca18a42635e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1459,6 +1459,12 @@ impl<'a> State<'a> {
self.print_type(ty);
self.print_view(fields);
}
+ ast::TyKind::DirectConstArg(expr) => {
+ self.word_nbsp("core::direct_const_arg!");
+ self.popen();
+ self.print_expr(expr, FixupContext::default());
+ self.pclose();
+ }
}
self.end(ib);
}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 176e91e544ec5..4f3281641359d 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -883,6 +883,12 @@ impl<'a> State<'a> {
self.word("/*DUMMY*/");
self.pclose();
}
+ ast::ExprKind::DirectConstArg(expr) => {
+ self.word_nbsp("core::direct_const_arg!");
+ self.popen();
+ self.print_expr(expr, FixupContext::default());
+ self.pclose()
+ }
}
self.ann.post(self, AnnNode::Expr(expr));
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index f15acc154baf3..1bc2bc8342559 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -323,6 +323,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
| ExprKind::Yeet(_)
| ExprKind::Become(_)
| ExprKind::Yield(_)
+ | ExprKind::DirectConstArg(_)
| ExprKind::UnsafeBinderCast(..) => {}
}
}
diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs
index 311a24280cfb7..bd5bf3a687d92 100644
--- a/compiler/rustc_builtin_macros/src/autodiff.rs
+++ b/compiler/rustc_builtin_macros/src/autodiff.rs
@@ -16,7 +16,7 @@ mod llvm_enzyme {
use rustc_ast::{
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemKind, BindingMode,
FnRetTy, FnSig, GenericArg, GenericArgs, GenericParamKind, Generics, ItemKind,
- MetaItemInner, MgcaDisambiguation, PatKind, Path, PathSegment, TyKind, Visibility,
+ MetaItemInner, PatKind, Path, PathSegment, TyKind, Visibility,
};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_hir::attrs::RustcAutodiff;
@@ -602,11 +602,7 @@ mod llvm_enzyme {
}
GenericParamKind::Const { .. } => {
let expr = ecx.expr_path(ast::Path::from_ident(p.ident));
- let anon_const = AnonConst {
- id: ast::DUMMY_NODE_ID,
- value: expr,
- mgca_disambiguation: MgcaDisambiguation::Direct,
- };
+ let anon_const = AnonConst { id: ast::DUMMY_NODE_ID, value: expr };
Some(AngleBracketedArg::Arg(GenericArg::Const(anon_const)))
}
GenericParamKind::Lifetime { .. } => None,
@@ -861,7 +857,6 @@ mod llvm_enzyme {
let anon_const = rustc_ast::AnonConst {
id: ast::DUMMY_NODE_ID,
value: ecx.expr_usize(span, 1 + x.width as usize),
- mgca_disambiguation: MgcaDisambiguation::Direct,
};
TyKind::Array(ty.clone(), anon_const)
};
@@ -876,7 +871,6 @@ mod llvm_enzyme {
let anon_const = rustc_ast::AnonConst {
id: ast::DUMMY_NODE_ID,
value: ecx.expr_usize(span, x.width as usize),
- mgca_disambiguation: MgcaDisambiguation::Direct,
};
let kind = TyKind::Array(ty.clone(), anon_const);
let ty =
diff --git a/compiler/rustc_builtin_macros/src/direct_const_arg.rs b/compiler/rustc_builtin_macros/src/direct_const_arg.rs
new file mode 100644
index 0000000000000..51c169134e03f
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/direct_const_arg.rs
@@ -0,0 +1,39 @@
+use rustc_ast::ast;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
+use rustc_span::Span;
+
+use crate::util::get_single_expr_from_tts;
+
+pub(crate) fn expand<'cx>(
+ cx: &'cx mut ExtCtxt<'_>,
+ span: Span,
+ tts: TokenStream,
+) -> MacroExpanderResult<'cx> {
+ let ExpandResult::Ready(expr) = get_single_expr_from_tts(cx, span, tts, "direct_const_arg!")
+ else {
+ return ExpandResult::Retry(());
+ };
+ let expr = match expr {
+ Ok(expr) => expr,
+ Err(err) => return ExpandResult::Ready(DummyResult::any(span, err)),
+ };
+
+ let id = ast::DUMMY_NODE_ID;
+ ExpandResult::Ready(Box::new(base::MacEager {
+ expr: Some(Box::new(ast::Expr {
+ id,
+ kind: ast::ExprKind::DirectConstArg(expr.clone()),
+ span,
+ attrs: Default::default(),
+ tokens: None,
+ })),
+ ty: Some(Box::new(ast::Ty {
+ id,
+ kind: ast::TyKind::DirectConstArg(expr),
+ span,
+ tokens: None,
+ })),
+ ..Default::default()
+ }))
+}
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index bd99b269ef5b6..78bf7d97bd7b8 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -34,6 +34,7 @@ mod define_opaque;
mod derive;
mod deriving;
mod diagnostics;
+mod direct_const_arg;
mod edition_panic;
mod eii;
mod env;
@@ -81,6 +82,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
concat_bytes: concat_bytes::expand_concat_bytes,
const_format_args: format::expand_format_args,
core_panic: edition_panic::expand_panic,
+ direct_const_arg: direct_const_arg::expand,
env: env::expand_env,
file: source_util::expand_file,
format_args: format::expand_format_args,
diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs
index 53ab3fcd9b34b..065ba9f6a2096 100644
--- a/compiler/rustc_builtin_macros/src/pattern_type.rs
+++ b/compiler/rustc_builtin_macros/src/pattern_type.rs
@@ -1,5 +1,5 @@
use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{AnonConst, DUMMY_NODE_ID, MgcaDisambiguation, Ty, TyPat, TyPatKind, ast, token};
+use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token};
use rustc_errors::PResult;
use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
use rustc_parse::exp;
@@ -60,20 +60,8 @@ fn ty_pat(kind: TyPatKind, span: Span) -> TyPat {
fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> TyPat {
let kind = match pat.kind {
ast::PatKind::Range(start, end, include_end) => TyPatKind::Range(
- start.map(|value| {
- Box::new(AnonConst {
- id: DUMMY_NODE_ID,
- value,
- mgca_disambiguation: MgcaDisambiguation::Direct,
- })
- }),
- end.map(|value| {
- Box::new(AnonConst {
- id: DUMMY_NODE_ID,
- value,
- mgca_disambiguation: MgcaDisambiguation::Direct,
- })
- }),
+ start.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })),
+ end.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })),
include_end,
),
ast::PatKind::Or(variants) => {
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 012951098fa15..ec17e72900dfb 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -220,7 +220,7 @@ fn make_local_place<'tcx>(
);
}
let place = if is_ssa {
- if let BackendRepr::ScalarPair(_, _) = layout.backend_repr {
+ if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } = layout.backend_repr {
CPlace::new_var_pair(fx, local, layout)
} else {
CPlace::new_var(fx, local, layout)
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 612f89e6a4217..75d7e4d9fd500 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -112,7 +112,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
_ => unreachable!("{:?}", self.layout.backend_repr),
},
PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr {
- BackendRepr::ScalarPair(a, b) => {
+ BackendRepr::ScalarPair { a, b, b_offset: _ } => {
let a = scalar_to_clif_type(tcx, a);
let b = scalar_to_clif_type(tcx, b);
smallvec![
@@ -167,7 +167,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
_ => unreachable!("{:?}", self.layout.backend_repr),
},
PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr {
- BackendRepr::ScalarPair(a, b) => {
+ BackendRepr::ScalarPair { a, b, b_offset: _ } => {
let a = scalar_to_clif_type(tcx, a);
let b = scalar_to_clif_type(tcx, b);
(
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index b37fb213d945a..bf6a98866cd12 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -695,7 +695,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
}
UnOp::PtrMetadata => match layout.backend_repr {
BackendRepr::Scalar(_) => CValue::zst(dest_layout),
- BackendRepr::ScalarPair(_, _) => {
+ BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => {
CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout)
}
_ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"),
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index e6b8c537d8451..d4bb8bd019331 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -572,7 +572,9 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = fx.layout_of(generic_args.type_at(0));
// Note: Can't use is_unsized here as truly unsized types need to take the fixed size
// branch
- let meta = if let BackendRepr::ScalarPair(_, _) = ptr.layout().backend_repr {
+ let meta = if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } =
+ ptr.layout().backend_repr
+ {
Some(ptr.load_scalar_pair(fx).1)
} else {
None
@@ -586,7 +588,9 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = fx.layout_of(generic_args.type_at(0));
// Note: Can't use is_unsized here as truly unsized types need to take the fixed size
// branch
- let meta = if let BackendRepr::ScalarPair(_, _) = ptr.layout().backend_repr {
+ let meta = if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } =
+ ptr.layout().backend_repr
+ {
Some(ptr.load_scalar_pair(fx).1)
} else {
None
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 995a70f24240b..d7248acfafef1 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -55,8 +55,7 @@ fn codegen_field<'tcx>(
}
}
-fn scalar_pair_calculate_b_offset(tcx: TyCtxt<'_>, a_scalar: Scalar, b_scalar: Scalar) -> Offset32 {
- let b_offset = a_scalar.size(&tcx).align_to(b_scalar.default_align(&tcx).abi);
+fn scalar_pair_convert_b_offset(b_offset: Size) -> Offset32 {
Offset32::new(b_offset.bytes().try_into().unwrap())
}
@@ -159,11 +158,11 @@ impl<'tcx> CValue<'tcx> {
let layout = self.1;
match self.0 {
CValueInner::ByRef(ptr, None) => {
- let (a_scalar, b_scalar) = match layout.backend_repr {
- BackendRepr::ScalarPair(a, b) => (a, b),
+ let (a_scalar, b_scalar, b_offset) = match layout.backend_repr {
+ BackendRepr::ScalarPair { a, b, b_offset } => (a, b, b_offset),
_ => unreachable!("load_scalar_pair({:?})", self),
};
- let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
+ let b_offset = scalar_pair_convert_b_offset(b_offset);
let clif_ty1 = scalar_to_clif_type(fx.tcx, a_scalar);
let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar);
let mut flags = MemFlags::new();
@@ -189,7 +188,7 @@ impl<'tcx> CValue<'tcx> {
match self.0 {
CValueInner::ByVal(_) => unreachable!(),
CValueInner::ByValPair(val1, val2) => match layout.backend_repr {
- BackendRepr::ScalarPair(_, _) => {
+ BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => {
let val = match field.as_u32() {
0 => val1,
1 => val2,
@@ -580,7 +579,7 @@ impl<'tcx> CPlace<'tcx> {
}
CPlaceInner::VarPair(_local, var1, var2) => {
let (data1, data2) = match from.1.backend_repr {
- BackendRepr::ScalarPair(_, _) => {
+ BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => {
CValue(from.0, dst_layout).load_scalar_pair(fx)
}
_ => {
@@ -607,9 +606,8 @@ impl<'tcx> CPlace<'tcx> {
to_ptr.store(fx, val, flags);
}
CValueInner::ByValPair(val1, val2) => match from.layout().backend_repr {
- BackendRepr::ScalarPair(a_scalar, b_scalar) => {
- let b_offset =
- scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
+ BackendRepr::ScalarPair { a: _, b: _, b_offset } => {
+ let b_offset = scalar_pair_convert_b_offset(b_offset);
to_ptr.store(fx, val1, flags);
to_ptr.offset(fx, b_offset).store(fx, val2, flags);
}
@@ -627,9 +625,8 @@ impl<'tcx> CPlace<'tcx> {
to_ptr.store(fx, val, flags);
return;
}
- BackendRepr::ScalarPair(a_scalar, b_scalar) => {
- let b_offset =
- scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
+ BackendRepr::ScalarPair { a: _, b: _, b_offset } => {
+ let b_offset = scalar_pair_convert_b_offset(b_offset);
let (val1, val2) = from.load_scalar_pair(fx);
to_ptr.store(fx, val1, flags);
to_ptr.offset(fx, b_offset).store(fx, val2, flags);
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index b5d241d8f39f2..3310e4e3a2228 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -56,13 +56,14 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
}
}
- let (ptr, vtable) = if let BackendRepr::ScalarPair(_, _) = arg.layout().backend_repr {
- let (ptr, vtable) = arg.load_scalar_pair(fx);
- (Pointer::new(ptr), vtable)
- } else {
- let (ptr, vtable) = arg.try_to_ptr().unwrap();
- (ptr, vtable.unwrap())
- };
+ let (ptr, vtable) =
+ if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } = arg.layout().backend_repr {
+ let (ptr, vtable) = arg.load_scalar_pair(fx);
+ (Pointer::new(ptr), vtable)
+ } else {
+ let (ptr, vtable) = arg.try_to_ptr().unwrap();
+ (ptr, vtable.unwrap())
+ };
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
let func_ref = fx.bcx.ins().load(
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index f9358872299b7..0bef86b1ae8c1 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1064,9 +1064,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
load
},
)
- } else if let abi::BackendRepr::ScalarPair(ref a, ref b) = place.layout.backend_repr {
- let b_offset = a.size(self).align_to(b.default_align(self).abi);
-
+ } else if let abi::BackendRepr::ScalarPair { ref a, ref b, b_offset } =
+ place.layout.backend_repr
+ {
let mut load = |i, scalar: &abi::Scalar, align| {
let ptr = if i == 0 {
place.val.llval
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 78a4c7e88c895..a5b8068e0f018 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -485,7 +485,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
let tp_ty = fn_args.type_at(0);
let layout = self.layout_of(tp_ty).layout;
let _use_integer_compare = match layout.backend_repr() {
- Scalar(_) | ScalarPair(_, _) => true,
+ Scalar(_) | ScalarPair { a: _, b: _, b_offset: _ } => true,
SimdVector { .. } | SimdScalableVector { .. } => false,
Memory { .. } => {
// For rusty ABIs, small aggregates are actually passed
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 9807a84c0788d..227b513c0ff30 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -75,7 +75,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(
};
return cx.context.new_vector_type(element, count);
}
- BackendRepr::ScalarPair(..) => {
+ BackendRepr::ScalarPair { .. } => {
return cx.type_struct(
&[
layout.scalar_pair_element_gcc_type(cx, 0),
@@ -182,13 +182,13 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true,
// FIXME(rustc_scalable_vector): Not yet implemented in rustc_codegen_gcc.
BackendRepr::SimdScalableVector { .. } => todo!(),
- BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false,
+ BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => false,
}
}
fn is_gcc_scalar_pair(&self) -> bool {
match self.backend_repr {
- BackendRepr::ScalarPair(..) => true,
+ BackendRepr::ScalarPair { .. } => true,
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. }
@@ -308,8 +308,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
// This must produce the same result for `repr(transparent)` wrappers as for the inner type!
// In other words, this should generally not look at the type at all, but only at the
// layout.
- let (a, b) = match self.backend_repr {
- BackendRepr::ScalarPair(ref a, ref b) => (a, b),
+ let (a, b, b_offset) = match self.backend_repr {
+ BackendRepr::ScalarPair { ref a, ref b, b_offset } => (a, b, b_offset),
_ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self),
};
let scalar = [a, b][index];
@@ -325,8 +325,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
return cx.type_i1();
}
- let offset =
- if index == 0 { Size::ZERO } else { a.size(cx).align_to(b.default_align(cx).abi) };
+ let offset = if index == 0 { Size::ZERO } else { b_offset };
self.scalar_gcc_type_at(cx, scalar, offset)
}
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index bdaf72cb17ce6..65bb32ee666f2 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -551,7 +551,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
PassMode::Pair(a, b) => {
let i = apply(a);
let ii = apply(b);
- if let BackendRepr::ScalarPair(scalar_a, scalar_b) = arg.layout.backend_repr {
+ if let BackendRepr::ScalarPair { a: scalar_a, b: scalar_b, b_offset: _ } =
+ arg.layout.backend_repr
+ {
apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a);
let primitive_b = scalar_b.primitive();
let scalar_b = if let rustc_abi::Primitive::Int(int, false) = primitive_b
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 23cf01a84f7fd..e753fff61aa41 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -793,9 +793,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
});
OperandValue::Immediate(llval)
- } else if let abi::BackendRepr::ScalarPair(a, b) = place.layout.backend_repr {
- let b_offset = a.size(self).align_to(b.default_align(self).abi);
-
+ } else if let abi::BackendRepr::ScalarPair { a, b, b_offset } = place.layout.backend_repr {
let mut load = |i, scalar: abi::Scalar, layout, align, offset| {
let llptr = if i == 0 {
place.val.llval
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 10e152a7c8c63..b0ac5c096efdf 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -118,7 +118,9 @@ pub(crate) fn adjust_activity_to_abi<'tcx>(
// If the argument is lowered as a `ScalarPair`, we need to duplicate its activity.
// Otherwise, the number of activities won't match the number of LLVM arguments and
// this will lead to errors when verifying the Enzyme call.
- if let rustc_abi::BackendRepr::ScalarPair(_, _) = layout.backend_repr() {
+ if let rustc_abi::BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } =
+ layout.backend_repr()
+ {
new_activities.push(da[i].clone());
new_positions.push(i + 1 - del_activities);
}
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index bd7a4cfe38d48..54456ddea620b 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -574,7 +574,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
let tp_ty = fn_args.type_at(0);
let layout = self.layout_of(tp_ty).layout;
let use_integer_compare = match layout.backend_repr() {
- Scalar(_) | ScalarPair(_, _) => true,
+ Scalar(_) | ScalarPair { a: _, b: _, b_offset: _ } => true,
SimdVector { .. } => false,
SimdScalableVector { .. } => {
let err = tcx.dcx().emit_err(InvalidMonomorphization::NonScalableType {
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 6d0490e4a1f79..d1c2e1d567e40 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -73,7 +73,7 @@ fn uncached_llvm_type<'a, 'tcx>(
_ => bug!("`#[rustc_scalable_vector]` tuple struct with too many fields"),
};
}
- BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {}
+ BackendRepr::Memory { .. } | BackendRepr::ScalarPair { .. } => {}
}
let name = match layout.ty.kind() {
@@ -228,13 +228,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. } => true,
- BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false,
+ BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => false,
}
}
fn is_llvm_scalar_pair(&self) -> bool {
match self.backend_repr {
- BackendRepr::ScalarPair(..) => true,
+ BackendRepr::ScalarPair { .. } => true,
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. }
@@ -313,7 +313,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
return cx.type_i1();
}
}
- BackendRepr::ScalarPair(..) => {
+ BackendRepr::ScalarPair { .. } => {
// An immediate pair always contains just the two elements, without any padding
// filler, as it should never be stored to memory.
return cx.type_struct(
@@ -346,7 +346,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
// This must produce the same result for `repr(transparent)` wrappers as for the inner type!
// In other words, this should generally not look at the type at all, but only at the
// layout.
- let BackendRepr::ScalarPair(a, b) = self.backend_repr else {
+ let BackendRepr::ScalarPair { a, b, b_offset: _ } = self.backend_repr else {
bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self);
};
let scalar = [a, b][index];
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index b8d1cd3504517..d2583f94cf80c 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -564,7 +564,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
BackendRepr::Scalar(scalar) => {
registers_for_primitive(scalar.primitive());
}
- BackendRepr::ScalarPair(scalar1, scalar2) => {
+ BackendRepr::ScalarPair { a: scalar1, b: scalar2, b_offset: _ } => {
registers_for_primitive(scalar1.primitive());
registers_for_primitive(scalar2.primitive());
}
@@ -641,7 +641,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
}
Primitive::Float(_) => bx.inbounds_ptradd(reg_save_area_v, fp_offset_v),
},
- BackendRepr::ScalarPair(scalar1, scalar2) => {
+ BackendRepr::ScalarPair { a: scalar1, b: scalar2, b_offset: offset } => {
let ty_lo = bx.cx().scalar_pair_element_backend_type(layout, 0, false);
let ty_hi = bx.cx().scalar_pair_element_backend_type(layout, 1, false);
@@ -665,9 +665,8 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
let reg_lo = bx.load(ty_lo, reg_lo_addr, align_lo);
let reg_hi = bx.load(ty_hi, reg_hi_addr, align_hi);
- let offset = scalar1.size(bx.cx).align_to(align_hi).bytes();
let field0 = tmp;
- let field1 = bx.inbounds_ptradd(tmp, bx.const_u32(offset as u32));
+ let field1 = bx.inbounds_ptradd(tmp, bx.const_u32(offset.bytes() as u32));
bx.store(reg_lo, field0, align);
bx.store(reg_hi, field1, align);
@@ -688,9 +687,8 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
let reg_lo = bx.load(ty_lo, reg_lo_addr, align_lo);
let reg_hi = bx.load(ty_hi, reg_hi_addr, align_hi);
- let offset = scalar1.size(bx.cx).align_to(align_hi).bytes();
let field0 = tmp;
- let field1 = bx.inbounds_ptradd(tmp, bx.const_u32(offset as u32));
+ let field1 = bx.inbounds_ptradd(tmp, bx.const_u32(offset.bytes() as u32));
bx.store(reg_lo, field0, align_lo);
bx.store(reg_hi, field1, align_hi);
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 4e979df471318..b9684eb52f3f4 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -877,12 +877,16 @@ pub fn codegen_crate<
/// Returns whether a call from the current crate to the [`Instance`] would produce a call
/// from `compiler_builtins` to a symbol the linker must resolve.
///
-/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
+/// Such calls from `compiler_builtins` are effectively impossible for the linker to handle. Some
/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
-/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
+/// not guaranteed. So we use this function in codegen backends to ensure we do not generate any
/// unlinkable calls.
///
/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
+/// Note also that calls to foreign items that are actually exported by the local crate are also
+/// okay. This situation arises because compiler-builtins calls functions in core that are
+/// `#[inline]` wrappers for `extern "C"` declarations in core, which resolve to a symbol exported
+/// by compiler-builtins.
pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
@@ -895,11 +899,19 @@ pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
}
}
+ fn is_extern_call_to_local_crate<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
+ tcx.is_foreign_item(instance.def_id())
+ && tcx.exported_non_generic_symbols(LOCAL_CRATE).iter().any(|(sym, _info)| {
+ sym.symbol_name_for_local_instance(tcx) == tcx.symbol_name(instance)
+ })
+ }
+
let def_id = instance.def_id();
!def_id.is_local()
&& tcx.is_compiler_builtins(LOCAL_CRATE)
&& !is_llvm_intrinsic(tcx, def_id)
&& !tcx.should_codegen_locally(instance)
+ && !is_extern_call_to_local_crate(tcx, instance)
}
impl CrateInfo {
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 71315acc4e5db..c586b8080ef30 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -611,7 +611,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// be marked as a `LocalVariable` for MSVC debuggers to visualize
// their data correctly. (See #81894 & #88625)
let var_ty_layout = self.cx.layout_of(var_ty);
- if let BackendRepr::ScalarPair(_, _) = var_ty_layout.backend_repr {
+ if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } =
+ var_ty_layout.backend_repr
+ {
VariableKind::LocalVariable
} else {
VariableKind::ArgumentVariable(arg_index)
diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
index 0b00b22b1a992..9ce8e6e48bbd1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
@@ -441,7 +441,7 @@ fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_t
signature.push_str(direct_type);
}
PassMode::Pair(_, _) => match arg_abi.layout.backend_repr {
- BackendRepr::ScalarPair(a, b) => {
+ BackendRepr::ScalarPair { a, b, b_offset: _ } => {
signature.push_str(wasm_primitive(a.primitive(), ptr_type));
signature.push_str(", ");
signature.push_str(wasm_primitive(b.primitive(), ptr_type));
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 0246da3f27829..f2594b712d8cd 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -168,7 +168,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
}
ConstValue::ZeroSized => return OperandRef::zero_sized(layout),
ConstValue::Slice { alloc_id, meta } => {
- let BackendRepr::ScalarPair(a_scalar, _) = layout.backend_repr else {
+ let BackendRepr::ScalarPair { a: a_scalar, b: _, b_offset: _ } =
+ layout.backend_repr
+ else {
bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
};
let a = Scalar::from_pointer(Pointer::new(alloc_id.into(), Size::ZERO), &bx.tcx());
@@ -222,12 +224,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout));
OperandRef { val: OperandValue::Immediate(val), layout, move_annotation: None }
}
- BackendRepr::ScalarPair(
- a @ abi::Scalar::Initialized { .. },
- b @ abi::Scalar::Initialized { .. },
- ) => {
+ BackendRepr::ScalarPair {
+ a: a @ abi::Scalar::Initialized { .. },
+ b: b @ abi::Scalar::Initialized { .. },
+ b_offset,
+ } => {
let (a_size, b_size) = (a.size(bx), b.size(bx));
- let b_offset = (offset + a_size).align_to(b.default_align(bx).abi);
assert!(b_offset.bytes() > 0);
let a_val = read_scalar(
offset,
@@ -345,7 +347,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
llval: V,
layout: TyAndLayout<'tcx>,
) -> Self {
- let val = if let BackendRepr::ScalarPair(..) = layout.backend_repr {
+ let val = if let BackendRepr::ScalarPair { .. } = layout.backend_repr {
debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout);
// Deconstruct the immediate aggregate.
@@ -383,12 +385,15 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
} else {
let (in_scalar, imm) = match (self.val, self.layout.backend_repr) {
// Extract a scalar component from a pair.
- (OperandValue::Pair(a_llval, b_llval), BackendRepr::ScalarPair(a, b)) => {
+ (
+ OperandValue::Pair(a_llval, b_llval),
+ BackendRepr::ScalarPair { a, b, b_offset },
+ ) => {
if offset.bytes() == 0 {
assert_eq!(field.size, a.size(bx.cx()));
(Some(a), a_llval)
} else {
- assert_eq!(offset, a.size(bx.cx()).align_to(b.default_align(bx.cx()).abi));
+ assert_eq!(offset, b_offset);
assert_eq!(field.size, b.size(bx.cx()));
(Some(b), b_llval)
}
@@ -419,7 +424,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
imm
}
}
- BackendRepr::ScalarPair(_, _)
+ BackendRepr::ScalarPair { a: _, b: _, b_offset: _ }
| BackendRepr::Memory { .. }
| BackendRepr::SimdScalableVector { .. } => bug!(),
})
@@ -705,7 +710,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> {
let val = match layout.backend_repr {
BackendRepr::Memory { .. } if layout.is_zst() => OperandValueBuilder::ZeroSized,
BackendRepr::Scalar(s) => OperandValueBuilder::Immediate(Either::Right(s)),
- BackendRepr::ScalarPair(a, b) => {
+ BackendRepr::ScalarPair { a, b, b_offset: _ } => {
OperandValueBuilder::Pair(Either::Right(a), Either::Right(b))
}
BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => {
@@ -733,7 +738,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> {
(OperandValue::Immediate(v), BackendRepr::SimdVector { .. }) => {
OperandValueBuilder::Vector(Either::Left(v))
}
- (OperandValue::Pair(a, b), BackendRepr::ScalarPair(_, _)) => {
+ (OperandValue::Pair(a, b), BackendRepr::ScalarPair { a: _, b: _, b_offset: _ }) => {
OperandValueBuilder::Pair(Either::Left(a), Either::Left(b))
}
(_, BackendRepr::Memory { .. }) => {
@@ -810,17 +815,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> {
bug!("Tried to insert {field_operand:?} into {variant:?}.{field:?} of {self:?}")
}
},
- (OperandValue::Pair(a, b), BackendRepr::ScalarPair(from_sa, from_sb)) => {
- match &mut self.val {
- OperandValueBuilder::Pair(fst @ Either::Right(_), snd @ Either::Right(_)) => {
- update(fst, a, from_sa);
- update(snd, b, from_sb);
- }
- _ => bug!(
- "Tried to insert {field_operand:?} into {variant:?}.{field:?} of {self:?}"
- ),
+ (
+ OperandValue::Pair(a, b),
+ BackendRepr::ScalarPair { a: from_sa, b: from_sb, b_offset: _ },
+ ) => match &mut self.val {
+ OperandValueBuilder::Pair(fst @ Either::Right(_), snd @ Either::Right(_)) => {
+ update(fst, a, from_sa);
+ update(snd, b, from_sb);
}
- }
+ _ => {
+ bug!("Tried to insert {field_operand:?} into {variant:?}.{field:?} of {self:?}")
+ }
+ },
(OperandValue::Ref(place), BackendRepr::Memory { .. }) => match &mut self.val {
OperandValueBuilder::Vector(val @ Either::Right(())) => {
let ibty = bx.cx().immediate_backend_type(self.layout);
@@ -1008,10 +1014,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue {
bx.store_with_flags(val, dest.val.llval, dest.val.align, flags);
}
OperandValue::Pair(a, b) => {
- let BackendRepr::ScalarPair(a_scalar, b_scalar) = dest.layout.backend_repr else {
+ let BackendRepr::ScalarPair { a: _, b: _, b_offset } = dest.layout.backend_repr
+ else {
bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout);
};
- let b_offset = a_scalar.size(bx).align_to(b_scalar.default_align(bx).abi);
let val = bx.from_immediate(a);
let align = dest.val.align;
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 49f03fe1376e2..f417dfba746f1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -36,7 +36,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// semantics regarding when assignment operators allow overlap of LHS and RHS.
if matches!(
cg_operand.layout.backend_repr,
- BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..),
+ BackendRepr::Scalar(..) | BackendRepr::ScalarPair { .. },
) {
debug_assert!(!matches!(cg_operand.val, OperandValue::Ref(..)));
}
@@ -323,9 +323,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
(
OperandValue::Pair(imm_a, imm_b),
- abi::BackendRepr::ScalarPair(in_a, in_b),
- abi::BackendRepr::ScalarPair(out_a, out_b),
- ) if in_a.size(cx) == out_a.size(cx) && in_b.size(cx) == out_b.size(cx) => {
+ abi::BackendRepr::ScalarPair { a: in_a, b: in_b, b_offset: in_offset },
+ abi::BackendRepr::ScalarPair { a: out_a, b: out_b, b_offset: out_offset },
+ ) if in_a.size(cx) == out_a.size(cx)
+ && in_b.size(cx) == out_b.size(cx)
+ && in_offset == out_offset =>
+ {
OperandValue::Pair(
transmute_scalar(bx, imm_a, in_a, out_a),
transmute_scalar(bx, imm_b, in_b, out_b),
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 1b6c948657e0d..7295df0ab2210 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -136,7 +136,7 @@ fn const_to_valtree_inner<'tcx>(
let val = ecx.read_immediate(place).report_err()?;
// We could allow wide raw pointers where both sides are integers in the future,
// but for now we reject them.
- if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) {
+ if matches!(val.layout.backend_repr, BackendRepr::ScalarPair { .. }) {
Err(ValTreeCreationError::NonSupportedType(ty))
} else {
let val = val.to_scalar();
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 1f67b896fc8ec..0c1e171c0edc9 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -84,7 +84,7 @@ impl Immediate {
pub fn to_scalar(self) -> Scalar {
match self {
Immediate::Scalar(val) => val,
- Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"),
+ Immediate::ScalarPair { .. } => bug!("Got a scalar pair where a scalar was expected"),
Immediate::Uninit => bug!("Got uninit where a scalar was expected"),
}
}
@@ -129,7 +129,10 @@ impl Immediate {
);
}
}
- (Immediate::ScalarPair(a_val, b_val), BackendRepr::ScalarPair(a, b)) => {
+ (
+ Immediate::ScalarPair(a_val, b_val),
+ BackendRepr::ScalarPair { a, b, b_offset: _ },
+ ) => {
assert_eq!(
a_val.size(),
a.size(cx),
@@ -263,7 +266,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
#[inline]
pub fn from_scalar_pair(a: Scalar, b: Scalar, layout: TyAndLayout<'tcx>) -> Self {
debug_assert!(
- matches!(layout.backend_repr, BackendRepr::ScalarPair(..)),
+ matches!(layout.backend_repr, BackendRepr::ScalarPair { .. }),
"`ImmTy::from_scalar_pair` on non-scalar-pair layout"
);
let imm = Immediate::ScalarPair(a, b);
@@ -276,7 +279,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
debug_assert!(
match (imm, layout.backend_repr) {
(Immediate::Scalar(..), BackendRepr::Scalar(..)) => true,
- (Immediate::ScalarPair(..), BackendRepr::ScalarPair(..)) => true,
+ (Immediate::ScalarPair { .. }, BackendRepr::ScalarPair { .. }) => true,
(Immediate::Uninit, _) if layout.is_sized() => true,
_ => false,
},
@@ -415,14 +418,15 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
**self
}
// extract fields from types with `ScalarPair` ABI
- (Immediate::ScalarPair(a_val, b_val), BackendRepr::ScalarPair(a, b)) => {
- Immediate::from(if offset.bytes() == 0 {
- a_val
- } else {
- assert_eq!(offset, a.size(cx).align_to(b.default_align(cx).abi));
- b_val
- })
- }
+ (
+ Immediate::ScalarPair(a_val, b_val),
+ BackendRepr::ScalarPair { a: _, b: _, b_offset },
+ ) => Immediate::from(if offset.bytes() == 0 {
+ a_val
+ } else {
+ assert_eq!(offset, b_offset);
+ b_val
+ }),
// everything else is a bug
_ => bug!(
"invalid field access on immediate {} at offset {}, original layout {:#?}",
@@ -606,15 +610,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
)?;
Some(ImmTy::from_scalar(scalar, mplace.layout))
}
- BackendRepr::ScalarPair(
- abi::Scalar::Initialized { value: a, .. },
- abi::Scalar::Initialized { value: b, .. },
- ) => {
+ BackendRepr::ScalarPair {
+ a: abi::Scalar::Initialized { value: a, .. },
+ b: abi::Scalar::Initialized { value: b, .. },
+ b_offset,
+ } => {
// We checked `ptr_align` above, so all fields will have the alignment they need.
// We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
let (a_size, b_size) = (a.size(self), b.size(self));
- let b_offset = a_size.align_to(b.default_align(self).abi);
assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields
let a_val = alloc.read_scalar(
alloc_range(Size::ZERO, a_size),
@@ -668,10 +672,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
if !matches!(
op.layout().backend_repr,
BackendRepr::Scalar(abi::Scalar::Initialized { .. })
- | BackendRepr::ScalarPair(
- abi::Scalar::Initialized { .. },
- abi::Scalar::Initialized { .. }
- )
+ | BackendRepr::ScalarPair {
+ a: abi::Scalar::Initialized { .. },
+ b: abi::Scalar::Initialized { .. },
+ b_offset: _,
+ }
) {
span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty);
}
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index d6d73b2d8da81..0c786c5831676 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -713,7 +713,6 @@ where
// to handle padding properly, which is only correct if we never look at this data with the
// wrong type.
- let tcx = *self.tcx;
let will_later_validate = M::enforce_validity(self, layout);
let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout })? else {
// zero-sized access
@@ -725,7 +724,7 @@ where
alloc.write_scalar(alloc_range(Size::ZERO, scalar.size()), scalar)?;
}
Immediate::ScalarPair(a_val, b_val) => {
- let BackendRepr::ScalarPair(_a, b) = layout.backend_repr else {
+ let BackendRepr::ScalarPair { a: _, b: _, b_offset } = layout.backend_repr else {
span_bug!(
self.cur_span(),
"write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
@@ -733,7 +732,7 @@ where
)
};
let a_size = a_val.size();
- let b_offset = a_size.align_to(b.default_align(&tcx).abi);
+ let b_size = b_val.size();
assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields
// It is tempting to verify `b_offset` against `layout.fields.offset(1)`,
@@ -744,12 +743,12 @@ where
// destination now to ensure that no stray pointer fragments are being
// preserved (see ).
// We can skip this if there is no padding (e.g. for wide pointers).
- if !will_later_validate && a_size + b_val.size() != layout.size {
+ if !will_later_validate && a_size + b_size != layout.size {
alloc.write_uninit_full();
}
alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?;
- alloc.write_scalar(alloc_range(b_offset, b_val.size()), b_val)?;
+ alloc.write_scalar(alloc_range(b_offset, b_size), b_val)?;
}
Immediate::Uninit => alloc.write_uninit_full(),
}
@@ -902,17 +901,19 @@ where
// padding in the target independent of layout choices.
let src_has_padding = match src.layout().backend_repr {
BackendRepr::Scalar(_) => false,
- BackendRepr::ScalarPair(left, right)
+ BackendRepr::ScalarPair { a: left, b: right, b_offset: _ }
if matches!(src.layout().ty.kind(), ty::Ref(..) | ty::RawPtr(..)) =>
{
// Wide pointers never have padding, so we can avoid calling `size()`.
debug_assert_eq!(left.size(self) + right.size(self), src.layout().size);
false
}
- BackendRepr::ScalarPair(left, right) => {
+ BackendRepr::ScalarPair { a: left, b: right, b_offset: _ } => {
let left_size = left.size(self);
let right_size = right.size(self);
// We have padding if the sizes don't add up to the total.
+ // (Why don't we need to check the offset? The scalars don't overlap so no padding
+ // implies `b_offset == left_size`, which would be superfluous to check explicitly.)
left_size + right_size != src.layout().size
}
// Everything else can only exist in memory anyway, so it doesn't matter.
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 262ef6ba74ed0..2d412e1124e5a 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -1397,7 +1397,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
self.path,
Uninit { expected }
),
- Immediate::Scalar(..) | Immediate::ScalarPair(..) =>
+ Immediate::Scalar(..) | Immediate::ScalarPair { .. } =>
bug!("arrays/slices can never have Scalar/ScalarPair layout"),
}
};
@@ -1486,7 +1486,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
self.visit_scalar(scalar, scalar_layout)?;
}
}
- BackendRepr::ScalarPair(a_layout, b_layout) => {
+ BackendRepr::ScalarPair { a: a_layout, b: b_layout, b_offset: _ } => {
// We can only proceed if *both* scalars need to be initialized.
// FIXME: find a way to also check ScalarPair when one side can be uninit but
// the other must be init.
@@ -1545,7 +1545,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
.expect("the above checks should have fully handled this situation");
}
}
- BackendRepr::ScalarPair(a_layout, b_layout) => {
+ BackendRepr::ScalarPair { a: a_layout, b: b_layout, b_offset: _ } => {
// We can only proceed if *both* scalars need to be initialized.
// FIXME: find a way to also check ScalarPair when one side can be uninit but
// the other must be init.
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index 00835a3cc990a..64688f56fe763 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -121,7 +121,7 @@ fn check_validity_requirement_lax<'tcx>(
let valid = !this.is_uninhabited() // definitely UB if uninhabited
&& match this.backend_repr {
BackendRepr::Scalar(s) => scalar_allows_raw_init(s),
- BackendRepr::ScalarPair(s1, s2) => {
+ BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } => {
scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2)
}
BackendRepr::SimdVector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 01886a97f55a2..f3792d4d45235 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -2,8 +2,8 @@ use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::util::literal;
use rustc_ast::{
- self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind,
- MgcaDisambiguation, PatKind, UnOp, attr, token, tokenstream,
+ self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind,
+ UnOp, attr, token, tokenstream,
};
use rustc_span::{DUMMY_SP, Ident, Span, Spanned, Symbol, kw, sym};
use thin_vec::{ThinVec, thin_vec};
@@ -100,7 +100,6 @@ impl<'a> ExtCtxt<'a> {
attrs: AttrVec::new(),
tokens: None,
}),
- mgca_disambiguation: MgcaDisambiguation::Direct,
}
}
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 8bded7662f423..641c50b620ff5 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -696,11 +696,15 @@ impl TtParser {
}
fn ambiguity_error<'matcher, T: Tracker<'matcher>>(
- &self,
+ &mut self,
parser: &Parser<'_>,
matcher: &'matcher [MatcherLoc],
track: &mut T,
) -> NamedParseResult {
+ // Use a reasonable and deterministic ordering for data in the error message.
+ self.bb_mps.sort_unstable_by_key(|mp| mp.idx);
+ self.next_mps.sort_unstable_by_key(|mp| mp.idx);
+
let bb_locs = self.bb_mps.iter().map(|mp| &matcher[mp.idx]);
let next_locs = self.next_mps.iter().map(|mp| &matcher[mp.idx]);
track.ambiguity(parser, bb_locs, next_locs);
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 811ed83e0bf48..d6a5db4c22f24 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -214,6 +214,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
"synthetic HIR should have its `generics_of` explicitly fed"
),
+ Node::ConstArg(..) => {
+ // These can show up in mGCA when representing "direct" const arguments. The
+ // DefCollector cannot know whether an anon const will be represented by an actual HIR
+ // Node::AnonConst, or whether it will be represented directly, so it must generate a
+ // DefId. If it ends up being direct, this DefId is then attached to the top-level
+ // ConstArg, which is what we are seeing here.
+ debug_assert!(tcx.features().min_generic_const_args());
+ // Forward to the real parent.
+ Some(tcx.local_parent(def_id))
+ }
+
_ => span_bug!(tcx.def_span(def_id), "generics_of: unexpected node kind {node:?}"),
};
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 1b6f366b9d133..e7b25dec4db59 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -299,7 +299,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
formal_input_tys,
provided_args,
expected_input_tys,
- c_variadic,
tuple_arguments,
fn_def_id,
callee_generic_args,
@@ -573,10 +572,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
provided_args: &'tcx [hir::Expr<'tcx>],
// The expected input types from the context of the call site
mut expected_input_tys: Option>>,
- // Whether the function is variadic (e.g. from C)
- c_variadic: bool,
- // Whether all the arguments have been bundled in a tuple (ex: closures).
- // Splatting is handled separately.
+ // Whether all the arguments have been bundled in a tuple (ex: closures), or one has been splatted
tuple_arguments: TupleArgumentsFlag,
// The DefId for the function being called, for better error messages
fn_def_id: Option,
@@ -592,6 +588,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
untupled_expected_input_tys: expected_input_tys,
};
};
+ let first_tupled_arg_index_usz = usize::from(first_tupled_arg_index);
// The argument difference can range from -1 to u16::MAX - 1, so we count the number
// of tupled arguments instead.
@@ -604,28 +601,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let tupled_args_count = (1 + provided_args.len()).checked_sub(formal_input_tys.len());
debug!(
?first_tupled_arg_index, ?is_self_splatted,
- ?tupled_args_count, ?tuple_arguments, ?c_variadic,
+ ?tupled_args_count, ?tuple_arguments,
provided_args_len = ?provided_args.len(), formal_input_tys_len = ?formal_input_tys.len()
);
// If earlier code has modified the FnSig argument list without adjusting the splatted
// argument, indexing into the formal input types will panic.
- if first_tupled_arg_index >= formal_input_tys.len() {
+ if first_tupled_arg_index_usz >= formal_input_tys.len() {
span_bug!(
call_span,
"splatted argument index is out of bounds: {first_tupled_arg_index:?} >= {}, \
is_self_splatted = {is_self_splatted:?}, \
tupled_args_count = {tupled_args_count:?}, {tuple_arguments:?}, \
- c_variadic = {c_variadic:?}, provided_args: {}",
+ provided_args: {}",
formal_input_tys.len(),
provided_args.len(),
);
}
+ let formal_input_tupled_ty = formal_input_tys[first_tupled_arg_index_usz];
// Keep the type variable if the argument is splatted, so we can force it to be a tuple later.
let tuple_type = if tuple_arguments.is_splatted() {
- let callee_tuple_type =
- self.resolve_vars_with_obligations(formal_input_tys[first_tupled_arg_index]);
+ let callee_tuple_type = self.resolve_vars_with_obligations(formal_input_tupled_ty);
if callee_tuple_type.is_ty_var()
&& let Some(tupled_args_count) = tupled_args_count
{
@@ -674,7 +671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
callee_tuple_type
}
} else {
- self.structurally_resolve_type(call_span, formal_input_tys[first_tupled_arg_index])
+ self.structurally_resolve_type(call_span, formal_input_tupled_ty)
};
// We expected a tuple and got a tuple (or made one ourselves).
@@ -687,7 +684,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err_code = Some(E0057);
}
if let Some(ref mut expected_input_tys) = expected_input_tys
- && let Some(ty) = expected_input_tys.get(first_tupled_arg_index)
+ && let Some(ty) = expected_input_tys.get(first_tupled_arg_index_usz)
&& let ty::Tuple(detup_expected_arg_tys) = ty.kind()
{
let substitute_tys = if Some(detup_expected_arg_tys.len()) == tupled_args_count {
@@ -697,26 +694,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
detup_formal_arg_tys.iter()
};
- expected_input_tys
- .splice(first_tupled_arg_index..=first_tupled_arg_index, substitute_tys);
+ expected_input_tys.splice(
+ first_tupled_arg_index_usz..=first_tupled_arg_index_usz,
+ substitute_tys,
+ );
} else {
expected_input_tys = None;
}
- // If splatting, record this call in a side-table, so MIR lowering can tuple the caller's arguments
- if tuple_arguments.is_splatted() {
- // FIXME(const_trait_impl): does not enforce constness yet
- self.write_splatted_call(
- call_expr.hir_id,
- call_span,
- fn_def_id,
- callee_generic_args,
- first_tupled_arg_index.try_into().unwrap(),
- tupled_args_count.unwrap().try_into().unwrap(),
- );
- }
-
formal_input_tys.splice(
- first_tupled_arg_index..=first_tupled_arg_index,
+ first_tupled_arg_index_usz..=first_tupled_arg_index_usz,
detup_formal_arg_tys.iter(),
);
if let Some(ref expected_input_tys) = expected_input_tys {
@@ -724,7 +710,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
formal_input_tys.len(),
expected_input_tys.len(),
"incorrectly constructed input type tuples, argument counts must match: \
- tuple_arguments: {tuple_arguments:?}",
+ tuple_arguments: {tuple_arguments:?}, \
+ first_tupled_arg_index: {first_tupled_arg_index}",
)
}
}
@@ -751,7 +738,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let spans = if let Some(def_id) = fn_def_id
&& let Some(hir_node) = self.tcx.hir_get_if_local(def_id)
&& let Some(fn_decl) = hir_node.fn_decl()
- && let Some(arg_ty) = fn_decl.inputs.get(first_tupled_arg_index)
+ && let Some(arg_ty) = fn_decl.inputs.get(first_tupled_arg_index_usz)
{
let arg_def_span = arg_ty.span;
vec![call_span, arg_def_span]
@@ -768,7 +755,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
tuple_type.kind(),
self.structurally_resolve_type(
call_span,
- formal_input_tys[first_tupled_arg_index]
+ formal_input_tys[first_tupled_arg_index_usz]
)
.kind(),
)
@@ -803,6 +790,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
untupled_expected_input_tys: None,
}
} else {
+ // If splatting, record this call in a side-table, so MIR lowering can tuple the caller's arguments
+ if tuple_arguments.is_splatted() {
+ // FIXME(const_trait_impl): does not enforce constness yet
+ self.write_splatted_call(
+ call_expr.hir_id,
+ call_span,
+ fn_def_id,
+ callee_generic_args,
+ first_tupled_arg_index,
+ tupled_args_count.unwrap().try_into().unwrap(),
+ );
+ }
+
TupledArgCheckOutcome {
new_err_code: err_code,
untupled_formal_input_tys: formal_input_tys,
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 6b5f084fc3dbe..85fdb9b6fe450 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -666,9 +666,9 @@ impl TupleArgumentsFlag {
/// Returns the tupled argument index, and whether the `self` argument is splatted.
/// Returns `None` if the arguments are not tupled, or if the `self` argument is splatted.
- fn tupled_arg_index(self) -> (Option, bool /* is_self_splatted */) {
+ fn tupled_arg_index(self) -> (Option, bool /* is_self_splatted */) {
match self {
- Self::TupleSplattedArg(index) => (Some(usize::from(index)), false),
+ Self::TupleSplattedArg(index) => (Some(u16::from(index)), false),
Self::TupleAllCallArgs => (Some(0), false),
Self::TupleSplattedSelfArg => (None, true),
Self::DontTupleArguments => (None, false),
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index ee6e13250e709..12c577d3a50e2 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -5,10 +5,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::def_id::DefId;
use rustc_middle::bug;
use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{
- self, InferConst, Term, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
- TypeVisitor,
-};
+use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
use tracing::{debug, instrument, warn};
@@ -362,45 +359,6 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
-/// Finds the max universe present
-struct MaxUniverse {
- max_universe: ty::UniverseIndex,
-}
-
-impl MaxUniverse {
- fn new() -> Self {
- MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
- }
-
- fn max_universe(self) -> ty::UniverseIndex {
- self.max_universe
- }
-}
-
-impl<'tcx> TypeVisitor> for MaxUniverse {
- fn visit_ty(&mut self, t: Ty<'tcx>) {
- if let ty::Placeholder(placeholder) = t.kind() {
- self.max_universe = self.max_universe.max(placeholder.universe);
- }
-
- t.super_visit_with(self)
- }
-
- fn visit_const(&mut self, c: ty::Const<'tcx>) {
- if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
- self.max_universe = self.max_universe.max(placeholder.universe);
- }
-
- c.super_visit_with(self)
- }
-
- fn visit_region(&mut self, r: ty::Region<'tcx>) {
- if let ty::RePlaceholder(placeholder) = r.kind() {
- self.max_universe = self.max_universe.max(placeholder.universe);
- }
- }
-}
-
/// The "generalizer" is used when handling inference variables.
///
/// The basic strategy for handling a constraint like `?A <: B` is to
@@ -511,10 +469,9 @@ impl<'tcx> Generalizer<'_, 'tcx> {
if is_nested_alias {
return Err(e);
} else {
- let mut visitor = MaxUniverse::new();
- alias.visit_with(&mut visitor);
+ let alias_max_universe = ty::max_universe_of_placeholders(self.infcx, alias);
let infer_replacement_is_complete =
- self.for_universe.can_name(visitor.max_universe())
+ self.for_universe.can_name(alias_max_universe)
&& !alias.has_escaping_bound_vars();
if !infer_replacement_is_complete {
warn!("may incompletely handle alias type: {alias:?}");
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 383023aa24457..0a070c6092d63 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2438,7 +2438,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
// Check if this ADT has a constrained layout (like `NonNull` and friends).
if let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) {
- if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
+ if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair { a: scalar, .. } =
&layout.backend_repr
{
let range = scalar.valid_range(cx);
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 16a5a6c8877a5..6a7942a2bad29 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1108,7 +1108,7 @@ fn should_encode_mir(
// instance_mir uses mir_for_ctfe rather than optimized_mir for constructors
DefKind::Ctor(_, _) => (true, false),
// Constants
- DefKind::AnonConst { .. }
+ DefKind::AnonConst
| DefKind::InlineConst
| DefKind::AssocConst { .. }
| DefKind::Const { .. } => (true, false),
@@ -1438,27 +1438,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// for trivial const arguments which are directly lowered to
// `ConstArgKind::Path`. We never actually access this `DefId`
// anywhere so we don't need to encode it for other crates.
+ // FIXME(mgca): This probably isn't true, they probably are accessed, but, test case?
if def_kind == DefKind::AnonConst
- && match tcx.hir_node_by_def_id(local_id) {
- hir::Node::ConstArg(hir::ConstArg { kind, .. }) => match kind {
- // Skip encoding defs for these as they should not have had a `DefId` created
- hir::ConstArgKind::Error(..)
- | hir::ConstArgKind::Struct(..)
- | hir::ConstArgKind::Array(..)
- | hir::ConstArgKind::TupleCall(..)
- | hir::ConstArgKind::Tup(..)
- | hir::ConstArgKind::Path(..)
- | hir::ConstArgKind::Literal { .. }
- | hir::ConstArgKind::Infer(..) => true,
- hir::ConstArgKind::Anon(..) => false,
- },
- _ => false,
- }
+ && matches!(tcx.hir_node_by_def_id(local_id), hir::Node::ConstArg(_))
{
- // MGCA doesn't have unnecessary DefIds
- if !tcx.features().min_generic_const_args() {
- continue;
- }
+ continue;
}
if def_kind == DefKind::Field
diff --git a/compiler/rustc_middle/src/ty/offload_meta.rs b/compiler/rustc_middle/src/ty/offload_meta.rs
index 9d0fcc50ef224..a58e517e05f61 100644
--- a/compiler/rustc_middle/src/ty/offload_meta.rs
+++ b/compiler/rustc_middle/src/ty/offload_meta.rs
@@ -76,7 +76,7 @@ impl OffloadMetadata {
Ty<'tcx>: TyAbiInterface<'tcx, C>,
{
match arg_abi.layout.backend_repr {
- BackendRepr::ScalarPair(_, _) => (0..2)
+ BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => (0..2)
.map(|i| {
let ty = arg_abi.layout.field(cx, i).ty;
(OffloadMetadata::from_ty(tcx, ty), ty)
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index c286c0819aea2..650dcf61c66ac 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -1225,26 +1225,50 @@ impl<'tcx> ThirBuildCx<'tcx> {
self.typeck_results.splatted_def(expr.hir_id).unwrap_or_else(|| {
span_bug!(expr.span, "no splatted def for function or method callee")
});
- let def_id = def_id.unwrap_or_else(|| {
- span_bug!(expr.span, "no splatted def for function or method callee")
- });
- let def_kind = self.tcx.def_kind(def_id);
- let user_ty = self.user_args_applied_to_res(expr.hir_id, Res::Def(def_kind, def_id));
- debug!(
- "splatted_callee: user_ty={:?} def_kind={:?} def_id={:?} arg_index={:?} arg_count={:?}",
- user_ty, def_kind, def_id, arg_index, arg_count
- );
- (
+ let expr = if let Some(def_id) = def_id {
+ // We're calling a function via a FnDef, and its possibly generic type
+ let def_kind = self.tcx.def_kind(def_id);
+ let user_ty = self.user_args_applied_to_res(expr.hir_id, Res::Def(def_kind, def_id));
+ debug!(
+ "splatted_callee FnDef: user_ty={:?} def_kind={:?} def_id={:?} arg_index={:?} arg_count={:?}",
+ user_ty, def_kind, def_id, arg_index, arg_count,
+ );
+
Expr {
temp_scope_id: expr.hir_id.local_id,
+ // Create a new FnDef type, representing the splatted function arguments with
+ // user-supplied generic types applied
ty: Ty::new_fn_def(self.tcx, def_id, self.typeck_results.node_args(expr.hir_id)),
span,
kind: ExprKind::ZstLiteral { user_ty },
- },
- arg_index,
- arg_count,
- )
+ }
+ } else {
+ // We're calling a function via a FnPtr and its type
+ // FIXME(splat): populate the side-tables for FnPtrs, using liberated_fn_sigs if needed
+ let fn_ty = self.typeck_results.expr_ty_adjusted(expr);
+ let user_ty =
+ self.typeck_results.user_provided_types().get(expr.hir_id).copied().map(Box::new);
+ debug!(
+ "splatted_callee FnPtr: user_ty={:?} fn_ty={:?} arg_index={:?} arg_count={:?}",
+ user_ty, fn_ty, arg_index, arg_count,
+ );
+
+ if !fn_ty.is_fn() {
+ span_bug!(expr.span, "splatted FnPtr side-tables are not yet implemented")
+ }
+
+ Expr {
+ temp_scope_id: expr.hir_id.local_id,
+ // Create a new FnPtr FnSig type, representing the splatted function arguments with
+ // user-supplied generic types applied
+ ty: Ty::new_fn_ptr(self.tcx, fn_ty.fn_sig(self.tcx)),
+ span,
+ kind: ExprKind::ZstLiteral { user_ty },
+ }
+ };
+
+ (expr, arg_index, arg_count)
}
/// The callee has a splatted tuple argument.
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 8b6a92071a7d7..5a4bf1a68dd5d 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -155,7 +155,6 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
match &stmt.kind {
StatementKind::StorageDead(l) => state.kill(*l),
- // If a place is assigned to in a statement, it needs storage for that statement.
StatementKind::Assign((place, _)) => {
state.gen_(place.local);
}
@@ -180,12 +179,35 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
fn apply_primary_statement_effect(
&self,
state: &mut Self::Domain,
- _: &Statement<'tcx>,
+ stmt: &Statement<'tcx>,
loc: Location,
) {
// If we move from a place then it only stops needing storage *after*
// that statement.
self.check_for_move(state, loc);
+
+ match &stmt.kind {
+ // If a place is assigned to in a statement, it needs storage after that statement.
+ // Even if the place was moved from in the rvalue (e.g. `x = x + 1` or `x = f(move x)`),
+ // the assignment restores a valid value into the place.
+ StatementKind::Assign((place, _)) => {
+ state.gen_(place.local);
+ }
+ StatementKind::SetDiscriminant { place, .. } => {
+ state.gen_(place.local);
+ }
+
+ StatementKind::StorageDead(_)
+ | StatementKind::AscribeUserType(..)
+ | StatementKind::PlaceMention(..)
+ | StatementKind::Coverage(..)
+ | StatementKind::FakeRead(..)
+ | StatementKind::ConstEvalCounter
+ | StatementKind::Nop
+ | StatementKind::Intrinsic(..)
+ | StatementKind::BackwardIncompatibleDropHint { .. }
+ | StatementKind::StorageLive(..) => {}
+ }
}
fn apply_early_terminator_effect(
diff --git a/compiler/rustc_mir_transform/src/coroutine/mod.rs b/compiler/rustc_mir_transform/src/coroutine/mod.rs
index 53283680c0966..a64d23b0b939f 100644
--- a/compiler/rustc_mir_transform/src/coroutine/mod.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/mod.rs
@@ -79,6 +79,7 @@ use rustc_span::def_id::DefId;
use tracing::{debug, instrument};
use crate::deref_separator::deref_finder;
+use crate::patch::MirPatch;
use crate::{abort_unwinding_calls, pass_manager as pm, simplify};
pub(super) struct StateTransform;
@@ -199,6 +200,8 @@ struct TransformVisitor<'tcx> {
old_yield_ty: Ty<'tcx>,
old_ret_ty: Ty<'tcx>,
+
+ patch: Option>,
}
impl<'tcx> TransformVisitor<'tcx> {
@@ -408,11 +411,51 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
}
#[tracing::instrument(level = "trace", skip(self), ret)]
- fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, _location: Location) {
+ fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) {
// Replace an Local in the remap with a coroutine struct access
if let Some(&Some((ty, variant_index, idx))) = self.remap.get(place.local) {
replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
}
+ if let Some(new_projection) = self.process_projection(&place.projection, location) {
+ place.projection = self.tcx.mk_place_elems(&new_projection);
+ }
+ }
+
+ fn process_projection_elem(
+ &mut self,
+ elem: PlaceElem<'tcx>,
+ location: Location,
+ ) -> Option> {
+ match elem {
+ PlaceElem::Index(local) => {
+ if let Some(&Some((ty, variant, idx))) = self.remap.get(local) {
+ // `PlaceElem::Index` only accepts a `Local`, not an arbitrary `Place`.
+ // If the local in indexing was saved across a yield point and remapped to a
+ // coroutine struct field, we cannot inline the struct field access into
+ // the index projection.
+ // For example, an local storing the counter to track which element to drop in
+ // an array is one such case.
+ //
+ // Instead, we inject an assignment before this location to restore the
+ // saved local from the coroutine struct (`local = copy $projection`),
+ // and leave the `PlaceElem::Index(local)` projection unchanged.
+ let field = self.make_field(variant, idx, ty);
+ self.patch.as_mut().unwrap().add_assign(
+ location,
+ Place::from(local),
+ Rvalue::Use(Operand::Copy(field), WithRetag::No),
+ );
+ }
+ None
+ }
+ PlaceElem::Field(..)
+ | PlaceElem::OpaqueCast(..)
+ | PlaceElem::UnwrapUnsafeBinder(..)
+ | PlaceElem::Deref
+ | PlaceElem::ConstantIndex { .. }
+ | PlaceElem::Subslice { .. }
+ | PlaceElem::Downcast(..) => None,
+ }
}
#[tracing::instrument(level = "trace", skip(self, stmt), ret)]
@@ -1096,6 +1139,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
new_ret_local,
old_ret_ty,
old_yield_ty,
+ patch: Some(MirPatch::new(body)),
};
transform.visit_body(body);
@@ -1116,6 +1160,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
Some(Statement::new(source_info, assign))
}),
);
+ transform.patch.take().unwrap().apply(body);
// Remove the context argument within generator bodies.
if matches!(coroutine_kind, CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) {
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index c7d18bd1cc92f..7e128ad72454e 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -647,7 +647,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
// a pair and sometimes not. But as a hack we always return a pair
// and just make the 2nd component `Bottom` when it does not exist.
Some(val) => {
- if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) {
+ if matches!(val.layout.backend_repr, BackendRepr::ScalarPair { .. }) {
let (val, overflow) = val.to_scalar_pair();
(FlatSet::Elem(val), FlatSet::Elem(overflow))
} else {
@@ -814,7 +814,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
return Some(Const::Val(ConstValue::Scalar(value), ty));
}
- if matches!(layout.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) {
+ if matches!(layout.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair { .. }) {
let alloc_id = ecx
.intern_with_temp_alloc(layout, |ecx, dest| {
try_write_constant(ecx, dest, place, ty, state, map)
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 2db4502ecc6b6..f00dd3fde5aac 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -608,7 +608,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
let fields =
fields.iter().map(|&f| self.eval_to_const(f)).collect::