From 89feef1e532f7ee989b670679fe87a1d577db1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 18 Jun 2026 14:46:24 +0200 Subject: [PATCH 1/9] introduce a test entrypoint marker for tools --- .../rustc_attr_parsing/src/attributes/test_attrs.rs | 11 +++++++++++ compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_builtin_macros/src/test.rs | 9 +++++++++ compiler/rustc_feature/src/builtin_attrs.rs | 1 + compiler/rustc_hir/src/attrs/data_structures.rs | 3 +++ compiler/rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + 8 files changed, 28 insertions(+) diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 8905591bdba5a..780b9e185b0ed 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -214,3 +214,14 @@ impl SingleAttributeParser for RustcTestMarkerParser { Some(AttributeKind::RustcTestMarker(value_str)) } } + +pub(crate) struct RustcTestEntrypointMarkerParser; + +impl NoArgsAttributeParser for RustcTestEntrypointMarkerParser { + const PATH: &[Symbol] = &[sym::rustc_test_entrypoint_marker]; + const ALLOWED_TARGETS: AllowedTargets<'_> = + AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::Closure)]); + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const STABILITY: AttributeStability = unstable!(rustc_attrs); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcTestEntrypointMarker; +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1595d2f80ddc7..e094447ec454b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -328,6 +328,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index fda0660c48403..677feda744ad1 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -24,6 +24,9 @@ use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; /// /// We mark item with an inert attribute "rustc_test_marker" which the test generation /// logic will pick up on. +/// +/// The test function also gains a `#[rustc_test_entrypoint_marker]` attribute for tools to pick up +/// on. This behavior is *unstable*. pub(crate) fn expand_test_case( ecx: &mut ExtCtxt<'_>, attr_sp: Span, @@ -381,6 +384,12 @@ pub(crate) fn expand_test_or_bench( let test_extern = cx.item(sp, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None, test_ident)); + let item = { + let mut item = item; + item.attrs.push(cx.attr_word(sym::rustc_test_entrypoint_marker, attr_sp)); + item + }; + debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); if is_stmt { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e081c2989d3c6..e7eb487b9b421 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -364,6 +364,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ sym::rustc_paren_sugar, sym::rustc_inherit_overflow_checks, sym::rustc_reservation_impl, + sym::rustc_test_entrypoint_marker, sym::rustc_test_marker, sym::rustc_unsafe_specialization_marker, sym::rustc_specialization_trait, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 17d00863d99d5..29cfbe2558751 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1636,6 +1636,9 @@ pub enum AttributeKind { /// Represents `#[rustc_strict_coherence]`. RustcStrictCoherence(Span), + /// Represents `#[rustc_test_entrypoint_marker]` + RustcTestEntrypointMarker, + /// Represents `#[rustc_test_marker]` RustcTestMarker(Symbol), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index f5a6eeec07406..01eab3cc8cb52 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -189,6 +189,7 @@ impl AttributeKind { RustcSpecializationTrait => No, RustcStdInternalSymbol => No, RustcStrictCoherence(..) => Yes, + RustcTestEntrypointMarker => No, RustcTestMarker(..) => No, RustcThenThisWouldNeed(..) => No, RustcTrivialFieldReads => Yes, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7ae6005e9bc98..fac8015df9c27 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -395,6 +395,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcSpecializationTrait => (), AttributeKind::RustcStdInternalSymbol => (), AttributeKind::RustcStrictCoherence(..) => (), + AttributeKind::RustcTestEntrypointMarker => (), AttributeKind::RustcTestMarker(..) => (), AttributeKind::RustcThenThisWouldNeed(..) => (), AttributeKind::RustcTrivialFieldReads => (), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 71eae246ebaff..fd0e52e5b2049 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1852,6 +1852,7 @@ symbols! { rustc_specialization_trait, rustc_std_internal_symbol, rustc_strict_coherence, + rustc_test_entrypoint_marker, rustc_test_marker, rustc_then_this_would_need, rustc_trivial_field_reads, From 1e795a9ebb83ae061cbb3ae8658e4053a18b27bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 6 Jul 2026 11:54:24 +0200 Subject: [PATCH 2/9] add test --- tests/ui-fulldeps/test_entrypoint_attrs.rs | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 tests/ui-fulldeps/test_entrypoint_attrs.rs diff --git a/tests/ui-fulldeps/test_entrypoint_attrs.rs b/tests/ui-fulldeps/test_entrypoint_attrs.rs new file mode 100644 index 0000000000000..af7b2c4338c8a --- /dev/null +++ b/tests/ui-fulldeps/test_entrypoint_attrs.rs @@ -0,0 +1,83 @@ +//@ run-pass +//@ ignore-cross-compile +//@ ignore-remote +//@ edition: 2024 +//! Uses a rustc driver to check that test entrypoints get a `#[rustc_test_entrypoint_marker]` +//! and can be found using that attribute in rustc drivers (the main use for this attribute). + +#![feature(rustc_private)] + +extern crate rustc_driver; +extern crate rustc_interface; +extern crate rustc_middle; +#[macro_use] +extern crate rustc_hir; + +use interface::Compiler; +use rustc_driver::Compilation; +use rustc_interface::interface; +use rustc_middle::ty::TyCtxt; +use std::io::Write; + +const CRATE_NAME: &str = "input"; + +struct TestAttr { + expected_tests: usize, +} + +impl rustc_driver::Callbacks for TestAttr { + fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, tcx: TyCtxt<'tcx>) -> Compilation { + let mut tests = Vec::new(); + for did in tcx.hir_crate_items(()).definitions() { + if find_attr!(tcx, did, RustcTestEntrypointMarker) { + tests.push(did); + } + } + + // the file contains one test, so we should find one entrypoint marker. + assert_eq!(tests.len(), self.expected_tests); + + Compilation::Stop + } +} + +fn count_tests(src: &str, expected_tests: usize) { + let path = "test_input.rs"; + let mut file = std::fs::File::create(path).unwrap(); + file.write_all(src.as_bytes()).unwrap(); + + let args = [ + "rustc".to_string(), + "--test".to_string(), + "--crate-type=lib".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + rustc_driver::catch_fatal_errors(|| -> interface::Result<()> { + rustc_driver::run_compiler(&args, &mut TestAttr { expected_tests }); + Ok(()) + }) + .unwrap() + .unwrap(); +} + +fn main() { + count_tests( + r#" + #[test] + fn meow() {{ }} + "#, + 1, + ); + count_tests( + r#" + #[test] + fn one() {{ }} + + #[test] + fn two() {{ }} + "#, + 2, + ); +} From 013325275767d4242dc9ae402190fd8957644501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 6 Jul 2026 13:51:24 +0200 Subject: [PATCH 3/9] bless existing tests --- tests/pretty/tests-are-sorted.pp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/pretty/tests-are-sorted.pp b/tests/pretty/tests-are-sorted.pp index 43f9838e68ce9..f49c79f31a5ec 100644 --- a/tests/pretty/tests-are-sorted.pp +++ b/tests/pretty/tests-are-sorted.pp @@ -30,6 +30,7 @@ testfn: test::StaticTestFn(#[coverage(off)] || test::assert_test_result(m_test())), }; +#[rustc_test_entrypoint_marker] fn m_test() {} extern crate test; @@ -55,6 +56,7 @@ test::assert_test_result(z_test())), }; #[ignore = "not yet implemented"] +#[rustc_test_entrypoint_marker] fn z_test() {} extern crate test; @@ -79,6 +81,7 @@ testfn: test::StaticTestFn(#[coverage(off)] || test::assert_test_result(a_test())), }; +#[rustc_test_entrypoint_marker] fn a_test() {} #[rustc_main] #[coverage(off)] From 8bb04f6b4cd36229ddd8e5199e06c3e87ca8589e Mon Sep 17 00:00:00 2001 From: Amirhossein Akhlaghpour Date: Wed, 8 Jul 2026 20:35:40 +0330 Subject: [PATCH 4/9] chore: add codegen test for Result is_ok unwrap Signed-off-by: Amirhossein Akhlaghpour --- .../issues/result-is-ok-unwrap.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/codegen-llvm/issues/result-is-ok-unwrap.rs diff --git a/tests/codegen-llvm/issues/result-is-ok-unwrap.rs b/tests/codegen-llvm/issues/result-is-ok-unwrap.rs new file mode 100644 index 0000000000000..ffcbb0ae142d9 --- /dev/null +++ b/tests/codegen-llvm/issues/result-is-ok-unwrap.rs @@ -0,0 +1,20 @@ +// Checking `Result::is_ok()` should make a following `unwrap()` branch-free. + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +use std::hint::black_box; + +// CHECK-LABEL: @unwrap_after_is_ok +#[no_mangle] +pub fn unwrap_after_is_ok(arg: Result) { + // CHECK-NOT: unwrap_failed + // CHECK-NOT: panic + if arg.is_ok() { + let value = arg.unwrap(); + if value == 42 { + black_box(value); + } + } +} From 87bb7c92132495b7cb0d476bc11b10ac27c2ea24 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu Date: Wed, 24 Jun 2026 14:24:27 +0800 Subject: [PATCH 5/9] codegen_ssa: pack small const aggregates into immediate stores For small repr(C) aggregates with padding, direct constant initialization can still lower into field-wise construction plus memcpy. That leaves the backend to rediscover that the whole object is a single constant byte pattern. This is especially visible for non-zero constant aggregates. Instead of materializing them as separate field stores, we want codegen_ssa to emit the packed value directly. For example, a value like InnerPadded { a: 0, b: 1, c: 0 } can otherwise lower to something like store i16 0, ptr %val, align 4 store i8 1, ptr %val_plus_2, align 2 store i32 0, ptr %val_plus_4, align 4 call void @llvm.memcpy(..., ptr %val, ...) while this change produces store i64 65536, ptr %val, align 4 call void @llvm.memcpy(..., ptr %val, ...) Why not solve this in LLVM? At the problematic lowering point, rustc still knows that the MIR aggregate is small and fully constant. LLVM only sees a lowered stack temporary built from per-field stores and then copied out. Recovering that packed constant there would require rediscovering front-end aggregate semantics after lowering, so emitting the packed store in rustc is the simpler and more local fix. Why not keep the previous typed-copy approach? An earlier approach zeroed padding on typed copies whose source could be traced back to a constant assignment. That helped some cases, but it also widened the optimization to runtime copy paths and could introduce extra runtime stores purely to maintain padding knowledge. That is not an acceptable tradeoff here. Keep the scope narrow instead: only handle direct MIR aggregates whose fields are all constants, and pack them according to the target endianness before emitting a single integer store. Add a focused codegen test covering the original PR 157690 entry points together with non-zero constant cases. The test uses -Cno-prepopulate-passes so it checks the immediate-store shape directly at rustc codegen time, instead of depending on later LLVM store merging. --- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 78 ++++++ tests/codegen-llvm/aggregate-padding-zero.rs | 244 +++++++++++++++++++ 2 files changed, 322 insertions(+) create mode 100644 tests/codegen-llvm/aggregate-padding-zero.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 469d6af12923e..7ad747689c44d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1,5 +1,6 @@ use itertools::Itertools as _; use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT}; +use rustc_index::IndexVec; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -15,6 +16,79 @@ use crate::traits::*; use crate::{MemFlags, base}; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + fn try_codegen_const_aggregate_as_immediate( + &mut self, + bx: &mut Bx, + dest: PlaceRef<'tcx, Bx::Value>, + kind: &mir::AggregateKind<'tcx>, + operands: &IndexVec>, + ) -> bool { + // Keep this allowlist limited to aggregate kinds with direct codegen coverage. + // Extract the variant index at the same time so we can verify it against + // the layout below. Tuples always use `FIRST_VARIANT` (index 0); the + // `None` in the `Adt` arm excludes unions (which carry an active field). + let variant_index = match kind { + mir::AggregateKind::Tuple => FIRST_VARIANT, + mir::AggregateKind::Adt(_, variant_index, _, _, None) => *variant_index, + _ => return false, + }; + if !matches!(dest.layout.fields, abi::FieldsShape::Arbitrary { .. }) { + return false; + } + // `dest.layout` is the layout of the *overall* type, not a specific + // variant. When the layout is `Variants::Single { index: M }`, the + // field offsets and counts below all refer to variant M. If the MIR + // aggregate is constructing a different variant N (e.g. because N is + // uninhabited and the layout collapsed to M), using `dest.layout` + // directly would read the wrong field metadata. Bail out and let the + // normal codegen path handle it via `project_downcast`. + if !matches!(dest.layout.variants, abi::Variants::Single { index } if index == variant_index) + { + return false; + } + // Now that the variant indices are known to match, the operand count + // and the layout field count must agree. + debug_assert_eq!(operands.len(), dest.layout.fields.count()); + + let size = dest.layout.size.bytes(); + let llty = match size { + 1 => bx.cx().type_i8(), + 2 => bx.cx().type_i16(), + 4 => bx.cx().type_i32(), + 8 => bx.cx().type_i64(), + 16 => bx.cx().type_i128(), + _ => return false, + }; + + let mut value = 0u128; + for (field_idx, operand) in operands.iter_enumerated() { + let field_layout = dest.layout.field(bx.cx(), field_idx.as_usize()); + if field_layout.is_zst() { + continue; + } + let mir::Operand::Constant(constant) = operand else { + return false; + }; + let Some(field_value) = self.eval_mir_constant(constant).try_to_bits(field_layout.size) + else { + return false; + }; + + let field_size = field_layout.size.bytes(); + let field_offset = dest.layout.fields.offset(field_idx.as_usize()).bytes(); + debug_assert!(field_offset + field_size <= size); + let shift = match bx.tcx().data_layout.endian { + abi::Endian::Little => field_offset * 8, + abi::Endian::Big => (size - field_offset - field_size) * 8, + }; + value |= field_value << shift; + } + + let value = bx.cx().const_uint_big(llty, value); + bx.store_to_place(value, dest.val); + true + } + #[instrument(level = "trace", skip(self, bx))] pub(crate) fn codegen_rvalue( &mut self, @@ -168,6 +242,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Aggregate(ref kind, ref operands) if !matches!(**kind, mir::AggregateKind::RawPtr(..)) => { + if self.try_codegen_const_aggregate_as_immediate(bx, dest, kind, operands) { + return; + } + let (variant_index, variant_dest, active_field_index) = match **kind { mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { let variant_dest = dest.project_downcast(bx, variant_index); diff --git a/tests/codegen-llvm/aggregate-padding-zero.rs b/tests/codegen-llvm/aggregate-padding-zero.rs new file mode 100644 index 0000000000000..8455b1d8583a5 --- /dev/null +++ b/tests/codegen-llvm/aggregate-padding-zero.rs @@ -0,0 +1,244 @@ +//@ add-minicore +//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -Z merge-functions=disabled -Z randomize-layout=no +//@ revisions: powerpc64 x86_64 +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64] needs-llvm-components: x86 + +// Regression test for . +// +// These cases specifically exercise direct codegen of small non-zero constant +// aggregates as a single integer store. They are chosen so they fail without +// `try_codegen_const_aggregate_as_immediate`. + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; + +use minicore::*; + +#[inline(always)] +unsafe fn ptr_write(dest: *mut T, value: T) { + *dest = value; +} + +trait MaybeUninitExt { + fn as_mut_ptr(&mut self) -> *mut T; + fn write(&mut self, value: T); +} + +impl MaybeUninitExt for MaybeUninit { + fn as_mut_ptr(&mut self) -> *mut T { + self as *mut _ as *mut T + } + + fn write(&mut self, value: T) { + unsafe { + ptr_write(self.as_mut_ptr(), value); + } + } +} + +// Inner padding between b (offset 2, size 1) and c (offset 4, size 4). +#[repr(C)] +pub struct InnerPadded { + a: u16, + b: u8, + c: u32, +} + +#[repr(transparent)] +pub struct Nested1(InnerPadded); + +#[repr(transparent)] +pub struct Nested2(Nested1); + +// PR 157690's original ptr::write entry point, checked against the current +// aggregate-immediate codegen shape. +// CHECK-LABEL: @via_ptr_write( +#[no_mangle] +pub fn via_ptr_write(dest: &mut MaybeUninit) { + let val = InnerPadded { a: 0, b: 0, c: 0 }; + // CHECK: %val = alloca [8 x i8], align 4 + // CHECK-NEXT: call void @llvm.lifetime.start.p0({{(i64 8, )?}}ptr %val) + // CHECK-NEXT: store i64 0, ptr %val, align 4 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %val, i64 8, i1 false) + unsafe { + ptr_write(dest.as_mut_ptr(), val); + } +} + +// PR 157690's original MaybeUninit::write entry point. +// CHECK-LABEL: @via_maybe_uninit_write( +#[no_mangle] +pub fn via_maybe_uninit_write(dest: &mut MaybeUninit) { + let val = InnerPadded { a: 0, b: 0, c: 0 }; + // CHECK: %val = alloca [8 x i8], align 4 + // CHECK-NEXT: call void @llvm.lifetime.start.p0({{(i64 8, )?}}ptr %val) + // CHECK-NEXT: store i64 0, ptr %val, align 4 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %{{.*}}, i64 8, i1 false) + dest.write(val); +} + +// Constant non-zero initialization: emitted as a single store including zero padding. +// CHECK-LABEL: @const_init_non_zero( +#[no_mangle] +pub fn const_init_non_zero(dest: *mut InnerPadded) { + let val = InnerPadded { a: 0, b: 1, c: 0 }; + // CHECK: %val = alloca [8 x i8], align 4 + // CHECK-NEXT: call void @llvm.lifetime.start.p0({{(i64 8, )?}}ptr %val) + // x86_64-NEXT: store i64 65536, ptr %val, align 4 + // powerpc64-NEXT: store i64 1099511627776, ptr %val, align 4 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %val, i64 8, i1 false) + unsafe { + ptr_write(dest, val); + } +} + +// From issue #157373: nesting wrapper structs used to change the lowering +// shape enough that LLVM would sometimes find the wide store only in the +// nested case. +// CHECK-LABEL: @bad( +#[no_mangle] +pub fn bad(a: &mut InnerPadded) { + let x = InnerPadded { a: 0, b: 1, c: 0 }; + // x86_64: store i64 65536, ptr %x, align 4 + // powerpc64: store i64 1099511627776, ptr %x, align 4 + *a = x; +} + +// CHECK-LABEL: @good( +#[no_mangle] +pub fn good(a: &mut Nested2) { + let x = InnerPadded { a: 0, b: 1, c: 0 }; + // x86_64: store i64 65536, ptr %x, align 4 + // powerpc64: store i64 1099511627776, ptr %x, align 4 + *a = Nested2(Nested1(x)); +} + +// The same direct constant aggregate packing should apply through ptr::write on MaybeUninit. +// CHECK-LABEL: @via_ptr_write_non_zero( +#[no_mangle] +pub fn via_ptr_write_non_zero(dest: &mut MaybeUninit) { + let val = InnerPadded { a: 0, b: 1, c: 0 }; + // CHECK: %val = alloca [8 x i8], align 4 + // CHECK-NEXT: call void @llvm.lifetime.start.p0({{(i64 8, )?}}ptr %val) + // x86_64-NEXT: store i64 65536, ptr %val, align 4 + // powerpc64-NEXT: store i64 1099511627776, ptr %val, align 4 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %val, i64 8, i1 false) + unsafe { + ptr_write(dest.as_mut_ptr(), val); + } +} + +// The same direct constant aggregate packing should apply through MaybeUninit::write. +// CHECK-LABEL: @via_maybe_uninit_write_non_zero( +#[no_mangle] +pub fn via_maybe_uninit_write_non_zero(dest: &mut MaybeUninit) { + let val = InnerPadded { a: 0, b: 1, c: 0 }; + // CHECK: %val = alloca [8 x i8], align 4 + // CHECK-NEXT: call void @llvm.lifetime.start.p0({{(i64 8, )?}}ptr %val) + // x86_64-NEXT: store i64 65536, ptr %val, align 4 + // powerpc64-NEXT: store i64 1099511627776, ptr %val, align 4 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %{{.*}}, i64 8, i1 false) + dest.write(val); +} + +// CHECK-LABEL: @bad_non_zero( +#[no_mangle] +pub fn bad_non_zero(a: &mut InnerPadded) { + let x = InnerPadded { a: 0, b: 1, c: 0 }; + // CHECK: %x = alloca [8 x i8], align 4 + // CHECK-NEXT: call void @llvm.lifetime.start.p0({{(i64 8, )?}}ptr %x) + // x86_64-NEXT: store i64 65536, ptr %x, align 4 + // powerpc64-NEXT: store i64 1099511627776, ptr %x, align 4 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a, ptr align 4 %x, i64 8, i1 false) + *a = x; +} + +// CHECK-LABEL: @good_non_zero( +#[no_mangle] +pub fn good_non_zero(a: &mut Nested2) { + let x = InnerPadded { a: 0, b: 1, c: 0 }; + // CHECK: %x = alloca [8 x i8], align 4 + // CHECK-NEXT: call void @llvm.lifetime.start.p0({{(i64 8, )?}}ptr %x) + // x86_64-NEXT: store i64 65536, ptr %x, align 4 + // powerpc64-NEXT: store i64 1099511627776, ptr %x, align 4 + // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a, ptr align 4 %{{.*}}, i64 8, i1 false) + *a = Nested2(Nested1(x)); +} + +// Trailing padding only (no inter-field padding): a (offset 0, size 4), +// b (offset 4, size 2), c (offset 6, size 1), trailing pad (offset 7, size 1). +#[repr(C)] +pub struct TailOnly { + a: u32, + b: u16, + c: u8, +} + +type TupleTailOnly = (u32, u16, u8); + +// PR 157690's trailing-padding-only entry point. +// CHECK-LABEL: @tail_only_write( +#[no_mangle] +pub fn tail_only_write(dest: &mut MaybeUninit) { + let val = TailOnly { a: 0, b: 0, c: 0 }; + // CHECK: %val = alloca [8 x i8], align 4 + // CHECK-NEXT: call void @llvm.lifetime.start.p0({{(i64 8, )?}}ptr %val) + // CHECK-NEXT: store i64 0, ptr %val, align 4 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %val, i64 8, i1 false) + unsafe { + ptr_write(dest.as_mut_ptr(), val); + } +} + +// Tuple aggregates should use the same const-packing path as structs when the +// whole tuple is constant and small enough to fit in an integer store. +// CHECK-LABEL: @tuple_tail_only_non_zero( +#[no_mangle] +pub fn tuple_tail_only_non_zero(dest: *mut TupleTailOnly) { + let val: TupleTailOnly = (0, 1, 0); + // CHECK: %val = alloca [8 x i8], align 4 + // CHECK-NEXT: call void @llvm.lifetime.start.p0({{(i64 8, )?}}ptr %val) + // x86_64-NEXT: store i64 4294967296, ptr %val, align 4 + // powerpc64-NEXT: store i64 65536, ptr %val, align 4 + // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %dest, ptr align 4 %val, i64 8, i1 false) + unsafe { + ptr_write(dest, val); + } +} + +// Regression test for the debug assertion failure in +// `try_codegen_const_aggregate_as_immediate` when the MIR aggregate's +// variant index doesn't match the layout's `Variants::Single { index }`. +// +// When `Data(Void)` is uninhabited, the layout of `E` collapses to +// `Variants::Single { index: 0 }` (only `Empty`). But generic code +// monomorphized with `T = Void` still contains an aggregate for `Data(x)` +// with 1 operand. The optimization must bail out gracefully instead of +// asserting `operands.len() == dest.layout.fields.count()` (1 == 0). +// +// See . +enum Void {} + +enum E { + Empty, + Data(T), +} + +#[inline(never)] +fn make_data(x: T) -> E { + E::Data(x) +} + +// Force codegen of `make_data::`. Without the variant index check, +// this triggers: assertion `left == right` failed (left: 1, right: 0). +// CHECK-LABEL: @force_variant_mismatch( +#[no_mangle] +pub fn force_variant_mismatch() -> fn(Void) -> E { + make_data:: +} From 79b72317fd2b6730b838fa63cb1cf10fa6a4af5a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 9 Jul 2026 12:27:19 +0200 Subject: [PATCH 6/9] Use `as_lang_item` instead of repeatedly matching --- .../src/coherence/builtin.rs | 46 +++++++------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 4ff870b405e5a..ecc7b170818d2 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -34,44 +34,30 @@ pub(super) fn check_trait<'tcx>( impl_def_id: LocalDefId, impl_header: ty::ImplTraitHeader<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let lang_items = tcx.lang_items(); - let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header }; - checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?; - checker.check(lang_items.async_drop_trait(), visit_implementation_of_drop)?; - checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?; - checker.check(lang_items.unpin_trait(), visit_implementation_of_unpin)?; - checker.check(lang_items.const_param_ty_trait(), |checker| { - visit_implementation_of_const_param_ty(checker) - })?; - checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?; - checker.check(lang_items.reborrow(), visit_implementation_of_reborrow)?; - checker.check(lang_items.coerce_shared(), visit_implementation_of_coerce_shared)?; - checker - .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?; - checker.check( - lang_items.coerce_pointee_validated_trait(), - visit_implementation_of_coerce_pointee_validity, - )?; - Ok(()) + let checker = Checker { tcx, impl_def_id, impl_header }; + match tcx.as_lang_item(trait_def_id) { + Some(LangItem::Drop) => visit_implementation_of_drop(&checker), + Some(LangItem::AsyncDrop) => visit_implementation_of_drop(&checker), + Some(LangItem::Copy) => visit_implementation_of_copy(&checker), + Some(LangItem::Unpin) => visit_implementation_of_unpin(&checker), + Some(LangItem::ConstParamTy) => visit_implementation_of_const_param_ty(&checker), + Some(LangItem::CoerceUnsized) => visit_implementation_of_coerce_unsized(&checker), + Some(LangItem::Reborrow) => visit_implementation_of_reborrow(&checker), + Some(LangItem::CoerceShared) => visit_implementation_of_coerce_shared(&checker), + Some(LangItem::DispatchFromDyn) => visit_implementation_of_dispatch_from_dyn(&checker), + Some(LangItem::CoercePointeeValidated) => { + visit_implementation_of_coerce_pointee_validity(&checker) + } + _ => Ok(()), + } } struct Checker<'tcx> { tcx: TyCtxt<'tcx>, - trait_def_id: DefId, impl_def_id: LocalDefId, impl_header: ty::ImplTraitHeader<'tcx>, } -impl<'tcx> Checker<'tcx> { - fn check( - &self, - trait_def_id: Option, - f: impl FnOnce(&Self) -> Result<(), ErrorGuaranteed>, - ) -> Result<(), ErrorGuaranteed> { - if Some(self.trait_def_id) == trait_def_id { f(self) } else { Ok(()) } - } -} - fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { let tcx = checker.tcx; let impl_did = checker.impl_def_id; From 22348eb6369bdb5d7a7a3114d4dbbeca8c4b5335 Mon Sep 17 00:00:00 2001 From: Adwin White Date: Fri, 10 Jul 2026 12:20:41 +0800 Subject: [PATCH 7/9] assert only opaques with sub unified hidden infer are non-rigid --- .../src/solve/assembly/mod.rs | 2 +- .../dont-ice-replacing-non-rigid-opaque.rs | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/next-solver/opaques/dont-ice-replacing-non-rigid-opaque.rs diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index db1a8228c43cb..5dd42b8f1154b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -1095,8 +1095,8 @@ where if let ty::Alias(is_rigid, alias_ty) = ty.kind() && let Some(opaque_ty) = alias_ty.try_to_opaque() { - debug_assert_eq!(is_rigid, ty::IsRigid::No); if opaque_ty == self.opaque_ty { + debug_assert_eq!(is_rigid, ty::IsRigid::No); return self.self_ty; } } diff --git a/tests/ui/traits/next-solver/opaques/dont-ice-replacing-non-rigid-opaque.rs b/tests/ui/traits/next-solver/opaques/dont-ice-replacing-non-rigid-opaque.rs new file mode 100644 index 0000000000000..69c53efa14c5c --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/dont-ice-replacing-non-rigid-opaque.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for #158784 +// +// We should assert that only opaque types that is to be replaced +// are non-rigid. We can have rigid opaque types elsewhere. + +#![feature(type_alias_impl_trait)] +type Rigid = impl Sized; +#[define_opaque(Rigid)] +fn define_rigid() -> Rigid {} + +type MyIter = impl Iterator; + +#[define_opaque(MyIter)] +fn define_my_iter(a: T) -> MyIter { + if false { + // `Rigid` being rigid is totally fine here. + let _: MyIter = std::iter::once(define_rigid()); + } + std::iter::once(a) +} + +fn main() {} From e30103a61f63034e89c919bd7ad9aa301920c0a3 Mon Sep 17 00:00:00 2001 From: mehdiakiki Date: Fri, 3 Jul 2026 13:14:00 +0100 Subject: [PATCH 8/9] Move NativeLib::filename to the rmeta-link archive member --- compiler/rustc_codegen_ssa/src/back/link.rs | 101 +++++++++++++++--- .../rustc_codegen_ssa/src/back/rmeta_link.rs | 64 ++++++++++- compiler/rustc_codegen_ssa/src/lib.rs | 2 - compiler/rustc_metadata/src/lib.rs | 4 +- compiler/rustc_metadata/src/native_libs.rs | 24 +---- compiler/rustc_session/src/cstore.rs | 2 - 6 files changed, 152 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c41f6f30a1da3..7cc7e7d7b5a62 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -26,7 +26,7 @@ use rustc_lint_defs::builtin::LINKER_INFO; use rustc_macros::Diagnostic; use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file}; use rustc_metadata::{ - EncodedMetadata, NativeLibSearchFallback, find_native_static_library, + EncodedMetadata, NativeLibSearchFallback, find_bundled_library, find_native_static_library, walk_native_lib_search_dirs, }; use rustc_middle::bug; @@ -329,8 +329,25 @@ fn link_rlib<'a>( .map(|obj| obj.file_name().unwrap().to_str().unwrap().to_string()) .collect(); + let native_lib_filenames: Vec> = crate_info + .used_libraries + .iter() + .map(|lib| { + find_bundled_library( + lib.name, + Some(lib.verbatim), + lib.kind, + lib.cfg.is_some(), + sess, + &crate_info.crate_types, + ) + }) + .collect(); + let metadata_link_file = if matches!(flavor, RlibFlavor::Normal) { - let metadata_link = rmeta_link::RmetaLink { rust_object_files }; + let native_lib_filenames: Vec> = + native_lib_filenames.iter().map(|f| f.map(|s| s.to_string())).collect(); + let metadata_link = rmeta_link::RmetaLink { rust_object_files, native_lib_filenames }; let metadata_link_data = metadata_link.encode(); let (wrapper, _) = create_wrapper_file(sess, rmeta_link::SECTION.to_string(), &metadata_link_data); @@ -413,12 +430,12 @@ fn link_rlib<'a>( // feature then we'll need to figure out how to record what objects were // loaded from the libraries found here and then encode that into the // metadata of the rlib we're generating somehow. - for lib in crate_info.used_libraries.iter() { + for (i, lib) in crate_info.used_libraries.iter().enumerate() { let NativeLibKind::Static { bundle: None | Some(true), .. } = lib.kind else { continue; }; if flavor == RlibFlavor::Normal - && let Some(filename) = lib.filename + && let Some(filename) = native_lib_filenames[i] { let path = find_native_static_library(filename.as_str(), true, sess); let src = read(path) @@ -532,11 +549,21 @@ fn link_staticlib( let lto = are_upstream_rust_objects_already_included(sess) && !ignored_for_lto(sess, crate_info, cnum); - let native_libs = crate_info.native_libraries[&cnum].iter(); - let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, lib)); - let relevant_libs: FxIndexSet<_> = relevant.filter_map(|lib| lib.filename).collect(); + let native_libs = &crate_info.native_libraries[&cnum]; + let bundled_filenames = + rmeta_link_cache.native_lib_filenames(&sess.target, path, native_libs); + let relevant_libs: FxIndexSet<_> = native_libs + .iter() + .enumerate() + .filter(|(_, lib)| relevant_lib(sess, lib)) + .filter_map(|(i, _)| bundled_filenames.get(i).copied().flatten()) + .collect(); - let bundled_libs: FxIndexSet<_> = native_libs.filter_map(|lib| lib.filename).collect(); + let bundled_libs: FxIndexSet<_> = native_libs + .iter() + .enumerate() + .filter_map(|(i, _)| bundled_filenames.get(i).copied().flatten()) + .collect(); ab.add_archive( path, AddArchiveKind::Rlib(rmeta_link_cache, &|fname: &str, entry_kind| { @@ -2739,6 +2766,7 @@ fn linker_with_args( cmd, sess, archive_builder_builder, + rmeta_link_cache, crate_info, tmpdir, link_output_kind, @@ -2761,6 +2789,7 @@ fn linker_with_args( cmd, sess, archive_builder_builder, + rmeta_link_cache, crate_info, tmpdir, link_output_kind, @@ -3060,6 +3089,7 @@ fn add_native_libs_from_crate( cmd: &mut dyn Linker, sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, + rmeta_link_cache: &mut RmetaLinkCache, crate_info: &CrateInfo, tmpdir: &Path, bundled_libs: &FxIndexSet, @@ -3083,13 +3113,38 @@ fn add_native_libs_from_crate( .unwrap_or_else(|e| sess.dcx().emit_fatal(e)); } - let native_libs = match cnum { - LOCAL_CRATE => &crate_info.used_libraries, - _ => &crate_info.native_libraries[&cnum], + let (native_libs, bundled_filenames): (&Vec, Vec>) = match cnum { + LOCAL_CRATE => { + let libs = &crate_info.used_libraries; + let filenames = libs + .iter() + .map(|lib| { + find_bundled_library( + lib.name, + Some(lib.verbatim), + lib.kind, + lib.cfg.is_some(), + sess, + &crate_info.crate_types, + ) + }) + .collect(); + (libs, filenames) + } + _ => { + let native_libs = &crate_info.native_libraries[&cnum]; + let filenames = + if let Some(rlib_path) = crate_info.used_crate_source[&cnum].rlib.as_ref() { + rmeta_link_cache.native_lib_filenames(&sess.target, rlib_path, native_libs) + } else { + Vec::new() + }; + (native_libs, filenames) + } }; let mut last = (None, NativeLibKind::Unspecified, false); - for lib in native_libs { + for (i, lib) in native_libs.iter().enumerate() { if !relevant_lib(sess, lib) { continue; } @@ -3109,7 +3164,7 @@ fn add_native_libs_from_crate( let bundle = bundle.unwrap_or(true); let whole_archive = whole_archive == Some(true); if bundle && cnum != LOCAL_CRATE { - if let Some(filename) = lib.filename { + if let Some(filename) = bundled_filenames.get(i).copied().flatten() { // If rlib contains native libs as archives, they are unpacked to tmpdir. let path = tmpdir.join(filename.as_str()); cmd.link_staticlib_by_path(&path, whole_archive); @@ -3161,6 +3216,7 @@ fn add_local_native_libraries( cmd: &mut dyn Linker, sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, + rmeta_link_cache: &mut RmetaLinkCache, crate_info: &CrateInfo, tmpdir: &Path, link_output_kind: LinkOutputKind, @@ -3172,6 +3228,7 @@ fn add_local_native_libraries( cmd, sess, archive_builder_builder, + rmeta_link_cache, crate_info, tmpdir, &Default::default(), @@ -3231,10 +3288,17 @@ fn add_upstream_rust_crates( match linkage { Linkage::Static | Linkage::IncludedFromDylib | Linkage::NotLinked => { if link_static_crate { - bundled_libs = crate_info.native_libraries[&cnum] - .iter() - .filter_map(|lib| lib.filename) - .collect(); + if let Some(rlib_path) = crate_info.used_crate_source[&cnum].rlib.as_ref() { + bundled_libs = rmeta_link_cache + .native_lib_filenames( + &sess.target, + rlib_path, + &crate_info.native_libraries[&cnum], + ) + .into_iter() + .flatten() + .collect(); + } add_static_crate( cmd, sess, @@ -3268,6 +3332,7 @@ fn add_upstream_rust_crates( cmd, sess, archive_builder_builder, + rmeta_link_cache, crate_info, tmpdir, &bundled_libs, @@ -3283,6 +3348,7 @@ fn add_upstream_native_libraries( cmd: &mut dyn Linker, sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, + rmeta_link_cache: &mut RmetaLinkCache, crate_info: &CrateInfo, tmpdir: &Path, link_output_kind: LinkOutputKind, @@ -3306,6 +3372,7 @@ fn add_upstream_native_libraries( cmd, sess, archive_builder_builder, + rmeta_link_cache, crate_info, tmpdir, &Default::default(), diff --git a/compiler/rustc_codegen_ssa/src/back/rmeta_link.rs b/compiler/rustc_codegen_ssa/src/back/rmeta_link.rs index 58da783277dfe..69ec3788ac632 100644 --- a/compiler/rustc_codegen_ssa/src/back/rmeta_link.rs +++ b/compiler/rustc_codegen_ssa/src/back/rmeta_link.rs @@ -2,27 +2,38 @@ //! and potentially other data collected and used when building or linking a rlib. //! See . +use std::fs::File; use std::path::{Path, PathBuf}; use object::read::archive::ArchiveFile; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::memmap::Mmap; +use rustc_hir::attrs::NativeLibKind; use rustc_serialize::opaque::mem_encoder::MemEncoder; use rustc_serialize::opaque::{MAGIC_END_BYTES, MemDecoder}; use rustc_serialize::{Decodable, Encodable}; +use rustc_span::Symbol; +use rustc_target::spec::Target; +use tracing::debug; -use super::metadata::search_for_section; +use super::metadata::{get_metadata_xcoff, search_for_section}; +use crate::NativeLib; pub(crate) const FILENAME: &str = "lib.rmeta-link"; pub(crate) const SECTION: &str = ".rmeta-link"; pub struct RmetaLink { pub rust_object_files: Vec, + /// Positionally aligned with `native_libraries` in regular metadata: index `i` is the + /// bundled filename for native library `i`, or `None` if that library needs no bundling. + pub native_lib_filenames: Vec>, } impl RmetaLink { pub(crate) fn encode(&self) -> Vec { let mut encoder = MemEncoder::new(); self.rust_object_files.encode(&mut encoder); + self.native_lib_filenames.encode(&mut encoder); let mut data = encoder.finish(); data.extend_from_slice(MAGIC_END_BYTES); data @@ -31,7 +42,8 @@ impl RmetaLink { pub(crate) fn decode(data: &[u8]) -> Option { let mut decoder = MemDecoder::new(data, 0).ok()?; let rust_object_files = Vec::::decode(&mut decoder); - Some(RmetaLink { rust_object_files }) + let native_lib_filenames = Vec::>::decode(&mut decoder); + Some(RmetaLink { rust_object_files, native_lib_filenames }) } } @@ -69,4 +81,52 @@ impl RmetaLinkCache { ) -> Option<&RmetaLink> { self.cache.entry(rlib_path.to_path_buf()).or_insert_with(load).as_ref() } + + pub fn native_lib_filenames( + &mut self, + target: &Target, + rlib_path: &Path, + native_libs: &[NativeLib], + ) -> Vec> { + if !crate_may_have_bundled_libs(native_libs) { + return Vec::new(); + } + self.get_or_insert_with(rlib_path, || read_from_path(target, rlib_path)) + .map(|rl| { + rl.native_lib_filenames.iter().map(|f| f.as_deref().map(Symbol::intern)).collect() + }) + .unwrap_or_default() + } +} + +fn crate_may_have_bundled_libs(libs: &[NativeLib]) -> bool { + libs.iter() + .any(|lib| matches!(lib.kind, NativeLibKind::Static { bundle: Some(true) | None, .. })) +} + +// FIXME: this is mostly a copy-paste of `DefaultMetadataLoader::get_rlib_metadata`. +fn read_from_path(target: &Target, path: &Path) -> Option { + let Ok(file) = File::open(path) else { + debug!("failed to open rlib for rmeta-link: {}", path.display()); + return None; + }; + let Ok(mmap) = (unsafe { Mmap::map(file) }) else { + debug!("failed to mmap rlib for rmeta-link: {}", path.display()); + return None; + }; + + if target.is_like_aix { + let archive = ArchiveFile::parse(&*mmap).ok()?; + for entry in archive.members() { + let entry = entry.ok()?; + if entry.name() == FILENAME.as_bytes() { + let member_data = entry.data(&*mmap).ok()?; + let section_data = get_metadata_xcoff(path, member_data).ok()?; + return RmetaLink::decode(section_data); + } + } + return None; + } + + read_from_data(&mmap, path) } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index f3f19f9e90d83..45aa64f332b6e 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -214,7 +214,6 @@ bitflags::bitflags! { pub struct NativeLib { pub kind: NativeLibKind, pub name: Symbol, - pub filename: Option, pub cfg: Option, pub verbatim: bool, pub dll_imports: Vec, @@ -224,7 +223,6 @@ impl From<&cstore::NativeLib> for NativeLib { fn from(lib: &cstore::NativeLib) -> Self { NativeLib { kind: lib.kind, - filename: lib.filename, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim.unwrap_or(false), diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 840b1c4c6fa2f..642dde52adb3c 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -29,7 +29,7 @@ pub mod locator; pub use fs::{METADATA_FILENAME, emit_wrapper_file}; pub use host_dylib::{DylibError, load_symbol_from_dylib}; pub use native_libs::{ - NativeLibSearchFallback, find_native_static_library, try_find_native_dynamic_library, - try_find_native_static_library, walk_native_lib_search_dirs, + NativeLibSearchFallback, find_bundled_library, find_native_static_library, + try_find_native_dynamic_library, try_find_native_static_library, walk_native_lib_search_dirs, }; pub use rmeta::{EncodedMetadata, METADATA_HEADER, ProcMacroKind, encode_metadata, rendered_const}; diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index c9e4ce60e1a01..edf867d0b3b66 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -168,16 +168,16 @@ pub fn find_native_static_library(name: &str, verbatim: bool, sess: &Session) -> }) } -fn find_bundled_library( +pub fn find_bundled_library( name: Symbol, verbatim: Option, kind: NativeLibKind, has_cfg: bool, - tcx: TyCtxt<'_>, + sess: &Session, + crate_types: &[CrateType], ) -> Option { - let sess = tcx.sess; if let NativeLibKind::Static { bundle: Some(true) | None, whole_archive, .. } = kind - && tcx.crate_types().iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::StaticLib)) + && crate_types.iter().any(|t| matches!(t, &CrateType::Rlib | CrateType::StaticLib)) && (sess.opts.unstable_opts.packed_bundled_libs || has_cfg || whole_archive == Some(true)) { let verbatim = verbatim.unwrap_or(false); @@ -275,16 +275,8 @@ impl<'tcx> Collector<'tcx> { } }; - let filename = find_bundled_library( - attr.name, - attr.verbatim, - attr.kind, - attr.cfg.is_some(), - self.tcx, - ); self.libs.push(NativeLib { name: attr.name, - filename, kind: attr.kind, cfg: attr.cfg.clone(), foreign_module: Some(def_id.to_def_id()), @@ -366,16 +358,8 @@ impl<'tcx> Collector<'tcx> { // Add if not found let new_name: Option<&str> = passed_lib.new_name.as_deref(); let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name)); - let filename = find_bundled_library( - name, - passed_lib.verbatim, - passed_lib.kind, - false, - self.tcx, - ); self.libs.push(NativeLib { name, - filename, kind: passed_lib.kind, cfg: None, foreign_module: None, diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 94237132bd393..c2b517824a058 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -68,8 +68,6 @@ pub enum LinkagePreference { pub struct NativeLib { pub kind: NativeLibKind, pub name: Symbol, - /// If packed_bundled_libs enabled, actual filename of library is stored. - pub filename: Option, pub cfg: Option, pub foreign_module: Option, pub verbatim: Option, From 2de1207818723b801380a808e92d4c844855d9bb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 10 Jul 2026 12:18:51 +0200 Subject: [PATCH 9/9] Apply MCP 1003 and move `diagnostics.rs` into its own module and move `error_helper.rs` into the `diagnostics` folder in `rustc_resolve` --- compiler/rustc_resolve/src/build_reduced_graph.rs | 2 +- .../src/{error_helper.rs => diagnostics/impls.rs} | 0 .../src/{diagnostics.rs => diagnostics/mod.rs} | 2 ++ compiler/rustc_resolve/src/imports.rs | 2 +- compiler/rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 6 +++--- 6 files changed, 8 insertions(+), 6 deletions(-) rename compiler/rustc_resolve/src/{error_helper.rs => diagnostics/impls.rs} (100%) rename compiler/rustc_resolve/src/{diagnostics.rs => diagnostics/mod.rs} (99%) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index c35dc02fb1de1..974577fd89a54 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -31,7 +31,7 @@ use tracing::debug; use crate::Namespace::{MacroNS, TypeNS, ValueNS}; use crate::def_collector::DefCollector; -use crate::error_helper::{OnUnknownData, StructCtor}; +use crate::diagnostics::impls::{OnUnknownData, StructCtor}; use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef}; use crate::ref_mut::CmCell; diff --git a/compiler/rustc_resolve/src/error_helper.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs similarity index 100% rename from compiler/rustc_resolve/src/error_helper.rs rename to compiler/rustc_resolve/src/diagnostics/impls.rs diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics/mod.rs similarity index 99% rename from compiler/rustc_resolve/src/diagnostics.rs rename to compiler/rustc_resolve/src/diagnostics/mod.rs index 22cc6a581f19a..94616f1c679ea 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics/mod.rs @@ -10,6 +10,8 @@ use rustc_span::{Ident, Span, Spanned, Symbol}; use crate::Res; use crate::late::PatternSource; +pub(crate) mod impls; + #[derive(Diagnostic)] #[diag("can't use {$is_self -> [true] `Self` diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 379ae992c9a6e..db7c95fbd511e 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -25,13 +25,13 @@ use rustc_span::{Ident, Span, Symbol, kw, sym}; use tracing::debug; use crate::Namespace::{self, *}; +use crate::diagnostics::impls::{OnUnknownData, Suggestion}; use crate::diagnostics::{ self, CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate, CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates, ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate, }; -use crate::error_helper::{OnUnknownData, Suggestion}; use crate::ref_mut::{CmCell, CmRefCell}; use crate::{ AmbiguityError, BindingKey, CmResolver, Decl, DeclData, DeclKind, Determinacy, Finalize, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 668278f13d9cf..4e901cd76b92e 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -32,7 +32,7 @@ use thin_vec::{ThinVec, thin_vec}; use tracing::debug; use super::NoConstantGenericsReason; -use crate::error_helper::{ImportSuggestion, LabelSuggestion, TypoSuggestion}; +use crate::diagnostics::impls::{ImportSuggestion, LabelSuggestion, TypoSuggestion}; use crate::late::{ AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet, QSelf, RibKind, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 911350665ed32..56e107c0c3369 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -29,7 +29,6 @@ use std::{fmt, mem}; use diagnostics::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; use effective_visibilities::EffectiveVisibilitiesVisitor; -use error_helper::{ImportSuggestion, LabelSuggestion, StructCtor, Suggestion}; use hygiene::Macros20NormalizedSyntaxContext; use imports::{Import, ImportData, ImportKind, NameResolution, PendingDecl}; use late::{ @@ -77,7 +76,9 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; -use crate::error_helper::OnUnknownData; +use crate::diagnostics::impls::{ + ImportSuggestion, LabelSuggestion, OnUnknownData, StructCtor, Suggestion, +}; use crate::imports::NameResolutionRef; use crate::ref_mut::{CmCell, CmRefCell}; @@ -86,7 +87,6 @@ mod check_unused; mod def_collector; mod diagnostics; mod effective_visibilities; -mod error_helper; mod ident; mod imports; mod late;