From cfb6a1f5c7883164b7fd9efb25431c23bda1daf5 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 13 Dec 2025 15:18:07 +0100 Subject: [PATCH 01/22] simplify how inline asm handles `MaybeUninit` --- compiler/rustc_codegen_cranelift/src/inline_asm.rs | 14 ++------------ compiler/rustc_hir_typeck/src/inline_asm.rs | 14 +------------- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 08cabe9d695c3..ac0da06cbb8e3 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -857,19 +857,9 @@ fn call_inline_asm<'tcx>( fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option { match ty.kind() { - // Adapted from https://github.com/rust-lang/rust/blob/f3c66088610c1b80110297c2d9a8b5f9265b013f/compiler/rustc_hir_analysis/src/check/intrinsicck.rs#L136-L151 + // Adapted from https://github.com/rust-lang/rust/blob/df44a57fd29fca899ce473f85ed64efd0708dd7c/compiler/rustc_hir_typeck/src/inline_asm.rs#L180-L183 ty::Adt(adt, args) if fx.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => { - let fields = &adt.non_enum_variant().fields; - let ty = fields[FieldIdx::ONE].ty(fx.tcx, args); - let ty::Adt(ty, args) = ty.kind() else { - unreachable!("expected first field of `MaybeUninit` to be an ADT") - }; - assert!( - ty.is_manually_drop(), - "expected first field of `MaybeUninit` to be `ManuallyDrop`" - ); - let fields = &ty.non_enum_variant().fields; - let ty = fields[FieldIdx::ZERO].ty(fx.tcx, args); + let ty = args.type_at(0); fx.clif_type(ty) } _ => fx.clif_type(ty), diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index 6626c3edb5466..7c1655f8201d7 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -178,19 +178,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Never if is_input => return None, _ if ty.references_error() => return None, ty::Adt(adt, args) if self.tcx().is_lang_item(adt.did(), LangItem::MaybeUninit) => { - let fields = &adt.non_enum_variant().fields; - let ty = fields[FieldIdx::ONE].ty(self.tcx(), args); - // FIXME: Are we just trying to map to the `T` in `MaybeUninit`? - // If so, just get it from the args. - let ty::Adt(ty, args) = ty.kind() else { - unreachable!("expected first field of `MaybeUninit` to be an ADT") - }; - assert!( - ty.is_manually_drop(), - "expected first field of `MaybeUninit` to be `ManuallyDrop`" - ); - let fields = &ty.non_enum_variant().fields; - let ty = fields[FieldIdx::ZERO].ty(self.tcx(), args); + let ty = args.type_at(0); self.get_asm_ty(expr.span, ty) } _ => self.get_asm_ty(expr.span, ty), From ddcd55fa66354b7a3a7b524ba773a06bcbe4ae27 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 9 Nov 2025 17:54:22 +0100 Subject: [PATCH 02/22] Don't allow codegen attributes on trait methods Signed-off-by: Jonathan Brouwer --- compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs | 1 - compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs | 3 +-- compiler/rustc_attr_parsing/src/attributes/link_attrs.rs | 3 +-- compiler/rustc_attr_parsing/src/attributes/repr.rs | 2 +- tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs | 4 ++++ 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 79f7171cc0c86..7323db06a8f1f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -61,7 +61,6 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), - Allow(Target::Method(MethodKind::Trait { body: false })), Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), ]); diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 7d3a7418f06c3..477b8adc67291 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -57,7 +57,6 @@ impl NoArgsAttributeParser for ColdParser { Allow(Target::Fn), Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), - Allow(Target::Method(MethodKind::Trait { body: false })), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::ForeignFn), Allow(Target::Closure), @@ -343,7 +342,7 @@ impl NoArgsAttributeParser for TrackCallerParser { Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), - Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: false })), // `#[track_caller]` is inherited from trait methods Allow(Target::ForeignFn), Allow(Target::Closure), Warn(Target::MacroDef), diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index fe8f3578fe145..79143823bc68f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -469,7 +469,6 @@ impl SingleAttributeParser for LinkSectionParser { Allow(Target::Static), Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), - Allow(Target::Method(MethodKind::Trait { body: false })), Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), ]); @@ -587,12 +586,12 @@ impl SingleAttributeParser for LinkageParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)), - Allow(Target::Method(MethodKind::Trait { body: false })), Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), Allow(Target::Static), Allow(Target::ForeignStatic), Allow(Target::ForeignFn), + Warn(Target::Method(MethodKind::Trait { body: false })), // Not inherited ]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: [ diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 4520e4f5dbac1..8df2f1d2c4685 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -315,7 +315,7 @@ impl AttributeParser for AlignParser { Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::Trait { body: true })), Allow(Target::Method(MethodKind::TraitImpl)), - Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: false })), // `#[align]` is inherited from trait methods Allow(Target::ForeignFn), ]); diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 4b5420a2ff8b4..6716e78a7197a 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -680,6 +680,10 @@ mod link_section { //~| HELP remove the attribute trait Tr { #[link_section = "1800"] + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to + //~| HELP remove the attribute fn inside_tr_no_default(&self); #[link_section = "1800"] From 8fa10c0ed768cc31bfc7a55cf02b9bae4f1fbc86 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 9 Nov 2025 18:34:24 +0100 Subject: [PATCH 03/22] Add regression test for codegen attributes on required trait methods Signed-off-by: Jonathan Brouwer --- .../codegen_attr_on_required_trait_method.rs | 24 +++ ...degen_attr_on_required_trait_method.stderr | 34 ++++ ...issue-43106-gating-of-builtin-attrs.stderr | 169 +++++++++--------- 3 files changed, 147 insertions(+), 80 deletions(-) create mode 100644 tests/ui/attributes/codegen_attr_on_required_trait_method.rs create mode 100644 tests/ui/attributes/codegen_attr_on_required_trait_method.stderr diff --git a/tests/ui/attributes/codegen_attr_on_required_trait_method.rs b/tests/ui/attributes/codegen_attr_on_required_trait_method.rs new file mode 100644 index 0000000000000..6301a5a8ebf70 --- /dev/null +++ b/tests/ui/attributes/codegen_attr_on_required_trait_method.rs @@ -0,0 +1,24 @@ +#![deny(unused_attributes)] +#![feature(linkage)] +#![feature(fn_align)] + +trait Test { + #[cold] + //~^ ERROR cannot be used on required trait methods [unused_attributes] + //~| WARN previously accepted + fn method1(&self); + #[link_section = ".text"] + //~^ ERROR cannot be used on required trait methods [unused_attributes] + //~| WARN previously accepted + fn method2(&self); + #[linkage = "common"] + //~^ ERROR cannot be used on required trait methods [unused_attributes] + //~| WARN previously accepted + fn method3(&self); + #[track_caller] + fn method4(&self); + #[rustc_align(1)] + fn method5(&self); +} + +fn main() {} diff --git a/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr new file mode 100644 index 0000000000000..0770ccae41469 --- /dev/null +++ b/tests/ui/attributes/codegen_attr_on_required_trait_method.stderr @@ -0,0 +1,34 @@ +error: `#[cold]` attribute cannot be used on required trait methods + --> $DIR/codegen_attr_on_required_trait_method.rs:6:5 + | +LL | #[cold] + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[cold]` can be applied to closures, foreign functions, functions, inherent methods, provided trait methods, and trait methods in impl blocks +note: the lint level is defined here + --> $DIR/codegen_attr_on_required_trait_method.rs:1:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: `#[link_section]` attribute cannot be used on required trait methods + --> $DIR/codegen_attr_on_required_trait_method.rs:10:5 + | +LL | #[link_section = ".text"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[link_section]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks + +error: `#[linkage]` attribute cannot be used on required trait methods + --> $DIR/codegen_attr_on_required_trait_method.rs:14:5 + | +LL | #[linkage = "common"] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[linkage]` can be applied to foreign functions, foreign statics, functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks + +error: aborting due to 3 previous errors + diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 676372ad85e05..8ed39a0079ba5 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -203,7 +203,7 @@ LL | #![reexport_test_harness_main = "2900"] | + warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:1 | LL | #[link(name = "x")] | ^^^^^^^^^^^^^^^^^^^ @@ -219,7 +219,7 @@ LL | | } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:832:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -230,7 +230,7 @@ LL | #![crate_type = "0800"] | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:856:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL | #![feature(x0600)] | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:881:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:1 | LL | #[no_main] | ^^^^^^^^^^ @@ -252,7 +252,7 @@ LL | #![no_main] | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:905:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:1 | LL | #[no_builtins] | ^^^^^^^^^^^^^^ @@ -329,7 +329,7 @@ LL | #![reexport_test_harness_main = "2900"] impl S { } | + warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:17 | LL | mod inner { #![link(name = "x")] } | ------------^^^^^^^^^^^^^^^^^^^^-- not an `extern` block @@ -337,7 +337,7 @@ LL | mod inner { #![link(name = "x")] } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 | LL | #[link(name = "x")] fn f() { } | ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block @@ -345,7 +345,7 @@ LL | #[link(name = "x")] fn f() { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[link(name = "x")] struct S; | ^^^^^^^^^^^^^^^^^^^ --------- not an `extern` block @@ -353,7 +353,7 @@ LL | #[link(name = "x")] struct S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:5 | LL | #[link(name = "x")] type T = S; | ^^^^^^^^^^^^^^^^^^^ ----------- not an `extern` block @@ -361,7 +361,7 @@ LL | #[link(name = "x")] type T = S; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5 | LL | #[link(name = "x")] impl S { } | ^^^^^^^^^^^^^^^^^^^ ---------- not an `extern` block @@ -369,7 +369,7 @@ LL | #[link(name = "x")] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5 | LL | #[link(name = "x")] extern "Rust" {} | ^^^^^^^^^^^^^^^^^^^ @@ -377,13 +377,13 @@ LL | #[link(name = "x")] extern "Rust" {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:840:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -394,7 +394,7 @@ LL | #![crate_type = "0800"] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -405,7 +405,7 @@ LL | #![crate_type = "0800"] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -416,7 +416,7 @@ LL | #![crate_type = "0800"] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -427,13 +427,13 @@ LL | #![crate_type = "0800"] impl S { } | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:863:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ @@ -444,7 +444,7 @@ LL | #![feature(x0600)] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ @@ -455,7 +455,7 @@ LL | #![feature(x0600)] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ @@ -466,7 +466,7 @@ LL | #![feature(x0600)] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:879:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ @@ -477,13 +477,13 @@ LL | #![feature(x0600)] impl S { } | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:889:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:888:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ @@ -494,7 +494,7 @@ LL | #![no_main] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ @@ -505,7 +505,7 @@ LL | #![no_main] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ @@ -516,7 +516,7 @@ LL | #![no_main] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:904:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ @@ -527,13 +527,13 @@ LL | #![no_main] impl S { } | + warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:909:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:913:17 | LL | mod inner { #![no_builtins] } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:912:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:916:5 | LL | #[no_builtins] fn f() { } | ^^^^^^^^^^^^^^ @@ -544,7 +544,7 @@ LL | #![no_builtins] fn f() { } | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:916:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:920:5 | LL | #[no_builtins] struct S; | ^^^^^^^^^^^^^^ @@ -555,7 +555,7 @@ LL | #![no_builtins] struct S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:920:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:924:5 | LL | #[no_builtins] type T = S; | ^^^^^^^^^^^^^^ @@ -566,7 +566,7 @@ LL | #![no_builtins] type T = S; | + warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:924:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:928:5 | LL | #[no_builtins] impl S { } | ^^^^^^^^^^^^^^ @@ -1222,8 +1222,17 @@ LL | #[link_section = "1800"] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[link_section]` can be applied to functions and statics +warning: `#[link_section]` attribute cannot be used on required trait methods + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:9 + | +LL | #[link_section = "1800"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[link_section]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks + warning: `#[must_use]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:757:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:1 | LL | #[must_use] | ^^^^^^^^^^^ @@ -1232,7 +1241,7 @@ LL | #[must_use] = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: `#[must_use]` attribute cannot be used on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:17 | LL | mod inner { #![must_use] } | ^^^^^^^^^^^^ @@ -1241,7 +1250,7 @@ LL | mod inner { #![must_use] } = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: `#[must_use]` attribute cannot be used on type aliases - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:771:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:775:5 | LL | #[must_use] type T = S; | ^^^^^^^^^^^ @@ -1250,7 +1259,7 @@ LL | #[must_use] type T = S; = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: `#[must_use]` attribute cannot be used on inherent impl blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:5 | LL | #[must_use] impl S { } | ^^^^^^^^^^^ @@ -1259,13 +1268,13 @@ LL | #[must_use] impl S { } = help: `#[must_use]` can be applied to data types, functions, traits, and unions warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:1 | LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:1 | LL | / mod windows_subsystem { LL | | @@ -1275,67 +1284,67 @@ LL | | } | |_^ warning: the `#![windows_subsystem]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:790:17 | LL | mod inner { #![windows_subsystem="windows"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:38 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:38 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:38 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![windows_subsystem]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:5 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:38 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:38 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:810:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1 | LL | / mod crate_name { LL | | @@ -1345,67 +1354,67 @@ LL | | } | |_^ warning: the `#![crate_name]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:812:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:816:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:815:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:28 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:28 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:28 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:28 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:931:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:935:1 | LL | / mod recursion_limit { LL | | @@ -1415,67 +1424,67 @@ LL | | } | |_^ warning: the `#![recursion_limit]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:936:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:936:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:31 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:31 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:31 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:952:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:31 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:952:31 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:955:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:959:1 | LL | / mod type_length_limit { LL | | @@ -1485,55 +1494,55 @@ LL | | } | |_^ warning: the `#![type_length_limit]` attribute can only be used at the crate root - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:960:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this function - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:960:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:33 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this struct - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:33 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:33 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:976:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: This attribute does not have an `!`, which means it is applied to this implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:33 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:976:33 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^ @@ -1601,5 +1610,5 @@ LL | #![must_use] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[must_use]` can be applied to data types, functions, traits, and unions -warning: 174 warnings emitted +warning: 175 warnings emitted From 7d57c6fc8e59f39765568717f8e687c7a4aa96eb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:40:55 +0000 Subject: [PATCH 04/22] Rename dep_root field of CrateOrigin to dep_root_for_errors --- compiler/rustc_metadata/src/creader.rs | 30 +++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index b02029cd9a19b..ed7943aa2c65f 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -156,8 +156,8 @@ impl<'a> std::fmt::Debug for CrateDump<'a> { enum CrateOrigin<'a> { /// This crate was a dependency of another crate. IndirectDependency { - /// Where this dependency was included from. - dep_root: &'a CratePaths, + /// Where this dependency was included from. Should only be used in error messages. + dep_root_for_errors: &'a CratePaths, /// True if the parent is private, meaning the dependent should also be private. parent_private: bool, /// Dependency info about this crate. @@ -171,9 +171,11 @@ enum CrateOrigin<'a> { impl<'a> CrateOrigin<'a> { /// Return the dependency root, if any. - fn dep_root(&self) -> Option<&'a CratePaths> { + fn dep_root_for_errors(&self) -> Option<&'a CratePaths> { match self { - CrateOrigin::IndirectDependency { dep_root, .. } => Some(dep_root), + CrateOrigin::IndirectDependency { dep_root_for_errors, .. } => { + Some(dep_root_for_errors) + } _ => None, } } @@ -597,8 +599,8 @@ impl CStore { // Maintain a reference to the top most crate. // Stash paths for top-most crate locally if necessary. let crate_paths; - let dep_root = if let Some(dep_root) = origin.dep_root() { - dep_root + let dep_root_for_errors = if let Some(dep_root_for_errors) = origin.dep_root_for_errors() { + dep_root_for_errors } else { crate_paths = CratePaths::new(crate_root.name(), source.clone()); &crate_paths @@ -606,7 +608,7 @@ impl CStore { let cnum_map = self.resolve_crate_deps( tcx, - dep_root, + dep_root_for_errors, &crate_root, &metadata, cnum, @@ -757,7 +759,7 @@ impl CStore { return Err(CrateError::NonAsciiName(name)); } - let dep_root = origin.dep_root(); + let dep_root_for_errors = origin.dep_root_for_errors(); let dep = origin.dep(); let hash = dep.map(|d| d.hash); let host_hash = dep.map(|d| d.host_hash).flatten(); @@ -795,7 +797,11 @@ impl CStore { host_hash, )? { Some(res) => res, - None => return Err(locator.into_error(crate_rejections, dep_root.cloned())), + None => { + return Err( + locator.into_error(crate_rejections, dep_root_for_errors.cloned()) + ); + } } } } @@ -856,7 +862,7 @@ impl CStore { fn resolve_crate_deps( &mut self, tcx: TyCtxt<'_>, - dep_root: &CratePaths, + dep_root_for_errors: &CratePaths, crate_root: &CrateRoot, metadata: &MetadataBlob, krate: CrateNum, @@ -866,7 +872,7 @@ impl CStore { debug!( "resolving deps of external crate `{}` with dep root `{}`", crate_root.name(), - dep_root.name + dep_root_for_errors.name ); if crate_root.is_proc_macro_crate() { return Ok(CrateNumMap::new()); @@ -896,7 +902,7 @@ impl CStore { dep.name, dep_kind, CrateOrigin::IndirectDependency { - dep_root, + dep_root_for_errors, parent_private: parent_is_private, dep: &dep, }, From a0f8dffeee3d3906033e88d2a278bd0863d39ccf Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:43:06 +0000 Subject: [PATCH 05/22] Use CrateDepKind::Explicit for the profiler runtime It is unconditionally included. --- compiler/rustc_codegen_ssa/src/back/link.rs | 4 +--- compiler/rustc_metadata/src/creader.rs | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 9abd7c1dd9c68..9b789d9e62b70 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2792,11 +2792,9 @@ fn add_upstream_rust_crates( // We must always link crates `compiler_builtins` and `profiler_builtins` statically. // Even if they were already included into a dylib // (e.g. `libstd` when `-C prefer-dynamic` is used). - // FIXME: `dependency_formats` can report `profiler_builtins` as `NotLinked` for some - // reason, it shouldn't do that because `profiler_builtins` should indeed be linked. let linkage = data[cnum]; let link_static_crate = linkage == Linkage::Static - || (linkage == Linkage::IncludedFromDylib || linkage == Linkage::NotLinked) + || linkage == Linkage::IncludedFromDylib && (codegen_results.crate_info.compiler_builtins == Some(cnum) || codegen_results.crate_info.profiler_runtime == Some(cnum)); diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index ed7943aa2c65f..5d58d5bae41ce 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -985,6 +985,8 @@ impl CStore { }; info!("panic runtime not found -- loading {}", name); + // This has to be implicit as both panic_unwind and panic_abort may be present in the crate + // graph at the same time. One of them will later be activated in dependency_formats. let Some(cnum) = self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected) else { @@ -1016,7 +1018,7 @@ impl CStore { let name = Symbol::intern(&tcx.sess.opts.unstable_opts.profiler_runtime); let Some(cnum) = - self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected) + self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Explicit, CrateOrigin::Injected) else { return; }; From c7a99e202911fc6b2e590282b07af452e8899352 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:47:47 +0000 Subject: [PATCH 06/22] Rename variants of CrateDepKind to be more descriptive Perhaps the old name used to be accurate in the past, but nowadays most injected dependencies are unconditionally linked too. --- compiler/rustc_metadata/src/creader.rs | 36 +++++++++++-------- .../rustc_metadata/src/dependency_format.rs | 6 ++-- compiler/rustc_session/src/cstore.rs | 13 +++---- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 5d58d5bae41ce..4be579f1e64ac 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -737,7 +737,7 @@ impl CStore { .maybe_resolve_crate( tcx, sym::core, - CrateDepKind::Explicit, + CrateDepKind::Unconditional, CrateOrigin::Extern, ) .is_err(); @@ -985,11 +985,15 @@ impl CStore { }; info!("panic runtime not found -- loading {}", name); - // This has to be implicit as both panic_unwind and panic_abort may be present in the crate - // graph at the same time. One of them will later be activated in dependency_formats. - let Some(cnum) = - self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected) - else { + // This has to be conditional as both panic_unwind and panic_abort may be present in the + // crate graph at the same time. One of them will later be activated in dependency_formats. + let Some(cnum) = self.resolve_crate( + tcx, + name, + DUMMY_SP, + CrateDepKind::Conditional, + CrateOrigin::Injected, + ) else { return; }; let data = self.get_crate_data(cnum); @@ -1017,9 +1021,13 @@ impl CStore { info!("loading profiler"); let name = Symbol::intern(&tcx.sess.opts.unstable_opts.profiler_runtime); - let Some(cnum) = - self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Explicit, CrateOrigin::Injected) - else { + let Some(cnum) = self.resolve_crate( + tcx, + name, + DUMMY_SP, + CrateDepKind::Unconditional, + CrateOrigin::Injected, + ) else { return; }; let data = self.get_crate_data(cnum); @@ -1139,7 +1147,7 @@ impl CStore { tcx, name_interned, DUMMY_SP, - CrateDepKind::Explicit, + CrateDepKind::Unconditional, CrateOrigin::Extern, ); } @@ -1171,7 +1179,7 @@ impl CStore { tcx, sym::compiler_builtins, krate.spans.inner_span.shrink_to_lo(), - CrateDepKind::Explicit, + CrateDepKind::Unconditional, CrateOrigin::Injected, ) else { info!("`compiler_builtins` not resolved"); @@ -1288,7 +1296,7 @@ impl CStore { let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) { CrateDepKind::MacrosOnly } else { - CrateDepKind::Explicit + CrateDepKind::Unconditional }; let cnum = @@ -1318,7 +1326,7 @@ impl CStore { span: Span, ) -> Option { let cnum = - self.resolve_crate(tcx, name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?; + self.resolve_crate(tcx, name, span, CrateDepKind::Unconditional, CrateOrigin::Extern)?; self.update_extern_crate( cnum, @@ -1336,7 +1344,7 @@ impl CStore { } pub fn maybe_process_path_extern(&mut self, tcx: TyCtxt<'_>, name: Symbol) -> Option { - self.maybe_resolve_crate(tcx, name, CrateDepKind::Explicit, CrateOrigin::Extern).ok() + self.maybe_resolve_crate(tcx, name, CrateDepKind::Unconditional, CrateOrigin::Extern).ok() } } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 8054a48d37af1..7b8e8cb42e536 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -242,7 +242,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { let src = tcx.used_crate_source(cnum); if src.dylib.is_none() && !formats.contains_key(&cnum) - && tcx.dep_kind(cnum) == CrateDepKind::Explicit + && tcx.dep_kind(cnum) == CrateDepKind::Unconditional { assert!(src.rlib.is_some() || src.rmeta.is_some()); info!("adding staticlib: {}", tcx.crate_name(cnum)); @@ -355,8 +355,8 @@ fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec) -> Option Linkage::Static, - CrateDepKind::MacrosOnly | CrateDepKind::Implicit => Linkage::NotLinked, + CrateDepKind::Unconditional => Linkage::Static, + CrateDepKind::MacrosOnly | CrateDepKind::Conditional => Linkage::NotLinked, }), cnum ); diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 9d000bc28edd2..2f969aefda182 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -39,12 +39,13 @@ impl CrateSource { pub enum CrateDepKind { /// A dependency that is only used for its macros. MacrosOnly, - /// A dependency that is always injected into the dependency list and so - /// doesn't need to be linked to an rlib, e.g., the injected panic runtime. - Implicit, + /// A dependency that is injected into the crate graph but which only + /// sometimes needs to actually be linked in, e.g., the injected panic runtime. + Conditional, /// A dependency that is required by an rlib version of this crate. - /// Ordinary `extern crate`s result in `Explicit` dependencies. - Explicit, + /// Ordinary `extern crate`s as well as most injected dependencies result + /// in `Unconditional` dependencies. + Unconditional, } impl CrateDepKind { @@ -52,7 +53,7 @@ impl CrateDepKind { pub fn macros_only(self) -> bool { match self { CrateDepKind::MacrosOnly => true, - CrateDepKind::Implicit | CrateDepKind::Explicit => false, + CrateDepKind::Conditional | CrateDepKind::Unconditional => false, } } } From aff1f2a0de2c69e071e543540fa0447169325738 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:50:13 +0000 Subject: [PATCH 07/22] Handle CrateOrigin::Injected in CrateOrigin::private_dep --- compiler/rustc_metadata/src/creader.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 4be579f1e64ac..f4ce692f41a8c 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -195,6 +195,7 @@ impl<'a> CrateOrigin<'a> { CrateOrigin::IndirectDependency { parent_private, dep, .. } => { Some(dep.is_private || *parent_private) } + CrateOrigin::Injected => Some(true), _ => None, } } @@ -546,17 +547,7 @@ impl CStore { /// Sometimes the directly dependent crate is not specified by `--extern`, in this case, /// `private-dep` is none during loading. This is equivalent to the scenario where the /// command parameter is set to `public-dependency` - fn is_private_dep( - &self, - externs: &Externs, - name: Symbol, - private_dep: Option, - origin: CrateOrigin<'_>, - ) -> bool { - if matches!(origin, CrateOrigin::Injected) { - return true; - } - + fn is_private_dep(&self, externs: &Externs, name: Symbol, private_dep: Option) -> bool { let extern_private = externs.get(name.as_str()).map(|e| e.is_private_dep); match (extern_private, private_dep) { // Explicit non-private via `--extern`, explicit non-private from metadata, or @@ -583,7 +574,7 @@ impl CStore { let Library { source, metadata } = lib; let crate_root = metadata.get_root(); let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash()); - let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin); + let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep); // Claim this crate number and cache it let feed = self.intern_stable_crate_id(tcx, &crate_root)?; @@ -814,8 +805,7 @@ impl CStore { // not specified by `--extern` on command line parameters, it may be // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to // `public-dependency` here. - let private_dep = - self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin); + let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep); let data = self.get_crate_data_mut(cnum); if data.is_proc_macro_crate() { dep_kind = CrateDepKind::MacrosOnly; From 0e1e72a4e7be62e624e5a46a3b9ca729ee600c33 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 28 Nov 2025 20:54:57 +0000 Subject: [PATCH 08/22] Remove dependencies field of CrateMetadata It is always identical to the list of values in cnum_map. --- compiler/rustc_metadata/src/creader.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 6 +----- .../src/rmeta/decoder/cstore_impl.rs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f4ce692f41a8c..4000f12459a90 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -719,7 +719,7 @@ impl CStore { self.used_extern_options.insert(name); match self.maybe_resolve_crate(tcx, name, dep_kind, origin) { Ok(cnum) => { - self.set_used_recursively(tcx, cnum); + self.set_used_recursively(cnum); Some(cnum) } Err(err) => { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 5f7bda9c9064f..e3c2113fe71c6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -116,8 +116,6 @@ pub(crate) struct CrateMetadata { /// Maps crate IDs as they are were seen from this crate's compilation sessions into /// IDs as they are seen from the current compilation session. cnum_map: CrateNumMap, - /// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime. - dependencies: Vec, /// How to link (or not link) this crate to the currently compiled crate. dep_kind: CrateDepKind, /// Filesystem location of this crate. @@ -1897,7 +1895,6 @@ impl CrateMetadata { .collect(); let alloc_decoding_state = AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect()); - let dependencies = cnum_map.iter().copied().collect(); // Pre-decode the DefPathHash->DefIndex table. This is a cheap operation // that does not copy any data. It just does some data verification. @@ -1915,7 +1912,6 @@ impl CrateMetadata { alloc_decoding_state, cnum, cnum_map, - dependencies, dep_kind, source: Arc::new(source), private_dep, @@ -1941,7 +1937,7 @@ impl CrateMetadata { } pub(crate) fn dependencies(&self) -> impl Iterator { - self.dependencies.iter().copied() + self.cnum_map.iter().copied() } pub(crate) fn target_modifiers(&self) -> TargetModifiers { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index f441788fdcb6a..36fe7f380069c 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -623,15 +623,15 @@ impl CStore { self.get_crate_data(cnum).get_proc_macro_quoted_span(tcx, id) } - pub fn set_used_recursively(&mut self, tcx: TyCtxt<'_>, cnum: CrateNum) { + pub fn set_used_recursively(&mut self, cnum: CrateNum) { let cmeta = self.get_crate_data_mut(cnum); if !cmeta.used { cmeta.used = true; - let dependencies = mem::take(&mut cmeta.dependencies); - for &dep_cnum in &dependencies { - self.set_used_recursively(tcx, dep_cnum); + let cnum_map = mem::take(&mut cmeta.cnum_map); + for &dep_cnum in cnum_map.iter() { + self.set_used_recursively(dep_cnum); } - self.get_crate_data_mut(cnum).dependencies = dependencies; + self.get_crate_data_mut(cnum).cnum_map = cnum_map; } } @@ -663,11 +663,11 @@ impl CStore { if cmeta.update_extern_crate_diagnostics(extern_crate) { // Propagate the extern crate info to dependencies if it was updated. let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate }; - let dependencies = mem::take(&mut cmeta.dependencies); - for &dep_cnum in &dependencies { + let cnum_map = mem::take(&mut cmeta.cnum_map); + for &dep_cnum in cnum_map.iter() { self.update_transitive_extern_crate_diagnostics(dep_cnum, extern_crate); } - self.get_crate_data_mut(cnum).dependencies = dependencies; + self.get_crate_data_mut(cnum).cnum_map = cnum_map; } } } From f55053224d9cc0c4380d572b256580cb9deae3d4 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Mon, 15 Dec 2025 10:47:58 +0100 Subject: [PATCH 09/22] Port `#[rustc_legacy_const_generics]` to use attribute parser --- compiler/rustc_ast_lowering/src/lib.rs | 36 ++--- .../src/attributes/rustc_internal.rs | 46 +++++++ compiler/rustc_attr_parsing/src/context.rs | 6 +- .../rustc_hir/src/attrs/data_structures.rs | 3 + .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../rustc_hir/src/attrs/pretty_printing.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 1 - compiler/rustc_passes/messages.ftl | 3 - compiler/rustc_passes/src/check_attr.rs | 64 +++------ compiler/rustc_passes/src/errors.rs | 7 - compiler/rustc_resolve/src/lib.rs | 63 ++++----- src/librustdoc/clean/mod.rs | 36 +++-- ...d-rustc_legacy_const_generics-arguments.rs | 20 +-- ...stc_legacy_const_generics-arguments.stderr | 125 +++++++++++------- 14 files changed, 226 insertions(+), 187 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 10093da97fe34..d0871b0b98f45 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -237,25 +237,27 @@ impl SpanLowerer { #[extension(trait ResolverAstLoweringExt)] impl ResolverAstLowering { fn legacy_const_generic_args(&self, expr: &Expr) -> Option> { - if let ExprKind::Path(None, path) = &expr.kind { - // Don't perform legacy const generics rewriting if the path already - // has generic arguments. - if path.segments.last().unwrap().args.is_some() { - return None; - } + let ExprKind::Path(None, path) = &expr.kind else { + return None; + }; - if let Res::Def(DefKind::Fn, def_id) = self.partial_res_map.get(&expr.id)?.full_res()? { - // We only support cross-crate argument rewriting. Uses - // within the same crate should be updated to use the new - // const generics style. - if def_id.is_local() { - return None; - } + // Don't perform legacy const generics rewriting if the path already + // has generic arguments. + if path.segments.last().unwrap().args.is_some() { + return None; + } - if let Some(v) = self.legacy_const_generic_args.get(&def_id) { - return v.clone(); - } - } + let def_id = self.partial_res_map.get(&expr.id)?.full_res()?.opt_def_id()?; + + // We only support cross-crate argument rewriting. Uses + // within the same crate should be updated to use the new + // const generics style. + if def_id.is_local() { + return None; + } + + if let Some(v) = self.legacy_const_generic_args.get(&def_id) { + return v.clone(); } None diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index d51fa2510b936..8cfe812f0c274 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -1,3 +1,5 @@ +use rustc_ast::{LitIntType, LitKind, MetaItemLit}; + use super::prelude::*; use super::util::parse_single_integer; @@ -76,3 +78,47 @@ impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?)) } } + +pub(crate) struct RustcLegacyConstGenericsParser; + +impl SingleAttributeParser for RustcLegacyConstGenericsParser { + const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + const TEMPLATE: AttributeTemplate = template!(List: &["N"]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let ArgParser::List(meta_items) = args else { + cx.expected_list(cx.attr_span, args); + return None; + }; + + let mut parsed_indexes = ThinVec::new(); + let mut errored = false; + + for possible_index in meta_items.mixed() { + if let MetaItemOrLitParser::Lit(MetaItemLit { + kind: LitKind::Int(index, LitIntType::Unsuffixed), + .. + }) = possible_index + { + parsed_indexes.push((index.0 as usize, possible_index.span())); + } else { + cx.expected_integer_literal(possible_index.span()); + errored = true; + } + } + if errored { + return None; + } else if parsed_indexes.is_empty() { + cx.expected_at_least_one_argument(args.span()?); + return None; + } + + Some(AttributeKind::RustcLegacyConstGenerics { + fn_indexes: parsed_indexes, + attr_span: cx.attr_span, + }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8f5f5c55dcd59..fb9cb8fa42773 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -59,8 +59,9 @@ use crate::attributes::proc_macro_attrs::{ use crate::attributes::prototype::CustomMirParser; use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ - RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcMainParser, - RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser, + RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, + RustcLegacyConstGenericsParser, RustcMainParser, RustcObjectLifetimeDefaultParser, + RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ @@ -208,6 +209,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 34d78afca9b2c..83fa70b74b444 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -869,6 +869,9 @@ pub enum AttributeKind { /// Represents `#[rustc_layout_scalar_valid_range_start]`. RustcLayoutScalarValidRangeStart(Box, Span), + /// Represents `#[rustc_legacy_const_generics]` + RustcLegacyConstGenerics { fn_indexes: ThinVec<(usize, Span)>, attr_span: Span }, + /// Represents `#[rustc_main]`. RustcMain, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 4cb786f59bfe4..2dbb0e42149cd 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -92,6 +92,7 @@ impl AttributeKind { RustcCoherenceIsCore(..) => No, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, + RustcLegacyConstGenerics { .. } => Yes, RustcMain => No, RustcObjectLifetimeDefault => No, RustcPassIndirectlyInNonRusticAbis(..) => No, diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index 0ad486cef43d0..9d42c005d5dab 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -159,7 +159,7 @@ macro_rules! print_tup { print_tup!(A B C D E F G H); print_skip!(Span, (), ErrorGuaranteed); -print_disp!(u16, u128, bool, NonZero, Limit); +print_disp!(u16, u128, usize, bool, NonZero, Limit); print_debug!( Symbol, Ident, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b91176e3d4862..79f3f935ecd92 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -195,7 +195,6 @@ pub struct ResolverGlobalCtxt { #[derive(Debug)] pub struct ResolverAstLowering { pub legacy_const_generic_args: FxHashMap>>, - /// Resolutions for nodes that have a single resolution. pub partial_res_map: NodeMap, /// Resolutions for import nodes, which have multiple resolutions in different namespaces. diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 21191085253bd..0f206edcc7758 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -478,9 +478,6 @@ passes_rustc_legacy_const_generics_index_exceed = *[other] arguments } -passes_rustc_legacy_const_generics_index_negative = - arguments should be non-negative integers - passes_rustc_legacy_const_generics_only = #[rustc_legacy_const_generics] functions must only have const generics .label = non-const generic parameter diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 34f73212e90bd..0506728f6afc0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,9 +10,10 @@ use std::collections::hash_map::Entry; use std::slice; use rustc_abi::{Align, ExternAbi, Size}; -use rustc_ast::{AttrStyle, LitKind, MetaItemKind, ast}; +use rustc_ast::{AttrStyle, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, @@ -211,6 +212,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::MacroExport { span, .. }) => { self.check_macro_export(hir_id, *span, target) }, + Attribute::Parsed(AttributeKind::RustcLegacyConstGenerics{attr_span, fn_indexes}) => { + self.check_rustc_legacy_const_generics(item, *attr_span, fn_indexes) + }, Attribute::Parsed(AttributeKind::Doc(attr)) => self.check_doc_attrs(attr, hir_id, target), Attribute::Parsed(AttributeKind::EiiImpls(impls)) => { self.check_eii_impl(impls, target) @@ -305,9 +309,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_never_returns_null_ptr, ..] => { self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target) } - [sym::rustc_legacy_const_generics, ..] => { - self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item) - } [sym::rustc_lint_query_instability, ..] => { self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target) } @@ -1217,33 +1218,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument. fn check_rustc_legacy_const_generics( &self, - hir_id: HirId, - attr: &Attribute, - span: Span, - target: Target, item: Option>, + attr_span: Span, + index_list: &ThinVec<(usize, Span)>, ) { - let is_function = matches!(target, Target::Fn); - if !is_function { - self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span(), - defn_span: span, - on_crate: hir_id == CRATE_HIR_ID, - }); - return; - } - - let Some(list) = attr.meta_item_list() else { - // The attribute form is validated on AST. - return; - }; - let Some(ItemLike::Item(Item { kind: ItemKind::Fn { sig: FnSig { decl, .. }, generics, .. }, .. })) = item else { - bug!("should be a function item"); + // No error here, since it's already given by the parser + return; }; for param in generics.params { @@ -1251,7 +1236,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { hir::GenericParamKind::Const { .. } => {} _ => { self.dcx().emit_err(errors::RustcLegacyConstGenericsOnly { - attr_span: attr.span(), + attr_span, param_span: param.span, }); return; @@ -1259,34 +1244,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - if list.len() != generics.params.len() { + if index_list.len() != generics.params.len() { self.dcx().emit_err(errors::RustcLegacyConstGenericsIndex { - attr_span: attr.span(), + attr_span, generics_span: generics.span, }); return; } - let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128; - let mut invalid_args = vec![]; - for meta in list { - if let Some(LitKind::Int(val, _)) = meta.lit().map(|lit| &lit.kind) { - if *val >= arg_count { - let span = meta.span(); - self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexExceed { - span, - arg_count: arg_count as usize, - }); - return; - } - } else { - invalid_args.push(meta.span()); + let arg_count = decl.inputs.len() + generics.params.len(); + for (index, span) in index_list { + if *index >= arg_count { + self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexExceed { + span: *span, + arg_count, + }); } } - - if !invalid_args.is_empty() { - self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args }); - } } /// Helper function for checking that the provided attribute is only applied to a function or diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7abd2c703aeb4..8ead69da9916c 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -290,13 +290,6 @@ pub(crate) struct RustcLegacyConstGenericsIndexExceed { pub arg_count: usize, } -#[derive(Diagnostic)] -#[diag(passes_rustc_legacy_const_generics_index_negative)] -pub(crate) struct RustcLegacyConstGenericsIndexNegative { - #[primary_span] - pub invalid_args: Vec, -} - #[derive(Diagnostic)] #[diag(passes_rustc_dirty_clean)] pub(crate) struct RustcDirtyClean { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b3141406e467e..d373d6136b523 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -44,7 +44,7 @@ use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; use rustc_ast::{ self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs, - LitKind, NodeId, Path, attr, + NodeId, Path, attr, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; @@ -54,7 +54,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed, LintBuffer}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; -use rustc_hir::attrs::StrippedCfgItem; +use rustc_hir::attrs::{AttributeKind, StrippedCfgItem}; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{ self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, MacroKinds, NonMacroAttrKind, PartialRes, @@ -62,7 +62,7 @@ use rustc_hir::def::{ }; use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; use rustc_hir::definitions::DisambiguatorState; -use rustc_hir::{PrimTy, TraitCandidate}; +use rustc_hir::{PrimTy, TraitCandidate, find_attr}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::CStore; use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; @@ -1676,8 +1676,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { node_id_to_def_id, disambiguator: DisambiguatorState::new(), placeholder_field_indices: Default::default(), - invocation_parents, legacy_const_generic_args: Default::default(), + invocation_parents, item_generics_num_lifetimes: Default::default(), trait_impls: Default::default(), confused_type_with_std_module: Default::default(), @@ -2396,40 +2396,33 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// `#[rustc_legacy_const_generics]` and returns the argument index list /// from the attribute. fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option> { - if let ExprKind::Path(None, path) = &expr.kind { - // Don't perform legacy const generics rewriting if the path already - // has generic arguments. - if path.segments.last().unwrap().args.is_some() { - return None; - } - - let res = self.partial_res_map.get(&expr.id)?.full_res()?; - if let Res::Def(def::DefKind::Fn, def_id) = res { - // We only support cross-crate argument rewriting. Uses - // within the same crate should be updated to use the new - // const generics style. - if def_id.is_local() { - return None; - } + let ExprKind::Path(None, path) = &expr.kind else { + return None; + }; + // Don't perform legacy const generics rewriting if the path already + // has generic arguments. + if path.segments.last().unwrap().args.is_some() { + return None; + } - if let Some(v) = self.legacy_const_generic_args.get(&def_id) { - return v.clone(); - } + let def_id = self.partial_res_map.get(&expr.id)?.full_res()?.opt_def_id()?; - let attr = self.tcx.get_attr(def_id, sym::rustc_legacy_const_generics)?; - let mut ret = Vec::new(); - for meta in attr.meta_item_list()? { - match meta.lit()?.kind { - LitKind::Int(a, _) => ret.push(a.get() as usize), - _ => panic!("invalid arg index"), - } - } - // Cache the lookup to avoid parsing attributes for an item multiple times. - self.legacy_const_generic_args.insert(def_id, Some(ret.clone())); - return Some(ret); - } + // We only support cross-crate argument rewriting. Uses + // within the same crate should be updated to use the new + // const generics style. + if def_id.is_local() { + return None; } - None + + let indexes = find_attr!( + // we can use parsed attrs here since for other crates they're already available + self.tcx.get_all_attrs(def_id), + AttributeKind::RustcLegacyConstGenerics{fn_indexes,..} => fn_indexes + ) + .map(|fn_indexes| fn_indexes.iter().map(|(num, _)| *num).collect()); + + self.legacy_const_generic_args.insert(def_id, indexes.clone()); + indexes } fn resolve_main(&mut self) { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dd5c50d2ba37c..3696f0ca5fd7a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -38,6 +38,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, In use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::codes::*; use rustc_errors::{FatalError, struct_span_code_err}; +use rustc_hir as hir; use rustc_hir::attrs::{AttributeKind, DocAttribute, DocInline}; use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; @@ -54,7 +55,6 @@ use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_trait_selection::traits::wf::object_region_bounds; use tracing::{debug, instrument}; use utils::*; -use {rustc_ast as ast, rustc_hir as hir}; pub(crate) use self::cfg::{CfgInfo, extract_cfg_from_attrs}; pub(crate) use self::types::*; @@ -1026,26 +1026,20 @@ fn clean_fn_or_proc_macro<'tcx>( /// `rustc_legacy_const_generics`. More information in /// . fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attribute]) { - for meta_item_list in attrs - .iter() - .filter(|a| a.has_name(sym::rustc_legacy_const_generics)) - .filter_map(|a| a.meta_item_list()) - { - for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() { - match literal.kind { - ast::LitKind::Int(a, _) => { - let GenericParamDef { name, kind, .. } = func.generics.params.remove(0); - if let GenericParamDefKind::Const { ty, .. } = kind { - func.decl.inputs.insert( - a.get() as _, - Parameter { name: Some(name), type_: *ty, is_const: true }, - ); - } else { - panic!("unexpected non const in position {pos}"); - } - } - _ => panic!("invalid arg index"), - } + let Some(indexes) = + find_attr!(attrs, AttributeKind::RustcLegacyConstGenerics{fn_indexes,..} => fn_indexes) + else { + return; + }; + + for (pos, (index, _)) in indexes.iter().enumerate() { + let GenericParamDef { name, kind, .. } = func.generics.params.remove(0); + if let GenericParamDefKind::Const { ty, .. } = kind { + func.decl + .inputs + .insert(*index, Parameter { name: Some(name), type_: *ty, is_const: true }); + } else { + panic!("unexpected non const in position {pos}"); } } } diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs b/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs index 73a0363904aeb..03a28fac95def 100644 --- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs +++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.rs @@ -9,20 +9,24 @@ fn foo2() {} #[rustc_legacy_const_generics(2)] //~ ERROR index exceeds number of arguments fn foo3(_: u8) {} -#[rustc_legacy_const_generics(a)] //~ ERROR arguments should be non-negative integers +#[rustc_legacy_const_generics(a)] //~ ERROR malformed `rustc_legacy_const_generics` attribute input fn foo4() {} -#[rustc_legacy_const_generics(1, a, 2, b)] //~ ERROR arguments should be non-negative integers +#[rustc_legacy_const_generics(1, a, 2, b)] +//~^ ERROR malformed `rustc_legacy_const_generics` attribute input +//~^^ ERROR malformed `rustc_legacy_const_generics` attribute input fn foo5() {} -#[rustc_legacy_const_generics(0)] //~ ERROR attribute should be applied to a function +#[rustc_legacy_const_generics(0)] //~ ERROR `#[rustc_legacy_const_generics]` attribute cannot be used on structs struct S; -#[rustc_legacy_const_generics(0usize)] //~ ERROR suffixed literals are not allowed in attributes +#[rustc_legacy_const_generics(0usize)] +//~^ ERROR suffixed literals are not allowed in attributes +//~^^ ERROR malformed `rustc_legacy_const_generics` attribute input fn foo6() {} extern "C" { - #[rustc_legacy_const_generics(1)] //~ ERROR attribute should be applied to a function + #[rustc_legacy_const_generics(1)] //~ ERROR `#[rustc_legacy_const_generics]` attribute cannot be used on foreign functions fn foo7(); //~ ERROR foreign items may not have const parameters } @@ -30,14 +34,14 @@ extern "C" { fn foo8() {} impl S { - #[rustc_legacy_const_generics(0)] //~ ERROR attribute should be applied to a function + #[rustc_legacy_const_generics(0)] //~ ERROR `#[rustc_legacy_const_generics]` attribute cannot be used on inherent methods fn foo9() {} } -#[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute +#[rustc_legacy_const_generics] //~ ERROR malformed `rustc_legacy_const_generics` attribute input fn bar1() {} -#[rustc_legacy_const_generics = 1] //~ ERROR malformed `rustc_legacy_const_generics` attribute +#[rustc_legacy_const_generics = 1] //~ ERROR malformed `rustc_legacy_const_generics` attribute input fn bar2() {} fn main() {} diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr b/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr index 1ced1433fe955..e4da6c86c83e5 100644 --- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr +++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr @@ -1,22 +1,88 @@ +error[E0539]: malformed `rustc_legacy_const_generics` attribute input + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:12:1 + | +LL | #[rustc_legacy_const_generics(a)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | | + | | expected an integer literal here + | help: must be of the form: `#[rustc_legacy_const_generics(N)]` + +error[E0539]: malformed `rustc_legacy_const_generics` attribute input + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:15:1 + | +LL | #[rustc_legacy_const_generics(1, a, 2, b)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^ + | | | + | | expected an integer literal here + | help: must be of the form: `#[rustc_legacy_const_generics(N)]` + +error[E0539]: malformed `rustc_legacy_const_generics` attribute input + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:15:1 + | +LL | #[rustc_legacy_const_generics(1, a, 2, b)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ + | | | + | | expected an integer literal here + | help: must be of the form: `#[rustc_legacy_const_generics(N)]` + +error: `#[rustc_legacy_const_generics]` attribute cannot be used on structs + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:20:1 + | +LL | #[rustc_legacy_const_generics(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_legacy_const_generics]` can only be applied to functions + error: suffixed literals are not allowed in attributes - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:21:31 + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:23:31 | LL | #[rustc_legacy_const_generics(0usize)] | ^^^^^^ | = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -error: malformed `rustc_legacy_const_generics` attribute input - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:37:1 +error[E0539]: malformed `rustc_legacy_const_generics` attribute input + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:23:1 + | +LL | #[rustc_legacy_const_generics(0usize)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^ + | | | + | | expected an integer literal here + | help: must be of the form: `#[rustc_legacy_const_generics(N)]` + +error: `#[rustc_legacy_const_generics]` attribute cannot be used on foreign functions + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:5 + | +LL | #[rustc_legacy_const_generics(1)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_legacy_const_generics]` can only be applied to functions + +error: `#[rustc_legacy_const_generics]` attribute cannot be used on inherent methods + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:37:5 + | +LL | #[rustc_legacy_const_generics(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_legacy_const_generics]` can only be applied to functions + +error[E0539]: malformed `rustc_legacy_const_generics` attribute input + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:41:1 | LL | #[rustc_legacy_const_generics] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[rustc_legacy_const_generics(N)]` -error: malformed `rustc_legacy_const_generics` attribute input - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:40:1 +error[E0539]: malformed `rustc_legacy_const_generics` attribute input + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:44:1 | LL | #[rustc_legacy_const_generics = 1] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_legacy_const_generics(N)]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^ + | | | + | | expected this to be a list + | help: must be of the form: `#[rustc_legacy_const_generics(N)]` error: #[rustc_legacy_const_generics] must have one index for each generic parameter --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:3:1 @@ -38,58 +104,23 @@ error: index exceeds number of arguments LL | #[rustc_legacy_const_generics(2)] | ^ there are only 2 arguments -error: arguments should be non-negative integers - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:12:31 - | -LL | #[rustc_legacy_const_generics(a)] - | ^ - -error: arguments should be non-negative integers - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:15:34 - | -LL | #[rustc_legacy_const_generics(1, a, 2, b)] - | ^ ^ - -error: attribute should be applied to a function definition - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:18:1 - | -LL | #[rustc_legacy_const_generics(0)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | struct S; - | --------- not a function definition - error: #[rustc_legacy_const_generics] functions must only have const generics - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:1 + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:1 | LL | #[rustc_legacy_const_generics(0)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | fn foo8() {} | - non-const generic parameter -error: attribute should be applied to a function definition - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:5 - | -LL | #[rustc_legacy_const_generics(0)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | fn foo9() {} - | ---------------------------- not a function definition - -error: attribute should be applied to a function definition - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:5 - | -LL | #[rustc_legacy_const_generics(1)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | fn foo7(); - | -------------------------- not a function definition - error[E0044]: foreign items may not have const parameters - --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:26:5 + --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:30:5 | LL | fn foo7(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't have const parameters | = help: replace the const parameters with concrete consts -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors -For more information about this error, try `rustc --explain E0044`. +Some errors have detailed explanations: E0044, E0539. +For more information about an error, try `rustc --explain E0044`. From 1fe0a85df732aeffb58e183561ebd22563c0d3cb Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Mon, 10 Nov 2025 14:52:54 +0000 Subject: [PATCH 10/22] Add rv64IM --- compiler/rustc_target/src/spec/mod.rs | 1 + .../targets/riscv64im_unknown_none_elf.rs | 35 ++++++++++++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 1 + .../riscv64im-unknown-none-elf.md | 54 +++++++++++++++++++ tests/assembly-llvm/targets/targets-elf.rs | 3 ++ 6 files changed, 95 insertions(+) create mode 100644 compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs create mode 100644 src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c76e345bb7b64..3d500694c978b 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1686,6 +1686,7 @@ supported_targets! { ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf), ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu), ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl), + ("riscv64im-unknown-none-elf", riscv64im_unknown_none_elf), ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf), ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf), ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu), diff --git a/compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs new file mode 100644 index 0000000000000..6aae40a3f90de --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv64im_unknown_none_elf.rs @@ -0,0 +1,35 @@ +use crate::spec::{ + Arch, Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetMetadata, + TargetOptions, +}; + +pub(crate) fn target() -> Target { + Target { + data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), + llvm_target: "riscv64".into(), + metadata: TargetMetadata { + description: Some("Bare RISC-V (RV64IM ISA)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + arch: Arch::RiscV64, + + options: TargetOptions { + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + cpu: "generic-rv64".into(), + max_atomic_width: Some(64), + atomic_cas: false, + features: "+m,+forced-atomics".into(), + llvm_abiname: "lp64".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + code_model: Some(CodeModel::Medium), + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 832b5a69d47c4..3b8852f8ff9f7 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -112,6 +112,7 @@ - [riscv32i\*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md) - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) + - [riscv64im-unknown-none-elf](platform-support/riscv64im-unknown-none-elf.md) - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md) - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md) - [riscv64a23-unknown-linux-gnu](platform-support/riscv64a23-unknown-linux-gnu.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d772702df76e2..5164ab69d3531 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -184,6 +184,7 @@ target | std | notes [`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA) [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | ✓ |RISC-V Linux (kernel 4.20+, musl 1.2.5) `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) +[`riscv64im-unknown-none-elf`](platform-support/riscv64im-unknown-none-elf.md) | * | Bare RISC-V (RV64IM ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4+, glibc 2.23) [`thumbv6m-none-eabi`](platform-support/thumbv6m-none-eabi.md) | * | Bare Armv6-M diff --git a/src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md new file mode 100644 index 0000000000000..033904959db33 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md @@ -0,0 +1,54 @@ +# `riscv64im-unknown-none-elf` + +**Tier: 3** + +Bare-metal target for RISC-V CPUs with the RV64IM ISA. + +## Target maintainers + +* Rust Embedded Working Group, [RISC-V team](https://github.com/rust-embedded/wg#the-risc-v-team) + +## Requirements + +This target is cross-compiled and uses static linking. The target supports `core` and `alloc`, but not `std`. + +The target does not support atomic compare-and-swap operations, as the RV64IM ISA lacks the "A" (Atomics) extension. Atomic operations are emulated using the `+forced-atomics` feature. + +No external toolchain is required and the default `rust-lld` linker works, but you must specify a linker script. The [`riscv-rt`] crate provides suitable linker scripts. The [`riscv-rust-quickstart`] repository gives examples of RISC-V bare-metal projects. + +[`riscv-rt`]: https://crates.io/crates/riscv-rt +[`riscv-rust-quickstart`]: https://github.com/riscv-rust/riscv-rust-quickstart + +## Building the target + +This target is included in Rust and can be installed via `rustup`: + +```bash +rustup target add riscv64im-unknown-none-elf +``` + +## Building Rust programs + +Build using the standard Cargo workflow: + +```bash +cargo build --target riscv64im-unknown-none-elf +``` + +You will need to provide a linker script. The [`riscv-rt`] crate handles this automatically when used as a dependency. + +## Testing + +This is a cross-compiled `no-std` target, which must be run either in a simulator or by programming onto suitable hardware. It is not possible to run the Rust test-suite on this target. + +You can test the target in QEMU with: + +```bash +qemu-system-riscv64 -machine virt -cpu rv64,a=false,c=false -nographic -semihosting -kernel your-binary +``` + +Note: You must explicitly disable the 'a' (atomics) and 'c' (compressed) extensions when using QEMU to accurately emulate an RV64IM-only CPU. + +## Cross-compilation toolchains and C code + +This target supports C code. If interlinking with C or C++, you may need to use `riscv64-unknown-elf-gcc` with the appropriate `-march=rv64im -mabi=lp64` flags as a linker instead of `rust-lld`. diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index 324c7fc9da4ee..c8b81cc858d6a 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -520,6 +520,9 @@ //@ revisions: riscv64gc_unknown_redox //@ [riscv64gc_unknown_redox] compile-flags: --target riscv64gc-unknown-redox //@ [riscv64gc_unknown_redox] needs-llvm-components: riscv +//@ revisions: riscv64im_unknown_none_elf +//@ [riscv64im_unknown_none_elf] compile-flags: --target riscv64im-unknown-none-elf +//@ [riscv64im_unknown_none_elf] needs-llvm-components: riscv //@ revisions: riscv64imac_unknown_none_elf //@ [riscv64imac_unknown_none_elf] compile-flags: --target riscv64imac-unknown-none-elf //@ [riscv64imac_unknown_none_elf] needs-llvm-components: riscv From 2846968f78b35e31f8087787d930db0708c93908 Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Mon, 10 Nov 2025 14:56:07 +0000 Subject: [PATCH 11/22] add riscv64im to ignore list for stage0 --- src/bootstrap/src/core/sanity.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 50d8154014bbc..d1f706fd9c3e8 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -41,6 +41,7 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ "sparc64-unknown-helenos", // just a dummy comment so the list doesn't get onelined "riscv64gc-unknown-redox", + "riscv64im-unknown-none-elf", "hexagon-unknown-qurt", ]; From 9ba7852ddf317a997f656ac123bdccc8d22db394 Mon Sep 17 00:00:00 2001 From: Kevaundray Wedderburn Date: Mon, 10 Nov 2025 21:25:13 +0000 Subject: [PATCH 12/22] refactor readme --- .../riscv64im-unknown-none-elf.md | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md index 033904959db33..505810caa4254 100644 --- a/src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md +++ b/src/doc/rustc/src/platform-support/riscv64im-unknown-none-elf.md @@ -12,7 +12,7 @@ Bare-metal target for RISC-V CPUs with the RV64IM ISA. This target is cross-compiled and uses static linking. The target supports `core` and `alloc`, but not `std`. -The target does not support atomic compare-and-swap operations, as the RV64IM ISA lacks the "A" (Atomics) extension. Atomic operations are emulated using the `+forced-atomics` feature. +As the RV64IM ISA lacks the "A" (Atomics) extension, atomic operations are emulated using the `+forced-atomics` feature. No external toolchain is required and the default `rust-lld` linker works, but you must specify a linker script. The [`riscv-rt`] crate provides suitable linker scripts. The [`riscv-rust-quickstart`] repository gives examples of RISC-V bare-metal projects. @@ -21,34 +21,27 @@ No external toolchain is required and the default `rust-lld` linker works, but y ## Building the target -This target is included in Rust and can be installed via `rustup`: +You can build Rust with support for the target by adding it to the `target` list in `bootstrap.toml`: -```bash -rustup target add riscv64im-unknown-none-elf +```toml +[build] +target = ["riscv64im-unknown-none-elf"] ``` -## Building Rust programs - -Build using the standard Cargo workflow: +Alternatively, you can use the `-Z build-std` flag to build the standard library on-demand: ```bash -cargo build --target riscv64im-unknown-none-elf +cargo build -Z build-std=core,alloc --target riscv64im-unknown-none-elf ``` -You will need to provide a linker script. The [`riscv-rt`] crate handles this automatically when used as a dependency. +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for this target (see "Building the target" above) ## Testing This is a cross-compiled `no-std` target, which must be run either in a simulator or by programming onto suitable hardware. It is not possible to run the Rust test-suite on this target. -You can test the target in QEMU with: - -```bash -qemu-system-riscv64 -machine virt -cpu rv64,a=false,c=false -nographic -semihosting -kernel your-binary -``` - -Note: You must explicitly disable the 'a' (atomics) and 'c' (compressed) extensions when using QEMU to accurately emulate an RV64IM-only CPU. - ## Cross-compilation toolchains and C code This target supports C code. If interlinking with C or C++, you may need to use `riscv64-unknown-elf-gcc` with the appropriate `-march=rv64im -mabi=lp64` flags as a linker instead of `rust-lld`. From 7cf35566e366a3e251cb3e9e2da9c075ee71d62c Mon Sep 17 00:00:00 2001 From: David <75451291+david-d-h@users.noreply.github.com> Date: Mon, 15 Dec 2025 14:09:13 +0100 Subject: [PATCH 13/22] document that mpmc channels deliver an item to (at most) one receiver --- library/std/src/sync/mpmc/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 673033034eff5..ee9795a528127 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -6,9 +6,10 @@ //! * [`Sender`] //! * [`Receiver`] //! -//! [`Sender`]s are used to send data to a set of [`Receiver`]s. Both -//! sender and receiver are cloneable (multi-producer) such that many threads can send -//! simultaneously to receivers (multi-consumer). +//! [`Sender`]s are used to send data to a set of [`Receiver`]s where each item +//! sent is delivered to (at most) one receiver. Both sender and receiver are +//! cloneable (multi-producer) such that many threads can send simultaneously +//! to receivers (multi-consumer). //! //! These channels come in two flavors: //! From 9c14e3f6317124684da58dd4923427dff40468d5 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sat, 29 Nov 2025 23:22:40 +0530 Subject: [PATCH 14/22] std: sys: fs: uefi: Implement set_times and set_perm - Tested on QEMU OVMF. Signed-off-by: Ayush Singh --- library/std/src/sys/fs/uefi.rs | 52 ++++++++++++++++++++----- library/std/src/sys/pal/uefi/helpers.rs | 4 ++ 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 44f8b6e80f903..21ef70b43dcd6 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -9,7 +9,6 @@ use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::{helpers, unsupported}; -#[expect(dead_code)] const FILE_PERMISSIONS_MASK: u64 = r_efi::protocols::file::READ_ONLY; pub struct File(!); @@ -109,7 +108,6 @@ impl FilePermissions { Self(attr & r_efi::protocols::file::READ_ONLY != 0) } - #[expect(dead_code)] const fn to_attr(&self) -> u64 { if self.0 { r_efi::protocols::file::READ_ONLY } else { 0 } } @@ -366,16 +364,40 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { unsupported() } -pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { - unsupported() +pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { + let f = uefi_fs::File::from_path(p, file::MODE_READ | file::MODE_WRITE, 0)?; + let mut file_info = f.file_info()?; + + unsafe { + (*file_info.as_mut_ptr()).attribute = + ((*file_info.as_ptr()).attribute & !FILE_PERMISSIONS_MASK) | perm.to_attr() + }; + + f.set_file_info(file_info) } -pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> { - unsupported() +pub fn set_times(p: &Path, times: FileTimes) -> io::Result<()> { + // UEFI does not support symlinks + set_times_nofollow(p, times) } -pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> { - unsupported() +pub fn set_times_nofollow(p: &Path, times: FileTimes) -> io::Result<()> { + let f = uefi_fs::File::from_path(p, file::MODE_READ | file::MODE_WRITE, 0)?; + let mut file_info = f.file_info()?; + + if let Some(x) = times.accessed { + unsafe { + (*file_info.as_mut_ptr()).last_access_time = uefi_fs::systemtime_to_uefi(x); + } + } + + if let Some(x) = times.modified { + unsafe { + (*file_info.as_mut_ptr()).modification_time = uefi_fs::systemtime_to_uefi(x); + } + } + + f.set_file_info(file_info) } pub fn rmdir(p: &Path) -> io::Result<()> { @@ -560,6 +582,17 @@ mod uefi_fs { if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(info) } } + pub(crate) fn set_file_info(&self, mut info: UefiBox) -> io::Result<()> { + let file_ptr = self.0.as_ptr(); + let mut info_id = file::INFO_ID; + + let r = unsafe { + ((*file_ptr).set_info)(file_ptr, &mut info_id, info.len(), info.as_mut_ptr().cast()) + }; + + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } + pub(crate) fn delete(self) -> io::Result<()> { let file_ptr = self.0.as_ptr(); let r = unsafe { ((*file_ptr).delete)(file_ptr) }; @@ -643,8 +676,7 @@ mod uefi_fs { } /// Convert to UEFI Time with the current timezone. - #[expect(dead_code)] - fn systemtime_to_uefi(time: SystemTime) -> r_efi::efi::Time { + pub(crate) fn systemtime_to_uefi(time: SystemTime) -> r_efi::efi::Time { let now = time::system_time_internal::now(); time.to_uefi_loose(now.timezone, now.daylight) } diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index bfad6491e3219..d059be010e98b 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -802,6 +802,10 @@ impl UefiBox { pub(crate) fn as_ptr(&self) -> *const T { self.inner.as_ptr().cast() } + + pub(crate) const fn len(&self) -> usize { + self.size + } } impl Drop for UefiBox { From 95c38b2bbaa666c52268902c3dff108615cfa63d Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 8 Nov 2025 11:36:01 -0500 Subject: [PATCH 15/22] Add libgccjit-libs-dir config --- bootstrap.example.toml | 25 +++ src/bootstrap/src/core/build_steps/compile.rs | 187 ++++++++++++++++-- src/bootstrap/src/core/build_steps/dist.rs | 6 +- src/bootstrap/src/core/build_steps/gcc.rs | 155 ++++++++++----- src/bootstrap/src/core/build_steps/test.rs | 7 +- src/bootstrap/src/core/config/config.rs | 7 +- src/bootstrap/src/core/config/toml/gcc.rs | 1 + src/bootstrap/src/lib.rs | 4 - 8 files changed, 313 insertions(+), 79 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 4e850810a30a9..63bf50722ca09 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -191,6 +191,31 @@ # Currently, this is only supported for the `x86_64-unknown-linux-gnu` target. #gcc.download-ci-gcc = false +# Provide a directory of prebuilt libgccjit.so dylibs for given (host, target) compilation pairs. +# This is useful when you want to cross-compile `rustc` to another target since GCC is not a +# multi-target compiler. +# You have to use a directory structure that looks like this: +# `///libgccjit.so`. +# For example: +# +# ``` +# +# ├── m68k-unknown-linux-gnu +# │ └── m68k-unknown-linux-gnu +# │ └── libgccjit.so +# └── x86_64-unknown-linux-gnu +# ├── m68k-unknown-linux-gnu +# │ └── libgccjit.so +# └── x86_64-unknown-linux-gnu +# └── libgccjit.so +# ``` +# The directory above would allow you to cross-compile rustc from x64 to m68k +# +# Note that this option has priority over `gcc.download-ci-gcc`. +# If you set both, bootstrap will first try to load libgccjit.so from this directory. +# Only if it isn't found, it will try to download it from CI or build it locally. +#gcc.libgccjit-libs-dir = "/path/to/libgccjit-libs-dir" + # ============================================================================= # General build configuration options # ============================================================================= diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 82cc25f123bc9..9adf889def002 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -7,7 +7,7 @@ //! goes along from the output of the previous stage. use std::borrow::Cow; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::ffi::OsStr; use std::io::BufReader; use std::io::prelude::*; @@ -19,7 +19,7 @@ use serde_derive::Deserialize; #[cfg(feature = "tracing")] use tracing::span; -use crate::core::build_steps::gcc::{Gcc, GccOutput, add_cg_gcc_cargo_flags}; +use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair, add_cg_gcc_cargo_flags}; use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts}; use crate::core::build_steps::{dist, llvm}; use crate::core::builder; @@ -1576,17 +1576,98 @@ impl Step for RustcLink { } } +/// Set of `libgccjit` dylibs that can be used by `cg_gcc` to compile code for a set of targets. +#[derive(Clone)] +pub struct GccDylibSet { + dylibs: BTreeMap, + host_pair: GccTargetPair, +} + +impl GccDylibSet { + /// Returns the libgccjit.so dylib that corresponds to a host target on which `cg_gcc` will be + /// executed, and which will target the host. So e.g. if `cg_gcc` will be executed on + /// x86_64-unknown-linux-gnu, the host dylib will be for compilation pair + /// `(x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu)`. + fn host_dylib(&self) -> &GccOutput { + self.dylibs.get(&self.host_pair).unwrap_or_else(|| { + panic!("libgccjit.so was not built for host target {}", self.host_pair) + }) + } + + /// Install the libgccjit dylibs to the corresponding target directories of the given compiler. + /// cg_gcc know how to search for the libgccjit dylibs in these directories, according to the + /// (host, target) pair that is being compiled by rustc and cg_gcc. + pub fn install_to(&self, builder: &Builder<'_>, compiler: Compiler) { + if builder.config.dry_run() { + return; + } + + // /lib//codegen-backends + let cg_sysroot = builder.sysroot_codegen_backends(compiler); + + for (target_pair, libgccjit) in &self.dylibs { + assert_eq!( + target_pair.host(), + compiler.host, + "Trying to install libgccjit ({target_pair}) to a compiler with a different host ({})", + compiler.host + ); + let libgccjit = libgccjit.libgccjit(); + let target_filename = libgccjit.file_name().unwrap().to_str().unwrap(); + + // If we build libgccjit ourselves, then `libgccjit` can actually be a symlink. + // In that case, we have to resolve it first, otherwise we'd create a symlink to a + // symlink, which wouldn't work. + let actual_libgccjit_path = t!( + libgccjit.canonicalize(), + format!("Cannot find libgccjit at {}", libgccjit.display()) + ); + + // /lib//libgccjit.so + let dest_dir = cg_sysroot.join("lib").join(target_pair.target()); + t!(fs::create_dir_all(&dest_dir)); + let dst = dest_dir.join(target_filename); + builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); + } + } +} + /// Output of the `compile::GccCodegenBackend` step. -/// It includes the path to the libgccjit library on which this backend depends. +/// +/// It contains paths to all built libgccjit libraries on which this backend depends here. #[derive(Clone)] pub struct GccCodegenBackendOutput { stamp: BuildStamp, - gcc: GccOutput, + dylib_set: GccDylibSet, } +/// Builds the GCC codegen backend (`cg_gcc`). +/// The `cg_gcc` backend uses `libgccjit`, which requires a separate build for each +/// `host -> target` pair. So if you are on linux-x64 and build for linux-aarch64, +/// you will need at least: +/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros) +/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code) +/// +/// We model this by having a single cg_gcc for a given host target, which contains one +/// libgccjit per (host, target) pair. +/// Note that the host target is taken from `self.compilers.target_compiler.host`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GccCodegenBackend { compilers: RustcPrivateCompilers, + targets: Vec, +} + +impl GccCodegenBackend { + /// Build `cg_gcc` that will run on host `H` (`compilers.target_compiler.host`) and will be + /// able to produce code target pairs (`H`, `T`) for all `T` from `targets`. + pub fn for_targets( + compilers: RustcPrivateCompilers, + mut targets: Vec, + ) -> Self { + // Sort targets to improve step cache hits + targets.sort(); + Self { compilers, targets } + } } impl Step for GccCodegenBackend { @@ -1599,23 +1680,34 @@ impl Step for GccCodegenBackend { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(GccCodegenBackend { - compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target), - }); + // By default, build cg_gcc that will only be able to compile native code for the given + // host target. + let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target); + run.builder.ensure(GccCodegenBackend { compilers, targets: vec![run.target] }); } fn run(self, builder: &Builder<'_>) -> Self::Output { - let target = self.compilers.target(); + let host = self.compilers.target(); let build_compiler = self.compilers.build_compiler(); let stamp = build_stamp::codegen_backend_stamp( builder, build_compiler, - target, + host, &CodegenBackendKind::Gcc, ); - let gcc = builder.ensure(Gcc { target }); + let dylib_set = GccDylibSet { + dylibs: self + .targets + .iter() + .map(|&target| { + let target_pair = GccTargetPair::for_target_pair(host, target); + (target_pair, builder.ensure(Gcc { target_pair })) + }) + .collect(), + host_pair: GccTargetPair::for_native_build(host), + }; if builder.config.keep_stage.contains(&build_compiler.stage) { trace!("`keep-stage` requested"); @@ -1625,7 +1717,7 @@ impl Step for GccCodegenBackend { ); // Codegen backends are linked separately from this step today, so we don't do // anything here. - return GccCodegenBackendOutput { stamp, gcc }; + return GccCodegenBackendOutput { stamp, dylib_set }; } let mut cargo = builder::Cargo::new( @@ -1633,21 +1725,21 @@ impl Step for GccCodegenBackend { build_compiler, Mode::Codegen, SourceType::InTree, - target, + host, Kind::Build, ); cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml")); - rustc_cargo_env(builder, &mut cargo, target); + rustc_cargo_env(builder, &mut cargo, host); - add_cg_gcc_cargo_flags(&mut cargo, &gcc); + add_cg_gcc_cargo_flags(&mut cargo, dylib_set.host_dylib()); let _guard = - builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, target); + builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host); let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); GccCodegenBackendOutput { stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()), - gcc, + dylib_set, } } @@ -2324,12 +2416,65 @@ impl Step for Assemble { copy_codegen_backends_to_sysroot(builder, stamp, target_compiler); } CodegenBackendKind::Gcc => { - let output = - builder.ensure(GccCodegenBackend { compilers: prepare_compilers() }); + // We need to build cg_gcc for the host target of the compiler which we + // build here, which is `target_compiler`. + // But we also need to build libgccjit for some additional targets, in + // the most general case. + // 1. We need to build (target_compiler.host, stdlib target) libgccjit + // for all stdlibs that we build, so that cg_gcc can be used to build code + // for all those targets. + // 2. We need to build (target_compiler.host, target_compiler.host) + // libgccjit, so that the target compiler can compile host code (e.g. proc + // macros). + // 3. We need to build (target_compiler.host, host target) libgccjit + // for all *host targets* that we build, so that cg_gcc can be used to + // build a (possibly cross-compiled) stage 2+ rustc. + // + // Assume that we are on host T1 and we do a stage2 build of rustc for T2. + // We want the T2 rustc compiler to be able to use cg_gcc and build code + // for T2 (host) and T3 (target). We also want to build the stage2 compiler + // itself using cg_gcc. + // This could correspond to the following bootstrap invocation: + // `x build rustc --build T1 --host T2 --target T3 --set codegen-backends=['gcc', 'llvm']` + // + // For that, we will need the following GCC target pairs: + // 1. T1 -> T2 (to cross-compile a T2 rustc using cg_gcc running on T1) + // 2. T2 -> T2 (to build host code with the stage 2 rustc running on T2) + // 3. T2 -> T3 (to cross-compile code with the stage 2 rustc running on T2) + // + // FIXME: this set of targets is *maximal*, in reality we might need + // less libgccjits at this current build stage. Try to reduce the set of + // GCC dylibs built below by taking a look at the current stage and whether + // cg_gcc is used as the default codegen backend. + + let compilers = prepare_compilers(); + + // The left side of the target pairs below is implied. It has to match the + // host target on which cg_gcc will run, which is the host target of + // `target_compiler`. We only pass the right side of the target pairs to + // the `GccCodegenBackend` constructor. + let mut targets = HashSet::new(); + // Add all host targets, so that we are able to build host code in this + // bootstrap invocation using cg_gcc. + for target in &builder.hosts { + targets.insert(*target); + } + // Add all stdlib targets, so that the built rustc can produce code for them + for target in &builder.targets { + targets.insert(*target); + } + // Add the host target of the built rustc itself, so that it can build + // host code (e.g. proc macros) using cg_gcc. + targets.insert(compilers.target_compiler().host); + + let output = builder.ensure(GccCodegenBackend::for_targets( + compilers, + targets.into_iter().collect(), + )); copy_codegen_backends_to_sysroot(builder, output.stamp, target_compiler); - // Also copy libgccjit to the library sysroot, so that it is available for - // the codegen backend. - output.gcc.install_to(builder, &rustc_libdir); + // Also copy all requires libgccjit dylibs to the corresponding + // library sysroots, so that they are available for the codegen backend. + output.dylib_set.install_to(builder, target_compiler); } CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue, } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index caf0af35e401d..cbbdc7e024195 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -21,6 +21,7 @@ use tracing::instrument; use crate::core::build_steps::compile::{get_codegen_backend_file, normalize_codegen_backend_name}; use crate::core::build_steps::doc::DocumentationFormat; +use crate::core::build_steps::gcc::GccTargetPair; use crate::core::build_steps::tool::{ self, RustcPrivateCompilers, ToolTargetBuildMode, get_tool_target_compiler, }; @@ -2856,8 +2857,9 @@ impl Step for Gcc { fn run(self, builder: &Builder<'_>) -> Self::Output { let tarball = Tarball::new(builder, "gcc", &self.target.triple); - let output = builder.ensure(super::gcc::Gcc { target: self.target }); - tarball.add_file(&output.libgccjit, "lib", FileType::NativeLibrary); + let output = builder + .ensure(super::gcc::Gcc { target_pair: GccTargetPair::for_native_build(self.target) }); + tarball.add_file(output.libgccjit(), "lib", FileType::NativeLibrary); tarball.generate() } diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index fc87c48f17b68..9cc5d0ed71b16 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -8,49 +8,69 @@ //! GCC and compiler-rt are essentially just wired up to everything else to //! ensure that they're always in place if needed. +use std::fmt::{Display, Formatter}; use std::fs; use std::path::{Path, PathBuf}; use std::sync::OnceLock; -use crate::FileType; use crate::core::builder::{Builder, Cargo, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash}; use crate::utils::exec::command; use crate::utils::helpers::{self, t}; +/// GCC cannot cross-compile from a single binary to multiple targets. +/// So we need to have a separate GCC dylib for each (host, target) pair. +/// We represent this explicitly using this struct. +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct GccTargetPair { + /// Target on which the libgccjit.so dylib will be executed. + host: TargetSelection, + /// Target for which the libgccjit.so dylib will generate assembly. + target: TargetSelection, +} + +impl GccTargetPair { + /// Create a target pair for a GCC that will run on `target` and generate assembly for `target`. + pub fn for_native_build(target: TargetSelection) -> Self { + Self { host: target, target } + } + + /// Create a target pair for a GCC that will run on `host` and generate assembly for `target`. + /// This may be cross-compilation if `host != target`. + pub fn for_target_pair(host: TargetSelection, target: TargetSelection) -> Self { + Self { host, target } + } + + pub fn host(&self) -> TargetSelection { + self.host + } + + pub fn target(&self) -> TargetSelection { + self.target + } +} + +impl Display for GccTargetPair { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{} -> {}", self.host, self.target) + } +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Gcc { - pub target: TargetSelection, + pub target_pair: GccTargetPair, } #[derive(Clone)] pub struct GccOutput { - pub libgccjit: PathBuf, - target: TargetSelection, + /// Path to a built or downloaded libgccjit. + libgccjit: PathBuf, } impl GccOutput { - /// Install the required libgccjit library file(s) to the specified `path`. - pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) { - if builder.config.dry_run() { - return; - } - - let target_filename = self.libgccjit.file_name().unwrap().to_str().unwrap().to_string(); - - // If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink. - // In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink, - // which wouldn't work. - let actual_libgccjit_path = t!( - self.libgccjit.canonicalize(), - format!("Cannot find libgccjit at {}", self.libgccjit.display()) - ); - - let dest_dir = directory.join("rustlib").join(self.target).join("lib"); - t!(fs::create_dir_all(&dest_dir)); - let dst = dest_dir.join(target_filename); - builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); + pub fn libgccjit(&self) -> &Path { + &self.libgccjit } } @@ -64,33 +84,38 @@ impl Step for Gcc { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Gcc { target: run.target }); + // By default, we build libgccjit that can do native compilation (no cross-compilation) + // on a given target. + run.builder + .ensure(Gcc { target_pair: GccTargetPair { host: run.target, target: run.target } }); } /// Compile GCC (specifically `libgccjit`) for `target`. fn run(self, builder: &Builder<'_>) -> Self::Output { - let target = self.target; + let target_pair = self.target_pair; // If GCC has already been built, we avoid building it again. - let metadata = match get_gcc_build_status(builder, target) { - GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path, target }, + let metadata = match get_gcc_build_status(builder, target_pair) { + GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path }, GccBuildStatus::ShouldBuild(m) => m, }; - let _guard = builder.msg_unstaged(Kind::Build, "GCC", target); + let action = Kind::Build.description(); + let msg = format!("{action} GCC for {target_pair}"); + let _guard = builder.group(&msg); t!(metadata.stamp.remove()); let _time = helpers::timeit(builder); let libgccjit_path = libgccjit_built_path(&metadata.install_dir); if builder.config.dry_run() { - return GccOutput { libgccjit: libgccjit_path, target }; + return GccOutput { libgccjit: libgccjit_path }; } - build_gcc(&metadata, builder, target); + build_gcc(&metadata, builder, target_pair); t!(metadata.stamp.write()); - GccOutput { libgccjit: libgccjit_path, target } + GccOutput { libgccjit: libgccjit_path } } } @@ -111,15 +136,27 @@ pub enum GccBuildStatus { /// are available for the given target. /// Returns a path to the libgccjit.so file. #[cfg(not(test))] -fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option { +fn try_download_gcc(builder: &Builder<'_>, target_pair: GccTargetPair) -> Option { use build_helper::git::PathFreshness; // Try to download GCC from CI if configured and available if !matches!(builder.config.gcc_ci_mode, crate::core::config::GccCiMode::DownloadFromCi) { return None; } - if target != "x86_64-unknown-linux-gnu" { - eprintln!("GCC CI download is only available for the `x86_64-unknown-linux-gnu` target"); + + // We currently do not support downloading CI GCC if the host/target pair doesn't match. + if target_pair.host != target_pair.target { + eprintln!( + "GCC CI download is not available when the host ({}) does not equal the compilation target ({}).", + target_pair.host, target_pair.target + ); + return None; + } + + if target_pair.host != "x86_64-unknown-linux-gnu" { + eprintln!( + "GCC CI download is only available for the `x86_64-unknown-linux-gnu` host/target" + ); return None; } let source = detect_gcc_freshness( @@ -132,7 +169,7 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option { // Download from upstream CI - let root = ci_gcc_root(&builder.config, target); + let root = ci_gcc_root(&builder.config, target_pair.target); let gcc_stamp = BuildStamp::new(&root).with_prefix("gcc").add_stamp(&upstream); if !gcc_stamp.is_up_to_date() && !builder.config.dry_run() { builder.config.download_ci_gcc(&upstream, &root); @@ -158,7 +195,7 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option, _target: TargetSelection) -> Option { +fn try_download_gcc(_builder: &Builder<'_>, _target_pair: GccTargetPair) -> Option { None } @@ -167,11 +204,28 @@ fn try_download_gcc(_builder: &Builder<'_>, _target: TargetSelection) -> Option< /// /// It's used to avoid busting caches during x.py check -- if we've already built /// GCC, it's fine for us to not try to avoid doing so. -pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus { - if let Some(path) = try_download_gcc(builder, target) { +pub fn get_gcc_build_status(builder: &Builder<'_>, target_pair: GccTargetPair) -> GccBuildStatus { + // Prefer taking externally provided prebuilt libgccjit dylib + if let Some(dir) = &builder.config.libgccjit_libs_dir { + // The dir structure should be ///libgccjit.so + let host_dir = dir.join(target_pair.host); + let path = host_dir.join(target_pair.target).join("libgccjit.so"); + if path.exists() { + return GccBuildStatus::AlreadyBuilt(path); + } else { + builder.info(&format!( + "libgccjit.so for `{target_pair}` was not found at `{}`", + path.display() + )); + } + } + + // If not available, try to download from CI + if let Some(path) = try_download_gcc(builder, target_pair) { return GccBuildStatus::AlreadyBuilt(path); } + // If not available, try to build (or use already built libgccjit from disk) static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { generate_smart_stamp_hash( @@ -185,8 +239,8 @@ pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> G builder.config.update_submodule("src/gcc"); let root = builder.src.join("src/gcc"); - let out_dir = builder.gcc_out(target).join("build"); - let install_dir = builder.gcc_out(target).join("install"); + let out_dir = gcc_out(builder, target_pair).join("build"); + let install_dir = gcc_out(builder, target_pair).join("install"); let stamp = BuildStamp::new(&out_dir).with_prefix("gcc").add_stamp(smart_stamp_hash); @@ -215,15 +269,20 @@ pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> G GccBuildStatus::ShouldBuild(Meta { stamp, out_dir, install_dir, root }) } +fn gcc_out(builder: &Builder<'_>, pair: GccTargetPair) -> PathBuf { + builder.out.join(pair.host).join("gcc").join(pair.target) +} + /// Returns the path to a libgccjit.so file in the install directory of GCC. fn libgccjit_built_path(install_dir: &Path) -> PathBuf { install_dir.join("lib/libgccjit.so") } -fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) { - if builder.build.cc_tool(target).is_like_clang() - || builder.build.cxx_tool(target).is_like_clang() - { +fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target_pair: GccTargetPair) { + // Target on which libgccjit.so will be executed. Here we will generate a dylib with + // instructions for that target. + let host = target_pair.host; + if builder.build.cc_tool(host).is_like_clang() || builder.build.cxx_tool(host).is_like_clang() { panic!( "Attempting to build GCC using Clang, which is known to misbehave. Please use GCC as the host C/C++ compiler. " ); @@ -241,7 +300,7 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) { // builds. // Therefore, we first copy the whole source directory to the build directory, and perform the // build from there. - let src_dir = builder.gcc_out(target).join("src"); + let src_dir = gcc_out(builder, target_pair).join("src"); if src_dir.exists() { builder.remove_dir(&src_dir); } @@ -259,7 +318,7 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) { .arg("--disable-multilib") .arg(format!("--prefix={}", install_dir.display())); - let cc = builder.build.cc(target).display().to_string(); + let cc = builder.build.cc(host).display().to_string(); let cc = builder .build .config @@ -268,7 +327,7 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) { .map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}")); configure_cmd.env("CC", cc); - if let Ok(ref cxx) = builder.build.cxx(target) { + if let Ok(ref cxx) = builder.build.cxx(host) { let cxx = cxx.display().to_string(); let cxx = builder .build diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 9f8bb4dea54fd..05aa2521b2e0a 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -16,7 +16,7 @@ use build_helper::exit; use crate::core::build_steps::compile::{Std, run_cargo}; use crate::core::build_steps::doc::{DocumentationFormat, prepare_doc_compiler}; -use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; +use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::{get_completion_paths, get_help_path}; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; @@ -3956,7 +3956,7 @@ impl Step for CodegenGCC { let compilers = self.compilers; let target = self.target; - let gcc = builder.ensure(Gcc { target }); + let gcc = builder.ensure(Gcc { target_pair: GccTargetPair::for_native_build(target) }); builder.ensure( compile::Std::new(compilers.build_compiler(), target) @@ -3997,12 +3997,13 @@ impl Step for CodegenGCC { .arg("--use-backend") .arg("gcc") .arg("--gcc-path") - .arg(gcc.libgccjit.parent().unwrap()) + .arg(gcc.libgccjit().parent().unwrap()) .arg("--out-dir") .arg(builder.stage_out(compilers.build_compiler(), Mode::Codegen).join("cg_gcc")) .arg("--release") .arg("--mini-tests") .arg("--std-tests"); + cargo.args(builder.config.test_args()); cargo.into_cmd().run(builder); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 2f493658ec0ec..a81b8ccb9140a 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -188,6 +188,7 @@ pub struct Config { // gcc codegen options pub gcc_ci_mode: GccCiMode, + pub libgccjit_libs_dir: Option, // rust codegen options pub rust_optimize: RustOptimize, @@ -620,7 +621,10 @@ impl Config { vendor: dist_vendor, } = toml.dist.unwrap_or_default(); - let Gcc { download_ci_gcc: gcc_download_ci_gcc } = toml.gcc.unwrap_or_default(); + let Gcc { + download_ci_gcc: gcc_download_ci_gcc, + libgccjit_libs_dir: gcc_libgccjit_libs_dir, + } = toml.gcc.unwrap_or_default(); if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() { panic!( @@ -1346,6 +1350,7 @@ impl Config { keep_stage: flags_keep_stage, keep_stage_std: flags_keep_stage_std, libdir: install_libdir.map(PathBuf::from), + libgccjit_libs_dir: gcc_libgccjit_libs_dir, library_docs_private_items: build_library_docs_private_items.unwrap_or(false), lld_enabled, lldb: build_lldb.map(PathBuf::from), diff --git a/src/bootstrap/src/core/config/toml/gcc.rs b/src/bootstrap/src/core/config/toml/gcc.rs index 9ea697edf159e..94d15a9baaff9 100644 --- a/src/bootstrap/src/core/config/toml/gcc.rs +++ b/src/bootstrap/src/core/config/toml/gcc.rs @@ -15,5 +15,6 @@ define_config! { #[derive(Default)] struct Gcc { download_ci_gcc: Option = "download-ci-gcc", + libgccjit_libs_dir: Option = "libgccjit-libs-dir", } } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index a31eb0c1c8012..adae9a1b8b081 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -975,10 +975,6 @@ impl Build { self.out.join(&*target.triple).join("enzyme") } - fn gcc_out(&self, target: TargetSelection) -> PathBuf { - self.out.join(&*target.triple).join("gcc") - } - fn lld_out(&self, target: TargetSelection) -> PathBuf { self.out.join(target).join("lld") } From a9511b9b49f2118e8176609389bf84a404ca15ac Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 11 Dec 2025 11:15:15 -0500 Subject: [PATCH 16/22] When we cannot load libgccjit.so, show the paths that were tried --- compiler/rustc_codegen_gcc/src/lib.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index a77239e23b4e5..96d3a0024f418 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -98,7 +98,6 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; use rustc_session::config::{OptLevel, OutputFilenames}; -use rustc_session::filesearch::make_target_lib_path; use rustc_span::Symbol; use rustc_target::spec::{Arch, RelocModel}; use tempfile::TempDir; @@ -207,18 +206,38 @@ impl CodegenBackend for GccCodegenBackend { } fn init(&self, sess: &Session) { + fn file_path(sysroot_path: &Path, sess: &Session) -> PathBuf { + let rustlib_path = + rustc_target::relative_target_rustlib_path(sysroot_path, &sess.host.llvm_target); + sysroot_path + .join(rustlib_path) + .join("codegen-backends") + .join("lib") + .join(sess.target.llvm_target.as_ref()) + .join("libgccjit.so") + } + // We use all_paths() instead of only path() in case the path specified by --sysroot is // invalid. // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null. for path in sess.opts.sysroot.all_paths() { - let libgccjit_target_lib_file = - make_target_lib_path(path, &sess.target.llvm_target).join("libgccjit.so"); + let libgccjit_target_lib_file = file_path(path, sess); if let Ok(true) = fs::exists(&libgccjit_target_lib_file) { load_libgccjit_if_needed(&libgccjit_target_lib_file); break; } } + if !gccjit::is_loaded() { + let mut paths = vec![]; + for path in sess.opts.sysroot.all_paths() { + let libgccjit_target_lib_file = file_path(path, sess); + paths.push(libgccjit_target_lib_file); + } + + panic!("Could not load libgccjit.so. Attempted paths: {:#?}", paths); + } + #[cfg(feature = "master")] { let target_cpu = target_cpu(sess); From 15e3955f3a6e38cf8cd4f678b588609c0617b2a1 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 11 Dec 2025 14:26:57 -0500 Subject: [PATCH 17/22] Document new gcc.download-ci-gcc option --- .../src/tests/codegen-backend-tests/cg_gcc.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md index 4325cc58797f8..7a1c5b9a98c03 100644 --- a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md +++ b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md @@ -77,6 +77,26 @@ will be downloaded from CI or built locally. The default value is `true`, which will download GCC from CI if there are no local changes to the GCC sources and the given host target is available on CI. +## Providing your own GCC + +There are cases where you will want to provide yourself the `libgccjit.so` file. +One such case is when you want to cross-compile `rustc` to another target since GCC is not a multi-target compiler. +To support this use case, there is the bootstrap option `gcc.libgccjit-libs-dir`. +This option override `gcc.download-ci-gcc`, meaning `libgccjit.so` won't be downloaded or built locally by bootstrap. +The directory structure of this directory is `//libgccjit.so`, for instance: + +``` +. +├── m68k-unknown-linux-gnu +│ └── m68k-unknown-linux-gnu +│ └── libgccjit.so +└── x86_64-unknown-linux-gnu + ├── m68k-unknown-linux-gnu + │ └── libgccjit.so + └── x86_64-unknown-linux-gnu + └── libgccjit.so +``` + ## Running tests of the backend itself In addition to running the compiler's test suites using the GCC codegen backend, you can also run the test suite of the backend itself. From 8f035402e074a285af3407b2989234bb7081d7ce Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Thu, 11 Dec 2025 14:27:29 -0500 Subject: [PATCH 18/22] Add new ChangeInfo for the new option gcc.libgccjit-libs-dir --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 37ad5f09897fa..d7990c2316d15 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -601,4 +601,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "New options `rust.rustflags` for all targets and per-target `rustflags` that will pass specified flags to rustc for all stages. Target-specific flags override global `rust.rustflags` ones.", }, + ChangeInfo { + change_id: 149354, + severity: ChangeSeverity::Info, + summary: "New option `gcc.libgccjit-libs-dir` to specify which libgccjit.so to use per target.", + }, ]; From b98a91e6ca1a5ab38eef810922b54405f0a2a5b8 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 14 Dec 2025 08:09:34 -0500 Subject: [PATCH 19/22] Error out if a GCC cross-compiler cannot be found --- src/bootstrap/src/core/build_steps/gcc.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 9cc5d0ed71b16..648a2bea41819 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -217,6 +217,15 @@ pub fn get_gcc_build_status(builder: &Builder<'_>, target_pair: GccTargetPair) - "libgccjit.so for `{target_pair}` was not found at `{}`", path.display() )); + + if target_pair.host != target_pair.target || target_pair.host != builder.host_target { + eprintln!( + "info: libgccjit.so for `{target_pair}` was not found at `{}`", + path.display() + ); + eprintln!("error: we do not support downloading or building a GCC cross-compiler"); + std::process::exit(1); + } } } From ddd5aad8a309ae49b3526334d2083db6b13d816a Mon Sep 17 00:00:00 2001 From: sgasho Date: Mon, 24 Nov 2025 20:50:08 +0900 Subject: [PATCH 20/22] feat: dlopen Enzyme --- Cargo.lock | 1 + compiler/rustc_codegen_llvm/Cargo.toml | 4 +- compiler/rustc_codegen_llvm/src/back/lto.rs | 32 +- compiler/rustc_codegen_llvm/src/back/write.rs | 9 +- compiler/rustc_codegen_llvm/src/lib.rs | 12 + .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 644 +++++++++++++----- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- compiler/rustc_codegen_llvm/src/typetree.rs | 11 +- compiler/rustc_codegen_ssa/src/back/write.rs | 3 + .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 33 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 12 - src/bootstrap/src/core/build_steps/compile.rs | 13 - typos.toml | 2 + 13 files changed, 534 insertions(+), 244 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07de5d2216855..1cd998a0bd2f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3613,6 +3613,7 @@ dependencies = [ "gimli 0.31.1", "itertools", "libc", + "libloading 0.9.0", "measureme", "object 0.37.3", "rustc-demangle", diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 0544a94fd59fe..21f6484bd0c9e 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -14,6 +14,7 @@ bitflags = "2.4.1" gimli = "0.31" itertools = "0.12" libc = "0.2" +libloading = { version = "0.9.0", optional = true } measureme = "12.0.1" object = { version = "0.37.0", default-features = false, features = ["std", "read"] } rustc-demangle = "0.1.21" @@ -46,7 +47,6 @@ tracing = "0.1" [features] # tidy-alphabetical-start check_only = ["rustc_llvm/check_only"] -llvm_enzyme = [] +llvm_enzyme = ["dep:libloading"] llvm_offload = [] # tidy-alphabetical-end - diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 482e954138553..c9a5e167d9f6f 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -528,31 +528,37 @@ fn thin_lto( } } -fn enable_autodiff_settings(ad: &[config::AutoDiff]) { +#[cfg(feature = "llvm_enzyme")] +pub(crate) fn enable_autodiff_settings( + sysroot: &rustc_session::config::Sysroot, + ad: &[config::AutoDiff], +) { + let mut enzyme = llvm::EnzymeWrapper::get_or_init(sysroot); + for val in ad { // We intentionally don't use a wildcard, to not forget handling anything new. match val { config::AutoDiff::PrintPerf => { - llvm::set_print_perf(true); + enzyme.set_print_perf(true); } config::AutoDiff::PrintAA => { - llvm::set_print_activity(true); + enzyme.set_print_activity(true); } config::AutoDiff::PrintTA => { - llvm::set_print_type(true); + enzyme.set_print_type(true); } config::AutoDiff::PrintTAFn(fun) => { - llvm::set_print_type(true); // Enable general type printing - llvm::set_print_type_fun(&fun); // Set specific function to analyze + enzyme.set_print_type(true); // Enable general type printing + enzyme.set_print_type_fun(&fun); // Set specific function to analyze } config::AutoDiff::Inline => { - llvm::set_inline(true); + enzyme.set_inline(true); } config::AutoDiff::LooseTypes => { - llvm::set_loose_types(true); + enzyme.set_loose_types(true); } config::AutoDiff::PrintSteps => { - llvm::set_print(true); + enzyme.set_print(true); } // We handle this in the PassWrapper.cpp config::AutoDiff::PrintPasses => {} @@ -571,9 +577,9 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff]) { } } // This helps with handling enums for now. - llvm::set_strict_aliasing(false); + enzyme.set_strict_aliasing(false); // FIXME(ZuseZ4): Test this, since it was added a long time ago. - llvm::set_rust_rules(true); + enzyme.set_rust_rules(true); } pub(crate) fn run_pass_manager( @@ -607,10 +613,6 @@ pub(crate) fn run_pass_manager( if enable_ad { write::AutodiffStage::DuringAD } else { write::AutodiffStage::PostAD } }; - if enable_ad { - enable_autodiff_settings(&config.autodiff); - } - unsafe { write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage); } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 2c4943e835a66..ecac6e6503cbb 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -730,6 +730,13 @@ pub(crate) unsafe fn llvm_optimize( let llvm_plugins = config.llvm_plugins.join(","); + let enzyme_fn = if consider_ad { + let wrapper = llvm::EnzymeWrapper::get_or_init(&cgcx.sysroot); + wrapper.registerEnzymeAndPassPipeline + } else { + std::ptr::null() + }; + let result = unsafe { llvm::LLVMRustOptimize( module.module_llvm.llmod(), @@ -749,7 +756,7 @@ pub(crate) unsafe fn llvm_optimize( vectorize_loop, config.no_builtins, config.emit_lifetime_markers, - run_enzyme, + enzyme_fn, print_before_enzyme, print_after_enzyme, print_passes, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 0da5810518c5c..b0901d5f3e1e3 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -240,6 +240,18 @@ impl CodegenBackend for LlvmCodegenBackend { fn init(&self, sess: &Session) { llvm_util::init(sess); // Make sure llvm is inited + + #[cfg(feature = "llvm_enzyme")] + { + use rustc_session::config::AutoDiff; + if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) { + { + use crate::back::lto::enable_autodiff_settings; + + enable_autodiff_settings(&sess.opts.sysroot, &sess.opts.unstable_opts.autodiff); + } + } + } } fn provide(&self, providers: &mut Providers) { diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index e63043b21227f..28923bf2743e4 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -91,102 +91,363 @@ pub(crate) use self::Enzyme_AD::*; #[cfg(feature = "llvm_enzyme")] pub(crate) mod Enzyme_AD { - use std::ffi::{CString, c_char}; + use std::ffi::{c_char, c_void}; + use std::sync::{Mutex, MutexGuard, OnceLock}; - use libc::c_void; + use rustc_middle::bug; + use rustc_session::config::{Sysroot, host_tuple}; + use rustc_session::filesearch; use super::{CConcreteType, CTypeTreeRef, Context}; - - unsafe extern "C" { - pub(crate) fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8); - pub(crate) fn EnzymeSetCLString(arg1: *mut ::std::os::raw::c_void, arg2: *const c_char); + use crate::llvm::{EnzymeTypeTree, LLVMRustVersionMajor}; + + type EnzymeSetCLBoolFn = unsafe extern "C" fn(*mut c_void, u8); + type EnzymeSetCLStringFn = unsafe extern "C" fn(*mut c_void, *const c_char); + + type EnzymeNewTypeTreeFn = unsafe extern "C" fn() -> CTypeTreeRef; + type EnzymeNewTypeTreeCTFn = unsafe extern "C" fn(CConcreteType, &Context) -> CTypeTreeRef; + type EnzymeNewTypeTreeTRFn = unsafe extern "C" fn(CTypeTreeRef) -> CTypeTreeRef; + type EnzymeFreeTypeTreeFn = unsafe extern "C" fn(CTypeTreeRef); + type EnzymeMergeTypeTreeFn = unsafe extern "C" fn(CTypeTreeRef, CTypeTreeRef) -> bool; + type EnzymeTypeTreeOnlyEqFn = unsafe extern "C" fn(CTypeTreeRef, i64); + type EnzymeTypeTreeData0EqFn = unsafe extern "C" fn(CTypeTreeRef); + type EnzymeTypeTreeShiftIndiciesEqFn = + unsafe extern "C" fn(CTypeTreeRef, *const c_char, i64, i64, u64); + type EnzymeTypeTreeInsertEqFn = + unsafe extern "C" fn(CTypeTreeRef, *const i64, usize, CConcreteType, &Context); + type EnzymeTypeTreeToStringFn = unsafe extern "C" fn(CTypeTreeRef) -> *const c_char; + type EnzymeTypeTreeToStringFreeFn = unsafe extern "C" fn(*const c_char); + + #[allow(non_snake_case)] + pub(crate) struct EnzymeWrapper { + EnzymeNewTypeTree: EnzymeNewTypeTreeFn, + EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn, + EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn, + EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn, + EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn, + EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn, + EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn, + EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn, + EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn, + EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn, + EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn, + + EnzymePrintPerf: *mut c_void, + EnzymePrintActivity: *mut c_void, + EnzymePrintType: *mut c_void, + EnzymeFunctionToAnalyze: *mut c_void, + EnzymePrint: *mut c_void, + EnzymeStrictAliasing: *mut c_void, + EnzymeInline: *mut c_void, + EnzymeMaxTypeDepth: *mut c_void, + RustTypeRules: *mut c_void, + looseTypeAnalysis: *mut c_void, + + EnzymeSetCLBool: EnzymeSetCLBoolFn, + EnzymeSetCLString: EnzymeSetCLStringFn, + pub registerEnzymeAndPassPipeline: *const c_void, + lib: libloading::Library, + } + + unsafe impl Sync for EnzymeWrapper {} + unsafe impl Send for EnzymeWrapper {} + + fn load_ptr_by_symbol_mut_void( + lib: &libloading::Library, + bytes: &[u8], + ) -> Result<*mut c_void, Box> { + unsafe { + let s: libloading::Symbol<'_, *mut c_void> = lib.get(bytes)?; + // libloading = 0.9.0: try_as_raw_ptr always succeeds and returns Some + let s = s.try_as_raw_ptr().unwrap(); + Ok(s) + } } - // TypeTree functions - unsafe extern "C" { - pub(crate) fn EnzymeNewTypeTree() -> CTypeTreeRef; - pub(crate) fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef; - pub(crate) fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef; - pub(crate) fn EnzymeFreeTypeTree(CTT: CTypeTreeRef); - pub(crate) fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool; - pub(crate) fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64); - pub(crate) fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef); - pub(crate) fn EnzymeTypeTreeShiftIndiciesEq( - arg1: CTypeTreeRef, + // e.g. + // load_ptrs_by_symbols_mut_void(ABC, XYZ); + // => + // let ABC = load_ptr_mut_void(&lib, b"ABC")?; + // let XYZ = load_ptr_mut_void(&lib, b"XYZ")?; + macro_rules! load_ptrs_by_symbols_mut_void { + ($lib:expr, $($name:ident),* $(,)?) => { + $( + #[allow(non_snake_case)] + let $name = load_ptr_by_symbol_mut_void(&$lib, stringify!($name).as_bytes())?; + )* + }; + } + + // e.g. + // load_ptrs_by_symbols_fn(ABC: ABCFn, XYZ: XYZFn); + // => + // let ABC: libloading::Symbol<'_, ABCFn> = unsafe { lib.get(b"ABC")? }; + // let XYZ: libloading::Symbol<'_, XYZFn> = unsafe { lib.get(b"XYZ")? }; + macro_rules! load_ptrs_by_symbols_fn { + ($lib:expr, $($name:ident : $ty:ty),* $(,)?) => { + $( + #[allow(non_snake_case)] + let $name: $ty = *unsafe { $lib.get::<$ty>(stringify!($name).as_bytes())? }; + )* + }; + } + + static ENZYME_INSTANCE: OnceLock> = OnceLock::new(); + + impl EnzymeWrapper { + /// Initialize EnzymeWrapper with the given sysroot if not already initialized. + /// Safe to call multiple times - subsequent calls are no-ops due to OnceLock. + pub(crate) fn get_or_init( + sysroot: &rustc_session::config::Sysroot, + ) -> MutexGuard<'static, Self> { + ENZYME_INSTANCE + .get_or_init(|| { + Self::call_dynamic(sysroot) + .unwrap_or_else(|e| bug!("failed to load Enzyme: {e}")) + .into() + }) + .lock() + .unwrap() + } + + /// Get the EnzymeWrapper instance. Panics if not initialized. + pub(crate) fn get_instance() -> MutexGuard<'static, Self> { + ENZYME_INSTANCE + .get() + .expect("EnzymeWrapper not initialized. Call get_or_init with sysroot first.") + .lock() + .unwrap() + } + + pub(crate) fn new_type_tree(&self) -> CTypeTreeRef { + unsafe { (self.EnzymeNewTypeTree)() } + } + + pub(crate) fn new_type_tree_ct( + &self, + t: CConcreteType, + ctx: &Context, + ) -> *mut EnzymeTypeTree { + unsafe { (self.EnzymeNewTypeTreeCT)(t, ctx) } + } + + pub(crate) fn new_type_tree_tr(&self, tree: CTypeTreeRef) -> CTypeTreeRef { + unsafe { (self.EnzymeNewTypeTreeTR)(tree) } + } + + pub(crate) fn free_type_tree(&self, tree: CTypeTreeRef) { + unsafe { (self.EnzymeFreeTypeTree)(tree) } + } + + pub(crate) fn merge_type_tree(&self, tree1: CTypeTreeRef, tree2: CTypeTreeRef) -> bool { + unsafe { (self.EnzymeMergeTypeTree)(tree1, tree2) } + } + + pub(crate) fn tree_only_eq(&self, tree: CTypeTreeRef, num: i64) { + unsafe { (self.EnzymeTypeTreeOnlyEq)(tree, num) } + } + + pub(crate) fn tree_data0_eq(&self, tree: CTypeTreeRef) { + unsafe { (self.EnzymeTypeTreeData0Eq)(tree) } + } + + pub(crate) fn shift_indicies_eq( + &self, + tree: CTypeTreeRef, data_layout: *const c_char, offset: i64, max_size: i64, add_offset: u64, - ); - pub(crate) fn EnzymeTypeTreeInsertEq( - CTT: CTypeTreeRef, + ) { + unsafe { + (self.EnzymeTypeTreeShiftIndiciesEq)( + tree, + data_layout, + offset, + max_size, + add_offset, + ) + } + } + + pub(crate) fn tree_insert_eq( + &self, + tree: CTypeTreeRef, indices: *const i64, len: usize, ct: CConcreteType, ctx: &Context, - ); - pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char; - pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char); - } + ) { + unsafe { (self.EnzymeTypeTreeInsertEq)(tree, indices, len, ct, ctx) } + } - unsafe extern "C" { - static mut EnzymePrintPerf: c_void; - static mut EnzymePrintActivity: c_void; - static mut EnzymePrintType: c_void; - static mut EnzymeFunctionToAnalyze: c_void; - static mut EnzymePrint: c_void; - static mut EnzymeStrictAliasing: c_void; - static mut looseTypeAnalysis: c_void; - static mut EnzymeInline: c_void; - static mut RustTypeRules: c_void; - } - pub(crate) fn set_print_perf(print: bool) { - unsafe { - EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintPerf), print as u8); + pub(crate) fn tree_to_string(&self, tree: *mut EnzymeTypeTree) -> *const c_char { + unsafe { (self.EnzymeTypeTreeToString)(tree) } } - } - pub(crate) fn set_print_activity(print: bool) { - unsafe { - EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintActivity), print as u8); + + pub(crate) fn tree_to_string_free(&self, ch: *const c_char) { + unsafe { (self.EnzymeTypeTreeToStringFree)(ch) } } - } - pub(crate) fn set_print_type(print: bool) { - unsafe { - EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrintType), print as u8); + + pub(crate) fn get_max_type_depth(&self) -> usize { + unsafe { std::ptr::read::(self.EnzymeMaxTypeDepth as *const u32) as usize } } - } - pub(crate) fn set_print_type_fun(fun_name: &str) { - let c_fun_name = CString::new(fun_name).unwrap(); - unsafe { - EnzymeSetCLString( - std::ptr::addr_of_mut!(EnzymeFunctionToAnalyze), - c_fun_name.as_ptr() as *const c_char, - ); + + pub(crate) fn set_print_perf(&mut self, print: bool) { + unsafe { + (self.EnzymeSetCLBool)(self.EnzymePrintPerf, print as u8); + } } - } - pub(crate) fn set_print(print: bool) { - unsafe { - EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymePrint), print as u8); + + pub(crate) fn set_print_activity(&mut self, print: bool) { + unsafe { + (self.EnzymeSetCLBool)(self.EnzymePrintActivity, print as u8); + } } - } - pub(crate) fn set_strict_aliasing(strict: bool) { - unsafe { - EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymeStrictAliasing), strict as u8); + + pub(crate) fn set_print_type(&mut self, print: bool) { + unsafe { + (self.EnzymeSetCLBool)(self.EnzymePrintType, print as u8); + } } - } - pub(crate) fn set_loose_types(loose: bool) { - unsafe { - EnzymeSetCLBool(std::ptr::addr_of_mut!(looseTypeAnalysis), loose as u8); + + pub(crate) fn set_print_type_fun(&mut self, fun_name: &str) { + let c_fun_name = std::ffi::CString::new(fun_name) + .unwrap_or_else(|err| bug!("failed to set_print_type_fun: {err}")); + unsafe { + (self.EnzymeSetCLString)( + self.EnzymeFunctionToAnalyze, + c_fun_name.as_ptr() as *const c_char, + ); + } } - } - pub(crate) fn set_inline(val: bool) { - unsafe { - EnzymeSetCLBool(std::ptr::addr_of_mut!(EnzymeInline), val as u8); + + pub(crate) fn set_print(&mut self, print: bool) { + unsafe { + (self.EnzymeSetCLBool)(self.EnzymePrint, print as u8); + } } - } - pub(crate) fn set_rust_rules(val: bool) { - unsafe { - EnzymeSetCLBool(std::ptr::addr_of_mut!(RustTypeRules), val as u8); + + pub(crate) fn set_strict_aliasing(&mut self, strict: bool) { + unsafe { + (self.EnzymeSetCLBool)(self.EnzymeStrictAliasing, strict as u8); + } + } + + pub(crate) fn set_loose_types(&mut self, loose: bool) { + unsafe { + (self.EnzymeSetCLBool)(self.looseTypeAnalysis, loose as u8); + } + } + + pub(crate) fn set_inline(&mut self, val: bool) { + unsafe { + (self.EnzymeSetCLBool)(self.EnzymeInline, val as u8); + } + } + + pub(crate) fn set_rust_rules(&mut self, val: bool) { + unsafe { + (self.EnzymeSetCLBool)(self.RustTypeRules, val as u8); + } + } + + #[allow(non_snake_case)] + fn call_dynamic( + sysroot: &rustc_session::config::Sysroot, + ) -> Result> { + let enzyme_path = Self::get_enzyme_path(sysroot)?; + let lib = unsafe { libloading::Library::new(enzyme_path)? }; + + load_ptrs_by_symbols_fn!( + lib, + EnzymeNewTypeTree: EnzymeNewTypeTreeFn, + EnzymeNewTypeTreeCT: EnzymeNewTypeTreeCTFn, + EnzymeNewTypeTreeTR: EnzymeNewTypeTreeTRFn, + EnzymeFreeTypeTree: EnzymeFreeTypeTreeFn, + EnzymeMergeTypeTree: EnzymeMergeTypeTreeFn, + EnzymeTypeTreeOnlyEq: EnzymeTypeTreeOnlyEqFn, + EnzymeTypeTreeData0Eq: EnzymeTypeTreeData0EqFn, + EnzymeTypeTreeShiftIndiciesEq: EnzymeTypeTreeShiftIndiciesEqFn, + EnzymeTypeTreeInsertEq: EnzymeTypeTreeInsertEqFn, + EnzymeTypeTreeToString: EnzymeTypeTreeToStringFn, + EnzymeTypeTreeToStringFree: EnzymeTypeTreeToStringFreeFn, + EnzymeSetCLBool: EnzymeSetCLBoolFn, + EnzymeSetCLString: EnzymeSetCLStringFn, + ); + + load_ptrs_by_symbols_mut_void!( + lib, + registerEnzymeAndPassPipeline, + EnzymePrintPerf, + EnzymePrintActivity, + EnzymePrintType, + EnzymeFunctionToAnalyze, + EnzymePrint, + EnzymeStrictAliasing, + EnzymeInline, + EnzymeMaxTypeDepth, + RustTypeRules, + looseTypeAnalysis, + ); + + Ok(Self { + EnzymeNewTypeTree, + EnzymeNewTypeTreeCT, + EnzymeNewTypeTreeTR, + EnzymeFreeTypeTree, + EnzymeMergeTypeTree, + EnzymeTypeTreeOnlyEq, + EnzymeTypeTreeData0Eq, + EnzymeTypeTreeShiftIndiciesEq, + EnzymeTypeTreeInsertEq, + EnzymeTypeTreeToString, + EnzymeTypeTreeToStringFree, + EnzymePrintPerf, + EnzymePrintActivity, + EnzymePrintType, + EnzymeFunctionToAnalyze, + EnzymePrint, + EnzymeStrictAliasing, + EnzymeInline, + EnzymeMaxTypeDepth, + RustTypeRules, + looseTypeAnalysis, + EnzymeSetCLBool, + EnzymeSetCLString, + registerEnzymeAndPassPipeline, + lib, + }) + } + + fn get_enzyme_path(sysroot: &Sysroot) -> Result { + let llvm_version_major = unsafe { LLVMRustVersionMajor() }; + + let path_buf = sysroot + .all_paths() + .map(|sysroot_path| { + filesearch::make_target_lib_path(sysroot_path, host_tuple()) + .join("lib") + .with_file_name(format!("libEnzyme-{llvm_version_major}")) + .with_extension(std::env::consts::DLL_EXTENSION) + }) + .find(|f| f.exists()) + .ok_or_else(|| { + let candidates = sysroot + .all_paths() + .map(|p| p.join("lib").display().to_string()) + .collect::>() + .join("\n* "); + format!( + "failed to find a `libEnzyme-{llvm_version_major}` folder \ + in the sysroot candidates:\n* {candidates}" + ) + })?; + + Ok(path_buf + .to_str() + .ok_or_else(|| format!("invalid UTF-8 in path: {}", path_buf.display()))? + .to_string()) } } } @@ -198,111 +459,156 @@ pub(crate) use self::Fallback_AD::*; pub(crate) mod Fallback_AD { #![allow(unused_variables)] + use std::ffi::c_void; + use std::sync::{Mutex, MutexGuard}; + use libc::c_char; + use rustc_codegen_ssa::back::write::CodegenContext; + use rustc_codegen_ssa::traits::WriteBackendMethods; - use super::{CConcreteType, CTypeTreeRef, Context}; + use super::{CConcreteType, CTypeTreeRef, Context, EnzymeTypeTree}; - // TypeTree function fallbacks - pub(crate) unsafe fn EnzymeNewTypeTree() -> CTypeTreeRef { - unimplemented!() + pub(crate) struct EnzymeWrapper { + pub registerEnzymeAndPassPipeline: *const c_void, } - pub(crate) unsafe fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef { - unimplemented!() - } + impl EnzymeWrapper { + pub(crate) fn get_or_init( + _sysroot: &rustc_session::config::Sysroot, + ) -> MutexGuard<'static, Self> { + unimplemented!("Enzyme not available: build with llvm_enzyme feature") + } - pub(crate) unsafe fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef { - unimplemented!() - } + pub(crate) fn init<'a, B: WriteBackendMethods>( + _cgcx: &'a CodegenContext, + ) -> &'static Mutex { + unimplemented!("Enzyme not available: build with llvm_enzyme feature") + } - pub(crate) unsafe fn EnzymeFreeTypeTree(CTT: CTypeTreeRef) { - unimplemented!() - } + pub(crate) fn get_instance() -> MutexGuard<'static, Self> { + unimplemented!("Enzyme not available: build with llvm_enzyme feature") + } - pub(crate) unsafe fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool { - unimplemented!() - } + pub(crate) fn new_type_tree(&self) -> CTypeTreeRef { + unimplemented!() + } - pub(crate) unsafe fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64) { - unimplemented!() - } + pub(crate) fn new_type_tree_ct( + &self, + t: CConcreteType, + ctx: &Context, + ) -> *mut EnzymeTypeTree { + unimplemented!() + } - pub(crate) unsafe fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef) { - unimplemented!() - } + pub(crate) fn new_type_tree_tr(&self, tree: CTypeTreeRef) -> CTypeTreeRef { + unimplemented!() + } - pub(crate) unsafe fn EnzymeTypeTreeShiftIndiciesEq( - arg1: CTypeTreeRef, - data_layout: *const c_char, - offset: i64, - max_size: i64, - add_offset: u64, - ) { - unimplemented!() - } + pub(crate) fn free_type_tree(&self, tree: CTypeTreeRef) { + unimplemented!() + } - pub(crate) unsafe fn EnzymeTypeTreeInsertEq( - CTT: CTypeTreeRef, - indices: *const i64, - len: usize, - ct: CConcreteType, - ctx: &Context, - ) { - unimplemented!() - } + pub(crate) fn merge_type_tree(&self, tree1: CTypeTreeRef, tree2: CTypeTreeRef) -> bool { + unimplemented!() + } - pub(crate) unsafe fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char { - unimplemented!() - } + pub(crate) fn tree_only_eq(&self, tree: CTypeTreeRef, num: i64) { + unimplemented!() + } - pub(crate) unsafe fn EnzymeTypeTreeToStringFree(arg1: *const c_char) { - unimplemented!() - } + pub(crate) fn tree_data0_eq(&self, tree: CTypeTreeRef) { + unimplemented!() + } - pub(crate) fn set_inline(val: bool) { - unimplemented!() - } - pub(crate) fn set_print_perf(print: bool) { - unimplemented!() - } - pub(crate) fn set_print_activity(print: bool) { - unimplemented!() - } - pub(crate) fn set_print_type(print: bool) { - unimplemented!() - } - pub(crate) fn set_print_type_fun(fun_name: &str) { - unimplemented!() - } - pub(crate) fn set_print(print: bool) { - unimplemented!() - } - pub(crate) fn set_strict_aliasing(strict: bool) { - unimplemented!() - } - pub(crate) fn set_loose_types(loose: bool) { - unimplemented!() - } - pub(crate) fn set_rust_rules(val: bool) { - unimplemented!() + pub(crate) fn shift_indicies_eq( + &self, + tree: CTypeTreeRef, + data_layout: *const c_char, + offset: i64, + max_size: i64, + add_offset: u64, + ) { + unimplemented!() + } + + pub(crate) fn tree_insert_eq( + &self, + tree: CTypeTreeRef, + indices: *const i64, + len: usize, + ct: CConcreteType, + ctx: &Context, + ) { + unimplemented!() + } + + pub(crate) fn tree_to_string(&self, tree: *mut EnzymeTypeTree) -> *const c_char { + unimplemented!() + } + + pub(crate) fn tree_to_string_free(&self, ch: *const c_char) { + unimplemented!() + } + + pub(crate) fn get_max_type_depth(&self) -> usize { + unimplemented!() + } + + pub(crate) fn set_inline(&mut self, val: bool) { + unimplemented!() + } + + pub(crate) fn set_print_perf(&mut self, print: bool) { + unimplemented!() + } + + pub(crate) fn set_print_activity(&mut self, print: bool) { + unimplemented!() + } + + pub(crate) fn set_print_type(&mut self, print: bool) { + unimplemented!() + } + + pub(crate) fn set_print_type_fun(&mut self, fun_name: &str) { + unimplemented!() + } + + pub(crate) fn set_print(&mut self, print: bool) { + unimplemented!() + } + + pub(crate) fn set_strict_aliasing(&mut self, strict: bool) { + unimplemented!() + } + + pub(crate) fn set_loose_types(&mut self, loose: bool) { + unimplemented!() + } + + pub(crate) fn set_rust_rules(&mut self, val: bool) { + unimplemented!() + } } } impl TypeTree { pub(crate) fn new() -> TypeTree { - let inner = unsafe { EnzymeNewTypeTree() }; + let wrapper = EnzymeWrapper::get_instance(); + let inner = wrapper.new_type_tree(); TypeTree { inner } } pub(crate) fn from_type(t: CConcreteType, ctx: &Context) -> TypeTree { - let inner = unsafe { EnzymeNewTypeTreeCT(t, ctx) }; + let wrapper = EnzymeWrapper::get_instance(); + let inner = wrapper.new_type_tree_ct(t, ctx); TypeTree { inner } } pub(crate) fn merge(self, other: Self) -> Self { - unsafe { - EnzymeMergeTypeTree(self.inner, other.inner); - } + let wrapper = EnzymeWrapper::get_instance(); + wrapper.merge_type_tree(self.inner, other.inner); drop(other); self } @@ -316,37 +622,36 @@ impl TypeTree { add_offset: usize, ) -> Self { let layout = std::ffi::CString::new(layout).unwrap(); - - unsafe { - EnzymeTypeTreeShiftIndiciesEq( - self.inner, - layout.as_ptr(), - offset as i64, - max_size as i64, - add_offset as u64, - ); - } + let wrapper = EnzymeWrapper::get_instance(); + wrapper.shift_indicies_eq( + self.inner, + layout.as_ptr(), + offset as i64, + max_size as i64, + add_offset as u64, + ); self } pub(crate) fn insert(&mut self, indices: &[i64], ct: CConcreteType, ctx: &Context) { - unsafe { - EnzymeTypeTreeInsertEq(self.inner, indices.as_ptr(), indices.len(), ct, ctx); - } + let wrapper = EnzymeWrapper::get_instance(); + wrapper.tree_insert_eq(self.inner, indices.as_ptr(), indices.len(), ct, ctx); } } impl Clone for TypeTree { fn clone(&self) -> Self { - let inner = unsafe { EnzymeNewTypeTreeTR(self.inner) }; + let wrapper = EnzymeWrapper::get_instance(); + let inner = wrapper.new_type_tree_tr(self.inner); TypeTree { inner } } } impl std::fmt::Display for TypeTree { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let ptr = unsafe { EnzymeTypeTreeToString(self.inner) }; + let wrapper = EnzymeWrapper::get_instance(); + let ptr = wrapper.tree_to_string(self.inner); let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) }; match cstr.to_str() { Ok(x) => write!(f, "{}", x)?, @@ -354,9 +659,7 @@ impl std::fmt::Display for TypeTree { } // delete C string pointer - unsafe { - EnzymeTypeTreeToStringFree(ptr); - } + wrapper.tree_to_string_free(ptr); Ok(()) } @@ -370,6 +673,7 @@ impl std::fmt::Debug for TypeTree { impl Drop for TypeTree { fn drop(&mut self) { - unsafe { EnzymeFreeTypeTree(self.inner) } + let wrapper = EnzymeWrapper::get_instance(); + wrapper.free_type_tree(self.inner) } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 8abf8b24d9d6f..7835319f5c1d0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2411,7 +2411,7 @@ unsafe extern "C" { LoopVectorize: bool, DisableSimplifyLibCalls: bool, EmitLifetimeMarkers: bool, - RunEnzyme: bool, + RunEnzyme: *const c_void, PrintBeforeEnzyme: bool, PrintAfterEnzyme: bool, PrintPasses: bool, diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs index 7e2635037008e..513a832e7fe8f 100644 --- a/compiler/rustc_codegen_llvm/src/typetree.rs +++ b/compiler/rustc_codegen_llvm/src/typetree.rs @@ -2,6 +2,7 @@ use rustc_ast::expand::typetree::FncTree; #[cfg(feature = "llvm_enzyme")] use { crate::attributes, + crate::llvm::EnzymeWrapper, rustc_ast::expand::typetree::TypeTree as RustTypeTree, std::ffi::{CString, c_char, c_uint}, }; @@ -77,7 +78,8 @@ pub(crate) fn add_tt<'ll>( for (i, input) in inputs.iter().enumerate() { unsafe { let enzyme_tt = to_enzyme_typetree(input.clone(), llvm_data_layout, llcx); - let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner); + let enzyme_wrapper = EnzymeWrapper::get_instance(); + let c_str = enzyme_wrapper.tree_to_string(enzyme_tt.inner); let c_str = std::ffi::CStr::from_ptr(c_str); let attr = llvm::LLVMCreateStringAttribute( @@ -89,13 +91,14 @@ pub(crate) fn add_tt<'ll>( ); attributes::apply_to_llfn(fn_def, llvm::AttributePlace::Argument(i as u32), &[attr]); - llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr()); + enzyme_wrapper.tree_to_string_free(c_str.as_ptr()); } } unsafe { let enzyme_tt = to_enzyme_typetree(ret_tt, llvm_data_layout, llcx); - let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner); + let enzyme_wrapper = EnzymeWrapper::get_instance(); + let c_str = enzyme_wrapper.tree_to_string(enzyme_tt.inner); let c_str = std::ffi::CStr::from_ptr(c_str); let ret_attr = llvm::LLVMCreateStringAttribute( @@ -107,7 +110,7 @@ pub(crate) fn add_tt<'ll>( ); attributes::apply_to_llfn(fn_def, llvm::AttributePlace::ReturnValue, &[ret_attr]); - llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr()); + enzyme_wrapper.tree_to_string_free(c_str.as_ptr()); } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 3e36bd8552b18..3196b51e0c2b4 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -29,6 +29,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{ self, CrateType, Lto, OutFileName, OutputFilenames, OutputType, Passes, SwitchWithOptPath, + Sysroot, }; use rustc_span::source_map::SourceMap; use rustc_span::{FileName, InnerSpan, Span, SpanData, sym}; @@ -346,6 +347,7 @@ pub struct CodegenContext { pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, pub pointer_size: Size, + pub sysroot: Sysroot, /// Emitter to use for diagnostics produced during codegen. pub diag_emitter: SharedEmitter, @@ -1317,6 +1319,7 @@ fn start_executing_work( parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, pointer_size: tcx.data_layout.pointer_size(), invocation_temp: sess.invocation_temp.clone(), + sysroot: sess.opts.sysroot.clone(), }; // This is the "main loop" of parallel work happening for parallel codegen. diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 714ba0f177a8f..95cbec1b37b4f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -550,17 +550,8 @@ struct LLVMRustSanitizerOptions { bool SanitizeKernelAddressRecover; }; -// This symbol won't be available or used when Enzyme is not enabled. -// Always set AugmentPassBuilder to true, since it registers optimizations which -// will improve the performance for Enzyme. -#ifdef ENZYME -extern "C" void registerEnzymeAndPassPipeline(llvm::PassBuilder &PB, - /* augmentPassBuilder */ bool); - -extern "C" { -extern llvm::cl::opt EnzymeFunctionToAnalyze; -} -#endif +extern "C" typedef void (*registerEnzymeAndPassPipelineFn)( + llvm::PassBuilder &PB, bool augment); extern "C" LLVMRustResult LLVMRustOptimize( LLVMModuleRef ModuleRef, LLVMTargetMachineRef TMRef, @@ -569,8 +560,8 @@ extern "C" LLVMRustResult LLVMRustOptimize( bool LintIR, LLVMRustThinLTOBuffer **ThinLTOBufferRef, bool EmitThinLTO, bool EmitThinLTOSummary, bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, bool DisableSimplifyLibCalls, - bool EmitLifetimeMarkers, bool RunEnzyme, bool PrintBeforeEnzyme, - bool PrintAfterEnzyme, bool PrintPasses, + bool EmitLifetimeMarkers, registerEnzymeAndPassPipelineFn EnzymePtr, + bool PrintBeforeEnzyme, bool PrintAfterEnzyme, bool PrintPasses, LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath, const char *PGOUsePath, bool InstrumentCoverage, const char *InstrProfileOutput, const char *PGOSampleUsePath, @@ -907,8 +898,8 @@ extern "C" LLVMRustResult LLVMRustOptimize( } // now load "-enzyme" pass: -#ifdef ENZYME - if (RunEnzyme) { + // With dlopen, ENZYME macro may not be defined, so check EnzymePtr directly + if (EnzymePtr) { if (PrintBeforeEnzyme) { // Handle the Rust flag `-Zautodiff=PrintModBefore`. @@ -916,29 +907,19 @@ extern "C" LLVMRustResult LLVMRustOptimize( MPM.addPass(PrintModulePass(outs(), Banner, true, false)); } - registerEnzymeAndPassPipeline(PB, false); + EnzymePtr(PB, false); if (auto Err = PB.parsePassPipeline(MPM, "enzyme")) { std::string ErrMsg = toString(std::move(Err)); LLVMRustSetLastError(ErrMsg.c_str()); return LLVMRustResult::Failure; } - // Check if PrintTAFn was used and add type analysis pass if needed - if (!EnzymeFunctionToAnalyze.empty()) { - if (auto Err = PB.parsePassPipeline(MPM, "print-type-analysis")) { - std::string ErrMsg = toString(std::move(Err)); - LLVMRustSetLastError(ErrMsg.c_str()); - return LLVMRustResult::Failure; - } - } - if (PrintAfterEnzyme) { // Handle the Rust flag `-Zautodiff=PrintModAfter`. std::string Banner = "Module after EnzymeNewPM"; MPM.addPass(PrintModulePass(outs(), Banner, true, false)); } } -#endif if (PrintPasses) { // Print all passes from the PM: std::string Pipeline; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index dda06e9b2bf68..0720af0eb7e0c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1791,18 +1791,6 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) { GV.setSanitizerMetadata(MD); } -#ifdef ENZYME -extern "C" { -extern llvm::cl::opt EnzymeMaxTypeDepth; -} - -extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() { return EnzymeMaxTypeDepth; } -#else -extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() { - return 6; // Default fallback depth -} -#endif - // Statically assert that the fixed metadata kind IDs declared in // `metadata_kind.rs` match the ones actually used by LLVM. #define FIXED_MD_KIND(VARIANT, VALUE) \ diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 82cc25f123bc9..2f6a0ef6575d5 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1232,19 +1232,6 @@ pub fn rustc_cargo( // . cargo.rustflag("-Zon-broken-pipe=kill"); - // We want to link against registerEnzyme and in the future we want to use additional - // functionality from Enzyme core. For that we need to link against Enzyme. - if builder.config.llvm_enzyme { - let arch = builder.build.host_target; - let enzyme_dir = builder.build.out.join(arch).join("enzyme").join("lib"); - cargo.rustflag("-L").rustflag(enzyme_dir.to_str().expect("Invalid path")); - - if let Some(llvm_config) = builder.llvm_config(builder.config.host_target) { - let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config); - cargo.rustflag("-l").rustflag(&format!("Enzyme-{llvm_version_major}")); - } - } - // Building with protected visibility reduces the number of dynamic relocations needed, giving // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object // with direct references to protected symbols, so for now we only use protected symbols if diff --git a/typos.toml b/typos.toml index 758239ffe751c..b9d9c6c3522cf 100644 --- a/typos.toml +++ b/typos.toml @@ -50,6 +50,8 @@ unstalled = "unstalled" debug_aranges = "debug_aranges" DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME = "DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME" EnzymeTypeTreeShiftIndiciesEq = "EnzymeTypeTreeShiftIndiciesEq" +EnzymeTypeTreeShiftIndiciesEqFn = "EnzymeTypeTreeShiftIndiciesEqFn" +shift_indicies_eq = "shift_indicies_eq" ERRNO_ACCES = "ERRNO_ACCES" ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS = "ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS" ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC = "ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC" From 4d12cb0fb8df408aa3df572f81411f799d82289c Mon Sep 17 00:00:00 2001 From: sgasho Date: Mon, 15 Dec 2025 21:29:52 +0900 Subject: [PATCH 21/22] refactor: initialize EnzymeWrapper in LlvmCodegenBackend::init --- compiler/rustc_codegen_llvm/src/back/lto.rs | 7 ++----- compiler/rustc_codegen_llvm/src/back/write.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 9 ++++----- compiler/rustc_codegen_ssa/src/back/write.rs | 3 --- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index c9a5e167d9f6f..314e64272ffea 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -529,11 +529,8 @@ fn thin_lto( } #[cfg(feature = "llvm_enzyme")] -pub(crate) fn enable_autodiff_settings( - sysroot: &rustc_session::config::Sysroot, - ad: &[config::AutoDiff], -) { - let mut enzyme = llvm::EnzymeWrapper::get_or_init(sysroot); +pub(crate) fn enable_autodiff_settings(ad: &[config::AutoDiff]) { + let mut enzyme = llvm::EnzymeWrapper::get_instance(); for val in ad { // We intentionally don't use a wildcard, to not forget handling anything new. diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index ecac6e6503cbb..18da945f5a318 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -731,7 +731,7 @@ pub(crate) unsafe fn llvm_optimize( let llvm_plugins = config.llvm_plugins.join(","); let enzyme_fn = if consider_ad { - let wrapper = llvm::EnzymeWrapper::get_or_init(&cgcx.sysroot); + let wrapper = llvm::EnzymeWrapper::get_instance(); wrapper.registerEnzymeAndPassPipeline } else { std::ptr::null() diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index b0901d5f3e1e3..c51b334d95e16 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -244,12 +244,11 @@ impl CodegenBackend for LlvmCodegenBackend { #[cfg(feature = "llvm_enzyme")] { use rustc_session::config::AutoDiff; - if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) { - { - use crate::back::lto::enable_autodiff_settings; - enable_autodiff_settings(&sess.opts.sysroot, &sess.opts.unstable_opts.autodiff); - } + use crate::back::lto::enable_autodiff_settings; + if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) { + drop(llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot)); + enable_autodiff_settings(&sess.opts.unstable_opts.autodiff); } } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 3196b51e0c2b4..3e36bd8552b18 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -29,7 +29,6 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{ self, CrateType, Lto, OutFileName, OutputFilenames, OutputType, Passes, SwitchWithOptPath, - Sysroot, }; use rustc_span::source_map::SourceMap; use rustc_span::{FileName, InnerSpan, Span, SpanData, sym}; @@ -347,7 +346,6 @@ pub struct CodegenContext { pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, pub pointer_size: Size, - pub sysroot: Sysroot, /// Emitter to use for diagnostics produced during codegen. pub diag_emitter: SharedEmitter, @@ -1319,7 +1317,6 @@ fn start_executing_work( parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, pointer_size: tcx.data_layout.pointer_size(), invocation_temp: sess.invocation_temp.clone(), - sysroot: sess.opts.sysroot.clone(), }; // This is the "main loop" of parallel work happening for parallel codegen. From 58aeab58ab8028a8b26ba02ffb8deb1d0c4a3e29 Mon Sep 17 00:00:00 2001 From: sgasho Date: Mon, 15 Dec 2025 21:41:40 +0900 Subject: [PATCH 22/22] add trailing line at compiler/rustc_codegen_llvm/Cargo.toml --- compiler/rustc_codegen_llvm/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 21f6484bd0c9e..076ec5e59eb6b 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -50,3 +50,4 @@ check_only = ["rustc_llvm/check_only"] llvm_enzyme = ["dep:libloading"] llvm_offload = [] # tidy-alphabetical-end +