From eb2913b01b3e423b2bcd73cc62406ffecbe59ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Thu, 19 Jun 2025 21:55:55 +0200 Subject: [PATCH 001/252] Fix unsoundness in some tests --- library/coretests/tests/io/borrowed_buf.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs index fbd3864dcac14..8fbf9c3e8a2ad 100644 --- a/library/coretests/tests/io/borrowed_buf.rs +++ b/library/coretests/tests/io/borrowed_buf.rs @@ -66,7 +66,7 @@ fn clear() { #[test] fn set_init() { - let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16]; let mut rbuf: BorrowedBuf<'_> = buf.into(); unsafe { @@ -134,7 +134,7 @@ fn reborrow_written() { #[test] fn cursor_set_init() { - let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16]; + let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16]; let mut rbuf: BorrowedBuf<'_> = buf.into(); unsafe { From 1045b70304ab6a875fc9fbf10cb7e7c010edd3ab Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 26 Jun 2025 18:03:00 -0700 Subject: [PATCH 002/252] tests: add test for invalid interrupt signatures --- .../interrupt-invalid-signature.avr.stderr | 28 +++++ .../interrupt-invalid-signature.i686.stderr | 15 +++ .../interrupt-invalid-signature.msp430.stderr | 28 +++++ ...interrupt-invalid-signature.riscv32.stderr | 54 +++++++++ ...interrupt-invalid-signature.riscv64.stderr | 54 +++++++++ tests/ui/abi/interrupt-invalid-signature.rs | 110 ++++++++++++++++++ .../interrupt-invalid-signature.x64.stderr | 15 +++ 7 files changed, 304 insertions(+) create mode 100644 tests/ui/abi/interrupt-invalid-signature.avr.stderr create mode 100644 tests/ui/abi/interrupt-invalid-signature.i686.stderr create mode 100644 tests/ui/abi/interrupt-invalid-signature.msp430.stderr create mode 100644 tests/ui/abi/interrupt-invalid-signature.riscv32.stderr create mode 100644 tests/ui/abi/interrupt-invalid-signature.riscv64.stderr create mode 100644 tests/ui/abi/interrupt-invalid-signature.rs create mode 100644 tests/ui/abi/interrupt-invalid-signature.x64.stderr diff --git a/tests/ui/abi/interrupt-invalid-signature.avr.stderr b/tests/ui/abi/interrupt-invalid-signature.avr.stderr new file mode 100644 index 0000000000000..91f5ca2022e38 --- /dev/null +++ b/tests/ui/abi/interrupt-invalid-signature.avr.stderr @@ -0,0 +1,28 @@ +error: invalid signature for `extern "avr-interrupt"` function + --> $DIR/interrupt-invalid-signature.rs:44:35 + | +LL | extern "avr-interrupt" fn avr_arg(_byte: u8) {} + | ^^^^^^^^^ + | + = note: functions with the "avr-interrupt" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "avr-interrupt" fn avr_arg(_byte: u8) {} +LL + extern "avr-interrupt" fn avr_arg() {} + | + +error: invalid signature for `extern "avr-interrupt"` function + --> $DIR/interrupt-invalid-signature.rs:59:40 + | +LL | extern "avr-interrupt" fn avr_ret() -> u8 { + | ^^ + | + = note: functions with the "avr-interrupt" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "avr-interrupt" fn avr_ret() -> u8 { +LL + extern "avr-interrupt" fn avr_ret() { + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/abi/interrupt-invalid-signature.i686.stderr b/tests/ui/abi/interrupt-invalid-signature.i686.stderr new file mode 100644 index 0000000000000..06fd513df19ea --- /dev/null +++ b/tests/ui/abi/interrupt-invalid-signature.i686.stderr @@ -0,0 +1,15 @@ +error: invalid signature for `extern "x86-interrupt"` function + --> $DIR/interrupt-invalid-signature.rs:83:40 + | +LL | extern "x86-interrupt" fn x86_ret() -> u8 { + | ^^ + | + = note: functions with the "custom" ABI cannot have a return type +help: remove the return type + --> $DIR/interrupt-invalid-signature.rs:83:40 + | +LL | extern "x86-interrupt" fn x86_ret() -> u8 { + | ^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/abi/interrupt-invalid-signature.msp430.stderr b/tests/ui/abi/interrupt-invalid-signature.msp430.stderr new file mode 100644 index 0000000000000..38479f93de58f --- /dev/null +++ b/tests/ui/abi/interrupt-invalid-signature.msp430.stderr @@ -0,0 +1,28 @@ +error: invalid signature for `extern "msp430-interrupt"` function + --> $DIR/interrupt-invalid-signature.rs:40:41 + | +LL | extern "msp430-interrupt" fn msp430_arg(_byte: u8) {} + | ^^^^^^^^^ + | + = note: functions with the "msp430-interrupt" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "msp430-interrupt" fn msp430_arg(_byte: u8) {} +LL + extern "msp430-interrupt" fn msp430_arg() {} + | + +error: invalid signature for `extern "msp430-interrupt"` function + --> $DIR/interrupt-invalid-signature.rs:65:46 + | +LL | extern "msp430-interrupt" fn msp430_ret() -> u8 { + | ^^ + | + = note: functions with the "msp430-interrupt" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "msp430-interrupt" fn msp430_ret() -> u8 { +LL + extern "msp430-interrupt" fn msp430_ret() { + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/abi/interrupt-invalid-signature.riscv32.stderr b/tests/ui/abi/interrupt-invalid-signature.riscv32.stderr new file mode 100644 index 0000000000000..d632b17ab83f7 --- /dev/null +++ b/tests/ui/abi/interrupt-invalid-signature.riscv32.stderr @@ -0,0 +1,54 @@ +error: invalid signature for `extern "riscv-interrupt-m"` function + --> $DIR/interrupt-invalid-signature.rs:48:43 + | +LL | extern "riscv-interrupt-m" fn riscv_m_arg(_byte: u8) {} + | ^^^^^^^^^ + | + = note: functions with the "riscv-interrupt-m" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "riscv-interrupt-m" fn riscv_m_arg(_byte: u8) {} +LL + extern "riscv-interrupt-m" fn riscv_m_arg() {} + | + +error: invalid signature for `extern "riscv-interrupt-s"` function + --> $DIR/interrupt-invalid-signature.rs:52:43 + | +LL | extern "riscv-interrupt-s" fn riscv_s_arg(_byte: u8) {} + | ^^^^^^^^^ + | + = note: functions with the "riscv-interrupt-s" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "riscv-interrupt-s" fn riscv_s_arg(_byte: u8) {} +LL + extern "riscv-interrupt-s" fn riscv_s_arg() {} + | + +error: invalid signature for `extern "riscv-interrupt-m"` function + --> $DIR/interrupt-invalid-signature.rs:71:48 + | +LL | extern "riscv-interrupt-m" fn riscv_m_ret() -> u8 { + | ^^ + | + = note: functions with the "riscv-interrupt-m" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "riscv-interrupt-m" fn riscv_m_ret() -> u8 { +LL + extern "riscv-interrupt-m" fn riscv_m_ret() { + | + +error: invalid signature for `extern "riscv-interrupt-s"` function + --> $DIR/interrupt-invalid-signature.rs:77:48 + | +LL | extern "riscv-interrupt-s" fn riscv_s_ret() -> u8 { + | ^^ + | + = note: functions with the "riscv-interrupt-s" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "riscv-interrupt-s" fn riscv_s_ret() -> u8 { +LL + extern "riscv-interrupt-s" fn riscv_s_ret() { + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/abi/interrupt-invalid-signature.riscv64.stderr b/tests/ui/abi/interrupt-invalid-signature.riscv64.stderr new file mode 100644 index 0000000000000..d632b17ab83f7 --- /dev/null +++ b/tests/ui/abi/interrupt-invalid-signature.riscv64.stderr @@ -0,0 +1,54 @@ +error: invalid signature for `extern "riscv-interrupt-m"` function + --> $DIR/interrupt-invalid-signature.rs:48:43 + | +LL | extern "riscv-interrupt-m" fn riscv_m_arg(_byte: u8) {} + | ^^^^^^^^^ + | + = note: functions with the "riscv-interrupt-m" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "riscv-interrupt-m" fn riscv_m_arg(_byte: u8) {} +LL + extern "riscv-interrupt-m" fn riscv_m_arg() {} + | + +error: invalid signature for `extern "riscv-interrupt-s"` function + --> $DIR/interrupt-invalid-signature.rs:52:43 + | +LL | extern "riscv-interrupt-s" fn riscv_s_arg(_byte: u8) {} + | ^^^^^^^^^ + | + = note: functions with the "riscv-interrupt-s" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "riscv-interrupt-s" fn riscv_s_arg(_byte: u8) {} +LL + extern "riscv-interrupt-s" fn riscv_s_arg() {} + | + +error: invalid signature for `extern "riscv-interrupt-m"` function + --> $DIR/interrupt-invalid-signature.rs:71:48 + | +LL | extern "riscv-interrupt-m" fn riscv_m_ret() -> u8 { + | ^^ + | + = note: functions with the "riscv-interrupt-m" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "riscv-interrupt-m" fn riscv_m_ret() -> u8 { +LL + extern "riscv-interrupt-m" fn riscv_m_ret() { + | + +error: invalid signature for `extern "riscv-interrupt-s"` function + --> $DIR/interrupt-invalid-signature.rs:77:48 + | +LL | extern "riscv-interrupt-s" fn riscv_s_ret() -> u8 { + | ^^ + | + = note: functions with the "riscv-interrupt-s" ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "riscv-interrupt-s" fn riscv_s_ret() -> u8 { +LL + extern "riscv-interrupt-s" fn riscv_s_ret() { + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/abi/interrupt-invalid-signature.rs b/tests/ui/abi/interrupt-invalid-signature.rs new file mode 100644 index 0000000000000..e389285b06917 --- /dev/null +++ b/tests/ui/abi/interrupt-invalid-signature.rs @@ -0,0 +1,110 @@ +/*! Tests interrupt ABIs have a constricted signature + +Most interrupt ABIs share a similar restriction in terms of not allowing most signatures. +Specifically, they generally cannot have arguments or return types. +So we test that they error in essentially all of the same places. +A notable and interesting exception is x86. + +This test uses `cfg` because it is not testing whether these ABIs work on the platform. +*/ +//@ add-core-stubs +//@ revisions: x64 i686 riscv32 riscv64 avr msp430 +// +//@ [x64] needs-llvm-components: x86 +//@ [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib +//@ [i686] needs-llvm-components: x86 +//@ [i686] compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib +//@ [riscv32] needs-llvm-components: riscv +//@ [riscv32] compile-flags: --target=riscv32i-unknown-none-elf --crate-type=rlib +//@ [riscv64] needs-llvm-components: riscv +//@ [riscv64] compile-flags: --target=riscv64gc-unknown-none-elf --crate-type=rlib +//@ [avr] needs-llvm-components: avr +//@ [avr] compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib +//@ [msp430] needs-llvm-components: msp430 +//@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib +#![no_core] +#![feature( + no_core, + abi_msp430_interrupt, + abi_avr_interrupt, + abi_x86_interrupt, + abi_riscv_interrupt +)] + +extern crate minicore; +use minicore::*; + +/* most extern "interrupt" definitions should not accept args */ + +#[cfg(msp430)] +extern "msp430-interrupt" fn msp430_arg(_byte: u8) {} +//[msp430]~^ ERROR invalid signature + +#[cfg(avr)] +extern "avr-interrupt" fn avr_arg(_byte: u8) {} +//[avr]~^ ERROR invalid signature + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-m" fn riscv_m_arg(_byte: u8) {} +//[riscv32,riscv64]~^ ERROR invalid signature + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-s" fn riscv_s_arg(_byte: u8) {} +//[riscv32,riscv64]~^ ERROR invalid signature + + +/* all extern "interrupt" definitions should not return non-1ZST values */ + +#[cfg(avr)] +extern "avr-interrupt" fn avr_ret() -> u8 { + //[avr]~^ ERROR invalid signature + 1 +} + +#[cfg(msp430)] +extern "msp430-interrupt" fn msp430_ret() -> u8 { + //[msp430]~^ ERROR invalid signature + 1 +} + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-m" fn riscv_m_ret() -> u8 { + //[riscv32,riscv64]~^ ERROR invalid signature + 1 +} + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-s" fn riscv_s_ret() -> u8 { + //[riscv32,riscv64]~^ ERROR invalid signature + 1 +} + +#[cfg(any(x64,i686))] +extern "x86-interrupt" fn x86_ret() -> u8 { + //[x64,i686]~^ ERROR invalid signature + 1 +} + + + +/* extern "interrupt" fnptrs with invalid signatures */ + +#[cfg(avr)] +fn avr_ptr(_f: extern "avr-interrupt" fn(u8) -> u8) { +} + +#[cfg(msp430)] +fn msp430_ptr(_f: extern "msp430-interrupt" fn(u8) -> u8) { +} + +#[cfg(any(riscv32,riscv64))] +fn riscv_m_ptr(_f: extern "riscv-interrupt-m" fn(u8) -> u8) { +} + +#[cfg(any(riscv32,riscv64))] +fn riscv_s_ptr(_f: extern "riscv-interrupt-s" fn(u8) -> u8) { +} + +#[cfg(any(x64,i686))] +fn x86_ptr(_f: extern "x86-interrupt" fn() -> u8) { +} diff --git a/tests/ui/abi/interrupt-invalid-signature.x64.stderr b/tests/ui/abi/interrupt-invalid-signature.x64.stderr new file mode 100644 index 0000000000000..06fd513df19ea --- /dev/null +++ b/tests/ui/abi/interrupt-invalid-signature.x64.stderr @@ -0,0 +1,15 @@ +error: invalid signature for `extern "x86-interrupt"` function + --> $DIR/interrupt-invalid-signature.rs:83:40 + | +LL | extern "x86-interrupt" fn x86_ret() -> u8 { + | ^^ + | + = note: functions with the "custom" ABI cannot have a return type +help: remove the return type + --> $DIR/interrupt-invalid-signature.rs:83:40 + | +LL | extern "x86-interrupt" fn x86_ret() -> u8 { + | ^^ + +error: aborting due to 1 previous error + From db33e98540fca8f3268cafc6276dbefd55681d55 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 26 Jun 2025 18:02:54 -0700 Subject: [PATCH 003/252] compiler: fixup error message for x86-interrupt invalid returns --- compiler/rustc_ast_passes/messages.ftl | 2 +- tests/ui/abi/interrupt-invalid-signature.i686.stderr | 2 +- tests/ui/abi/interrupt-invalid-signature.x64.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 6eddce7b590ac..869c3a58ae3df 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -17,7 +17,7 @@ ast_passes_abi_must_not_have_parameters_or_return_type= ast_passes_abi_must_not_have_return_type= invalid signature for `extern {$abi}` function - .note = functions with the "custom" ABI cannot have a return type + .note = functions with the {$abi} ABI cannot have a return type .help = remove the return type ast_passes_assoc_const_without_body = diff --git a/tests/ui/abi/interrupt-invalid-signature.i686.stderr b/tests/ui/abi/interrupt-invalid-signature.i686.stderr index 06fd513df19ea..86f2e097c37e1 100644 --- a/tests/ui/abi/interrupt-invalid-signature.i686.stderr +++ b/tests/ui/abi/interrupt-invalid-signature.i686.stderr @@ -4,7 +4,7 @@ error: invalid signature for `extern "x86-interrupt"` function LL | extern "x86-interrupt" fn x86_ret() -> u8 { | ^^ | - = note: functions with the "custom" ABI cannot have a return type + = note: functions with the "x86-interrupt" ABI cannot have a return type help: remove the return type --> $DIR/interrupt-invalid-signature.rs:83:40 | diff --git a/tests/ui/abi/interrupt-invalid-signature.x64.stderr b/tests/ui/abi/interrupt-invalid-signature.x64.stderr index 06fd513df19ea..86f2e097c37e1 100644 --- a/tests/ui/abi/interrupt-invalid-signature.x64.stderr +++ b/tests/ui/abi/interrupt-invalid-signature.x64.stderr @@ -4,7 +4,7 @@ error: invalid signature for `extern "x86-interrupt"` function LL | extern "x86-interrupt" fn x86_ret() -> u8 { | ^^ | - = note: functions with the "custom" ABI cannot have a return type + = note: functions with the "x86-interrupt" ABI cannot have a return type help: remove the return type --> $DIR/interrupt-invalid-signature.rs:83:40 | From d6b3314fb29cc688a968811b6a78dc8a5309cb7d Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 26 Jun 2025 19:35:28 -0700 Subject: [PATCH 004/252] compiler: allow interrupts to return () or ! --- .../rustc_ast_passes/src/ast_validation.rs | 16 ++- .../ui/abi/interrupt-returns-never-or-unit.rs | 110 ++++++++++++++++++ 2 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 tests/ui/abi/interrupt-returns-never-or-unit.rs diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index da24825120376..478cec23fd57e 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -396,7 +396,13 @@ impl<'a> AstValidator<'a> { if let InterruptKind::X86 = interrupt_kind { // "x86-interrupt" is special because it does have arguments. // FIXME(workingjubilee): properly lint on acceptable input types. - if let FnRetTy::Ty(ref ret_ty) = sig.decl.output { + if let FnRetTy::Ty(ref ret_ty) = sig.decl.output + && match &ret_ty.kind { + TyKind::Never => false, + TyKind::Tup(tup) if tup.is_empty() => false, + _ => true, + } + { self.dcx().emit_err(errors::AbiMustNotHaveReturnType { span: ret_ty.span, abi, @@ -455,7 +461,13 @@ impl<'a> AstValidator<'a> { fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) { let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect(); - if let FnRetTy::Ty(ref ret_ty) = sig.decl.output { + if let FnRetTy::Ty(ref ret_ty) = sig.decl.output + && match &ret_ty.kind { + TyKind::Never => false, + TyKind::Tup(tup) if tup.is_empty() => false, + _ => true, + } + { spans.push(ret_ty.span); } diff --git a/tests/ui/abi/interrupt-returns-never-or-unit.rs b/tests/ui/abi/interrupt-returns-never-or-unit.rs new file mode 100644 index 0000000000000..34d509c832872 --- /dev/null +++ b/tests/ui/abi/interrupt-returns-never-or-unit.rs @@ -0,0 +1,110 @@ +/*! Tests interrupt ABIs can return ! + +Most interrupt ABIs share a similar restriction in terms of not allowing most signatures, +but it makes sense to allow them to return ! because they could indeed be divergent. + +This test uses `cfg` because it is not testing whether these ABIs work on the platform. +*/ +//@ add-core-stubs +//@ revisions: x64 i686 riscv32 riscv64 avr msp430 +//@ build-pass +// +//@ [x64] needs-llvm-components: x86 +//@ [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib +//@ [i686] needs-llvm-components: x86 +//@ [i686] compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib +//@ [riscv32] needs-llvm-components: riscv +//@ [riscv32] compile-flags: --target=riscv32i-unknown-none-elf --crate-type=rlib +//@ [riscv64] needs-llvm-components: riscv +//@ [riscv64] compile-flags: --target=riscv64gc-unknown-none-elf --crate-type=rlib +//@ [avr] needs-llvm-components: avr +//@ [avr] compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib +//@ [msp430] needs-llvm-components: msp430 +//@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib +#![no_core] +#![feature( + no_core, + abi_msp430_interrupt, + abi_avr_interrupt, + abi_x86_interrupt, + abi_riscv_interrupt +)] + +extern crate minicore; +use minicore::*; + +/* interrupts can return never */ + +#[cfg(avr)] +extern "avr-interrupt" fn avr_ret_never() -> ! { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(msp430)] +extern "msp430-interrupt" fn msp430_ret_never() -> ! { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-m" fn riscv_m_ret_never() -> ! { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-s" fn riscv_s_ret_never() -> ! { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(x64,i686))] +extern "x86-interrupt" fn x86_ret_never() -> ! { + unsafe { hint::unreachable_unchecked() } +} + +/* interrupts can return explicit () */ + +#[cfg(avr)] +extern "avr-interrupt" fn avr_ret_unit() -> () { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(msp430)] +extern "msp430-interrupt" fn msp430_ret_unit() -> () { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-m" fn riscv_m_ret_unit() -> () { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-s" fn riscv_s_ret_unit() -> () { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(x64,i686))] +extern "x86-interrupt" fn x86_ret_unit() -> () { + unsafe { hint::unreachable_unchecked() } +} + +/* extern "interrupt" fnptrs can return ! too */ + +#[cfg(avr)] +fn avr_ptr(_f: extern "avr-interrupt" fn() -> !) { +} + +#[cfg(msp430)] +fn msp430_ptr(_f: extern "msp430-interrupt" fn() -> !) { +} + +#[cfg(any(riscv32,riscv64))] +fn riscv_m_ptr(_f: extern "riscv-interrupt-m" fn() -> !) { +} + +#[cfg(any(riscv32,riscv64))] +fn riscv_s_ptr(_f: extern "riscv-interrupt-s" fn() -> !) { +} + +#[cfg(any(x64,i686))] +fn x86_ptr(_f: extern "x86-interrupt" fn() -> !) { +} From b5ab966626e006172027e658fb1e43cf79f1c21a Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 27 Jun 2025 11:03:23 -0700 Subject: [PATCH 005/252] remember how to write never returns --- .../ui/abi/interrupt-returns-never-or-unit.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/ui/abi/interrupt-returns-never-or-unit.rs b/tests/ui/abi/interrupt-returns-never-or-unit.rs index 34d509c832872..8e224229a0b17 100644 --- a/tests/ui/abi/interrupt-returns-never-or-unit.rs +++ b/tests/ui/abi/interrupt-returns-never-or-unit.rs @@ -37,54 +37,54 @@ use minicore::*; #[cfg(avr)] extern "avr-interrupt" fn avr_ret_never() -> ! { - unsafe { hint::unreachable_unchecked() } + loop {} } #[cfg(msp430)] extern "msp430-interrupt" fn msp430_ret_never() -> ! { - unsafe { hint::unreachable_unchecked() } + loop {} } #[cfg(any(riscv32,riscv64))] extern "riscv-interrupt-m" fn riscv_m_ret_never() -> ! { - unsafe { hint::unreachable_unchecked() } + loop {} } #[cfg(any(riscv32,riscv64))] extern "riscv-interrupt-s" fn riscv_s_ret_never() -> ! { - unsafe { hint::unreachable_unchecked() } + loop {} } #[cfg(any(x64,i686))] extern "x86-interrupt" fn x86_ret_never() -> ! { - unsafe { hint::unreachable_unchecked() } + loop {} } /* interrupts can return explicit () */ #[cfg(avr)] extern "avr-interrupt" fn avr_ret_unit() -> () { - unsafe { hint::unreachable_unchecked() } + () } #[cfg(msp430)] extern "msp430-interrupt" fn msp430_ret_unit() -> () { - unsafe { hint::unreachable_unchecked() } + () } #[cfg(any(riscv32,riscv64))] extern "riscv-interrupt-m" fn riscv_m_ret_unit() -> () { - unsafe { hint::unreachable_unchecked() } + () } #[cfg(any(riscv32,riscv64))] extern "riscv-interrupt-s" fn riscv_s_ret_unit() -> () { - unsafe { hint::unreachable_unchecked() } + () } #[cfg(any(x64,i686))] extern "x86-interrupt" fn x86_ret_unit() -> () { - unsafe { hint::unreachable_unchecked() } + () } /* extern "interrupt" fnptrs can return ! too */ From f6bdffdcba7498fd3fe7b18bca966b23da6c463f Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Mon, 20 Nov 2023 02:18:52 +0300 Subject: [PATCH 006/252] Add Ref/RefMut try_map method --- library/core/src/cell.rs | 93 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c53a2b2beb4cc..2f1a74fa2416f 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1573,6 +1573,47 @@ impl<'b, T: ?Sized> Ref<'b, T> { } } + /// Tries to makes a new `Ref` for a component of the borrowed data. + /// On failure, the original guard is returned alongside with the error + /// returned by the closure. + /// + /// The `RefCell` is already immutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `Ref::try_map(...)`. A method would interfere with methods of the same + /// name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(refcell_try_map)] + /// use std::cell::{RefCell, Ref}; + /// use std::str::{from_utf8, Utf8Error}; + /// + /// let c = RefCell::new(vec![0xF0, 0x9F, 0xA6 ,0x80]); + /// let b1: Ref<'_, Vec> = c.borrow(); + /// let b2: Result, _> = Ref::try_map(b1, |v| from_utf8(v)); + /// assert_eq!(&*b2.unwrap(), "🦀"); + /// + /// let c = RefCell::new(vec![0xF0, 0x9F, 0xA6]); + /// let b1: Ref<'_, Vec> = c.borrow(); + /// let b2: Result<_, (Ref<'_, Vec>, Utf8Error)> = Ref::try_map(b1, |v| from_utf8(v)); + /// let (b3, e) = b2.unwrap_err(); + /// assert_eq!(*b3, vec![0xF0, 0x9F, 0xA6]); + /// assert_eq!(e.valid_up_to(), 0); + /// ``` + #[unstable(feature = "refcell_try_map", issue = "143801")] + #[inline] + pub fn try_map( + orig: Ref<'b, T>, + f: impl FnOnce(&T) -> Result<&U, E>, + ) -> Result, (Self, E)> { + match f(&*orig) { + Ok(value) => Ok(Ref { value: NonNull::from(value), borrow: orig.borrow }), + Err(e) => Err((orig, e)), + } + } + /// Splits a `Ref` into multiple `Ref`s for different components of the /// borrowed data. /// @@ -1734,6 +1775,58 @@ impl<'b, T: ?Sized> RefMut<'b, T> { } } + /// Tries to makes a new `RefMut` for a component of the borrowed data. + /// On failure, the original guard is returned alongside with the error + /// returned by the closure. + /// + /// The `RefCell` is already mutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RefMut::try_map(...)`. A method would interfere with methods of the same + /// name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(refcell_try_map)] + /// use std::cell::{RefCell, RefMut}; + /// use std::str::{from_utf8_mut, Utf8Error}; + /// + /// let c = RefCell::new(vec![0x68, 0x65, 0x6C, 0x6C, 0x6F]); + /// { + /// let b1: RefMut<'_, Vec> = c.borrow_mut(); + /// let b2: Result, _> = RefMut::try_map(b1, |v| from_utf8_mut(v)); + /// let mut b2 = b2.unwrap(); + /// assert_eq!(&*b2, "hello"); + /// b2.make_ascii_uppercase(); + /// } + /// assert_eq!(*c.borrow(), "HELLO".as_bytes()); + /// + /// let c = RefCell::new(vec![0xFF]); + /// let b1: RefMut<'_, Vec> = c.borrow_mut(); + /// let b2: Result<_, (RefMut<'_, Vec>, Utf8Error)> = RefMut::try_map(b1, |v| from_utf8_mut(v)); + /// let (b3, e) = b2.unwrap_err(); + /// assert_eq!(*b3, vec![0xFF]); + /// assert_eq!(e.valid_up_to(), 0); + /// ``` + #[unstable(feature = "refcell_try_map", issue = "143801")] + #[inline] + pub fn try_map( + mut orig: RefMut<'b, T>, + f: impl FnOnce(&mut T) -> Result<&mut U, E>, + ) -> Result, (Self, E)> { + // SAFETY: function holds onto an exclusive reference for the duration + // of its call through `orig`, and the pointer is only de-referenced + // inside of the function call never allowing the exclusive reference to + // escape. + match f(&mut *orig) { + Ok(value) => { + Ok(RefMut { value: NonNull::from(value), borrow: orig.borrow, marker: PhantomData }) + } + Err(e) => Err((orig, e)), + } + } + /// Splits a `RefMut` into multiple `RefMut`s for different components of the /// borrowed data. /// From 87dd4695fe5fe2e76999d5040deb20a018e21942 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 15 Jul 2025 17:41:31 -0400 Subject: [PATCH 007/252] Add `Default` impls for `Pin`ned `Box`, `Rc`, `Arc` --- library/alloc/src/boxed.rs | 16 +++++++++++++++- library/alloc/src/rc.rs | 19 ++++++++++++++++--- library/alloc/src/sync.rs | 13 +++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 3db37f1d16f3d..fa12d379c8cae 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1672,7 +1672,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box { - /// Creates a `Box`, with the `Default` value for T. + /// Creates a `Box`, with the `Default` value for `T`. #[inline] fn default() -> Self { let mut x: Box> = Box::new_uninit(); @@ -1695,6 +1695,7 @@ impl Default for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box<[T]> { + /// Creates an empty `[T]` inside a `Box`. #[inline] fn default() -> Self { let ptr: Unique<[T]> = Unique::<[T; 0]>::dangling(); @@ -1716,6 +1717,19 @@ impl Default for Box { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "pin_default_impls", since = "CURRENT_RUSTC_VERSION")] +impl Default for Pin> +where + T: ?Sized, + Box: Default, +{ + #[inline] + fn default() -> Self { + Box::into_pin(Box::::default()) + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Box { diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 5018ff4ad71f3..529b583cdd2bc 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2357,7 +2357,7 @@ impl Default for Rc { /// assert_eq!(*x, 0); /// ``` #[inline] - fn default() -> Rc { + fn default() -> Self { unsafe { Self::from_inner( Box::leak(Box::write( @@ -2373,7 +2373,7 @@ impl Default for Rc { #[cfg(not(no_global_oom_handling))] #[stable(feature = "more_rc_default_impls", since = "1.80.0")] impl Default for Rc { - /// Creates an empty str inside an Rc + /// Creates an empty `str` inside an `Rc`. /// /// This may or may not share an allocation with other Rcs on the same thread. #[inline] @@ -2387,7 +2387,7 @@ impl Default for Rc { #[cfg(not(no_global_oom_handling))] #[stable(feature = "more_rc_default_impls", since = "1.80.0")] impl Default for Rc<[T]> { - /// Creates an empty `[T]` inside an Rc + /// Creates an empty `[T]` inside an `Rc`. /// /// This may or may not share an allocation with other Rcs on the same thread. #[inline] @@ -2397,6 +2397,19 @@ impl Default for Rc<[T]> { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "pin_default_impls", since = "CURRENT_RUSTC_VERSION")] +impl Default for Pin> +where + T: ?Sized, + Rc: Default, +{ + #[inline] + fn default() -> Self { + unsafe { Pin::new_unchecked(Rc::::default()) } + } +} + #[stable(feature = "rust1", since = "1.0.0")] trait RcEqIdent { fn eq(&self, other: &Rc) -> bool; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index b8925f4544f44..29caa7bc5393c 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -3654,6 +3654,19 @@ impl Default for Arc<[T]> { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "pin_default_impls", since = "CURRENT_RUSTC_VERSION")] +impl Default for Pin> +where + T: ?Sized, + Arc: Default, +{ + #[inline] + fn default() -> Self { + unsafe { Pin::new_unchecked(Arc::::default()) } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Hash for Arc { fn hash(&self, state: &mut H) { From 14c6e50d4740e13bf36b6c272485804ba9ad9117 Mon Sep 17 00:00:00 2001 From: Josh Simmons Date: Thu, 17 Jul 2025 09:11:44 +0200 Subject: [PATCH 008/252] Stabilize as_array_of_cells --- library/core/src/cell.rs | 4 ++-- tests/ui/rfcs/rfc-1789-as-cell/from-mut.rs | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index d6d1bf2effae2..583a3340c2620 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -698,14 +698,14 @@ impl Cell<[T; N]> { /// # Examples /// /// ``` - /// #![feature(as_array_of_cells)] /// use std::cell::Cell; /// /// let mut array: [i32; 3] = [1, 2, 3]; /// let cell_array: &Cell<[i32; 3]> = Cell::from_mut(&mut array); /// let array_cell: &[Cell; 3] = cell_array.as_array_of_cells(); /// ``` - #[unstable(feature = "as_array_of_cells", issue = "88248")] + #[stable(feature = "as_array_of_cells", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "as_array_of_cells", since = "CURRENT_RUSTC_VERSION")] pub const fn as_array_of_cells(&self) -> &[Cell; N] { // SAFETY: `Cell` has the same memory layout as `T`. unsafe { &*(self as *const Cell<[T; N]> as *const [Cell; N]) } diff --git a/tests/ui/rfcs/rfc-1789-as-cell/from-mut.rs b/tests/ui/rfcs/rfc-1789-as-cell/from-mut.rs index d3b441fbe88f6..700f875a4f63b 100644 --- a/tests/ui/rfcs/rfc-1789-as-cell/from-mut.rs +++ b/tests/ui/rfcs/rfc-1789-as-cell/from-mut.rs @@ -1,7 +1,5 @@ //@ run-pass -#![feature(as_array_of_cells)] - use std::cell::Cell; fn main() { From 7ead5764a88d91803db898e679dd49f2520cdae6 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 26 Jul 2025 13:22:24 -0700 Subject: [PATCH 009/252] Implement `ptr_cast_array` --- library/core/src/ptr/const_ptr.rs | 9 +++++++++ library/core/src/ptr/mut_ptr.rs | 9 +++++++++ library/core/src/ptr/non_null.rs | 7 +++++++ 3 files changed, 25 insertions(+) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 2ad520b7ead72..90d08f60a0451 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1547,6 +1547,15 @@ impl *const [T] { } } +impl *const T { + /// Casts from a pointer-to-`T` to a pointer-to-`[T; N]`. + #[inline] + #[unstable(feature = "ptr_cast_array", issue = "144514")] + pub const fn cast_array(self) -> *const [T; N] { + self.cast() + } +} + impl *const [T; N] { /// Returns a raw pointer to the array's buffer. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 579e2461103d8..dec212d04c96f 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1965,6 +1965,15 @@ impl *mut [T] { } } +impl *mut T { + /// Casts from a pointer-to-`T` to a pointer-to-`[T; N]`. + #[inline] + #[unstable(feature = "ptr_cast_array", issue = "144514")] + pub const fn cast_array(self) -> *mut [T; N] { + self.cast() + } +} + impl *mut [T; N] { /// Returns a raw pointer to the array's buffer. /// diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 62da6567cca75..245a0a08321cf 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -193,6 +193,13 @@ impl NonNull { // requirements for a reference. unsafe { &mut *self.cast().as_ptr() } } + + /// Casts from a pointer-to-`T` to a pointer-to-`[T; N]`. + #[inline] + #[unstable(feature = "ptr_cast_array", issue = "144514")] + pub const fn cast_array(self) -> NonNull<[T; N]> { + self.cast() + } } impl NonNull { From 51b0416c19f436393b3c070cc037a8f062bcbd83 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 26 Jul 2025 13:26:53 -0700 Subject: [PATCH 010/252] Use `cast_array` in core --- library/core/src/slice/mod.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 6fe5affc48be7..13e182b5f87a4 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -330,7 +330,7 @@ impl [T] { } else { // SAFETY: We explicitly check for the correct number of elements, // and do not let the reference outlive the slice. - Some(unsafe { &*(self.as_ptr().cast::<[T; N]>()) }) + Some(unsafe { &*(self.as_ptr().cast_array()) }) } } @@ -361,7 +361,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and require exclusive access to the entire slice to mutate the chunk. - Some(unsafe { &mut *(self.as_mut_ptr().cast::<[T; N]>()) }) + Some(unsafe { &mut *(self.as_mut_ptr().cast_array()) }) } } @@ -389,7 +389,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some((unsafe { &*(first.as_ptr().cast::<[T; N]>()) }, tail)) + Some((unsafe { &*(first.as_ptr().cast_array()) }, tail)) } /// Returns a mutable array reference to the first `N` items in the slice and the remaining @@ -422,7 +422,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and enforce exclusive mutability of the chunk by the split. - Some((unsafe { &mut *(first.as_mut_ptr().cast::<[T; N]>()) }, tail)) + Some((unsafe { &mut *(first.as_mut_ptr().cast_array()) }, tail)) } /// Returns an array reference to the last `N` items in the slice and the remaining slice. @@ -450,7 +450,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some((init, unsafe { &*(last.as_ptr().cast::<[T; N]>()) })) + Some((init, unsafe { &*(last.as_ptr().cast_array()) })) } /// Returns a mutable array reference to the last `N` items in the slice and the remaining @@ -484,7 +484,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and enforce exclusive mutability of the chunk by the split. - Some((init, unsafe { &mut *(last.as_mut_ptr().cast::<[T; N]>()) })) + Some((init, unsafe { &mut *(last.as_mut_ptr().cast_array()) })) } /// Returns an array reference to the last `N` items in the slice. @@ -513,7 +513,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some(unsafe { &*(last.as_ptr().cast::<[T; N]>()) }) + Some(unsafe { &*(last.as_ptr().cast_array()) }) } /// Returns a mutable array reference to the last `N` items in the slice. @@ -544,7 +544,7 @@ impl [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and require exclusive access to the entire slice to mutate the chunk. - Some(unsafe { &mut *(last.as_mut_ptr().cast::<[T; N]>()) }) + Some(unsafe { &mut *(last.as_mut_ptr().cast_array()) }) } /// Returns a reference to an element or subslice depending on the type of @@ -848,7 +848,7 @@ impl [T] { #[must_use] pub const fn as_array(&self) -> Option<&[T; N]> { if self.len() == N { - let ptr = self.as_ptr() as *const [T; N]; + let ptr = self.as_ptr().cast_array(); // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. let me = unsafe { &*ptr }; @@ -866,7 +866,7 @@ impl [T] { #[must_use] pub const fn as_mut_array(&mut self) -> Option<&mut [T; N]> { if self.len() == N { - let ptr = self.as_mut_ptr() as *mut [T; N]; + let ptr = self.as_mut_ptr().cast_array(); // SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length. let me = unsafe { &mut *ptr }; From ba5b6b9ec472dc32bdaa8b18c22d30bd6abf7ebc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Jul 2025 20:00:19 +0200 Subject: [PATCH 011/252] const-eval: full support for pointer fragments --- compiler/rustc_const_eval/messages.ftl | 11 +- .../src/const_eval/eval_queries.rs | 7 + compiler/rustc_const_eval/src/errors.rs | 16 +- .../rustc_const_eval/src/interpret/intern.rs | 97 +++++++----- .../rustc_const_eval/src/interpret/memory.rs | 44 ++---- .../rustc_const_eval/src/interpret/place.rs | 8 +- .../src/interpret/validity.rs | 4 +- .../src/mir/interpret/allocation.rs | 84 ++++++----- .../interpret/allocation/provenance_map.rs | 142 +++++++++--------- .../rustc_middle/src/mir/interpret/error.rs | 3 - .../rustc_middle/src/mir/interpret/pointer.rs | 12 +- compiler/rustc_middle/src/mir/pretty.rs | 4 +- library/core/src/ptr/mod.rs | 38 +---- library/coretests/tests/ptr.rs | 12 +- src/tools/miri/src/machine.rs | 10 +- src/tools/miri/src/shims/native_lib/mod.rs | 2 +- .../miri/tests/fail/provenance/mix-ptrs1.rs | 21 +++ .../tests/fail/provenance/mix-ptrs1.stderr | 16 ++ .../miri/tests/fail/provenance/mix-ptrs2.rs | 37 +++++ .../tests/fail/provenance/mix-ptrs2.stderr | 16 ++ ...uninit_alloc_diagnostic_with_provenance.rs | 11 +- ...it_alloc_diagnostic_with_provenance.stderr | 2 +- .../fail/tracing/partial_init.stderr | 2 +- src/tools/miri/tests/pass/provenance.rs | 35 ----- src/tools/miri/tests/pass/transmute_ptr.rs | 21 +-- .../heap/ptr_not_made_global.stderr | 4 +- .../heap/ptr_not_made_global_mut.stderr | 2 +- .../const-eval/partial_ptr_overwrite.rs | 12 -- .../const-eval/partial_ptr_overwrite.stderr | 12 -- tests/ui/consts/const-eval/ptr_fragments.rs | 63 ++++++++ .../const-eval/ptr_fragments_in_final.rs | 25 +++ .../const-eval/ptr_fragments_in_final.stderr | 10 ++ .../ui/consts/const-eval/read_partial_ptr.rs | 49 ++++++ .../consts/const-eval/read_partial_ptr.stderr | 39 +++++ tests/ui/consts/missing_span_in_backtrace.rs | 13 +- .../consts/missing_span_in_backtrace.stderr | 16 +- 36 files changed, 542 insertions(+), 358 deletions(-) create mode 100644 src/tools/miri/tests/fail/provenance/mix-ptrs1.rs create mode 100644 src/tools/miri/tests/fail/provenance/mix-ptrs1.stderr create mode 100644 src/tools/miri/tests/fail/provenance/mix-ptrs2.rs create mode 100644 src/tools/miri/tests/fail/provenance/mix-ptrs2.stderr delete mode 100644 tests/ui/consts/const-eval/partial_ptr_overwrite.rs delete mode 100644 tests/ui/consts/const-eval/partial_ptr_overwrite.stderr create mode 100644 tests/ui/consts/const-eval/ptr_fragments.rs create mode 100644 tests/ui/consts/const-eval/ptr_fragments_in_final.rs create mode 100644 tests/ui/consts/const-eval/ptr_fragments_in_final.stderr create mode 100644 tests/ui/consts/const-eval/read_partial_ptr.rs create mode 100644 tests/ui/consts/const-eval/read_partial_ptr.stderr diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index aa0bc42d44850..10cdc372ddd49 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -57,7 +57,7 @@ const_eval_const_context = {$kind -> } const_eval_const_heap_ptr_in_final = encountered `const_allocate` pointer in final value that was not made global - .note = use `const_make_global` to make allocated pointers immutable before returning + .note = use `const_make_global` to turn allocated pointers into immutable globals before returning const_eval_const_make_global_ptr_already_made_global = attempting to call `const_make_global` twice on the same allocation {$alloc} @@ -231,6 +231,9 @@ const_eval_mutable_borrow_escaping = const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind} +const_eval_partial_pointer_in_final = encountered partial pointer in final value of {const_eval_intern_kind} + .note = while pointers can be broken apart into individual bytes during const-evaluation, only complete pointers (with all their bytes in the right order) are supported in the final value + const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead const_eval_non_const_await = @@ -299,10 +302,8 @@ const_eval_panic = evaluation panicked: {$msg} const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str` -const_eval_partial_pointer_copy = - unable to copy parts of a pointer from memory at {$ptr} -const_eval_partial_pointer_overwrite = - unable to overwrite parts of a pointer in memory at {$ptr} +const_eval_partial_pointer_read = + unable to read parts of a pointer from memory at {$ptr} const_eval_pointer_arithmetic_overflow = overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 5835660e1c38f..4da2663319c34 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -117,6 +117,13 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( ecx.tcx.dcx().emit_err(errors::ConstHeapPtrInFinal { span: ecx.tcx.span }), ))); } + Err(InternError::PartialPointer) => { + throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error( + ecx.tcx + .dcx() + .emit_err(errors::PartialPtrInFinal { span: ecx.tcx.span, kind: intern_kind }), + ))); + } } interp_ok(R::make_result(ret, ecx)) diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index b6a64035261e5..322fd8e9363a4 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -51,6 +51,15 @@ pub(crate) struct ConstHeapPtrInFinal { pub span: Span, } +#[derive(Diagnostic)] +#[diag(const_eval_partial_pointer_in_final)] +#[note] +pub(crate) struct PartialPtrInFinal { + #[primary_span] + pub span: Span, + pub kind: InternKind, +} + #[derive(Diagnostic)] #[diag(const_eval_unstable_in_stable_exposed)] pub(crate) struct UnstableInStableExposed { @@ -832,8 +841,7 @@ impl ReportErrorExt for UnsupportedOpInfo { UnsupportedOpInfo::Unsupported(s) => s.clone().into(), UnsupportedOpInfo::ExternTypeField => const_eval_extern_type_field, UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local, - UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite, - UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy, + UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_read, UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int, UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static, UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static, @@ -844,7 +852,7 @@ impl ReportErrorExt for UnsupportedOpInfo { use UnsupportedOpInfo::*; use crate::fluent_generated::*; - if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self { + if let ReadPointerAsInt(_) | ReadPartialPointer(_) = self { diag.help(const_eval_ptr_as_bytes_1); diag.help(const_eval_ptr_as_bytes_2); } @@ -856,7 +864,7 @@ impl ReportErrorExt for UnsupportedOpInfo { | UnsupportedOpInfo::ExternTypeField | Unsupported(_) | ReadPointerAsInt(_) => {} - OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => { + ReadPartialPointer(ptr) => { diag.arg("ptr", ptr); } ThreadLocalStatic(did) | ExternStatic(did) => rustc_middle::ty::tls::with(|tcx| { diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index bb59b9f54186c..5d510a9835264 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -19,9 +19,12 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir as hir; use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult}; +use rustc_middle::mir::interpret::{ + AllocBytes, ConstAllocation, CtfeProvenance, InterpResult, Provenance, +}; use rustc_middle::query::TyCtxtAt; use rustc_middle::span_bug; +use rustc_middle::ty::TyCtxt; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::def_id::LocalDefId; use tracing::{instrument, trace}; @@ -52,39 +55,30 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { } } -/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory. -/// -/// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the -/// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be* -/// already mutable (as a sanity check). -/// -/// Returns an iterator over all relocations referred to by this allocation. -fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( - ecx: &mut InterpCx<'tcx, M>, - alloc_id: AllocId, +fn prepare_alloc<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( + tcx: TyCtxt<'tcx>, + kind: MemoryKind, + alloc: &mut Allocation, mutability: Mutability, - disambiguator: Option<&mut DisambiguatorState>, -) -> Result + 'tcx, InternError> { - trace!("intern_shallow {:?}", alloc_id); - // remove allocation - // FIXME(#120456) - is `swap_remove` correct? - let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else { - return Err(InternError::DanglingPointer); - }; - +) -> Result<(), InternError> { match kind { MemoryKind::Machine(const_eval::MemoryKind::Heap { was_made_global }) => { if !was_made_global { // Attempting to intern a `const_allocate`d pointer that was not made global via - // `const_make_global`. We want to error here, but we have to first put the - // allocation back into the `alloc_map` to keep things in a consistent state. - ecx.memory.alloc_map.insert(alloc_id, (kind, alloc)); + // `const_make_global`. + tcx.dcx().delayed_bug("non-global heap allocation in const value"); return Err(InternError::ConstAllocNotGlobal); } } MemoryKind::Stack | MemoryKind::CallerLocation => {} } + if !alloc.provenance_merge_bytes(&tcx) { + // Per-byte provenance is not supported by backends, so we cannot accept it here. + tcx.dcx().delayed_bug("partial pointer in const value"); + return Err(InternError::PartialPointer); + } + // Set allocation mutability as appropriate. This is used by LLVM to put things into // read-only memory, and also by Miri when evaluating other globals that // access this one. @@ -97,6 +91,36 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( assert_eq!(alloc.mutability, Mutability::Mut); } } + Ok(()) +} + +/// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory. +/// +/// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the +/// allocation is interned immutably; if it is `Mutability::Mut`, then the allocation *must be* +/// already mutable (as a sanity check). +/// +/// Returns an iterator over all relocations referred to by this allocation. +fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( + ecx: &mut InterpCx<'tcx, M>, + alloc_id: AllocId, + mutability: Mutability, + disambiguator: Option<&mut DisambiguatorState>, +) -> Result + 'tcx, InternError> { + trace!("intern_shallow {:?}", alloc_id); + // remove allocation + // FIXME(#120456) - is `swap_remove` correct? + let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else { + return Err(InternError::DanglingPointer); + }; + + if let Err(err) = prepare_alloc(*ecx.tcx, kind, &mut alloc, mutability) { + // We want to error here, but we have to first put the + // allocation back into the `alloc_map` to keep things in a consistent state. + ecx.memory.alloc_map.insert(alloc_id, (kind, alloc)); + return Err(err); + } + // link the alloc id to the actual allocation let alloc = ecx.tcx.mk_const_alloc(alloc); if let Some(static_id) = ecx.machine.static_def_id() { @@ -166,6 +190,7 @@ pub enum InternError { BadMutablePointer, DanglingPointer, ConstAllocNotGlobal, + PartialPointer, } /// Intern `ret` and everything it references. @@ -221,13 +246,11 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( let mut todo: Vec<_> = if is_static { // Do not steal the root allocation, we need it later to create the return value of `eval_static_initializer`. // But still change its mutability to match the requested one. - let alloc = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap(); - alloc.1.mutability = base_mutability; - alloc.1.provenance().ptrs().iter().map(|&(_, prov)| prov).collect() + let (kind, alloc) = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap(); + prepare_alloc(*ecx.tcx, *kind, alloc, base_mutability)?; + alloc.provenance().ptrs().iter().map(|&(_, prov)| prov).collect() } else { - intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguator)) - .unwrap() - .collect() + intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguator))?.collect() }; // We need to distinguish "has just been interned" from "was already in `tcx`", // so we track this in a separate set. @@ -235,7 +258,6 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( // Whether we encountered a bad mutable pointer. // We want to first report "dangling" and then "mutable", so we need to delay reporting these // errors. - let mut result = Ok(()); let mut found_bad_mutable_ptr = false; // Keep interning as long as there are things to intern. @@ -310,20 +332,15 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( // okay with losing some potential for immutability here. This can anyway only affect // `static mut`. just_interned.insert(alloc_id); - match intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguator)) { - Ok(nested) => todo.extend(nested), - Err(err) => { - ecx.tcx.dcx().delayed_bug("error during const interning"); - result = Err(err); - } - } + let next = intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguator))?; + todo.extend(next); } - if found_bad_mutable_ptr && result.is_ok() { + if found_bad_mutable_ptr { // We found a mutable pointer inside a const where inner allocations should be immutable, // and there was no other error. This should usually never happen! However, this can happen // in unleash-miri mode, so report it as a normal error then. if ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { - result = Err(InternError::BadMutablePointer); + return Err(InternError::BadMutablePointer); } else { span_bug!( ecx.tcx.span, @@ -331,7 +348,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( ); } } - result + Ok(()) } /// Intern `ret`. This function assumes that `ret` references no other allocation. diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 47bebf5371a9a..b5703e789ff46 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1310,29 +1310,20 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> } /// Mark the given sub-range (relative to this allocation reference) as uninitialized. - pub fn write_uninit(&mut self, range: AllocRange) -> InterpResult<'tcx> { + pub fn write_uninit(&mut self, range: AllocRange) { let range = self.range.subrange(range); - self.alloc - .write_uninit(&self.tcx, range) - .map_err(|e| e.to_interp_error(self.alloc_id)) - .into() + self.alloc.write_uninit(&self.tcx, range); } /// Mark the entire referenced range as uninitialized - pub fn write_uninit_full(&mut self) -> InterpResult<'tcx> { - self.alloc - .write_uninit(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id)) - .into() + pub fn write_uninit_full(&mut self) { + self.alloc.write_uninit(&self.tcx, self.range); } /// Remove all provenance in the reference range. - pub fn clear_provenance(&mut self) -> InterpResult<'tcx> { - self.alloc - .clear_provenance(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id)) - .into() + pub fn clear_provenance(&mut self) { + self.alloc.clear_provenance(&self.tcx, self.range); } } @@ -1423,11 +1414,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Side-step AllocRef and directly access the underlying bytes more efficiently. // (We are staying inside the bounds here and all bytes do get overwritten so all is good.) - let alloc_id = alloc_ref.alloc_id; - let bytes = alloc_ref - .alloc - .get_bytes_unchecked_for_overwrite(&alloc_ref.tcx, alloc_ref.range) - .map_err(move |e| e.to_interp_error(alloc_id))?; + let bytes = + alloc_ref.alloc.get_bytes_unchecked_for_overwrite(&alloc_ref.tcx, alloc_ref.range); // `zip` would stop when the first iterator ends; we want to definitely // cover all of `bytes`. for dest in bytes { @@ -1509,10 +1497,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `get_bytes_mut` will clear the provenance, which is correct, // since we don't want to keep any provenance at the target. // This will also error if copying partial provenance is not supported. - let provenance = src_alloc - .provenance() - .prepare_copy(src_range, dest_offset, num_copies, self) - .map_err(|e| e.to_interp_error(src_alloc_id))?; + let provenance = + src_alloc.provenance().prepare_copy(src_range, dest_offset, num_copies, self); // Prepare a copy of the initialization mask. let init = src_alloc.init_mask().prepare_copy(src_range); @@ -1530,10 +1516,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { dest_range, )?; // Yes we do overwrite all bytes in `dest_bytes`. - let dest_bytes = dest_alloc - .get_bytes_unchecked_for_overwrite_ptr(&tcx, dest_range) - .map_err(|e| e.to_interp_error(dest_alloc_id))? - .as_mut_ptr(); + let dest_bytes = + dest_alloc.get_bytes_unchecked_for_overwrite_ptr(&tcx, dest_range).as_mut_ptr(); if init.no_bytes_init() { // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range @@ -1542,9 +1526,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // This also avoids writing to the target bytes so that the backing allocation is never // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary // operating system this can avoid physically allocating the page. - dest_alloc - .write_uninit(&tcx, dest_range) - .map_err(|e| e.to_interp_error(dest_alloc_id))?; + dest_alloc.write_uninit(&tcx, dest_range); // `write_uninit` also resets the provenance, so we are done. return interp_ok(()); } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index e2284729efdcf..afd96a7c0c9e8 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -700,7 +700,7 @@ where match value { Immediate::Scalar(scalar) => { - alloc.write_scalar(alloc_range(Size::ZERO, scalar.size()), scalar) + alloc.write_scalar(alloc_range(Size::ZERO, scalar.size()), scalar)?; } Immediate::ScalarPair(a_val, b_val) => { let BackendRepr::ScalarPair(a, b) = layout.backend_repr else { @@ -720,10 +720,10 @@ where alloc.write_scalar(alloc_range(Size::ZERO, a_val.size()), a_val)?; alloc.write_scalar(alloc_range(b_offset, b_val.size()), b_val)?; // We don't have to reset padding here, `write_immediate` will anyway do a validation run. - interp_ok(()) } Immediate::Uninit => alloc.write_uninit_full(), } + interp_ok(()) } pub fn write_uninit( @@ -743,7 +743,7 @@ where // Zero-sized access return interp_ok(()); }; - alloc.write_uninit_full()?; + alloc.write_uninit_full(); } } interp_ok(()) @@ -767,7 +767,7 @@ where // Zero-sized access return interp_ok(()); }; - alloc.clear_provenance()?; + alloc.clear_provenance(); } } interp_ok(()) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 693b378296004..f8d9ebcafa76f 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -949,7 +949,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { let padding_size = offset - padding_cleared_until; let range = alloc_range(padding_start, padding_size); trace!("reset_padding on {}: resetting padding range {range:?}", mplace.layout.ty); - alloc.write_uninit(range)?; + alloc.write_uninit(range); } padding_cleared_until = offset + size; } @@ -1239,7 +1239,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, if self.reset_provenance_and_padding { // We can't share this with above as above, we might be looking at read-only memory. let mut alloc = self.ecx.get_ptr_alloc_mut(mplace.ptr(), size)?.expect("we already excluded size 0"); - alloc.clear_provenance()?; + alloc.clear_provenance(); // Also, mark this as containing data, not padding. self.add_data_range(mplace.ptr(), size); } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 27ead51453195..2ea92a39d4828 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -306,8 +306,6 @@ pub enum AllocError { ScalarSizeMismatch(ScalarSizeMismatch), /// Encountered a pointer where we needed raw bytes. ReadPointerAsInt(Option), - /// Partially overwriting a pointer. - OverwritePartialPointer(Size), /// Partially copying a pointer. ReadPartialPointer(Size), /// Using uninitialized data where it is not allowed. @@ -331,9 +329,6 @@ impl AllocError { ReadPointerAsInt(info) => InterpErrorKind::Unsupported( UnsupportedOpInfo::ReadPointerAsInt(info.map(|b| (alloc_id, b))), ), - OverwritePartialPointer(offset) => InterpErrorKind::Unsupported( - UnsupportedOpInfo::OverwritePartialPointer(Pointer::new(alloc_id, offset)), - ), ReadPartialPointer(offset) => InterpErrorKind::Unsupported( UnsupportedOpInfo::ReadPartialPointer(Pointer::new(alloc_id, offset)), ), @@ -633,11 +628,11 @@ impl Allocation &mut self, cx: &impl HasDataLayout, range: AllocRange, - ) -> AllocResult<&mut [u8]> { + ) -> &mut [u8] { self.mark_init(range, true); - self.provenance.clear(range, cx)?; + self.provenance.clear(range, cx); - Ok(&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]) + &mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()] } /// A raw pointer variant of `get_bytes_unchecked_for_overwrite` that avoids invalidating existing immutable aliases @@ -646,15 +641,15 @@ impl Allocation &mut self, cx: &impl HasDataLayout, range: AllocRange, - ) -> AllocResult<*mut [u8]> { + ) -> *mut [u8] { self.mark_init(range, true); - self.provenance.clear(range, cx)?; + self.provenance.clear(range, cx); assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check // Crucially, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`. let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize()); let len = range.end().bytes_usize() - range.start.bytes_usize(); - Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len)) + ptr::slice_from_raw_parts_mut(begin_ptr, len) } /// This gives direct mutable access to the entire buffer, just exposing their internal state @@ -723,26 +718,45 @@ impl Allocation let ptr = Pointer::new(prov, Size::from_bytes(bits)); return Ok(Scalar::from_pointer(ptr, cx)); } - - // If we can work on pointers byte-wise, join the byte-wise provenances. - if Prov::OFFSET_IS_ADDR { - let mut prov = self.provenance.get(range.start, cx); + // The other easy case is total absence of provenance. + if self.provenance.range_empty(range, cx) { + return Ok(Scalar::from_uint(bits, range.size)); + } + // If we get here, we have to check per-byte provenance, and join them together. + let prov = 'prov: { + // Initialize with first fragment. Must have index 0. + let Some((mut joint_prov, 0)) = self.provenance.get_byte(range.start, cx) else { + break 'prov None; + }; + // Update with the remaining fragments. for offset in Size::from_bytes(1)..range.size { - let this_prov = self.provenance.get(range.start + offset, cx); - prov = Prov::join(prov, this_prov); + // Ensure there is provenance here and it has the right index. + let Some((frag_prov, frag_idx)) = + self.provenance.get_byte(range.start + offset, cx) + else { + break 'prov None; + }; + // Wildcard provenance is allowed to come with any index (this is needed + // for Miri's native-lib mode to work). + if u64::from(frag_idx) != offset.bytes() && Some(frag_prov) != Prov::WILDCARD { + break 'prov None; + } + // Merge this byte's provenance with the previous ones. + joint_prov = match Prov::join(joint_prov, frag_prov) { + Some(prov) => prov, + None => break 'prov None, + }; } - // Now use this provenance. - let ptr = Pointer::new(prov, Size::from_bytes(bits)); - return Ok(Scalar::from_maybe_pointer(ptr, cx)); - } else { - // Without OFFSET_IS_ADDR, the only remaining case we can handle is total absence of - // provenance. - if self.provenance.range_empty(range, cx) { - return Ok(Scalar::from_uint(bits, range.size)); - } - // Else we have mixed provenance, that doesn't work. + break 'prov Some(joint_prov); + }; + if prov.is_none() && !Prov::OFFSET_IS_ADDR { + // There are some bytes with provenance here but overall the provenance does not add up. + // We need `OFFSET_IS_ADDR` to fall back to no-provenance here; without that option, we must error. return Err(AllocError::ReadPartialPointer(range.start)); } + // We can use this provenance. + let ptr = Pointer::new(prov, Size::from_bytes(bits)); + return Ok(Scalar::from_maybe_pointer(ptr, cx)); } else { // We are *not* reading a pointer. // If we can just ignore provenance or there is none, that's easy. @@ -782,7 +796,7 @@ impl Allocation let endian = cx.data_layout().endian; // Yes we do overwrite all the bytes in `dst`. - let dst = self.get_bytes_unchecked_for_overwrite(cx, range)?; + let dst = self.get_bytes_unchecked_for_overwrite(cx, range); write_target_uint(endian, dst, bytes).unwrap(); // See if we have to also store some provenance. @@ -795,10 +809,9 @@ impl Allocation } /// Write "uninit" to the given memory range. - pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { + pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) { self.mark_init(range, false); - self.provenance.clear(range, cx)?; - Ok(()) + self.provenance.clear(range, cx); } /// Mark all bytes in the given range as initialised and reset the provenance @@ -817,9 +830,12 @@ impl Allocation } /// Remove all provenance in the given memory range. - pub fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { - self.provenance.clear(range, cx)?; - return Ok(()); + pub fn clear_provenance(&mut self, cx: &impl HasDataLayout, range: AllocRange) { + self.provenance.clear(range, cx); + } + + pub fn provenance_merge_bytes(&mut self, cx: &impl HasDataLayout) -> bool { + self.provenance.merge_bytes(cx) } /// Applies a previously prepared provenance copy. diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 119d4be64e6a1..ea8596ea28658 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -10,7 +10,7 @@ use rustc_macros::HashStable; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use tracing::trace; -use super::{AllocError, AllocRange, AllocResult, CtfeProvenance, Provenance, alloc_range}; +use super::{AllocRange, CtfeProvenance, Provenance, alloc_range}; /// Stores the provenance information of pointers stored in memory. #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -19,25 +19,25 @@ pub struct ProvenanceMap { /// `Provenance` in this map applies from the given offset for an entire pointer-size worth of /// bytes. Two entries in this map are always at least a pointer size apart. ptrs: SortedMap, - /// Provenance in this map only applies to the given single byte. - /// This map is disjoint from the previous. It will always be empty when - /// `Prov::OFFSET_IS_ADDR` is false. - bytes: Option>>, + /// This stores byte-sized provenance fragments. + /// The `u8` indicates the position of this byte inside its original pointer. + /// If the bytes are re-assembled in their original order, the pointer can be used again. + /// Wildcard provenance is allowed to have index 0 everywhere. + bytes: Option>>, } // These impls are generic over `Prov` since `CtfeProvenance` is only decodable/encodable // for some particular `D`/`S`. impl> Decodable for ProvenanceMap { fn decode(d: &mut D) -> Self { - assert!(!Prov::OFFSET_IS_ADDR); // only `CtfeProvenance` is ever serialized + // `bytes` is not in the serialized format Self { ptrs: Decodable::decode(d), bytes: None } } } impl> Encodable for ProvenanceMap { fn encode(&self, s: &mut S) { let Self { ptrs, bytes } = self; - assert!(!Prov::OFFSET_IS_ADDR); // only `CtfeProvenance` is ever serialized - debug_assert!(bytes.is_none()); // without `OFFSET_IS_ADDR`, this is always empty + assert!(bytes.is_none()); // interning refuses allocations with pointer fragments ptrs.encode(s) } } @@ -58,10 +58,10 @@ impl ProvenanceMap { /// Give access to the ptr-sized provenances (which can also be thought of as relocations, and /// indeed that is how codegen treats them). /// - /// Only exposed with `CtfeProvenance` provenance, since it panics if there is bytewise provenance. + /// Only use on interned allocations, as other allocations may have per-byte provenance! #[inline] pub fn ptrs(&self) -> &SortedMap { - debug_assert!(self.bytes.is_none()); // `CtfeProvenance::OFFSET_IS_ADDR` is false so this cannot fail + assert!(self.bytes.is_none(), "`ptrs()` called on non-interned allocation"); &self.ptrs } } @@ -88,12 +88,12 @@ impl ProvenanceMap { } /// `pm.range_ptrs_is_empty(r, cx)` == `pm.range_ptrs_get(r, cx).is_empty()`, but is faster. - pub(super) fn range_ptrs_is_empty(&self, range: AllocRange, cx: &impl HasDataLayout) -> bool { + fn range_ptrs_is_empty(&self, range: AllocRange, cx: &impl HasDataLayout) -> bool { self.ptrs.range_is_empty(Self::adjusted_range_ptrs(range, cx)) } /// Returns all byte-wise provenance in the given range. - fn range_bytes_get(&self, range: AllocRange) -> &[(Size, Prov)] { + fn range_bytes_get(&self, range: AllocRange) -> &[(Size, (Prov, u8))] { if let Some(bytes) = self.bytes.as_ref() { bytes.range(range.start..range.end()) } else { @@ -107,19 +107,47 @@ impl ProvenanceMap { } /// Get the provenance of a single byte. - pub fn get(&self, offset: Size, cx: &impl HasDataLayout) -> Option { + pub fn get_byte(&self, offset: Size, cx: &impl HasDataLayout) -> Option<(Prov, u8)> { let prov = self.range_ptrs_get(alloc_range(offset, Size::from_bytes(1)), cx); debug_assert!(prov.len() <= 1); if let Some(entry) = prov.first() { // If it overlaps with this byte, it is on this byte. debug_assert!(self.bytes.as_ref().is_none_or(|b| !b.contains_key(&offset))); - Some(entry.1) + Some((entry.1, (offset - entry.0).bytes() as u8)) } else { // Look up per-byte provenance. self.bytes.as_ref().and_then(|b| b.get(&offset).copied()) } } + /// Attempt to merge per-byte provenance back into ptr chunks, if the right fragments + /// sit next to each other. Return `false` is that is not possible due to partial pointers. + pub fn merge_bytes(&mut self, cx: &impl HasDataLayout) -> bool { + let Some(bytes) = self.bytes.as_deref_mut() else { + return true; + }; + let ptr_size = cx.data_layout().pointer_size(); + while let Some((offset, (prov, _))) = bytes.iter().next().copied() { + // Check if this fragment starts a pointer. + let range = offset..offset + ptr_size; + let frags = bytes.range(range.clone()); + if frags.len() != ptr_size.bytes_usize() { + return false; + } + for (idx, (_offset, (frag_prov, frag_idx))) in frags.iter().copied().enumerate() { + if frag_prov != prov || frag_idx != idx as u8 { + return false; + } + } + // Looks like a pointer! Move it over to the ptr provenance map. + bytes.remove_range(range); + self.ptrs.insert(offset, prov); + } + // We managed to convert everything into whole pointers. + self.bytes = None; + true + } + /// Check if there is ptr-sized provenance at the given index. /// Does not mean anything for bytewise provenance! But can be useful as an optimization. pub fn get_ptr(&self, offset: Size) -> Option { @@ -137,7 +165,7 @@ impl ProvenanceMap { /// Yields all the provenances stored in this map. pub fn provenances(&self) -> impl Iterator { - let bytes = self.bytes.iter().flat_map(|b| b.values()); + let bytes = self.bytes.iter().flat_map(|b| b.values().map(|(p, _i)| p)); self.ptrs.values().chain(bytes).copied() } @@ -148,16 +176,12 @@ impl ProvenanceMap { /// Removes all provenance inside the given range. /// If there is provenance overlapping with the edges, might result in an error. - pub fn clear(&mut self, range: AllocRange, cx: &impl HasDataLayout) -> AllocResult { + pub fn clear(&mut self, range: AllocRange, cx: &impl HasDataLayout) { let start = range.start; let end = range.end(); // Clear the bytewise part -- this is easy. - if Prov::OFFSET_IS_ADDR { - if let Some(bytes) = self.bytes.as_mut() { - bytes.remove_range(start..end); - } - } else { - debug_assert!(self.bytes.is_none()); + if let Some(bytes) = self.bytes.as_mut() { + bytes.remove_range(start..end); } let pointer_size = cx.data_layout().pointer_size(); @@ -168,7 +192,7 @@ impl ProvenanceMap { // Find all provenance overlapping the given range. if self.range_ptrs_is_empty(range, cx) { // No provenance in this range, we are done. This is the common case. - return Ok(()); + return; } // This redoes some of the work of `range_get_ptrs_is_empty`, but this path is much @@ -179,28 +203,20 @@ impl ProvenanceMap { // We need to handle clearing the provenance from parts of a pointer. if first < start { - if !Prov::OFFSET_IS_ADDR { - // We can't split up the provenance into less than a pointer. - return Err(AllocError::OverwritePartialPointer(first)); - } // Insert the remaining part in the bytewise provenance. let prov = self.ptrs[&first]; let bytes = self.bytes.get_or_insert_with(Box::default); for offset in first..start { - bytes.insert(offset, prov); + bytes.insert(offset, (prov, (offset - first).bytes() as u8)); } } if last > end { let begin_of_last = last - pointer_size; - if !Prov::OFFSET_IS_ADDR { - // We can't split up the provenance into less than a pointer. - return Err(AllocError::OverwritePartialPointer(begin_of_last)); - } // Insert the remaining part in the bytewise provenance. let prov = self.ptrs[&begin_of_last]; let bytes = self.bytes.get_or_insert_with(Box::default); for offset in end..last { - bytes.insert(offset, prov); + bytes.insert(offset, (prov, (offset - begin_of_last).bytes() as u8)); } } @@ -208,8 +224,6 @@ impl ProvenanceMap { // Since provenance do not overlap, we know that removing until `last` (exclusive) is fine, // i.e., this will not remove any other provenance just after the ones we care about. self.ptrs.remove_range(first..last); - - Ok(()) } /// Overwrites all provenance in the given range with wildcard provenance. @@ -218,10 +232,6 @@ impl ProvenanceMap { /// /// Provided for usage in Miri and panics otherwise. pub fn write_wildcards(&mut self, cx: &impl HasDataLayout, range: AllocRange) { - assert!( - Prov::OFFSET_IS_ADDR, - "writing wildcard provenance is not supported when `OFFSET_IS_ADDR` is false" - ); let wildcard = Prov::WILDCARD.unwrap(); let bytes = self.bytes.get_or_insert_with(Box::default); @@ -229,21 +239,22 @@ impl ProvenanceMap { // Remove pointer provenances that overlap with the range, then readd the edge ones bytewise. let ptr_range = Self::adjusted_range_ptrs(range, cx); let ptrs = self.ptrs.range(ptr_range.clone()); - if let Some((offset, prov)) = ptrs.first() { - for byte_ofs in *offset..range.start { - bytes.insert(byte_ofs, *prov); + if let Some((offset, prov)) = ptrs.first().copied() { + for byte_ofs in offset..range.start { + bytes.insert(byte_ofs, (prov, (byte_ofs - offset).bytes() as u8)); } } - if let Some((offset, prov)) = ptrs.last() { - for byte_ofs in range.end()..*offset + cx.data_layout().pointer_size() { - bytes.insert(byte_ofs, *prov); + if let Some((offset, prov)) = ptrs.last().copied() { + for byte_ofs in range.end()..offset + cx.data_layout().pointer_size() { + bytes.insert(byte_ofs, (prov, (byte_ofs - offset).bytes() as u8)); } } self.ptrs.remove_range(ptr_range); // Overwrite bytewise provenance. for offset in range.start..range.end() { - bytes.insert(offset, wildcard); + // The fragment index does not matter for wildcard provenance. + bytes.insert(offset, (wildcard, 0)); } } } @@ -253,7 +264,7 @@ impl ProvenanceMap { /// Offsets are already adjusted to the destination allocation. pub struct ProvenanceCopy { dest_ptrs: Option>, - dest_bytes: Option>, + dest_bytes: Option>, } impl ProvenanceMap { @@ -263,7 +274,7 @@ impl ProvenanceMap { dest: Size, count: u64, cx: &impl HasDataLayout, - ) -> AllocResult> { + ) -> ProvenanceCopy { let shift_offset = move |idx, offset| { // compute offset for current repetition let dest_offset = dest + src.size * idx; // `Size` operations @@ -301,24 +312,16 @@ impl ProvenanceMap { let mut dest_bytes_box = None; let begin_overlap = self.range_ptrs_get(alloc_range(src.start, Size::ZERO), cx).first(); let end_overlap = self.range_ptrs_get(alloc_range(src.end(), Size::ZERO), cx).first(); - if !Prov::OFFSET_IS_ADDR { - // There can't be any bytewise provenance, and we cannot split up the begin/end overlap. - if let Some(entry) = begin_overlap { - return Err(AllocError::ReadPartialPointer(entry.0)); - } - if let Some(entry) = end_overlap { - return Err(AllocError::ReadPartialPointer(entry.0)); - } - debug_assert!(self.bytes.is_none()); - } else { - let mut bytes = Vec::new(); + // We only need to go here if there is some overlap or some bytewise provenance. + if begin_overlap.is_some() || end_overlap.is_some() || self.bytes.is_some() { + let mut bytes: Vec<(Size, (Prov, u8))> = Vec::new(); // First, if there is a part of a pointer at the start, add that. if let Some(entry) = begin_overlap { trace!("start overlapping entry: {entry:?}"); // For really small copies, make sure we don't run off the end of the `src` range. let entry_end = cmp::min(entry.0 + ptr_size, src.end()); for offset in src.start..entry_end { - bytes.push((offset, entry.1)); + bytes.push((offset, (entry.1, (offset - entry.0).bytes() as u8))); } } else { trace!("no start overlapping entry"); @@ -334,8 +337,9 @@ impl ProvenanceMap { let entry_start = cmp::max(entry.0, src.start); for offset in entry_start..src.end() { if bytes.last().is_none_or(|bytes_entry| bytes_entry.0 < offset) { - // The last entry, if it exists, has a lower offset than us. - bytes.push((offset, entry.1)); + // The last entry, if it exists, has a lower offset than us, so we + // can add it at the end and remain sorted. + bytes.push((offset, (entry.1, (offset - entry.0).bytes() as u8))); } else { // There already is an entry for this offset in there! This can happen when the // start and end range checks actually end up hitting the same pointer, so we @@ -358,7 +362,7 @@ impl ProvenanceMap { dest_bytes_box = Some(dest_bytes.into_boxed_slice()); } - Ok(ProvenanceCopy { dest_ptrs: dest_ptrs_box, dest_bytes: dest_bytes_box }) + ProvenanceCopy { dest_ptrs: dest_ptrs_box, dest_bytes: dest_bytes_box } } /// Applies a provenance copy. @@ -368,14 +372,10 @@ impl ProvenanceMap { if let Some(dest_ptrs) = copy.dest_ptrs { self.ptrs.insert_presorted(dest_ptrs.into()); } - if Prov::OFFSET_IS_ADDR { - if let Some(dest_bytes) = copy.dest_bytes - && !dest_bytes.is_empty() - { - self.bytes.get_or_insert_with(Box::default).insert_presorted(dest_bytes.into()); - } - } else { - debug_assert!(copy.dest_bytes.is_none()); + if let Some(dest_bytes) = copy.dest_bytes + && !dest_bytes.is_empty() + { + self.bytes.get_or_insert_with(Box::default).insert_presorted(dest_bytes.into()); } } } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 2b0cfb865645f..d8168697b4ae0 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -577,9 +577,6 @@ pub enum UnsupportedOpInfo { // // The variants below are only reachable from CTFE/const prop, miri will never emit them. // - /// Overwriting parts of a pointer; without knowing absolute addresses, the resulting state - /// cannot be represented by the CTFE interpreter. - OverwritePartialPointer(Pointer), /// Attempting to read or copy parts of a pointer to somewhere else; without knowing absolute /// addresses, the resulting state cannot be represented by the CTFE interpreter. ReadPartialPointer(Pointer), diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index e25ff7651f657..c581b2ebf092d 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -56,7 +56,7 @@ impl PointerArithmetic for T {} /// mostly opaque; the `Machine` trait extends it with some more operations that also have access to /// some global state. /// The `Debug` rendering is used to display bare provenance, and for the default impl of `fmt`. -pub trait Provenance: Copy + fmt::Debug + 'static { +pub trait Provenance: Copy + PartialEq + fmt::Debug + 'static { /// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address. /// - If `false`, the offset *must* be relative. This means the bytes representing a pointer are /// different from what the Abstract Machine prescribes, so the interpreter must prevent any @@ -79,7 +79,7 @@ pub trait Provenance: Copy + fmt::Debug + 'static { fn get_alloc_id(self) -> Option; /// Defines the 'join' of provenance: what happens when doing a pointer load and different bytes have different provenance. - fn join(left: Option, right: Option) -> Option; + fn join(left: Self, right: Self) -> Option; } /// The type of provenance in the compile-time interpreter. @@ -192,8 +192,8 @@ impl Provenance for CtfeProvenance { Some(self.alloc_id()) } - fn join(_left: Option, _right: Option) -> Option { - panic!("merging provenance is not supported when `OFFSET_IS_ADDR` is false") + fn join(left: Self, right: Self) -> Option { + if left == right { Some(left) } else { None } } } @@ -224,8 +224,8 @@ impl Provenance for AllocId { Some(self) } - fn join(_left: Option, _right: Option) -> Option { - panic!("merging provenance is not supported when `OFFSET_IS_ADDR` is false") + fn join(_left: Self, _right: Self) -> Option { + unreachable!() } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 809cdb329f79e..c0dd9a58f85a1 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1826,7 +1826,7 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( ascii.push('╼'); i += ptr_size; } - } else if let Some(prov) = alloc.provenance().get(i, &tcx) { + } else if let Some((prov, idx)) = alloc.provenance().get_byte(i, &tcx) { // Memory with provenance must be defined assert!( alloc.init_mask().is_range_initialized(alloc_range(i, Size::from_bytes(1))).is_ok() @@ -1836,7 +1836,7 @@ pub fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( // Format is similar to "oversized" above. let j = i.bytes_usize(); let c = alloc.inspect_with_uninit_and_ptr_outside_interpreter(j..j + 1)[0]; - write!(w, "╾{c:02x}{prov:#?} (1 ptr byte)╼")?; + write!(w, "╾{c:02x}{prov:#?} (ptr fragment {idx})╼")?; i += Size::from_bytes(1); } else if alloc .init_mask() diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index dbe3999b4a433..7339ccd40488d 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1345,40 +1345,6 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { /// assert_eq!(x, [7, 8, 3, 4]); /// assert_eq!(y, [1, 2, 9]); /// ``` -/// -/// # Const evaluation limitations -/// -/// If this function is invoked during const-evaluation, the current implementation has a small (and -/// rarely relevant) limitation: if `count` is at least 2 and the data pointed to by `x` or `y` -/// contains a pointer that crosses the boundary of two `T`-sized chunks of memory, the function may -/// fail to evaluate (similar to a panic during const-evaluation). This behavior may change in the -/// future. -/// -/// The limitation is illustrated by the following example: -/// -/// ``` -/// use std::mem::size_of; -/// use std::ptr; -/// -/// const { unsafe { -/// const PTR_SIZE: usize = size_of::<*const i32>(); -/// let mut data1 = [0u8; PTR_SIZE]; -/// let mut data2 = [0u8; PTR_SIZE]; -/// // Store a pointer in `data1`. -/// data1.as_mut_ptr().cast::<*const i32>().write_unaligned(&42); -/// // Swap the contents of `data1` and `data2` by swapping `PTR_SIZE` many `u8`-sized chunks. -/// // This call will fail, because the pointer in `data1` crosses the boundary -/// // between several of the 1-byte chunks that are being swapped here. -/// //ptr::swap_nonoverlapping(data1.as_mut_ptr(), data2.as_mut_ptr(), PTR_SIZE); -/// // Swap the contents of `data1` and `data2` by swapping a single chunk of size -/// // `[u8; PTR_SIZE]`. That works, as there is no pointer crossing the boundary between -/// // two chunks. -/// ptr::swap_nonoverlapping(&mut data1, &mut data2, 1); -/// // Read the pointer from `data2` and dereference it. -/// let ptr = data2.as_ptr().cast::<*const i32>().read_unaligned(); -/// assert!(*ptr == 42); -/// } } -/// ``` #[inline] #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] #[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "1.88.0")] @@ -1407,9 +1373,7 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { const_eval_select!( @capture[T] { x: *mut T, y: *mut T, count: usize }: if const { - // At compile-time we want to always copy this in chunks of `T`, to ensure that if there - // are pointers inside `T` we will copy them in one go rather than trying to copy a part - // of a pointer (which would not work). + // At compile-time we don't need all the special code below. // SAFETY: Same preconditions as this function unsafe { swap_nonoverlapping_const(x, y, count) } } else { diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs index 197a14423b59d..c13fb96a67f92 100644 --- a/library/coretests/tests/ptr.rs +++ b/library/coretests/tests/ptr.rs @@ -936,22 +936,18 @@ fn test_const_swap_ptr() { assert!(*s1.0.ptr == 666); assert!(*s2.0.ptr == 1); - // Swap them back, again as an array. + // Swap them back, byte-for-byte unsafe { ptr::swap_nonoverlapping( - ptr::from_mut(&mut s1).cast::(), - ptr::from_mut(&mut s2).cast::(), - 1, + ptr::from_mut(&mut s1).cast::(), + ptr::from_mut(&mut s2).cast::(), + size_of::(), ); } // Make sure they still work. assert!(*s1.0.ptr == 1); assert!(*s2.0.ptr == 666); - - // This is where we'd swap again using a `u8` type and a `count` of `size_of::()` if it - // were not for the limitation of `swap_nonoverlapping` around pointers crossing multiple - // elements. }; } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 7271d3f619c75..b8a187fed7c01 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -285,16 +285,16 @@ impl interpret::Provenance for Provenance { Ok(()) } - fn join(left: Option, right: Option) -> Option { + fn join(left: Self, right: Self) -> Option { match (left, right) { // If both are the *same* concrete tag, that is the result. ( - Some(Provenance::Concrete { alloc_id: left_alloc, tag: left_tag }), - Some(Provenance::Concrete { alloc_id: right_alloc, tag: right_tag }), - ) if left_alloc == right_alloc && left_tag == right_tag => left, + Provenance::Concrete { alloc_id: left_alloc, tag: left_tag }, + Provenance::Concrete { alloc_id: right_alloc, tag: right_tag }, + ) if left_alloc == right_alloc && left_tag == right_tag => Some(left), // If one side is a wildcard, the best possible outcome is that it is equal to the other // one, and we use that. - (Some(Provenance::Wildcard), o) | (o, Some(Provenance::Wildcard)) => o, + (Provenance::Wildcard, o) | (o, Provenance::Wildcard) => Some(o), // Otherwise, fall back to `None`. _ => None, } diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 2827ed997a7c6..36c18379cb863 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -246,7 +246,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let p_map = alloc.provenance(); for idx in overlap { // If a provenance was read by the foreign code, expose it. - if let Some(prov) = p_map.get(Size::from_bytes(idx), this) { + if let Some((prov, _idx)) = p_map.get_byte(Size::from_bytes(idx), this) { this.expose_provenance(prov)?; } } diff --git a/src/tools/miri/tests/fail/provenance/mix-ptrs1.rs b/src/tools/miri/tests/fail/provenance/mix-ptrs1.rs new file mode 100644 index 0000000000000..0b7266a4da6d7 --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/mix-ptrs1.rs @@ -0,0 +1,21 @@ +use std::{mem, ptr}; + +const PTR_SIZE: usize = mem::size_of::<&i32>(); + +fn main() { + unsafe { + let ptr = &0 as *const i32; + let arr = [ptr; 2]; + // We want to do a scalar read of a pointer at offset PTR_SIZE/2 into this array. But we + // cannot use a packed struct or `read_unaligned`, as those use the memcpy code path in + // Miri. So instead we shift the entire array by a bit and then the actual read we want to + // do is perfectly aligned. + let mut target_arr = [ptr::null::(); 3]; + let target = target_arr.as_mut_ptr().cast::(); + target.add(PTR_SIZE / 2).cast::<[*const i32; 2]>().write_unaligned(arr); + // Now target_arr[1] is a mix of the two `ptr` we had stored in `arr`. + // They all have the same provenance, but not in the right order, so we reject this. + let strange_ptr = target_arr[1]; + assert_eq!(*strange_ptr.with_addr(ptr.addr()), 0); //~ERROR: no provenance + } +} diff --git a/src/tools/miri/tests/fail/provenance/mix-ptrs1.stderr b/src/tools/miri/tests/fail/provenance/mix-ptrs1.stderr new file mode 100644 index 0000000000000..88d75135a763d --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/mix-ptrs1.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + --> tests/fail/provenance/mix-ptrs1.rs:LL:CC + | +LL | assert_eq!(*strange_ptr.with_addr(ptr.addr()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at RUSTLIB/core/src/macros/mod.rs:LL:CC + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/provenance/mix-ptrs2.rs b/src/tools/miri/tests/fail/provenance/mix-ptrs2.rs new file mode 100644 index 0000000000000..9ef40c194abd0 --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/mix-ptrs2.rs @@ -0,0 +1,37 @@ +use std::mem; + +const PTR_SIZE: usize = mem::size_of::<&i32>(); + +/// Overwrite one byte of a pointer, then restore it. +fn main() { + unsafe fn ptr_bytes<'x>(ptr: &'x mut *const i32) -> &'x mut [mem::MaybeUninit; PTR_SIZE] { + mem::transmute(ptr) + } + + // Returns a value with the same provenance as `x` but 0 for the integer value. + // `x` must be initialized. + unsafe fn zero_with_provenance(x: mem::MaybeUninit) -> mem::MaybeUninit { + let ptr = [x; PTR_SIZE]; + let ptr: *const i32 = mem::transmute(ptr); + let mut ptr = ptr.with_addr(0); + ptr_bytes(&mut ptr)[0] + } + + unsafe { + let ptr = &42; + let mut ptr = ptr as *const i32; + // Get a bytewise view of the pointer. + let ptr_bytes = ptr_bytes(&mut ptr); + + // The highest bytes must be 0 for this to work. + let hi = if cfg!(target_endian = "little") { ptr_bytes.len() - 1 } else { 0 }; + assert_eq!(*ptr_bytes[hi].as_ptr().cast::(), 0); + // Overwrite provenance on the last byte. + ptr_bytes[hi] = mem::MaybeUninit::new(0); + // Restore it from the another byte. + ptr_bytes[hi] = zero_with_provenance(ptr_bytes[1]); + + // Now ptr is almost good, except the provenance fragment indices do not work out... + assert_eq!(*ptr, 42); //~ERROR: no provenance + } +} diff --git a/src/tools/miri/tests/fail/provenance/mix-ptrs2.stderr b/src/tools/miri/tests/fail/provenance/mix-ptrs2.stderr new file mode 100644 index 0000000000000..636378952ba5a --- /dev/null +++ b/src/tools/miri/tests/fail/provenance/mix-ptrs2.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + --> tests/fail/provenance/mix-ptrs2.rs:LL:CC + | +LL | assert_eq!(*ptr, 42); + | ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at RUSTLIB/core/src/macros/mod.rs:LL:CC + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs index 1cf70d9d9a340..78a5098d21a13 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs @@ -9,11 +9,10 @@ use std::alloc::{Layout, alloc, dealloc}; use std::mem::{self, MaybeUninit}; use std::slice::from_raw_parts; -fn byte_with_provenance(val: u8, prov: *const T) -> MaybeUninit { - let ptr = prov.with_addr(val as usize); +fn byte_with_provenance(val: u8, prov: *const T, frag_idx: usize) -> MaybeUninit { + let ptr = prov.with_addr(usize::from_ne_bytes([val; _])); let bytes: [MaybeUninit; mem::size_of::<*const ()>()] = unsafe { mem::transmute(ptr) }; - let lsb = if cfg!(target_endian = "little") { 0 } else { bytes.len() - 1 }; - bytes[lsb] + bytes[frag_idx] } fn main() { @@ -21,10 +20,10 @@ fn main() { unsafe { let ptr = alloc(layout); let ptr_raw = ptr.cast::>(); - *ptr_raw.add(0) = byte_with_provenance(0x42, &42u8); + *ptr_raw.add(0) = byte_with_provenance(0x42, &42u8, 0); *ptr.add(1) = 0x12; *ptr.add(2) = 0x13; - *ptr_raw.add(3) = byte_with_provenance(0x43, &0u8); + *ptr_raw.add(3) = byte_with_provenance(0x43, &0u8, 1); let slice1 = from_raw_parts(ptr, 8); let slice2 = from_raw_parts(ptr.add(8), 8); drop(slice1.cmp(slice2)); diff --git a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr index d3253317faeef..305d8d4fbede1 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr @@ -17,7 +17,7 @@ LL | drop(slice1.cmp(slice2)); Uninitialized memory occurred at ALLOC[0x4..0x8], in this allocation: ALLOC (Rust heap, size: 16, align: 8) { - ╾42[ALLOC] (1 ptr byte)╼ 12 13 ╾43[ALLOC] (1 ptr byte)╼ __ __ __ __ __ __ __ __ __ __ __ __ │ ━..━░░░░░░░░░░░░ + ╾42[ALLOC] (ptr fragment 0)╼ 12 13 ╾43[ALLOC] (ptr fragment 1)╼ __ __ __ __ __ __ __ __ __ __ __ __ │ ━..━░░░░░░░░░░░░ } ALLOC (global (static or const), size: 1, align: 1) { 2a │ * diff --git a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr index 74a599ede5c3c..1c0ad2f0dc916 100644 --- a/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr +++ b/src/tools/miri/tests/native-lib/fail/tracing/partial_init.stderr @@ -35,7 +35,7 @@ LL | partial_init(); Uninitialized memory occurred at ALLOC[0x2..0x3], in this allocation: ALLOC (stack variable, size: 3, align: 1) { - ╾00[wildcard] (1 ptr byte)╼ ╾00[wildcard] (1 ptr byte)╼ __ │ ━━░ + ╾00[wildcard] (ptr fragment 0)╼ ╾00[wildcard] (ptr fragment 0)╼ __ │ ━━░ } note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/pass/provenance.rs b/src/tools/miri/tests/pass/provenance.rs index 8c52b703190d2..46f5bd73d55bb 100644 --- a/src/tools/miri/tests/pass/provenance.rs +++ b/src/tools/miri/tests/pass/provenance.rs @@ -6,7 +6,6 @@ const PTR_SIZE: usize = mem::size_of::<&i32>(); fn main() { basic(); - partial_overwrite_then_restore(); bytewise_ptr_methods(); bytewise_custom_memcpy(); bytewise_custom_memcpy_chunked(); @@ -29,40 +28,6 @@ fn basic() { assert_eq!(unsafe { *ptr_back }, 42); } -/// Overwrite one byte of a pointer, then restore it. -fn partial_overwrite_then_restore() { - unsafe fn ptr_bytes<'x>(ptr: &'x mut *const i32) -> &'x mut [mem::MaybeUninit; PTR_SIZE] { - mem::transmute(ptr) - } - - // Returns a value with the same provenance as `x` but 0 for the integer value. - // `x` must be initialized. - unsafe fn zero_with_provenance(x: mem::MaybeUninit) -> mem::MaybeUninit { - let ptr = [x; PTR_SIZE]; - let ptr: *const i32 = mem::transmute(ptr); - let mut ptr = ptr.with_addr(0); - ptr_bytes(&mut ptr)[0] - } - - unsafe { - let ptr = &42; - let mut ptr = ptr as *const i32; - // Get a bytewise view of the pointer. - let ptr_bytes = ptr_bytes(&mut ptr); - - // The highest bytes must be 0 for this to work. - let hi = if cfg!(target_endian = "little") { ptr_bytes.len() - 1 } else { 0 }; - assert_eq!(*ptr_bytes[hi].as_ptr().cast::(), 0); - // Overwrite provenance on the last byte. - ptr_bytes[hi] = mem::MaybeUninit::new(0); - // Restore it from the another byte. - ptr_bytes[hi] = zero_with_provenance(ptr_bytes[1]); - - // Now ptr should be good again. - assert_eq!(*ptr, 42); - } -} - fn bytewise_ptr_methods() { let mut ptr1 = &1; let mut ptr2 = &2; diff --git a/src/tools/miri/tests/pass/transmute_ptr.rs b/src/tools/miri/tests/pass/transmute_ptr.rs index 0944781c6defa..0a53b77829473 100644 --- a/src/tools/miri/tests/pass/transmute_ptr.rs +++ b/src/tools/miri/tests/pass/transmute_ptr.rs @@ -1,6 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -use std::{mem, ptr}; +use std::mem; fn t1() { // If we are careful, we can exploit data layout... @@ -27,27 +27,8 @@ fn ptr_integer_array() { let _x: [u8; PTR_SIZE] = unsafe { mem::transmute(&0) }; } -fn ptr_in_two_halves() { - unsafe { - let ptr = &0 as *const i32; - let arr = [ptr; 2]; - // We want to do a scalar read of a pointer at offset PTR_SIZE/2 into this array. But we - // cannot use a packed struct or `read_unaligned`, as those use the memcpy code path in - // Miri. So instead we shift the entire array by a bit and then the actual read we want to - // do is perfectly aligned. - let mut target_arr = [ptr::null::(); 3]; - let target = target_arr.as_mut_ptr().cast::(); - target.add(PTR_SIZE / 2).cast::<[*const i32; 2]>().write_unaligned(arr); - // Now target_arr[1] is a mix of the two `ptr` we had stored in `arr`. - let strange_ptr = target_arr[1]; - // Check that the provenance works out. - assert_eq!(*strange_ptr.with_addr(ptr.addr()), 0); - } -} - fn main() { t1(); t2(); ptr_integer_array(); - ptr_in_two_halves(); } diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr index cb2bb1e8cd852..e5b108df29826 100644 --- a/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr @@ -4,7 +4,7 @@ error: encountered `const_allocate` pointer in final value that was not made glo LL | const FOO: &i32 = foo(); | ^^^^^^^^^^^^^^^ | - = note: use `const_make_global` to make allocated pointers immutable before returning + = note: use `const_make_global` to turn allocated pointers into immutable globals before returning error: encountered `const_allocate` pointer in final value that was not made global --> $DIR/ptr_not_made_global.rs:12:1 @@ -12,7 +12,7 @@ error: encountered `const_allocate` pointer in final value that was not made glo LL | const FOO_RAW: *const i32 = foo(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: use `const_make_global` to make allocated pointers immutable before returning + = note: use `const_make_global` to turn allocated pointers into immutable globals before returning error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr index 2445ce633d6ff..2d1993f96d379 100644 --- a/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global_mut.stderr @@ -4,7 +4,7 @@ error: encountered `const_allocate` pointer in final value that was not made glo LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; | ^^^^^^^^^^^^^^^^^^^ | - = note: use `const_make_global` to make allocated pointers immutable before returning + = note: use `const_make_global` to turn allocated pointers into immutable globals before returning error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.rs b/tests/ui/consts/const-eval/partial_ptr_overwrite.rs deleted file mode 100644 index bd97bec0f71a9..0000000000000 --- a/tests/ui/consts/const-eval/partial_ptr_overwrite.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Test for the behavior described in . - -const PARTIAL_OVERWRITE: () = { - let mut p = &42; - unsafe { - let ptr: *mut _ = &mut p; - *(ptr as *mut u8) = 123; //~ ERROR unable to overwrite parts of a pointer - } - let x = *p; -}; - -fn main() {} diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr deleted file mode 100644 index 6ef1cfd35c8c5..0000000000000 --- a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0080]: unable to overwrite parts of a pointer in memory at ALLOC0 - --> $DIR/partial_ptr_overwrite.rs:7:9 - | -LL | *(ptr as *mut u8) = 123; - | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `PARTIAL_OVERWRITE` failed here - | - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ptr_fragments.rs b/tests/ui/consts/const-eval/ptr_fragments.rs new file mode 100644 index 0000000000000..04dcbe55590e9 --- /dev/null +++ b/tests/ui/consts/const-eval/ptr_fragments.rs @@ -0,0 +1,63 @@ +//! Test that various operations involving pointer fragments work as expected. +//@ run-pass + +use std::mem::{self, MaybeUninit, transmute}; +use std::ptr; + +type Byte = MaybeUninit; + +const unsafe fn memcpy(dst: *mut Byte, src: *const Byte, n: usize) { + let mut i = 0; + while i < n { + *dst.add(i) = *src.add(i); + i += 1; + } +} + +const _MEMCPY: () = unsafe { + let ptr = &42; + let mut ptr2 = ptr::null::(); + memcpy(&mut ptr2 as *mut _ as *mut _, &ptr as *const _ as *const _, mem::size_of::<&i32>()); + assert!(*ptr2 == 42); +}; +const _MEMCPY_OFFSET: () = unsafe { + // Same as above, but the pointer has a non-zero offset so not all the data bytes are the same. + let ptr = &(42, 18); + let ptr = &ptr.1; + let mut ptr2 = ptr::null::(); + memcpy(&mut ptr2 as *mut _ as *mut _, &ptr as *const _ as *const _, mem::size_of::<&i32>()); + assert!(*ptr2 == 18); +}; + +const MEMCPY_RET: MaybeUninit<*const i32> = unsafe { + let ptr = &42; + let mut ptr2 = MaybeUninit::new(ptr::null::()); + memcpy(&mut ptr2 as *mut _ as *mut _, &ptr as *const _ as *const _, mem::size_of::<&i32>()); + // Return in a MaybeUninit so it does not get treated as a scalar. + ptr2 +}; + +#[allow(dead_code)] +fn reassemble_ptr_fragments_in_static() { + static DATA: i32 = 1i32; + + #[cfg(target_pointer_width = "64")] + struct Thing { + x: MaybeUninit, + y: MaybeUninit, + } + #[cfg(target_pointer_width = "32")] + struct Thing { + x: MaybeUninit, + y: MaybeUninit, + } + + static X: Thing = unsafe { + let Thing { x, y } = transmute(&raw const DATA); + Thing { x, y } + }; +} + +fn main() { + assert_eq!(unsafe { MEMCPY_RET.assume_init().read() }, 42); +} diff --git a/tests/ui/consts/const-eval/ptr_fragments_in_final.rs b/tests/ui/consts/const-eval/ptr_fragments_in_final.rs new file mode 100644 index 0000000000000..e2f3f51b08638 --- /dev/null +++ b/tests/ui/consts/const-eval/ptr_fragments_in_final.rs @@ -0,0 +1,25 @@ +//! Test that we properly error when there is a pointer fragment in the final value. + +use std::{mem::{self, MaybeUninit}, ptr}; + +type Byte = MaybeUninit; + +const unsafe fn memcpy(dst: *mut Byte, src: *const Byte, n: usize) { + let mut i = 0; + while i < n { + dst.add(i).write(src.add(i).read()); + i += 1; + } +} + +const MEMCPY_RET: MaybeUninit<*const i32> = unsafe { //~ERROR: partial pointer in final value + let ptr = &42; + let mut ptr2 = MaybeUninit::new(ptr::null::()); + memcpy(&mut ptr2 as *mut _ as *mut _, &ptr as *const _ as *const _, mem::size_of::<&i32>() / 2); + // Return in a MaybeUninit so it does not get treated as a scalar. + ptr2 +}; + +fn main() { + assert_eq!(unsafe { MEMCPY_RET.assume_init().read() }, 42); +} diff --git a/tests/ui/consts/const-eval/ptr_fragments_in_final.stderr b/tests/ui/consts/const-eval/ptr_fragments_in_final.stderr new file mode 100644 index 0000000000000..628bf2566e592 --- /dev/null +++ b/tests/ui/consts/const-eval/ptr_fragments_in_final.stderr @@ -0,0 +1,10 @@ +error: encountered partial pointer in final value of constant + --> $DIR/ptr_fragments_in_final.rs:15:1 + | +LL | const MEMCPY_RET: MaybeUninit<*const i32> = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: while pointers can be broken apart into individual bytes during const-evaluation, only complete pointers (with all their bytes in the right order) are supported in the final value + +error: aborting due to 1 previous error + diff --git a/tests/ui/consts/const-eval/read_partial_ptr.rs b/tests/ui/consts/const-eval/read_partial_ptr.rs new file mode 100644 index 0000000000000..bccef9c0bc6ca --- /dev/null +++ b/tests/ui/consts/const-eval/read_partial_ptr.rs @@ -0,0 +1,49 @@ +//! Ensure we error when trying to load from a pointer whose provenance has been messed with. + +const PARTIAL_OVERWRITE: () = { + let mut p = &42; + // Overwrite one byte with a no-provenance value. + unsafe { + let ptr: *mut _ = &mut p; + *(ptr as *mut u8) = 123; + } + let x = *p; //~ ERROR: unable to read parts of a pointer +}; + +const PTR_BYTES_SWAP: () = { + let mut p = &42; + // Swap the first two bytes. + unsafe { + let ptr = &mut p as *mut _ as *mut std::mem::MaybeUninit; + let byte0 = ptr.read(); + let byte1 = ptr.add(1).read(); + ptr.write(byte1); + ptr.add(1).write(byte0); + } + let x = *p; //~ ERROR: unable to read parts of a pointer +}; + +const PTR_BYTES_REPEAT: () = { + let mut p = &42; + // Duplicate the first byte over the second. + unsafe { + let ptr = &mut p as *mut _ as *mut std::mem::MaybeUninit; + let byte0 = ptr.read(); + ptr.add(1).write(byte0); + } + let x = *p; //~ ERROR: unable to read parts of a pointer +}; + +const PTR_BYTES_MIX: () = { + let mut p = &42; + let q = &43; + // Overwrite the first byte of p with the first byte of q. + unsafe { + let ptr = &mut p as *mut _ as *mut std::mem::MaybeUninit; + let qtr = &q as *const _ as *const std::mem::MaybeUninit; + ptr.write(qtr.read()); + } + let x = *p; //~ ERROR: unable to read parts of a pointer +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/read_partial_ptr.stderr b/tests/ui/consts/const-eval/read_partial_ptr.stderr new file mode 100644 index 0000000000000..196606c77a37f --- /dev/null +++ b/tests/ui/consts/const-eval/read_partial_ptr.stderr @@ -0,0 +1,39 @@ +error[E0080]: unable to read parts of a pointer from memory at ALLOC0 + --> $DIR/read_partial_ptr.rs:10:13 + | +LL | let x = *p; + | ^^ evaluation of `PARTIAL_OVERWRITE` failed here + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: unable to read parts of a pointer from memory at ALLOC1 + --> $DIR/read_partial_ptr.rs:23:13 + | +LL | let x = *p; + | ^^ evaluation of `PTR_BYTES_SWAP` failed here + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: unable to read parts of a pointer from memory at ALLOC2 + --> $DIR/read_partial_ptr.rs:34:13 + | +LL | let x = *p; + | ^^ evaluation of `PTR_BYTES_REPEAT` failed here + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: unable to read parts of a pointer from memory at ALLOC3 + --> $DIR/read_partial_ptr.rs:46:13 + | +LL | let x = *p; + | ^^ evaluation of `PTR_BYTES_MIX` failed here + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/missing_span_in_backtrace.rs b/tests/ui/consts/missing_span_in_backtrace.rs index 4f3f9aa6adacc..09a11c75fd7bd 100644 --- a/tests/ui/consts/missing_span_in_backtrace.rs +++ b/tests/ui/consts/missing_span_in_backtrace.rs @@ -1,3 +1,4 @@ +//! Check what happens when the error occurs inside a std function that we can't print the span of. //@ ignore-backends: gcc //@ compile-flags: -Z ui-testing=no @@ -7,15 +8,15 @@ use std::{ }; const X: () = { - let mut ptr1 = &1; - let mut ptr2 = &2; + let mut x1 = 1; + let mut x2 = 2; // Swap them, bytewise. unsafe { - ptr::swap_nonoverlapping( //~ ERROR unable to copy parts of a pointer - &mut ptr1 as *mut _ as *mut MaybeUninit, - &mut ptr2 as *mut _ as *mut MaybeUninit, - mem::size_of::<&i32>(), + ptr::swap_nonoverlapping( //~ ERROR beyond the end of the allocation + &mut x1 as *mut _ as *mut MaybeUninit, + &mut x2 as *mut _ as *mut MaybeUninit, + 10, ); } }; diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index 0ac1e281107d8..55dde63582861 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -1,15 +1,13 @@ -error[E0080]: unable to copy parts of a pointer from memory at ALLOC0 - --> $DIR/missing_span_in_backtrace.rs:15:9 +error[E0080]: memory access failed: attempting to access 1 byte, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes + --> $DIR/missing_span_in_backtrace.rs:16:9 | -15 | / ptr::swap_nonoverlapping( -16 | | &mut ptr1 as *mut _ as *mut MaybeUninit, -17 | | &mut ptr2 as *mut _ as *mut MaybeUninit, -18 | | mem::size_of::<&i32>(), -19 | | ); +16 | / ptr::swap_nonoverlapping( +17 | | &mut x1 as *mut _ as *mut MaybeUninit, +18 | | &mut x2 as *mut _ as *mut MaybeUninit, +19 | | 10, +20 | | ); | |_________^ evaluation of `X` failed inside this call | - = help: this code performed an operation that depends on the underlying bytes representing a pointer - = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported note: inside `swap_nonoverlapping::compiletime::>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL note: inside `std::ptr::swap_nonoverlapping_const::>` From 02ac116e53f525a929d251bf9dc4f2ea1cacd3c8 Mon Sep 17 00:00:00 2001 From: Eduard Stefes Date: Tue, 29 Jul 2025 11:27:07 +0200 Subject: [PATCH 012/252] Fix tests for big-endian The tests fail on s390x and presumably other big-endian systems, due to print of raw values and padding bytes. To fix the tests remove the raw output values in the error note with `normalize-stderr`. --- tests/ui/consts/const-eval/union-const-eval-field.rs | 1 + tests/ui/consts/const-eval/union-const-eval-field.stderr | 8 ++++---- tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs | 1 + tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr | 8 ++++---- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/ui/consts/const-eval/union-const-eval-field.rs b/tests/ui/consts/const-eval/union-const-eval-field.rs index 719e59b007c00..2c9061a7a50f8 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.rs +++ b/tests/ui/consts/const-eval/union-const-eval-field.rs @@ -1,5 +1,6 @@ //@ dont-require-annotations: NOTE //@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" +//@ normalize-stderr: "([[:xdigit:]]{2}\s){4}(__\s){4}\s+│\s+([?|\.]){4}\W{4}" -> "HEX_DUMP" type Field1 = i32; type Field2 = f32; diff --git a/tests/ui/consts/const-eval/union-const-eval-field.stderr b/tests/ui/consts/const-eval/union-const-eval-field.stderr index 1843ce273ac04..3b7e5508d56c4 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.stderr +++ b/tests/ui/consts/const-eval/union-const-eval-field.stderr @@ -1,21 +1,21 @@ error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory - --> $DIR/union-const-eval-field.rs:29:37 + --> $DIR/union-const-eval-field.rs:30:37 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^ evaluation of `read_field3::FIELD3` failed here | = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - 00 00 80 3f __ __ __ __ │ ...?░░░░ + HEX_DUMP } note: erroneous constant encountered - --> $DIR/union-const-eval-field.rs:31:5 + --> $DIR/union-const-eval-field.rs:32:5 | LL | FIELD3 | ^^^^^^ note: erroneous constant encountered - --> $DIR/union-const-eval-field.rs:31:5 + --> $DIR/union-const-eval-field.rs:32:5 | LL | FIELD3 | ^^^^^^ diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs index 15f4a9a778ed6..ed15f5bba9622 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs @@ -1,3 +1,4 @@ +//@ normalize-stderr: "[[:xdigit:]]{2} __ ([[:xdigit:]]{2}\s){2}" -> "HEX_DUMP" #![feature(core_intrinsics)] const RAW_EQ_PADDING: bool = unsafe { diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr index 5f4ef14d58697..329da35297e1c 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr @@ -1,15 +1,15 @@ error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory - --> $DIR/intrinsic-raw_eq-const-bad.rs:4:5 + --> $DIR/intrinsic-raw_eq-const-bad.rs:5:5 | LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_PADDING` failed here | = note: the raw bytes of the constant (size: 4, align: 2) { - 01 __ 02 00 │ .░.. + HEX_DUMP │ .░.. } error[E0080]: unable to turn pointer into integer - --> $DIR/intrinsic-raw_eq-const-bad.rs:9:5 + --> $DIR/intrinsic-raw_eq-const-bad.rs:10:5 | LL | std::intrinsics::raw_eq(&(&0), &(&1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_PTR` failed here @@ -18,7 +18,7 @@ LL | std::intrinsics::raw_eq(&(&0), &(&1)) = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: accessing memory with alignment 1, but alignment 4 is required - --> $DIR/intrinsic-raw_eq-const-bad.rs:16:5 + --> $DIR/intrinsic-raw_eq-const-bad.rs:17:5 | LL | std::intrinsics::raw_eq(aref, aref) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_NOT_ALIGNED` failed here From 24c770ba1c53c4c04acdba945cd9f59d687f4d5b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 1 Aug 2025 00:32:56 +0000 Subject: [PATCH 013/252] aarch64: Make `outline-atomics` a known target feature This is a feature used by LLVM that is enabled for our `aarch64-linux` targets, which we would like to configure on in `std`. Thus, mark `outline-atomics` a known feature. It is left unstable for now. --- compiler/rustc_target/src/target_features.rs | 4 ++++ tests/assembly-llvm/asm/aarch64-outline-atomics.rs | 4 ++++ tests/ui/check-cfg/target_feature.stderr | 1 + 3 files changed, 9 insertions(+) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b2af99228fe6d..7551d5a66fc92 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -248,6 +248,10 @@ static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("mte", Stable, &[]), // FEAT_AdvSimd & FEAT_FP ("neon", Stable, &[]), + // Backend option to turn atomic operations into an intrinsic call when `lse` is not known to be + // available, so the intrinsic can do runtime LSE feature detection rather than unconditionally + // using slower non-LSE operations. Unstable since it doesn't need to user-togglable. + ("outline-atomics", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_PAUTH (address authentication) ("paca", Stable, &[]), // FEAT_PAUTH (generic authentication) diff --git a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs index 22599c18dcf37..1177c1e68ed56 100644 --- a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs +++ b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs @@ -8,6 +8,10 @@ use std::sync::atomic::AtomicI32; use std::sync::atomic::Ordering::*; +// Verify config on outline-atomics works (it is always enabled on aarch64-linux). +#[cfg(not(target_feature = "outline-atomics"))] +compile_error!("outline-atomics is not enabled"); + pub fn compare_exchange(a: &AtomicI32) { // On AArch64 LLVM should outline atomic operations. // CHECK: __aarch64_cas4_relax diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index f422919983b75..e730492fd9b09 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -183,6 +183,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `nnp-assist` `nontrapping-fptoint` `nvic` +`outline-atomics` `paca` `pacg` `pan` From 4c4b8b23c6935e719ca01b614922024abb694656 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Mon, 4 Aug 2025 01:06:04 +0500 Subject: [PATCH 014/252] remove gate --- library/std/src/path.rs | 3 +-- library/std/tests/path.rs | 8 +------- src/tools/clippy/tests/missing-test-files.rs | 2 +- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 055e7f814800d..5dd52a23e97c7 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2678,7 +2678,6 @@ impl Path { /// # Examples /// /// ``` - /// # #![feature(path_file_prefix)] /// use std::path::Path; /// /// assert_eq!("foo", Path::new("foo.rs").file_prefix().unwrap()); @@ -2691,7 +2690,7 @@ impl Path { /// /// [`Path::file_stem`]: Path::file_stem /// - #[unstable(feature = "path_file_prefix", issue = "86319")] + #[stable(feature = "path_file_prefix", since = "CURRENT_RUSTC_VERSION")] #[must_use] pub fn file_prefix(&self) -> Option<&OsStr> { self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before)) diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs index 901d2770f203e..e1576a0d4231a 100644 --- a/library/std/tests/path.rs +++ b/library/std/tests/path.rs @@ -1,10 +1,4 @@ -#![feature( - clone_to_uninit, - path_add_extension, - path_file_prefix, - maybe_uninit_slice, - normalize_lexically -)] +#![feature(clone_to_uninit, path_add_extension, maybe_uninit_slice, normalize_lexically)] use std::clone::CloneToUninit; use std::ffi::OsStr; diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs index 565dcd73f582d..63f960c92fa32 100644 --- a/src/tools/clippy/tests/missing-test-files.rs +++ b/src/tools/clippy/tests/missing-test-files.rs @@ -1,6 +1,6 @@ #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::assertions_on_constants)] -#![feature(path_file_prefix)] +#![cfg_attr(bootstrap, feature(path_file_prefix))] use std::cmp::Ordering; use std::ffi::OsStr; From 2db126d651b6803c9b37fd021376ce6e5dd5a09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 1 Mar 2025 22:27:16 +0000 Subject: [PATCH 015/252] Include whitespace in "remove `|`" suggestion and make it hidden --- compiler/rustc_errors/src/diagnostic.rs | 2 +- compiler/rustc_parse/messages.ftl | 4 +- compiler/rustc_parse/src/errors.rs | 17 +++- compiler/rustc_parse/src/parser/pat.rs | 18 ++-- .../issue-64879-trailing-before-guard.fixed | 18 ++++ .../issue-64879-trailing-before-guard.rs | 5 +- .../issue-64879-trailing-before-guard.stderr | 22 ++--- .../ui/or-patterns/remove-leading-vert.fixed | 26 +++--- tests/ui/or-patterns/remove-leading-vert.rs | 2 +- .../ui/or-patterns/remove-leading-vert.stderr | 85 +------------------ ...30779-never-arm-no-oatherwise-block.stderr | 6 -- 11 files changed, 76 insertions(+), 129 deletions(-) create mode 100644 tests/ui/or-patterns/issue-64879-trailing-before-guard.fixed diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 96c7ba6ed27b9..0034a30be08a4 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1112,7 +1112,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { .map(|snippet| { debug_assert!( !(sp.is_empty() && snippet.is_empty()), - "Span must not be empty and have no suggestion" + "Span `{sp:?}` must not be empty and have no suggestion" ); Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] } }) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 859118a4adee5..83c5ac449c20e 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -851,8 +851,8 @@ parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up parse_too_short_hex_escape = numeric character escape is too short -parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern - .suggestion = remove the `{$token}` +parse_trailing_vert_not_allowed = a trailing `{$token}` is not allowed in an or-pattern +parse_trailing_vert_not_allowed_suggestion = remove the `{$token}` parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` parse_trait_alias_cannot_be_const = trait aliases cannot be `const` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 4aaaba01faeb3..871d4a53b5c17 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2620,7 +2620,7 @@ pub(crate) enum TopLevelOrPatternNotAllowedSugg { parse_sugg_remove_leading_vert_in_pattern, code = "", applicability = "machine-applicable", - style = "verbose" + style = "tool-only" )] RemoveLeadingVert { #[primary_span] @@ -2653,12 +2653,25 @@ pub(crate) struct UnexpectedVertVertInPattern { pub start: Option, } +#[derive(Subdiagnostic)] +#[suggestion( + parse_trailing_vert_not_allowed, + code = "", + applicability = "machine-applicable", + style = "tool-only" +)] +pub(crate) struct TrailingVertSuggestion { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_trailing_vert_not_allowed)] pub(crate) struct TrailingVertNotAllowed { #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] pub span: Span, + #[subdiagnostic] + pub suggestion: TrailingVertSuggestion, #[label(parse_label_while_parsing_or_pattern_here)] pub start: Option, pub token: Token, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 64653ee2a04c9..a5d16ee423151 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -25,10 +25,10 @@ use crate::errors::{ GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, - TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedExpressionInPattern, - UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, - UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, - UnexpectedVertVertInPattern, WrapInParens, + TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, TrailingVertSuggestion, + UnexpectedExpressionInPattern, UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern, + UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, + UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens, }; use crate::parser::expr::{DestructuredFloat, could_be_unclosed_char_literal}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; @@ -268,10 +268,9 @@ impl<'a> Parser<'a> { if let PatKind::Or(pats) = &pat.kind { let span = pat.span; - let sub = if pats.len() == 1 { - Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { - span: span.with_hi(span.lo() + BytePos(1)), - }) + let sub = if let [_] = &pats[..] { + let span = span.with_hi(span.lo() + BytePos(1)); + Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span }) } else { Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, @@ -363,6 +362,9 @@ impl<'a> Parser<'a> { self.dcx().emit_err(TrailingVertNotAllowed { span: self.token.span, start: lo, + suggestion: TrailingVertSuggestion { + span: self.prev_token.span.shrink_to_hi().with_hi(self.token.span.hi()), + }, token: self.token, note_double_vert: self.token.kind == token::OrOr, }); diff --git a/tests/ui/or-patterns/issue-64879-trailing-before-guard.fixed b/tests/ui/or-patterns/issue-64879-trailing-before-guard.fixed new file mode 100644 index 0000000000000..0c65f709d6636 --- /dev/null +++ b/tests/ui/or-patterns/issue-64879-trailing-before-guard.fixed @@ -0,0 +1,18 @@ +// In this regression test we check that a trailing `|` in an or-pattern just +// before the `if` token of a `match` guard will receive parser recovery with +// an appropriate error message. +//@ run-rustfix +#![allow(dead_code)] + +enum E { A, B } + +fn main() { + match E::A { + E::A | + E::B //~ ERROR a trailing `|` is not allowed in an or-pattern + if true => { + let _recovery_witness: i32 = 0i32; //~ ERROR mismatched types + } + _ => {} + } +} diff --git a/tests/ui/or-patterns/issue-64879-trailing-before-guard.rs b/tests/ui/or-patterns/issue-64879-trailing-before-guard.rs index 181c770096a5f..d7da564c2e1d6 100644 --- a/tests/ui/or-patterns/issue-64879-trailing-before-guard.rs +++ b/tests/ui/or-patterns/issue-64879-trailing-before-guard.rs @@ -1,6 +1,8 @@ // In this regression test we check that a trailing `|` in an or-pattern just // before the `if` token of a `match` guard will receive parser recovery with // an appropriate error message. +//@ run-rustfix +#![allow(dead_code)] enum E { A, B } @@ -9,7 +11,8 @@ fn main() { E::A | E::B | //~ ERROR a trailing `|` is not allowed in an or-pattern if true => { - let recovery_witness: bool = 0; //~ ERROR mismatched types + let _recovery_witness: i32 = 0u32; //~ ERROR mismatched types } + _ => {} } } diff --git a/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr b/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr index 91db3d049f629..238c76080dc4f 100644 --- a/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr +++ b/tests/ui/or-patterns/issue-64879-trailing-before-guard.stderr @@ -1,24 +1,24 @@ error: a trailing `|` is not allowed in an or-pattern - --> $DIR/issue-64879-trailing-before-guard.rs:10:14 + --> $DIR/issue-64879-trailing-before-guard.rs:12:14 | LL | E::A | | ---- while parsing this or-pattern starting here LL | E::B | | ^ + +error[E0308]: mismatched types + --> $DIR/issue-64879-trailing-before-guard.rs:14:42 | -help: remove the `|` +LL | let _recovery_witness: i32 = 0u32; + | --- ^^^^ expected `i32`, found `u32` + | | + | expected due to this | -LL - E::B | -LL + E::B +help: change the type of the numeric literal from `u32` to `i32` | - -error[E0308]: mismatched types - --> $DIR/issue-64879-trailing-before-guard.rs:12:42 +LL - let _recovery_witness: i32 = 0u32; +LL + let _recovery_witness: i32 = 0i32; | -LL | let recovery_witness: bool = 0; - | ---- ^ expected `bool`, found integer - | | - | expected due to this error: aborting due to 2 previous errors diff --git a/tests/ui/or-patterns/remove-leading-vert.fixed b/tests/ui/or-patterns/remove-leading-vert.fixed index 2851b8f18c54a..aa7975dc508aa 100644 --- a/tests/ui/or-patterns/remove-leading-vert.fixed +++ b/tests/ui/or-patterns/remove-leading-vert.fixed @@ -23,26 +23,26 @@ fn leading() { #[cfg(false)] fn trailing() { - let ( A ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern - let (a ,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern - let ( A | B ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern - let [ A | B ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern - let S { f: B }; //~ ERROR a trailing `|` is not allowed in an or-pattern - let ( A | B ): E; //~ ERROR unexpected token `||` in pattern + let ( A ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern + let (a,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern + let ( A | B ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern + let [ A | B ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern + let S { f: B }; //~ ERROR a trailing `|` is not allowed in an or-pattern + let ( A | B ): E; //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern match A { - A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern - A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern - A | B => {} //~ ERROR unexpected token `||` in pattern + A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern + A => {} //~ ERROR a trailing `||` is not allowed in an or-pattern + A | B => {} //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern - | A | B => {} + | A | B => {} //~^ ERROR a trailing `|` is not allowed in an or-pattern } // These test trailing-vert in `let` bindings, but they also test that we don't emit a // duplicate suggestion that would confuse rustfix. - let a : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern - let a = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern - let a ; //~ ERROR a trailing `|` is not allowed in an or-pattern + let a : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern + let a = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern + let a ; //~ ERROR a trailing `|` is not allowed in an or-pattern } diff --git a/tests/ui/or-patterns/remove-leading-vert.rs b/tests/ui/or-patterns/remove-leading-vert.rs index 1e1dbfbc6e665..1b4eb669fbb45 100644 --- a/tests/ui/or-patterns/remove-leading-vert.rs +++ b/tests/ui/or-patterns/remove-leading-vert.rs @@ -32,7 +32,7 @@ fn trailing() { //~^ ERROR a trailing `|` is not allowed in an or-pattern match A { A | => {} //~ ERROR a trailing `|` is not allowed in an or-pattern - A || => {} //~ ERROR a trailing `|` is not allowed in an or-pattern + A || => {} //~ ERROR a trailing `||` is not allowed in an or-pattern A || B | => {} //~ ERROR unexpected token `||` in pattern //~^ ERROR a trailing `|` is not allowed in an or-pattern | A | B | => {} diff --git a/tests/ui/or-patterns/remove-leading-vert.stderr b/tests/ui/or-patterns/remove-leading-vert.stderr index 0323c64f04231..29450153ba459 100644 --- a/tests/ui/or-patterns/remove-leading-vert.stderr +++ b/tests/ui/or-patterns/remove-leading-vert.stderr @@ -3,12 +3,6 @@ error: function parameters require top-level or-patterns in parentheses | LL | fn fun1( | A: E) {} | ^^^ - | -help: remove the `|` - | -LL - fn fun1( | A: E) {} -LL + fn fun1( A: E) {} - | error: unexpected `||` before function parameter --> $DIR/remove-leading-vert.rs:12:14 @@ -78,12 +72,6 @@ LL | let ( A | ): E; | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - let ( A | ): E; -LL + let ( A ): E; - | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:27:12 @@ -92,12 +80,6 @@ LL | let (a |,): (E,); | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - let (a |,): (E,); -LL + let (a ,): (E,); - | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:28:17 @@ -106,12 +88,6 @@ LL | let ( A | B | ): E; | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - let ( A | B | ): E; -LL + let ( A | B ): E; - | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:29:17 @@ -120,12 +96,6 @@ LL | let [ A | B | ]: [E; 1]; | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - let [ A | B | ]: [E; 1]; -LL + let [ A | B ]: [E; 1]; - | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:30:18 @@ -134,12 +104,6 @@ LL | let S { f: B | }; | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - let S { f: B | }; -LL + let S { f: B }; - | error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:31:13 @@ -162,12 +126,6 @@ LL | let ( A || B | ): E; | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - let ( A || B | ): E; -LL + let ( A || B ): E; - | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:34:11 @@ -176,14 +134,8 @@ LL | A | => {} | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - A | => {} -LL + A => {} - | -error: a trailing `|` is not allowed in an or-pattern +error: a trailing `||` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:35:11 | LL | A || => {} @@ -192,11 +144,6 @@ LL | A || => {} | while parsing this or-pattern starting here | = note: alternatives in or-patterns are separated with `|`, not `||` -help: remove the `||` - | -LL - A || => {} -LL + A => {} - | error: unexpected token `||` in pattern --> $DIR/remove-leading-vert.rs:36:11 @@ -219,12 +166,6 @@ LL | A || B | => {} | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - A || B | => {} -LL + A || B => {} - | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:38:17 @@ -233,12 +174,6 @@ LL | | A | B | => {} | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - | A | B | => {} -LL + | A | B => {} - | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:45:11 @@ -247,12 +182,6 @@ LL | let a | : u8 = 0; | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - let a | : u8 = 0; -LL + let a : u8 = 0; - | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:46:11 @@ -261,12 +190,6 @@ LL | let a | = 0; | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - let a | = 0; -LL + let a = 0; - | error: a trailing `|` is not allowed in an or-pattern --> $DIR/remove-leading-vert.rs:47:11 @@ -275,12 +198,6 @@ LL | let a | ; | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - let a | ; -LL + let a ; - | error: aborting due to 21 previous errors diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr index 26731e29ffc57..5f4a5f31e34fb 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr @@ -5,12 +5,6 @@ LL | ! | | - ^ | | | while parsing this or-pattern starting here - | -help: remove the `|` - | -LL - ! | -LL + ! - | error: a never pattern is always unreachable --> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:10:20 From 566cdab16d74f29837b0978f25159c9ee7c51440 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 Aug 2025 21:04:53 +1000 Subject: [PATCH 016/252] Clarify `value_path_str_with_args`. The use of `print_value_path` means the value namespace is always used and the `guess_def_namespace` call is unnecessary. This commit removes the `guess_def_namespace` call and hard-codes `ValueNS`. It also changes the `print_value_path` to `print_def_path` for consistency with `def_path_str_with_args`. --- compiler/rustc_middle/src/ty/print/pretty.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b381d62be47e6..c150aa65b9be5 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2131,8 +2131,6 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> { } } -// HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always -// (but also some things just print a `DefId` generally so maybe we need this?) fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace { match tcx.def_key(def_id).disambiguated_data.data { DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::OpaqueTy => { @@ -2157,6 +2155,7 @@ impl<'t> TyCtxt<'t> { self.def_path_str_with_args(def_id, &[]) } + /// For this one we determine the appropriate namespace for the `def_id`. pub fn def_path_str_with_args( self, def_id: impl IntoQueryParam, @@ -2169,16 +2168,17 @@ impl<'t> TyCtxt<'t> { FmtPrinter::print_string(self, ns, |p| p.print_def_path(def_id, args)).unwrap() } + /// For this one we always use value namespace. pub fn value_path_str_with_args( self, def_id: impl IntoQueryParam, args: &'t [GenericArg<'t>], ) -> String { let def_id = def_id.into_query_param(); - let ns = guess_def_namespace(self, def_id); + let ns = Namespace::ValueNS; debug!("value_path_str: def_id={:?}, ns={:?}", def_id, ns); - FmtPrinter::print_string(self, ns, |p| p.print_value_path(def_id, args)).unwrap() + FmtPrinter::print_string(self, ns, |p| p.print_def_path(def_id, args)).unwrap() } } From b0c36dd4c7519d295239b69127ff84f51f14acc3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 Aug 2025 23:58:46 +1000 Subject: [PATCH 017/252] Rename most of the printers. Three of them are named `AbsolutePathPrinter`, which is confusing, so give those names that better indicate how they are used. And then there is `SymbolPrinter` and `SymbolMangler`, which are renamed as `LegacySymbolMangler` and `V0SymbolMangler`, better indicating their similarity. --- compiler/rustc_const_eval/src/util/type_name.rs | 10 +++++----- compiler/rustc_lint/src/context.rs | 6 +++--- compiler/rustc_symbol_mangling/src/legacy.rs | 10 +++++----- compiler/rustc_symbol_mangling/src/v0.rs | 12 ++++++------ .../src/error_reporting/infer/mod.rs | 6 +++--- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index e6b9759819f1b..573c734e931d9 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -7,12 +7,12 @@ use rustc_middle::bug; use rustc_middle::ty::print::{PrettyPrinter, PrintError, Printer}; use rustc_middle::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt}; -struct AbsolutePathPrinter<'tcx> { +struct TypeNamePrinter<'tcx> { tcx: TyCtxt<'tcx>, path: String, } -impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { +impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -133,7 +133,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } } -impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { +impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> { fn should_print_region(&self, _region: ty::Region<'_>) -> bool { false } @@ -157,7 +157,7 @@ impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { } } -impl Write for AbsolutePathPrinter<'_> { +impl Write for TypeNamePrinter<'_> { fn write_str(&mut self, s: &str) -> std::fmt::Result { self.path.push_str(s); Ok(()) @@ -165,7 +165,7 @@ impl Write for AbsolutePathPrinter<'_> { } pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String { - let mut p = AbsolutePathPrinter { tcx, path: String::new() }; + let mut p = TypeNamePrinter { tcx, path: String::new() }; p.print_type(ty).unwrap(); p.path } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 11181d10af5ee..0dd50af2efcda 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -745,12 +745,12 @@ impl<'tcx> LateContext<'tcx> { /// } /// ``` pub fn get_def_path(&self, def_id: DefId) -> Vec { - struct AbsolutePathPrinter<'tcx> { + struct LintPathPrinter<'tcx> { tcx: TyCtxt<'tcx>, path: Vec, } - impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { + impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -853,7 +853,7 @@ impl<'tcx> LateContext<'tcx> { } } - let mut p = AbsolutePathPrinter { tcx: self.tcx, path: vec![] }; + let mut p = LintPathPrinter { tcx: self.tcx, path: vec![] }; p.print_def_path(def_id, &[]).unwrap(); p.path } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index aa8292c050440..f8bab0f5d0c1c 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -58,7 +58,7 @@ pub(super) fn mangle<'tcx>( let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate); - let mut p = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false }; + let mut p = LegacySymbolMangler { tcx, path: SymbolPath::new(), keep_within_component: false }; p.print_def_path( def_id, if let ty::InstanceKind::DropGlue(_, _) @@ -213,7 +213,7 @@ impl SymbolPath { } } -struct SymbolPrinter<'tcx> { +struct LegacySymbolMangler<'tcx> { tcx: TyCtxt<'tcx>, path: SymbolPath, @@ -228,7 +228,7 @@ struct SymbolPrinter<'tcx> { // `PrettyPrinter` aka pretty printing of e.g. types in paths, // symbol names should have their own printing machinery. -impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { +impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -453,7 +453,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { } } -impl<'tcx> PrettyPrinter<'tcx> for SymbolPrinter<'tcx> { +impl<'tcx> PrettyPrinter<'tcx> for LegacySymbolMangler<'tcx> { fn should_print_region(&self, _region: ty::Region<'_>) -> bool { false } @@ -489,7 +489,7 @@ impl<'tcx> PrettyPrinter<'tcx> for SymbolPrinter<'tcx> { } } -impl fmt::Write for SymbolPrinter<'_> { +impl fmt::Write for LegacySymbolMangler<'_> { fn write_str(&mut self, s: &str) -> fmt::Result { // Name sanitation. LLVM will happily accept identifiers with weird names, but // gas doesn't! diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index c2458ae814b71..2aad5f315f36e 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -33,7 +33,7 @@ pub(super) fn mangle<'tcx>( let args = tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), instance.args); let prefix = "_R"; - let mut p: SymbolMangler<'_> = SymbolMangler { + let mut p: V0SymbolMangler<'_> = V0SymbolMangler { tcx, start_offset: prefix.len(), is_exportable, @@ -88,7 +88,7 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin } let prefix = "_R"; - let mut p: SymbolMangler<'_> = SymbolMangler { + let mut p: V0SymbolMangler<'_> = V0SymbolMangler { tcx, start_offset: prefix.len(), is_exportable: false, @@ -131,7 +131,7 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>( trait_ref: ty::ExistentialTraitRef<'tcx>, ) -> String { // FIXME(flip1995): See comment in `mangle_typeid_for_fnabi`. - let mut p = SymbolMangler { + let mut p = V0SymbolMangler { tcx, start_offset: 0, is_exportable: false, @@ -159,7 +159,7 @@ struct BinderLevel { lifetime_depths: Range, } -struct SymbolMangler<'tcx> { +struct V0SymbolMangler<'tcx> { tcx: TyCtxt<'tcx>, binders: Vec, out: String, @@ -173,7 +173,7 @@ struct SymbolMangler<'tcx> { consts: FxHashMap, usize>, } -impl<'tcx> SymbolMangler<'tcx> { +impl<'tcx> V0SymbolMangler<'tcx> { fn push(&mut self, s: &str) { self.out.push_str(s); } @@ -272,7 +272,7 @@ impl<'tcx> SymbolMangler<'tcx> { } } -impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { +impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index ed8229154a9bf..0aefb4580f86e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -224,12 +224,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { use ty::GenericArg; use ty::print::Printer; - struct AbsolutePathPrinter<'tcx> { + struct ConflictingPathPrinter<'tcx> { tcx: TyCtxt<'tcx>, segments: Vec, } - impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { + impl<'tcx> Printer<'tcx> for ConflictingPathPrinter<'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { self.tcx } @@ -300,7 +300,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // let _ = [{struct Foo; Foo}, {struct Foo; Foo}]; if did1.krate != did2.krate { let abs_path = |def_id| { - let mut p = AbsolutePathPrinter { tcx: self.tcx, segments: vec![] }; + let mut p = ConflictingPathPrinter { tcx: self.tcx, segments: vec![] }; p.print_def_path(def_id, &[]).map(|_| p.segments) }; From d76eef481e2deaf3635da967e8afc5ac63c4c13e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 2 Aug 2025 00:03:28 +1000 Subject: [PATCH 018/252] Simplify multiple things. - `same_path` can just be a `bool`. - `expected` and `found` are only needed inside the block. - Neaten a comment. --- .../src/error_reporting/infer/mod.rs | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 0aefb4580f86e..fd204412564f2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -304,24 +304,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { p.print_def_path(def_id, &[]).map(|_| p.segments) }; - // We compare strings because DefPath can be different - // for imported and non-imported crates + // We compare strings because DefPath can be different for imported and + // non-imported crates. let expected_str = self.tcx.def_path_str(did1); let found_str = self.tcx.def_path_str(did2); let Ok(expected_abs) = abs_path(did1) else { return false }; let Ok(found_abs) = abs_path(did2) else { return false }; - let same_path = || -> Result<_, PrintError> { - Ok(expected_str == found_str || expected_abs == found_abs) - }; - // We want to use as unique a type path as possible. If both types are "locally - // known" by the same name, we use the "absolute path" which uses the original - // crate name instead. - let (expected, found) = if expected_str == found_str { - (join_path_syms(&expected_abs), join_path_syms(&found_abs)) - } else { - (expected_str.clone(), found_str.clone()) - }; - if same_path().unwrap_or(false) { + let same_path = expected_str == found_str || expected_abs == found_abs; + if same_path { + // We want to use as unique a type path as possible. If both types are "locally + // known" by the same name, we use the "absolute path" which uses the original + // crate name instead. + let (expected, found) = if expected_str == found_str { + (join_path_syms(&expected_abs), join_path_syms(&found_abs)) + } else { + (expected_str.clone(), found_str.clone()) + }; + // We've displayed "expected `a::b`, found `a::b`". We add context to // differentiate the different cases where that might happen. let expected_crate_name = self.tcx.crate_name(did1.krate); From f7e46f9d603010be83b3302500c65130a5186782 Mon Sep 17 00:00:00 2001 From: Marco Cavenati Date: Tue, 5 Aug 2025 15:35:59 +0200 Subject: [PATCH 019/252] fix(unicode-table-generator): fix duplicated unique indices unicode-table-generator panicked while populating distinct_indices because of duplicated indices. This was introduced by swapping the order of canonical_words.push(...) and canonical_words.len(). --- src/tools/unicode-table-generator/src/raw_emitter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index e9e0efc459442..03ed9499e26c5 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -341,7 +341,7 @@ impl Canonicalized { for &w in unique_words { unique_mapping.entry(w).or_insert_with(|| { canonical_words.push(w); - UniqueMapping::Canonical(canonical_words.len()) + UniqueMapping::Canonical(canonical_words.len() - 1) }); } assert_eq!(canonicalized_words.len() + canonical_words.len(), unique_words.len()); From b038197b161e61a04fcf77e28f5284853640631c Mon Sep 17 00:00:00 2001 From: Ross MacArthur Date: Tue, 5 Aug 2025 17:05:23 +0200 Subject: [PATCH 020/252] Stabilize `core::iter::chain` --- library/core/src/iter/adapters/chain.rs | 4 +--- library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/iter/mod.rs | 2 +- library/coretests/tests/lib.rs | 1 - 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index dad3d79acb183..943b88e23305a 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -45,8 +45,6 @@ impl Chain { /// # Examples /// /// ``` -/// #![feature(iter_chain)] -/// /// use std::iter::chain; /// /// let a = [1, 2, 3]; @@ -62,7 +60,7 @@ impl Chain { /// assert_eq!(iter.next(), Some(6)); /// assert_eq!(iter.next(), None); /// ``` -#[unstable(feature = "iter_chain", reason = "recently added", issue = "125964")] +#[stable(feature = "iter_chain", since = "CURRENT_RUSTC_VERSION")] pub fn chain(a: A, b: B) -> Chain where A: IntoIterator, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 2a0ef0189d165..6c6de0a4e5c98 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -32,7 +32,7 @@ mod zip; pub use self::array_chunks::ArrayChunks; #[unstable(feature = "std_internals", issue = "none")] pub use self::by_ref_sized::ByRefSized; -#[unstable(feature = "iter_chain", reason = "recently added", issue = "125964")] +#[stable(feature = "iter_chain", since = "CURRENT_RUSTC_VERSION")] pub use self::chain::chain; #[stable(feature = "iter_cloned", since = "1.1.0")] pub use self::cloned::Cloned; diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 56ca1305b601b..bc07324f5204c 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -404,7 +404,7 @@ pub use self::adapters::StepBy; pub use self::adapters::TrustedRandomAccess; #[unstable(feature = "trusted_random_access", issue = "none")] pub use self::adapters::TrustedRandomAccessNoCoerce; -#[unstable(feature = "iter_chain", reason = "recently added", issue = "125964")] +#[stable(feature = "iter_chain", since = "CURRENT_RUSTC_VERSION")] pub use self::adapters::chain; pub(crate) use self::adapters::try_process; #[stable(feature = "iter_zip", since = "1.59.0")] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0a9c0c61c9584..b15ee88b8d773 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -59,7 +59,6 @@ #![feature(isolate_most_least_significant_one)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] -#![feature(iter_chain)] #![feature(iter_collect_into)] #![feature(iter_intersperse)] #![feature(iter_is_partitioned)] From 9c0cfd262f4c1197d9993a78ad0fbfc04a9c774c Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 5 Aug 2025 08:59:08 +0000 Subject: [PATCH 021/252] Fix description of unsigned `checked_exact_div` Like its signed counterpart, this function does not panic. Also, fix the examples to document how it returns Some/None. --- library/core/src/num/uint_macros.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 584cd60fbe5cc..ac5cbcec0b199 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1103,23 +1103,17 @@ macro_rules! uint_impl { self / rhs } - /// Checked integer division without remainder. Computes `self / rhs`. - /// - /// # Panics - /// - /// This function will panic if `rhs == 0` or `self % rhs != 0`. + /// Checked integer division without remainder. Computes `self / rhs`, + /// returning `None` if `rhs == 0` or if `self % rhs != 0`. /// /// # Examples /// /// ``` /// #![feature(exact_div)] - #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), 32);")] - #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), 2);")] - /// ``` - /// - /// ```should_panic - /// #![feature(exact_div)] - #[doc = concat!("let _ = 65", stringify!($SelfT), ".exact_div(2);")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_exact_div(2), Some(32));")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_exact_div(32), Some(2));")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_exact_div(0), None);")] + #[doc = concat!("assert_eq!(65", stringify!($SelfT), ".checked_exact_div(2), None);")] /// ``` #[unstable( feature = "exact_div", From 9a1d38047fe367c32685b07a9ac41da4675b892d Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Thu, 3 Jul 2025 23:38:17 -0400 Subject: [PATCH 022/252] Add `u8`-as-ASCII methods to `core::ascii::Char` --- library/core/src/ascii/ascii_char.rs | 604 ++++++++++++++++++++++++++- 1 file changed, 603 insertions(+), 1 deletion(-) diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index 054ddf844700e..bde4b92c27159 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -445,7 +445,7 @@ pub enum AsciiChar { } impl AsciiChar { - /// Creates an ascii character from the byte `b`, + /// Creates an ASCII character from the byte `b`, /// or returns `None` if it's too large. #[unstable(feature = "ascii_char", issue = "110998")] #[inline] @@ -540,6 +540,608 @@ impl AsciiChar { pub const fn as_str(&self) -> &str { crate::slice::from_ref(self).as_str() } + + /// Makes a copy of the value in its upper case equivalent. + /// + /// Letters 'a' to 'z' are mapped to 'A' to 'Z'. + /// + /// To uppercase the value in-place, use [`make_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let lowercase_a = ascii::Char::SmallA; + /// + /// assert_eq!( + /// ascii::Char::CapitalA, + /// lowercase_a.to_uppercase(), + /// ); + /// ``` + /// + /// [`make_uppercase`]: Self::make_uppercase + #[must_use = "to uppercase the value in-place, use `make_uppercase()`"] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn to_uppercase(self) -> Self { + let uppercase_byte = self.to_u8().to_ascii_uppercase(); + // SAFETY: Toggling the 6th bit won't convert ASCII to non-ASCII. + unsafe { Self::from_u8_unchecked(uppercase_byte) } + } + + /// Makes a copy of the value in its lower case equivalent. + /// + /// Letters 'A' to 'Z' are mapped to 'a' to 'z'. + /// + /// To lowercase the value in-place, use [`make_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// + /// assert_eq!( + /// ascii::Char::SmallA, + /// uppercase_a.to_lowercase(), + /// ); + /// ``` + /// + /// [`make_lowercase`]: Self::make_lowercase + #[must_use = "to lowercase the value in-place, use `make_lowercase()`"] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn to_lowercase(self) -> Self { + let lowercase_byte = self.to_u8().to_ascii_lowercase(); + // SAFETY: Setting the 6th bit won't convert ASCII to non-ASCII. + unsafe { Self::from_u8_unchecked(lowercase_byte) } + } + + /// Checks that two values are a case-insensitive match. + /// + /// This is equivalent to `to_lowercase(a) == to_lowercase(b)`. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let lowercase_a = ascii::Char::SmallA; + /// let uppercase_a = ascii::Char::CapitalA; + /// + /// assert!(lowercase_a.eq_ignore_case(uppercase_a)); + /// ``` + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn eq_ignore_case(self, other: Self) -> bool { + // FIXME(const-hack) `arg.to_u8().to_ascii_lowercase()` -> `arg.to_lowercase()` + // once `PartialEq` is const for `Self`. + self.to_u8().to_ascii_lowercase() == other.to_u8().to_ascii_lowercase() + } + + /// Converts this value to its upper case equivalent in-place. + /// + /// Letters 'a' to 'z' are mapped to 'A' to 'Z'. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let mut letter_a = ascii::Char::SmallA; + /// + /// letter_a.make_uppercase(); + /// + /// assert_eq!(ascii::Char::CapitalA, letter_a); + /// ``` + /// + /// [`to_uppercase`]: Self::to_uppercase + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn make_uppercase(&mut self) { + *self = self.to_uppercase(); + } + + /// Converts this value to its lower case equivalent in-place. + /// + /// Letters 'A' to 'Z' are mapped to 'a' to 'z'. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let mut letter_a = ascii::Char::CapitalA; + /// + /// letter_a.make_lowercase(); + /// + /// assert_eq!(ascii::Char::SmallA, letter_a); + /// ``` + /// + /// [`to_lowercase`]: Self::to_lowercase + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn make_lowercase(&mut self) { + *self = self.to_lowercase(); + } + + /// Checks if the value is an alphabetic character: + /// + /// - 0x41 'A' ..= 0x5A 'Z', or + /// - 0x61 'a' ..= 0x7A 'z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let uppercase_g = ascii::Char::CapitalG; + /// let a = ascii::Char::SmallA; + /// let g = ascii::Char::SmallG; + /// let zero = ascii::Char::Digit0; + /// let percent = ascii::Char::PercentSign; + /// let space = ascii::Char::Space; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(uppercase_a.is_alphabetic()); + /// assert!(uppercase_g.is_alphabetic()); + /// assert!(a.is_alphabetic()); + /// assert!(g.is_alphabetic()); + /// assert!(!zero.is_alphabetic()); + /// assert!(!percent.is_alphabetic()); + /// assert!(!space.is_alphabetic()); + /// assert!(!lf.is_alphabetic()); + /// assert!(!esc.is_alphabetic()); + /// ``` + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn is_alphabetic(self) -> bool { + self.to_u8().is_ascii_alphabetic() + } + + /// Checks if the value is an uppercase character: + /// 0x41 'A' ..= 0x5A 'Z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let uppercase_g = ascii::Char::CapitalG; + /// let a = ascii::Char::SmallA; + /// let g = ascii::Char::SmallG; + /// let zero = ascii::Char::Digit0; + /// let percent = ascii::Char::PercentSign; + /// let space = ascii::Char::Space; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(uppercase_a.is_uppercase()); + /// assert!(uppercase_g.is_uppercase()); + /// assert!(!a.is_uppercase()); + /// assert!(!g.is_uppercase()); + /// assert!(!zero.is_uppercase()); + /// assert!(!percent.is_uppercase()); + /// assert!(!space.is_uppercase()); + /// assert!(!lf.is_uppercase()); + /// assert!(!esc.is_uppercase()); + /// ``` + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn is_uppercase(self) -> bool { + self.to_u8().is_ascii_uppercase() + } + + /// Checks if the value is a lowercase character: + /// 0x61 'a' ..= 0x7A 'z'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let uppercase_g = ascii::Char::CapitalG; + /// let a = ascii::Char::SmallA; + /// let g = ascii::Char::SmallG; + /// let zero = ascii::Char::Digit0; + /// let percent = ascii::Char::PercentSign; + /// let space = ascii::Char::Space; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(!uppercase_a.is_lowercase()); + /// assert!(!uppercase_g.is_lowercase()); + /// assert!(a.is_lowercase()); + /// assert!(g.is_lowercase()); + /// assert!(!zero.is_lowercase()); + /// assert!(!percent.is_lowercase()); + /// assert!(!space.is_lowercase()); + /// assert!(!lf.is_lowercase()); + /// assert!(!esc.is_lowercase()); + /// ``` + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn is_lowercase(self) -> bool { + self.to_u8().is_ascii_lowercase() + } + + /// Checks if the value is an alphanumeric character: + /// + /// - 0x41 'A' ..= 0x5A 'Z', or + /// - 0x61 'a' ..= 0x7A 'z', or + /// - 0x30 '0' ..= 0x39 '9'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let uppercase_g = ascii::Char::CapitalG; + /// let a = ascii::Char::SmallA; + /// let g = ascii::Char::SmallG; + /// let zero = ascii::Char::Digit0; + /// let percent = ascii::Char::PercentSign; + /// let space = ascii::Char::Space; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(uppercase_a.is_alphanumeric()); + /// assert!(uppercase_g.is_alphanumeric()); + /// assert!(a.is_alphanumeric()); + /// assert!(g.is_alphanumeric()); + /// assert!(zero.is_alphanumeric()); + /// assert!(!percent.is_alphanumeric()); + /// assert!(!space.is_alphanumeric()); + /// assert!(!lf.is_alphanumeric()); + /// assert!(!esc.is_alphanumeric()); + /// ``` + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn is_alphanumeric(self) -> bool { + self.to_u8().is_ascii_alphanumeric() + } + + /// Checks if the value is a decimal digit: + /// 0x30 '0' ..= 0x39 '9'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let uppercase_g = ascii::Char::CapitalG; + /// let a = ascii::Char::SmallA; + /// let g = ascii::Char::SmallG; + /// let zero = ascii::Char::Digit0; + /// let percent = ascii::Char::PercentSign; + /// let space = ascii::Char::Space; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(!uppercase_a.is_digit()); + /// assert!(!uppercase_g.is_digit()); + /// assert!(!a.is_digit()); + /// assert!(!g.is_digit()); + /// assert!(zero.is_digit()); + /// assert!(!percent.is_digit()); + /// assert!(!space.is_digit()); + /// assert!(!lf.is_digit()); + /// assert!(!esc.is_digit()); + /// ``` + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn is_digit(self) -> bool { + self.to_u8().is_ascii_digit() + } + + /// Checks if the value is an octal digit: + /// 0x30 '0' ..= 0x37 '7'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants, is_ascii_octdigit)] + /// + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let a = ascii::Char::SmallA; + /// let zero = ascii::Char::Digit0; + /// let seven = ascii::Char::Digit7; + /// let eight = ascii::Char::Digit8; + /// let percent = ascii::Char::PercentSign; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(!uppercase_a.is_octdigit()); + /// assert!(!a.is_octdigit()); + /// assert!(zero.is_octdigit()); + /// assert!(seven.is_octdigit()); + /// assert!(!eight.is_octdigit()); + /// assert!(!percent.is_octdigit()); + /// assert!(!lf.is_octdigit()); + /// assert!(!esc.is_octdigit()); + /// ``` + #[must_use] + // This is blocked on two unstable features. Please ensure both are + // stabilized before marking this method as stable. + #[unstable(feature = "ascii_char", issue = "110998")] + // #[unstable(feature = "is_ascii_octdigit", issue = "101288")] + #[inline] + pub const fn is_octdigit(self) -> bool { + self.to_u8().is_ascii_octdigit() + } + + /// Checks if the value is a hexadecimal digit: + /// + /// - 0x30 '0' ..= 0x39 '9', or + /// - 0x41 'A' ..= 0x46 'F', or + /// - 0x61 'a' ..= 0x66 'f'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let uppercase_g = ascii::Char::CapitalG; + /// let a = ascii::Char::SmallA; + /// let g = ascii::Char::SmallG; + /// let zero = ascii::Char::Digit0; + /// let percent = ascii::Char::PercentSign; + /// let space = ascii::Char::Space; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(uppercase_a.is_hexdigit()); + /// assert!(!uppercase_g.is_hexdigit()); + /// assert!(a.is_hexdigit()); + /// assert!(!g.is_hexdigit()); + /// assert!(zero.is_hexdigit()); + /// assert!(!percent.is_hexdigit()); + /// assert!(!space.is_hexdigit()); + /// assert!(!lf.is_hexdigit()); + /// assert!(!esc.is_hexdigit()); + /// ``` + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn is_hexdigit(self) -> bool { + self.to_u8().is_ascii_hexdigit() + } + + /// Checks if the value is a punctuation character: + /// + /// - 0x21 ..= 0x2F `! " # $ % & ' ( ) * + , - . /`, or + /// - 0x3A ..= 0x40 `: ; < = > ? @`, or + /// - 0x5B ..= 0x60 `` [ \ ] ^ _ ` ``, or + /// - 0x7B ..= 0x7E `{ | } ~` + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let uppercase_g = ascii::Char::CapitalG; + /// let a = ascii::Char::SmallA; + /// let g = ascii::Char::SmallG; + /// let zero = ascii::Char::Digit0; + /// let percent = ascii::Char::PercentSign; + /// let space = ascii::Char::Space; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(!uppercase_a.is_punctuation()); + /// assert!(!uppercase_g.is_punctuation()); + /// assert!(!a.is_punctuation()); + /// assert!(!g.is_punctuation()); + /// assert!(!zero.is_punctuation()); + /// assert!(percent.is_punctuation()); + /// assert!(!space.is_punctuation()); + /// assert!(!lf.is_punctuation()); + /// assert!(!esc.is_punctuation()); + /// ``` + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn is_punctuation(self) -> bool { + self.to_u8().is_ascii_punctuation() + } + + /// Checks if the value is a graphic character: + /// 0x21 '!' ..= 0x7E '~'. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let uppercase_g = ascii::Char::CapitalG; + /// let a = ascii::Char::SmallA; + /// let g = ascii::Char::SmallG; + /// let zero = ascii::Char::Digit0; + /// let percent = ascii::Char::PercentSign; + /// let space = ascii::Char::Space; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(uppercase_a.is_graphic()); + /// assert!(uppercase_g.is_graphic()); + /// assert!(a.is_graphic()); + /// assert!(g.is_graphic()); + /// assert!(zero.is_graphic()); + /// assert!(percent.is_graphic()); + /// assert!(!space.is_graphic()); + /// assert!(!lf.is_graphic()); + /// assert!(!esc.is_graphic()); + /// ``` + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn is_graphic(self) -> bool { + self.to_u8().is_ascii_graphic() + } + + /// Checks if the value is a whitespace character: + /// 0x20 SPACE, 0x09 HORIZONTAL TAB, 0x0A LINE FEED, + /// 0x0C FORM FEED, or 0x0D CARRIAGE RETURN. + /// + /// Rust uses the WhatWG Infra Standard's [definition of ASCII + /// whitespace][infra-aw]. There are several other definitions in + /// wide use. For instance, [the POSIX locale][pct] includes + /// 0x0B VERTICAL TAB as well as all the above characters, + /// but—from the very same specification—[the default rule for + /// "field splitting" in the Bourne shell][bfs] considers *only* + /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace. + /// + /// If you are writing a program that will process an existing + /// file format, check what that format's definition of whitespace is + /// before using this function. + /// + /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace + /// [pct]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 + /// [bfs]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let uppercase_g = ascii::Char::CapitalG; + /// let a = ascii::Char::SmallA; + /// let g = ascii::Char::SmallG; + /// let zero = ascii::Char::Digit0; + /// let percent = ascii::Char::PercentSign; + /// let space = ascii::Char::Space; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(!uppercase_a.is_whitespace()); + /// assert!(!uppercase_g.is_whitespace()); + /// assert!(!a.is_whitespace()); + /// assert!(!g.is_whitespace()); + /// assert!(!zero.is_whitespace()); + /// assert!(!percent.is_whitespace()); + /// assert!(space.is_whitespace()); + /// assert!(lf.is_whitespace()); + /// assert!(!esc.is_whitespace()); + /// ``` + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn is_whitespace(self) -> bool { + self.to_u8().is_ascii_whitespace() + } + + /// Checks if the value is a control character: + /// 0x00 NUL ..= 0x1F UNIT SEPARATOR, or 0x7F DELETE. + /// Note that most whitespace characters are control + /// characters, but SPACE is not. + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let uppercase_a = ascii::Char::CapitalA; + /// let uppercase_g = ascii::Char::CapitalG; + /// let a = ascii::Char::SmallA; + /// let g = ascii::Char::SmallG; + /// let zero = ascii::Char::Digit0; + /// let percent = ascii::Char::PercentSign; + /// let space = ascii::Char::Space; + /// let lf = ascii::Char::LineFeed; + /// let esc = ascii::Char::Escape; + /// + /// assert!(!uppercase_a.is_control()); + /// assert!(!uppercase_g.is_control()); + /// assert!(!a.is_control()); + /// assert!(!g.is_control()); + /// assert!(!zero.is_control()); + /// assert!(!percent.is_control()); + /// assert!(!space.is_control()); + /// assert!(lf.is_control()); + /// assert!(esc.is_control()); + /// ``` + #[must_use] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub const fn is_control(self) -> bool { + self.to_u8().is_ascii_control() + } + + /// Returns an iterator that produces an escaped version of a + /// character. + /// + /// The behavior is identical to + /// [`ascii::escape_default`](crate::ascii::escape_default). + /// + /// # Examples + /// + /// ``` + /// #![feature(ascii_char, ascii_char_variants)] + /// use std::ascii; + /// + /// let zero = ascii::Char::Digit0; + /// let tab = ascii::Char::CharacterTabulation; + /// let cr = ascii::Char::CarriageReturn; + /// let lf = ascii::Char::LineFeed; + /// let apostrophe = ascii::Char::Apostrophe; + /// let double_quote = ascii::Char::QuotationMark; + /// let backslash = ascii::Char::ReverseSolidus; + /// + /// assert_eq!("0", zero.escape_ascii().to_string()); + /// assert_eq!("\\t", tab.escape_ascii().to_string()); + /// assert_eq!("\\r", cr.escape_ascii().to_string()); + /// assert_eq!("\\n", lf.escape_ascii().to_string()); + /// assert_eq!("\\'", apostrophe.escape_ascii().to_string()); + /// assert_eq!("\\\"", double_quote.escape_ascii().to_string()); + /// assert_eq!("\\\\", backslash.escape_ascii().to_string()); + /// ``` + #[must_use = "this returns the escaped character as an iterator, \ + without modifying the original"] + #[unstable(feature = "ascii_char", issue = "110998")] + #[inline] + pub fn escape_ascii(self) -> super::EscapeDefault { + super::escape_default(self.to_u8()) + } } macro_rules! into_int_impl { From d811581ba7b8f577b537d33446856eb6c6ad41fa Mon Sep 17 00:00:00 2001 From: "Chai T. Rex" Date: Fri, 4 Jul 2025 23:32:58 -0400 Subject: [PATCH 023/252] Add `std::ascii::Char` `MIN` and `MAX` constants --- library/core/src/ascii/ascii_char.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index bde4b92c27159..419e4694594f0 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -445,6 +445,14 @@ pub enum AsciiChar { } impl AsciiChar { + /// The character with the lowest ASCII code. + #[unstable(feature = "ascii_char", issue = "110998")] + pub const MIN: Self = Self::Null; + + /// The character with the highest ASCII code. + #[unstable(feature = "ascii_char", issue = "110998")] + pub const MAX: Self = Self::Delete; + /// Creates an ASCII character from the byte `b`, /// or returns `None` if it's too large. #[unstable(feature = "ascii_char", issue = "110998")] From 070425e54d36fd20d363d6994d8ffdfa44ec160d Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Tue, 5 Aug 2025 16:26:42 +0200 Subject: [PATCH 024/252] Add aarch64_be-unknown-none-softfloat target Signed-off-by: Jens Reidel --- compiler/rustc_target/src/spec/mod.rs | 1 + .../aarch64_be_unknown_none_softfloat.rs | 43 +++++++++++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 1 + .../aarch64_be-unknown-none-softfloat.md | 74 +++++++++++++++++++ tests/assembly-llvm/targets/targets-elf.rs | 3 + 6 files changed, 123 insertions(+) create mode 100644 compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs create mode 100644 src/doc/rustc/src/platform-support/aarch64_be-unknown-none-softfloat.md diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 033590e01a67d..126d17b97584a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2146,6 +2146,7 @@ supported_targets! { ("aarch64-unknown-none", aarch64_unknown_none), ("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat), + ("aarch64_be-unknown-none-softfloat", aarch64_be_unknown_none_softfloat), ("aarch64-unknown-nuttx", aarch64_unknown_nuttx), ("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs new file mode 100644 index 0000000000000..7f918e8508094 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs @@ -0,0 +1,43 @@ +// Generic big-endian AArch64 target for bare-metal code - Floating point disabled +// +// Can be used in conjunction with the `target-feature` and +// `target-cpu` compiler flags to opt-in more hardware-specific +// features. +// +// For example, `-C target-cpu=cortex-a53`. +use rustc_abi::Endian; + +use crate::spec::{ + Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target, + TargetMetadata, TargetOptions, +}; + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + abi: "softfloat".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + features: "+v8a,+strict-align,-neon,-fp-armv8".into(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(128), + supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + stack_probes: StackProbeType::Inline, + panic_strategy: PanicStrategy::Abort, + endian: Endian::Big, + ..Default::default() + }; + Target { + llvm_target: "aarch64_be-unknown-none".into(), + metadata: TargetMetadata { + description: Some("Bare ARM64 (big-endian), softfloat".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), + arch: "aarch64".into(), + options: opts, + } +} diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 7c688e32bc0dd..83e51ca63696b 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -47,6 +47,7 @@ - [\*-apple-visionos](platform-support/apple-visionos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md) + - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md) - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) - [arm-none-eabi](platform-support/arm-none-eabi.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 65b7063015388..005be9c4d6629 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -273,6 +273,7 @@ target | std | host | notes `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian) +[`aarch64_be-unknown-none-softfloat`](platform-support/aarch64_be-unknown-none-softfloat.md) | * | | Bare big-endian ARM64, softfloat [`amdgcn-amd-amdhsa`](platform-support/amdgcn-amd-amdhsa.md) | * | | `-Ctarget-cpu=gfx...` to specify [the AMD GPU] to compile for [`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | Arm Apple WatchOS 64-bit with 32-bit pointers [`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md) | ✓ | ✓ | ARM64e Apple Darwin diff --git a/src/doc/rustc/src/platform-support/aarch64_be-unknown-none-softfloat.md b/src/doc/rustc/src/platform-support/aarch64_be-unknown-none-softfloat.md new file mode 100644 index 0000000000000..a28ddcdf7f2f2 --- /dev/null +++ b/src/doc/rustc/src/platform-support/aarch64_be-unknown-none-softfloat.md @@ -0,0 +1,74 @@ +# aarch64_be-unknown-none-softfloat + +**Tier: 3** + +Target for freestanding/bare-metal big-endian ARM64 binaries in ELF format: +firmware, kernels, etc. + +## Target maintainers + +[@Gelbpunkt](https://github.com/Gelbpunkt) + +## Requirements + +This target is cross-compiled. There is no support for `std`. There is no +default allocator, but it's possible to use `alloc` by supplying an allocator. + +The target does not assume existence of a FPU and does not make use of any +non-GPR register. This allows the generated code to run in environments, such +as kernels, which may need to avoid the use of such registers or which may have +special considerations about the use of such registers (e.g. saving and +restoring them to avoid breaking userspace code using the same registers). You +can change code generation to use additional CPU features via the +`-C target-feature=` codegen options to rustc, or via the `#[target_feature]` +mechanism within Rust code. + +By default, code generated with the soft-float target should run on any +big-endian ARM64 hardware, enabling additional target features may raise this +baseline. + +`extern "C"` uses the [architecture's standard calling convention][aapcs64]. + +[aapcs64]: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst + +The targets generate binaries in the ELF format. Any alternate formats or +special considerations for binary layout will require linker options or linker +scripts. + +## Building the target + +You can build Rust with support for the target by adding it to the `target` +list in `bootstrap.toml`: + +```toml +[build] +target = ["aarch64_be-unknown-none-softfloat"] +``` + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will first need to build Rust with the target enabled (see +"Building the target" above). + +## Cross-compilation + +For cross builds, you will need an appropriate ARM64 C/C++ toolchain for +linking, or if you want to compile C code along with Rust (such as for Rust +crates with C dependencies). + +Rust *may* be able to use an `aarch64_be-unknown-linux-{gnu,musl}-` toolchain +with appropriate standalone flags to build for this target (depending on the +assumptions of that toolchain, see below), or you may wish to use a separate +`aarch64_be-unknown-none-softfloat` toolchain. + +On some ARM64 hosts that use ELF binaries, you *may* be able to use the host C +toolchain, if it does not introduce assumptions about the host environment that +don't match the expectations of a standalone environment. Otherwise, you may +need a separate toolchain for standalone/freestanding development, just as when +cross-compiling from a non-ARM64 platform. + +## Testing + +As the target supports a variety of different environments and does not support +`std`, it does not support running the Rust test suite. diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index edf16548e7de0..11c7567cfa130 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -10,6 +10,9 @@ //@ revisions: aarch64_be_unknown_netbsd //@ [aarch64_be_unknown_netbsd] compile-flags: --target aarch64_be-unknown-netbsd //@ [aarch64_be_unknown_netbsd] needs-llvm-components: aarch64 +//@ revisions: aarch64_be_unknown_none_softfloat +//@ [aarch64_be_unknown_none_softfloat] compile-flags: --target aarch64_be-unknown-none-softfloat +//@ [aarch64_be_unknown_none_softfloat] needs-llvm-components: aarch64 //@ revisions: aarch64_kmc_solid_asp3 //@ [aarch64_kmc_solid_asp3] compile-flags: --target aarch64-kmc-solid_asp3 //@ [aarch64_kmc_solid_asp3] needs-llvm-components: aarch64 From dfd38f0d36d04c1d080578481546029e4ebbebca Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 2 Aug 2025 02:18:47 +1000 Subject: [PATCH 025/252] Add comments to `Printer`. These details took me some time to work out. --- compiler/rustc_middle/src/ty/print/mod.rs | 56 ++++++++++++++++------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 8a125c7fe2840..e404206d19e8a 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -21,18 +21,16 @@ pub trait Print<'tcx, P> { fn print(&self, p: &mut P) -> Result<(), PrintError>; } -/// Interface for outputting user-facing "type-system entities" -/// (paths, types, lifetimes, constants, etc.) as a side-effect -/// (e.g. formatting, like `PrettyPrinter` implementors do) or by -/// constructing some alternative representation (e.g. an AST), -/// which the associated types allow passing through the methods. -/// -/// For pretty-printing/formatting in particular, see `PrettyPrinter`. -// -// FIXME(eddyb) find a better name; this is more general than "printing". +/// A trait that "prints" user-facing type system entities: paths, types, lifetimes, constants, +/// etc. "Printing" here means building up a representation of the entity's path, usually as a +/// `String` (e.g. "std::io::Read") or a `Vec` (e.g. `[sym::std, sym::io, sym::Read]`). The +/// representation is built up by appending one or more pieces. The specific details included in +/// the built-up representation depend on the purpose of the printer. The more advanced printers +/// also rely on the `PrettyPrinter` sub-trait. pub trait Printer<'tcx>: Sized { fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; + /// Appends a representation of an entity with a normal path, e.g. "std::io::Read". fn print_def_path( &mut self, def_id: DefId, @@ -41,6 +39,7 @@ pub trait Printer<'tcx>: Sized { self.default_print_def_path(def_id, args) } + /// Like `print_def_path`, but for `DefPathData::Impl`. fn print_impl_path( &mut self, impl_def_id: DefId, @@ -66,25 +65,40 @@ pub trait Printer<'tcx>: Sized { self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref) } + /// Appends a representation of a region. fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>; + /// Appends a representation of a type. fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError>; + /// Appends a representation of a list of `PolyExistentialPredicate`s. fn print_dyn_existential( &mut self, predicates: &'tcx ty::List>, ) -> Result<(), PrintError>; + /// Appends a representation of a const. fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError>; + /// Appends a representation of a crate name, e.g. `std`, or even ``. fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError>; - fn path_qualified( + /// Appends a representation of a (full or partial) simple path, in two parts. `print_prefix`, + /// when called, appends the representation of the leading segments. The rest of the method + /// appends the representation of the final segment, the details of which are in + /// `disambiguated_data`. + /// + /// E.g. `std::io` + `Read` -> `std::io::Read`. + fn path_append( &mut self, - self_ty: Ty<'tcx>, - trait_ref: Option>, + print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, + disambiguated_data: &DisambiguatedDefPathData, ) -> Result<(), PrintError>; + /// Similar to `path_append`, but the final segment is an `impl` segment. + /// + /// E.g. `slice` + `` -> `slice::`, which may then be further appended to, + /// giving a longer path representation such as `slice::::to_vec_in::ConvertVec`. fn path_append_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, @@ -92,16 +106,24 @@ pub trait Printer<'tcx>: Sized { trait_ref: Option>, ) -> Result<(), PrintError>; - fn path_append( + /// Appends a representation of a path ending in generic args, in two parts. `print_prefix`, + /// when called, appends the leading segments. The rest of the method appends the + /// representation of the generic args. (Some printers choose to skip appending the generic + /// args.) + /// + /// E.g. `ImplementsTraitForUsize` + `` -> `ImplementsTraitForUsize`. + fn path_generic_args( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - disambiguated_data: &DisambiguatedDefPathData, + args: &[GenericArg<'tcx>], ) -> Result<(), PrintError>; - fn path_generic_args( + /// Appends a representation of a qualified path segment, e.g. `>`. + /// If `trait_ref` is `None`, it may fall back to simpler forms, e.g. `>` or just `Foo`. + fn path_qualified( &mut self, - print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, - args: &[GenericArg<'tcx>], + self_ty: Ty<'tcx>, + trait_ref: Option>, ) -> Result<(), PrintError>; fn should_truncate(&mut self) -> bool { From 69bcd79ab78fb02798406424ab64d209bfed1880 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 3 Aug 2025 20:38:11 +1000 Subject: [PATCH 026/252] Move `should_truncate` from trait `Printer` to sub-trait `PrettyPrinter`. It's not used in `Printer`. --- compiler/rustc_middle/src/ty/print/mod.rs | 4 ---- compiler/rustc_middle/src/ty/print/pretty.rs | 12 ++++++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index e404206d19e8a..c0ad1ba38460a 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -126,10 +126,6 @@ pub trait Printer<'tcx>: Sized { trait_ref: Option>, ) -> Result<(), PrintError>; - fn should_truncate(&mut self) -> bool { - false - } - // Defaults (should not be overridden): #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index c150aa65b9be5..394b94999bff7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -333,6 +333,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { f: impl FnOnce(&mut Self) -> Result<(), PrintError>, ) -> Result<(), PrintError>; + fn should_truncate(&mut self) -> bool { + false + } + /// Returns `true` if the region should be printed in /// optional positions, e.g., `&'a T` or `dyn Tr + 'b`. /// This is typically the case for all non-`'_` regions. @@ -2295,10 +2299,6 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } } - fn should_truncate(&mut self) -> bool { - !self.type_length_limit.value_within_limit(self.printed_type_count) - } - fn print_dyn_existential( &mut self, predicates: &'tcx ty::List>, @@ -2487,6 +2487,10 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { Ok(()) } + fn should_truncate(&mut self) -> bool { + !self.type_length_limit.value_within_limit(self.printed_type_count) + } + fn should_print_region(&self, region: ty::Region<'tcx>) -> bool { let highlight = self.region_highlight_mode; if highlight.region_highlighted(region).is_some() { From b8adda6194dfe3296fff73812dcaa88c58a4f0f1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 3 Aug 2025 21:02:28 +1000 Subject: [PATCH 027/252] Rename some `Printer` methods. I find these name clearer, and starting them all with `print_` makes things more consistent. --- .../rustc_const_eval/src/util/type_name.rs | 10 ++--- compiler/rustc_lint/src/context.rs | 10 ++--- compiler/rustc_middle/src/ty/print/mod.rs | 30 ++++++++------- compiler/rustc_middle/src/ty/print/pretty.rs | 37 ++++++++++--------- compiler/rustc_symbol_mangling/src/legacy.rs | 17 +++++---- compiler/rustc_symbol_mangling/src/v0.rs | 16 ++++---- .../src/error_reporting/infer/mod.rs | 10 ++--- .../error_reporting/infer/note_and_explain.rs | 2 +- 8 files changed, 71 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 573c734e931d9..2f74f998fd042 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -73,12 +73,12 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { self.pretty_print_dyn_existential(predicates) } - fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { + fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> { self.path.push_str(self.tcx.crate_name(cnum).as_str()); Ok(()) } - fn path_qualified( + fn print_path_with_qualified( &mut self, self_ty: Ty<'tcx>, trait_ref: Option>, @@ -86,7 +86,7 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { self.pretty_path_qualified(self_ty, trait_ref) } - fn path_append_impl( + fn print_path_with_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, self_ty: Ty<'tcx>, @@ -105,7 +105,7 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { ) } - fn path_append( + fn print_path_with_simple( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, disambiguated_data: &DisambiguatedDefPathData, @@ -117,7 +117,7 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { Ok(()) } - fn path_generic_args( + fn print_path_with_generic_args( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, args: &[GenericArg<'tcx>], diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 0dd50af2efcda..d9163d94710e8 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -774,12 +774,12 @@ impl<'tcx> LateContext<'tcx> { unreachable!(); // because `path_generic_args` ignores the `GenericArgs` } - fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { + fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> { self.path = vec![self.tcx.crate_name(cnum)]; Ok(()) } - fn path_qualified( + fn print_path_with_qualified( &mut self, self_ty: Ty<'tcx>, trait_ref: Option>, @@ -800,7 +800,7 @@ impl<'tcx> LateContext<'tcx> { }) } - fn path_append_impl( + fn print_path_with_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, self_ty: Ty<'tcx>, @@ -825,7 +825,7 @@ impl<'tcx> LateContext<'tcx> { Ok(()) } - fn path_append( + fn print_path_with_simple( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, disambiguated_data: &DisambiguatedDefPathData, @@ -844,7 +844,7 @@ impl<'tcx> LateContext<'tcx> { Ok(()) } - fn path_generic_args( + fn print_path_with_generic_args( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, _args: &[GenericArg<'tcx>], diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index c0ad1ba38460a..4ca483eafe3ca 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -81,7 +81,7 @@ pub trait Printer<'tcx>: Sized { fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError>; /// Appends a representation of a crate name, e.g. `std`, or even ``. - fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError>; + fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError>; /// Appends a representation of a (full or partial) simple path, in two parts. `print_prefix`, /// when called, appends the representation of the leading segments. The rest of the method @@ -89,17 +89,17 @@ pub trait Printer<'tcx>: Sized { /// `disambiguated_data`. /// /// E.g. `std::io` + `Read` -> `std::io::Read`. - fn path_append( + fn print_path_with_simple( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, disambiguated_data: &DisambiguatedDefPathData, ) -> Result<(), PrintError>; - /// Similar to `path_append`, but the final segment is an `impl` segment. + /// Similar to `print_path_with_simple`, but the final segment is an `impl` segment. /// /// E.g. `slice` + `` -> `slice::`, which may then be further appended to, /// giving a longer path representation such as `slice::::to_vec_in::ConvertVec`. - fn path_append_impl( + fn print_path_with_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, self_ty: Ty<'tcx>, @@ -112,7 +112,7 @@ pub trait Printer<'tcx>: Sized { /// args.) /// /// E.g. `ImplementsTraitForUsize` + `` -> `ImplementsTraitForUsize`. - fn path_generic_args( + fn print_path_with_generic_args( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, args: &[GenericArg<'tcx>], @@ -120,7 +120,7 @@ pub trait Printer<'tcx>: Sized { /// Appends a representation of a qualified path segment, e.g. `>`. /// If `trait_ref` is `None`, it may fall back to simpler forms, e.g. `>` or just `Foo`. - fn path_qualified( + fn print_path_with_qualified( &mut self, self_ty: Ty<'tcx>, trait_ref: Option>, @@ -140,7 +140,7 @@ pub trait Printer<'tcx>: Sized { match key.disambiguated_data.data { DefPathData::CrateRoot => { assert!(key.parent.is_none()); - self.path_crate(def_id.krate) + self.print_crate_name(def_id.krate) } DefPathData::Impl => self.print_impl_path(def_id, args), @@ -164,7 +164,7 @@ pub trait Printer<'tcx>: Sized { )) = self.tcx().coroutine_kind(def_id) && args.len() > parent_args.len() { - return self.path_generic_args( + return self.print_path_with_generic_args( |p| p.print_def_path(def_id, parent_args), &args[..parent_args.len() + 1][..1], ); @@ -186,7 +186,7 @@ pub trait Printer<'tcx>: Sized { _ => { if !generics.is_own_empty() && args.len() >= generics.count() { let args = generics.own_args_no_defaults(self.tcx(), args); - return self.path_generic_args( + return self.print_path_with_generic_args( |p| p.print_def_path(def_id, parent_args), args, ); @@ -202,7 +202,7 @@ pub trait Printer<'tcx>: Sized { && self.tcx().generics_of(parent_def_id).parent_count == 0; } - self.path_append( + self.print_path_with_simple( |p: &mut Self| { if trait_qualify_parent { let trait_ref = ty::TraitRef::new( @@ -210,7 +210,7 @@ pub trait Printer<'tcx>: Sized { parent_def_id, parent_args.iter().copied(), ); - p.path_qualified(trait_ref.self_ty(), Some(trait_ref)) + p.print_path_with_qualified(trait_ref.self_ty(), Some(trait_ref)) } else { p.print_def_path(parent_def_id, parent_args) } @@ -253,11 +253,15 @@ pub trait Printer<'tcx>: Sized { // If the impl is not co-located with either self-type or // trait-type, then fallback to a format that identifies // the module more clearly. - self.path_append_impl(|p| p.print_def_path(parent_def_id, &[]), self_ty, impl_trait_ref) + self.print_path_with_impl( + |p| p.print_def_path(parent_def_id, &[]), + self_ty, + impl_trait_ref, + ) } else { // Otherwise, try to give a good form that would be valid language // syntax. Preferably using associated item notation. - self.path_qualified(self_ty, impl_trait_ref) + self.print_path_with_qualified(self_ty, impl_trait_ref) } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 394b94999bff7..a7ff1b518331b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -474,7 +474,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // path to the crate followed by the path to the item within the crate. if let Some(cnum) = def_id.as_crate_root() { if cnum == LOCAL_CRATE { - self.path_crate(cnum)?; + self.print_crate_name(cnum)?; return Ok(true); } @@ -498,7 +498,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // or avoid ending up with `ExternCrateSource::Extern`, // for the injected `std`/`core`. if span.is_dummy() { - self.path_crate(cnum)?; + self.print_crate_name(cnum)?; return Ok(true); } @@ -512,13 +512,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return Ok(true); } (ExternCrateSource::Path, LOCAL_CRATE) => { - self.path_crate(cnum)?; + self.print_crate_name(cnum)?; return Ok(true); } _ => {} }, None => { - self.path_crate(cnum)?; + self.print_crate_name(cnum)?; return Ok(true); } } @@ -628,7 +628,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return Ok(false); } callers.push(visible_parent); - // HACK(eddyb) this bypasses `path_append`'s prefix printing to avoid + // HACK(eddyb) this bypasses `print_path_with_simple`'s prefix printing to avoid // knowing ahead of time whether the entire path will succeed or not. // To support printers that do not implement `PrettyPrinter`, a `Vec` or // linked list on the stack would need to be built, before any printing. @@ -637,7 +637,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { true => {} } callers.pop(); - self.path_append(|_| Ok(()), &DisambiguatedDefPathData { data, disambiguator: 0 })?; + self.print_path_with_simple( + |_| Ok(()), + &DisambiguatedDefPathData { data, disambiguator: 0 }, + )?; Ok(true) } @@ -1312,10 +1315,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { alias_ty: ty::AliasTerm<'tcx>, ) -> Result<(), PrintError> { let def_key = self.tcx().def_key(alias_ty.def_id); - self.path_generic_args( + self.print_path_with_generic_args( |p| { - p.path_append( - |p| p.path_qualified(alias_ty.self_ty(), None), + p.print_path_with_simple( + |p| p.print_path_with_qualified(alias_ty.self_ty(), None), &def_key.disambiguated_data, ) }, @@ -1400,7 +1403,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } } - // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, + // HACK(eddyb) this duplicates `FmtPrinter`'s `print_path_with_generic_args`, // in order to place the projections inside the `<...>`. if !resugared { let principal_with_self = @@ -2234,7 +2237,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { self.print_def_path(parent_def_id, &[])?; - // HACK(eddyb) copy of `path_append` to avoid + // HACK(eddyb) copy of `print_path_with_simple` to avoid // constructing a `DisambiguatedDefPathData`. if !self.empty_path { write!(self, "::")?; @@ -2310,7 +2313,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { self.pretty_print_const(ct, false) } - fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { + fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> { self.empty_path = true; if cnum == LOCAL_CRATE { if self.tcx.sess.at_least_rust_2018() { @@ -2327,7 +2330,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { Ok(()) } - fn path_qualified( + fn print_path_with_qualified( &mut self, self_ty: Ty<'tcx>, trait_ref: Option>, @@ -2337,7 +2340,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { Ok(()) } - fn path_append_impl( + fn print_path_with_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, self_ty: Ty<'tcx>, @@ -2359,7 +2362,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { Ok(()) } - fn path_append( + fn print_path_with_simple( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, disambiguated_data: &DisambiguatedDefPathData, @@ -2390,7 +2393,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { Ok(()) } - fn path_generic_args( + fn print_path_with_generic_args( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, args: &[GenericArg<'tcx>], @@ -3229,7 +3232,7 @@ define_print! { // The args don't contain the self ty (as it has been erased) but the corresp. // generics do as the trait always has a self ty param. We need to offset. let args = &self.args[p.tcx().generics_of(self.def_id).parent_count - 1..]; - p.path_generic_args(|p| write!(p, "{name}"), args)?; + p.print_path_with_generic_args(|p| write!(p, "{name}"), args)?; write!(p, " = ")?; self.term.print(p)?; } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index f8bab0f5d0c1c..350546d4b6659 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -218,8 +218,8 @@ struct LegacySymbolMangler<'tcx> { path: SymbolPath, // When `true`, `finalize_pending_component` isn't used. - // This is needed when recursing into `path_qualified`, - // or `path_generic_args`, as any nested paths are + // This is needed when recursing into `print_path_with_qualified`, + // or `print_path_with_generic_args`, as any nested paths are // logically within one component. keep_within_component: bool, } @@ -303,11 +303,12 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { Ok(()) } - fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { + fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> { self.write_str(self.tcx.crate_name(cnum).as_str())?; Ok(()) } - fn path_qualified( + + fn print_path_with_qualified( &mut self, self_ty: Ty<'tcx>, trait_ref: Option>, @@ -329,7 +330,7 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { } } - fn path_append_impl( + fn print_path_with_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, self_ty: Ty<'tcx>, @@ -352,7 +353,8 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { trait_ref, ) } - fn path_append( + + fn print_path_with_simple( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, disambiguated_data: &DisambiguatedDefPathData, @@ -375,7 +377,8 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { Ok(()) } - fn path_generic_args( + + fn print_path_with_generic_args( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, args: &[GenericArg<'tcx>], diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 2aad5f315f36e..0cbd48ba08c4a 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -365,7 +365,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { // Encode impl generic params if the generic parameters contain non-region parameters // and this isn't an inherent impl. if impl_trait_ref.is_some() && args.iter().any(|a| a.has_non_region_param()) { - self.path_generic_args( + self.print_path_with_generic_args( |this| { this.path_append_ns( |p| p.print_def_path(parent_def_id, &[]), @@ -786,7 +786,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { None => { self.push("S"); for (field_def, field) in iter::zip(&variant_def.fields, fields) { - // HACK(eddyb) this mimics `path_append`, + // HACK(eddyb) this mimics `print_path_with_simple`, // instead of simply using `field_def.ident`, // just to be able to handle disambiguators. let disambiguated_field = @@ -819,7 +819,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { Ok(()) } - fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { + fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> { self.push("C"); if !self.is_exportable { let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); @@ -830,7 +830,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { Ok(()) } - fn path_qualified( + fn print_path_with_qualified( &mut self, self_ty: Ty<'tcx>, trait_ref: Option>, @@ -843,7 +843,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { self.print_def_path(trait_ref.def_id, trait_ref.args) } - fn path_append_impl( + fn print_path_with_impl( &mut self, _: impl FnOnce(&mut Self) -> Result<(), PrintError>, _: Ty<'tcx>, @@ -853,7 +853,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { unreachable!() } - fn path_append( + fn print_path_with_simple( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, disambiguated_data: &DisambiguatedDefPathData, @@ -873,7 +873,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { DefPathData::SyntheticCoroutineBody => 's', DefPathData::NestedStatic => 'n', - // These should never show up as `path_append` arguments. + // These should never show up as `print_path_with_simple` arguments. DefPathData::CrateRoot | DefPathData::Use | DefPathData::GlobalAsm @@ -896,7 +896,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { ) } - fn path_generic_args( + fn print_path_with_generic_args( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, args: &[GenericArg<'tcx>], diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index fd204412564f2..839a8007bf206 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -253,12 +253,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { unreachable!(); // because `path_generic_args` ignores the `GenericArgs` } - fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { + fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> { self.segments = vec![self.tcx.crate_name(cnum)]; Ok(()) } - fn path_qualified( + fn print_path_with_qualified( &mut self, _self_ty: Ty<'tcx>, _trait_ref: Option>, @@ -266,7 +266,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Err(fmt::Error) } - fn path_append_impl( + fn print_path_with_impl( &mut self, _print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, _self_ty: Ty<'tcx>, @@ -275,7 +275,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Err(fmt::Error) } - fn path_append( + fn print_path_with_simple( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, disambiguated_data: &DisambiguatedDefPathData, @@ -285,7 +285,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Ok(()) } - fn path_generic_args( + fn print_path_with_generic_args( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, _args: &[GenericArg<'tcx>], diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 129d0963a75a8..b9284c07d8305 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -947,7 +947,7 @@ fn foo(&self) -> Self::T { String::new() } pub fn format_generic_args(&self, args: &[ty::GenericArg<'tcx>]) -> String { FmtPrinter::print_string(self.tcx, hir::def::Namespace::TypeNS, |p| { - p.path_generic_args(|_| Ok(()), args) + p.print_path_with_generic_args(|_| Ok(()), args) }) .expect("could not write to `String`.") } From 42a1042f9b915b48d1e7176802cb130d029b3b48 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 3 Aug 2025 21:14:01 +1000 Subject: [PATCH 028/252] Rename some `PrettyPrinter` methods. More consistency. --- .../rustc_const_eval/src/util/type_name.rs | 4 +- compiler/rustc_middle/src/mir/pretty.rs | 4 +- compiler/rustc_middle/src/ty/print/pretty.rs | 52 +++++++++---------- compiler/rustc_symbol_mangling/src/legacy.rs | 6 +-- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 2f74f998fd042..d50507f65eb1e 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -83,7 +83,7 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result<(), PrintError> { - self.pretty_path_qualified(self_ty, trait_ref) + self.pretty_print_path_with_qualified(self_ty, trait_ref) } fn print_path_with_impl( @@ -92,7 +92,7 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result<(), PrintError> { - self.pretty_path_append_impl( + self.pretty_print_path_with_impl( |cx| { print_prefix(cx)?; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index ed067d491276f..a3949308eb4cc 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1969,7 +1969,7 @@ fn pretty_print_const_value_tcx<'tcx>( let args = tcx.lift(args).unwrap(); let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; - p.print_value_path(variant_def.def_id, args)?; + p.pretty_print_value_path(variant_def.def_id, args)?; fmt.write_str(&p.into_buffer())?; match variant_def.ctor_kind() { @@ -2011,7 +2011,7 @@ fn pretty_print_const_value_tcx<'tcx>( (ConstValue::ZeroSized, ty::FnDef(d, s)) => { let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; - p.print_value_path(*d, s)?; + p.pretty_print_value_path(*d, s)?; fmt.write_str(&p.into_buffer())?; return Ok(()); } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index a7ff1b518331b..46876cef1d0fe 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -245,7 +245,7 @@ impl<'tcx> RegionHighlightMode<'tcx> { /// Trait for printers that pretty-print using `fmt::Write` to the printer. pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { /// Like `print_def_path` but for value paths. - fn print_value_path( + fn pretty_print_value_path( &mut self, def_id: DefId, args: &'tcx [GenericArg<'tcx>], @@ -253,7 +253,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { self.print_def_path(def_id, args) } - fn print_in_binder(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError> + fn pretty_print_in_binder(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError> where T: Print<'tcx, Self> + TypeFoldable>, { @@ -644,7 +644,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Ok(true) } - fn pretty_path_qualified( + fn pretty_print_path_with_qualified( &mut self, self_ty: Ty<'tcx>, trait_ref: Option>, @@ -679,7 +679,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { }) } - fn pretty_path_append_impl( + fn pretty_print_path_with_impl( &mut self, print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>, self_ty: Ty<'tcx>, @@ -746,7 +746,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } sig.print(self)?; write!(self, " {{")?; - self.print_value_path(def_id, args)?; + self.pretty_print_value_path(def_id, args)?; write!(self, "}}")?; } } @@ -1393,7 +1393,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { if let ty::Tuple(tys) = principal.args.type_at(0).kind() { let mut projections = predicates.projection_bounds(); if let (Some(proj), None) = (projections.next(), projections.next()) { - p.pretty_fn_sig( + p.pretty_print_fn_sig( tys, false, proj.skip_binder().term.as_type().expect("Return type was a const"), @@ -1495,7 +1495,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Ok(()) } - fn pretty_fn_sig( + fn pretty_print_fn_sig( &mut self, inputs: &[Ty<'tcx>], c_variadic: bool, @@ -1532,7 +1532,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { match self.tcx().def_kind(def) { DefKind::Const | DefKind::AssocConst => { - self.print_value_path(def, args)?; + self.pretty_print_value_path(def, args)?; } DefKind::AnonConst => { if def.is_local() @@ -1541,13 +1541,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { { write!(self, "{snip}")?; } else { - // Do not call `print_value_path` as if a parent of this anon const is - // an impl it will attempt to print out the impl trait ref i.e. `::{constant#0}`. This would cause printing to enter an - // infinite recursion if the anon const is in the self type i.e. - // `impl Default for [T; 32 - 1 - 1 - 1] {` where we would - // try to print - // `<[T; /* print constant#0 again */] as // Default>::{constant#0}`. + // Do not call `pretty_print_value_path` as if a parent of this anon + // const is an impl it will attempt to print out the impl trait ref + // i.e. `::{constant#0}`. This would cause printing to + // enter an infinite recursion if the anon const is in the self type + // i.e. `impl Default for [T; 32 - 1 - 1 - 1] {` where we + // would try to print `<[T; /* print constant#0 again */] as // + // Default>::{constant#0}`. write!( self, "{}::{}", @@ -1749,7 +1749,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { self.tcx().try_get_global_alloc(prov.alloc_id()) { self.typed_value( - |this| this.print_value_path(instance.def_id(), instance.args), + |this| this.pretty_print_value_path(instance.def_id(), instance.args), |this| this.print_type(ty), " as ", )?; @@ -1943,7 +1943,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let variant_idx = contents.variant.expect("destructed const of adt without variant idx"); let variant_def = &def.variant(variant_idx); - self.print_value_path(variant_def.def_id, args)?; + self.pretty_print_value_path(variant_def.def_id, args)?; match variant_def.ctor_kind() { Some(CtorKind::Const) => {} Some(CtorKind::Fn) => { @@ -1979,7 +1979,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } (_, ty::FnDef(def_id, args)) => { // Never allowed today, but we still encounter them in invalid const args. - self.print_value_path(def_id, args)?; + self.pretty_print_value_path(def_id, args)?; return Ok(()); } // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading @@ -2000,7 +2000,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Ok(()) } - fn pretty_closure_as_impl( + fn pretty_print_closure_as_impl( &mut self, closure: ty::ClosureArgs>, ) -> Result<(), PrintError> { @@ -2335,7 +2335,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result<(), PrintError> { - self.pretty_path_qualified(self_ty, trait_ref)?; + self.pretty_print_path_with_qualified(self_ty, trait_ref)?; self.empty_path = false; Ok(()) } @@ -2346,7 +2346,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result<(), PrintError> { - self.pretty_path_append_impl( + self.pretty_print_path_with_impl( |p| { print_prefix(p)?; if !p.empty_path { @@ -2424,7 +2424,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id)) } - fn print_value_path( + fn pretty_print_value_path( &mut self, def_id: DefId, args: &'tcx [GenericArg<'tcx>], @@ -2436,7 +2436,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { Ok(()) } - fn print_in_binder(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError> + fn pretty_print_in_binder(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError> where T: Print<'tcx, Self> + TypeFoldable>, { @@ -2899,7 +2899,7 @@ where T: Print<'tcx, P> + TypeFoldable>, { fn print(&self, p: &mut P) -> Result<(), PrintError> { - p.print_in_binder(self) + p.pretty_print_in_binder(self) } } @@ -3097,7 +3097,7 @@ define_print! { } write!(p, "fn")?; - p.pretty_fn_sig(self.inputs(), self.c_variadic, self.output())?; + p.pretty_print_fn_sig(self.inputs(), self.c_variadic, self.output())?; } ty::TraitRef<'tcx> { @@ -3321,7 +3321,7 @@ define_print_and_forward_display! { } PrintClosureAsImpl<'tcx> { - p.pretty_closure_as_impl(self.closure)?; + p.pretty_print_closure_as_impl(self.closure)?; } ty::ParamTy { diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 350546d4b6659..923318ef30367 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -313,7 +313,7 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result<(), PrintError> { - // Similar to `pretty_path_qualified`, but for the other + // Similar to `pretty_print_path_with_qualified`, but for the other // types that are printed as paths (see `print_type` above). match self_ty.kind() { ty::FnDef(..) @@ -326,7 +326,7 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { self.print_type(self_ty) } - _ => self.pretty_path_qualified(self_ty, trait_ref), + _ => self.pretty_print_path_with_qualified(self_ty, trait_ref), } } @@ -336,7 +336,7 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { self_ty: Ty<'tcx>, trait_ref: Option>, ) -> Result<(), PrintError> { - self.pretty_path_append_impl( + self.pretty_print_path_with_impl( |cx| { print_prefix(cx)?; From 2472d19625fa39ed635a211be397319d2b62cb24 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 6 Aug 2025 13:38:26 +0000 Subject: [PATCH 029/252] Include allocator module in LLVM_passes timer --- compiler/rustc_codegen_ssa/src/back/write.rs | 7 +-- compiler/rustc_codegen_ssa/src/base.rs | 56 ++++++++++---------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index aa29afb7f5b11..a2ae03a7611bc 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -110,7 +110,6 @@ pub struct ModuleConfig { pub lint_llvm_ir: bool, pub no_prepopulate_passes: bool, pub no_builtins: bool, - pub time_module: bool, pub vectorize_loop: bool, pub vectorize_slp: bool, pub merge_functions: bool, @@ -228,10 +227,6 @@ impl ModuleConfig { no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes, no_builtins: no_builtins || sess.target.no_builtins, - // Exclude metadata and allocator modules from time_passes output, - // since they throw off the "LLVM passes" measurement. - time_module: if_regular!(true, false), - // Copy what clang does by turning on loop vectorization at O2 and // slp vectorization at O3. vectorize_loop: !sess.opts.cg.no_vectorize_loops @@ -1740,7 +1735,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>( llvm_start_time: &mut Option>, work: WorkItem, ) { - if cgcx.config(work.module_kind()).time_module && llvm_start_time.is_none() { + if llvm_start_time.is_none() { *llvm_start_time = Some(cgcx.prof.verbose_generic_activity("LLVM_passes")); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index b4556ced0b3fb..10a25bb3caaa1 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -681,33 +681,6 @@ pub fn codegen_crate( let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu, autodiff_items); - // Codegen an allocator shim, if necessary. - if let Some(kind) = allocator_kind_for_codegen(tcx) { - let llmod_id = - cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); - let module_llvm = tcx.sess.time("write_allocator_module", || { - backend.codegen_allocator( - tcx, - &llmod_id, - kind, - // If allocator_kind is Some then alloc_error_handler_kind must - // also be Some. - tcx.alloc_error_handler_kind(()).unwrap(), - ) - }); - - ongoing_codegen.wait_for_signal_to_codegen_item(); - ongoing_codegen.check_for_errors(tcx.sess); - - // These modules are generally cheap and won't throw off scheduling. - let cost = 0; - submit_codegened_module_to_llvm( - &ongoing_codegen.coordinator, - ModuleCodegen::new_allocator(llmod_id, module_llvm), - cost, - ); - } - // For better throughput during parallel processing by LLVM, we used to sort // CGUs largest to smallest. This would lead to better thread utilization // by, for example, preventing a large CGU from being processed last and @@ -823,6 +796,35 @@ pub fn codegen_crate( } } + // Codegen an allocator shim, if necessary. + // Do this last to ensure the LLVM_passes timer doesn't start while no CGUs have been codegened + // yet for the backend to optimize. + if let Some(kind) = allocator_kind_for_codegen(tcx) { + let llmod_id = + cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); + let module_llvm = tcx.sess.time("write_allocator_module", || { + backend.codegen_allocator( + tcx, + &llmod_id, + kind, + // If allocator_kind is Some then alloc_error_handler_kind must + // also be Some. + tcx.alloc_error_handler_kind(()).unwrap(), + ) + }); + + ongoing_codegen.wait_for_signal_to_codegen_item(); + ongoing_codegen.check_for_errors(tcx.sess); + + // These modules are generally cheap and won't throw off scheduling. + let cost = 0; + submit_codegened_module_to_llvm( + &ongoing_codegen.coordinator, + ModuleCodegen::new_allocator(llmod_id, module_llvm), + cost, + ); + } + ongoing_codegen.codegen_finished(tcx); // Since the main thread is sometimes blocked during codegen, we keep track From ee38bc06ce68d3f426f191a012ab529eceecb700 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 6 Aug 2025 14:03:35 +0000 Subject: [PATCH 030/252] Remove unused field from ModuleConfig --- compiler/rustc_codegen_ssa/src/back/write.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index a2ae03a7611bc..17dcca753987b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -76,12 +76,9 @@ pub struct ModuleConfig { /// Names of additional optimization passes to run. pub passes: Vec, /// Some(level) to optimize at a certain level, or None to run - /// absolutely no optimizations (used for the metadata module). + /// absolutely no optimizations (used for the allocator module). pub opt_level: Option, - /// Some(level) to optimize binary size, or None to not affect program size. - pub opt_size: Option, - pub pgo_gen: SwitchWithOptPath, pub pgo_use: Option, pub pgo_sample_use: Option, @@ -170,7 +167,6 @@ impl ModuleConfig { passes: if_regular!(sess.opts.cg.passes.clone(), vec![]), opt_level: opt_level_and_size, - opt_size: opt_level_and_size, pgo_gen: if_regular!( sess.opts.cg.profile_generate.clone(), From 8f648d7185a8455151951f30357b93dee726c6cb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 8 Aug 2025 11:24:28 +0000 Subject: [PATCH 031/252] Remove bitcode_llvm_cmdline It used to be necessary on Apple platforms to ship with the App Store, but XCode 15 has stopped embedding LLVM bitcode and the App Store no longer accepts apps with bitcode embedded. --- compiler/rustc_codegen_llvm/src/back/write.rs | 11 ++++++----- compiler/rustc_codegen_ssa/src/back/write.rs | 2 -- compiler/rustc_target/src/spec/json.rs | 3 --- compiler/rustc_target/src/spec/mod.rs | 3 --- 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 85a06f457ebea..62998003ca114 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -862,7 +862,7 @@ pub(crate) fn codegen( .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); let thin_bc = module.thin_lto_buffer.as_deref().expect("cannot find embedded bitcode"); - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); + embed_bitcode(cgcx, llcx, llmod, &thin_bc); } } @@ -1058,7 +1058,6 @@ fn embed_bitcode( cgcx: &CodegenContext, llcx: &llvm::Context, llmod: &llvm::Module, - cmdline: &str, bitcode: &[u8], ) { // We're adding custom sections to the output object file, but we definitely @@ -1074,7 +1073,9 @@ fn embed_bitcode( // * Mach-O - this is for macOS. Inspecting the source code for the native // linker here shows that the `.llvmbc` and `.llvmcmd` sections are // automatically skipped by the linker. In that case there's nothing extra - // that we need to do here. + // that we need to do here. We do need to make sure that the + // `__LLVM,__cmdline` section exists even though it is empty as otherwise + // ld64 rejects the object file. // // * Wasm - the native LLD linker is hard-coded to skip `.llvmbc` and // `.llvmcmd` sections, so there's nothing extra we need to do. @@ -1111,7 +1112,7 @@ fn embed_bitcode( llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); - let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); + let llconst = common::bytes_in_context(llcx, &[]); let llglobal = llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); llvm::set_initializer(llglobal, llconst); let section = if cgcx.target_is_like_darwin { @@ -1128,7 +1129,7 @@ fn embed_bitcode( let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); llvm::append_module_inline_asm(llmod, &asm); - let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); + let asm = create_section_with_flags_asm(".llvmcmd", section_flags, &[]); llvm::append_module_inline_asm(llmod, &asm); } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 17dcca753987b..7ceb9885716eb 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -99,7 +99,6 @@ pub struct ModuleConfig { pub emit_obj: EmitObj, pub emit_thin_lto: bool, pub emit_thin_lto_summary: bool, - pub bc_cmdline: String, // Miscellaneous flags. These are mostly copied from command-line // options. @@ -216,7 +215,6 @@ impl ModuleConfig { sess.opts.output_types.contains_key(&OutputType::ThinLinkBitcode), false ), - bc_cmdline: sess.target.bitcode_llvm_cmdline.to_string(), verify_llvm_ir: sess.verify_llvm_ir(), lint_llvm_ir: sess.opts.unstable_opts.lint_llvm_ir, diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index d27c1929aef74..ba7a3a3969e38 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -167,7 +167,6 @@ impl Target { forward!(main_needs_argc_argv); forward!(has_thread_local); forward!(obj_is_bitcode); - forward!(bitcode_llvm_cmdline); forward_opt!(max_atomic_width); forward_opt!(min_atomic_width); forward!(atomic_cas); @@ -359,7 +358,6 @@ impl ToJson for Target { target_option_val!(main_needs_argc_argv); target_option_val!(has_thread_local); target_option_val!(obj_is_bitcode); - target_option_val!(bitcode_llvm_cmdline); target_option_val!(min_atomic_width); target_option_val!(max_atomic_width); target_option_val!(atomic_cas); @@ -552,7 +550,6 @@ struct TargetSpecJson { main_needs_argc_argv: Option, has_thread_local: Option, obj_is_bitcode: Option, - bitcode_llvm_cmdline: Option>, max_atomic_width: Option, min_atomic_width: Option, atomic_cas: Option, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 033590e01a67d..0c7ff7dd16564 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2620,8 +2620,6 @@ pub struct TargetOptions { /// If we give emcc .o files that are actually .bc files it /// will 'just work'. pub obj_is_bitcode: bool, - /// Content of the LLVM cmdline section associated with embedded bitcode. - pub bitcode_llvm_cmdline: StaticCow, /// Don't use this field; instead use the `.min_atomic_width()` method. pub min_atomic_width: Option, @@ -2984,7 +2982,6 @@ impl Default for TargetOptions { allow_asm: true, has_thread_local: false, obj_is_bitcode: false, - bitcode_llvm_cmdline: "".into(), min_atomic_width: None, max_atomic_width: None, atomic_cas: true, From cde14e65bf4d072ab38cf7e909113979b12ae044 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 5 Jun 2025 12:01:20 +0200 Subject: [PATCH 032/252] apply_member_constraints: fix placeholder check --- .../rustc_borrowck/src/handle_placeholders.rs | 4 +++ .../rustc_borrowck/src/region_infer/mod.rs | 9 +++++- .../non-root-universe-existential-1.rs | 29 +++++++++++++++++ .../non-root-universe-existential-2.rs | 31 +++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/ui/nll/member-constraints/non-root-universe-existential-1.rs create mode 100644 tests/ui/nll/member-constraints/non-root-universe-existential-2.rs diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index aaaf2f45c869d..8893ba662ae67 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -103,6 +103,10 @@ impl RegionTracker { self.max_nameable_universe } + pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex { + self.max_placeholder_universe_reached + } + fn merge_min_max_seen(&mut self, other: &Self) { self.max_placeholder_universe_reached = std::cmp::max( self.max_placeholder_universe_reached, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f13200485332f..192059a770085 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -713,7 +713,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // If the member region lives in a higher universe, we currently choose // the most conservative option by leaving it unchanged. - if !self.max_nameable_universe(scc).is_root() { + if !self.max_placeholder_universe_reached(scc).is_root() { return; } @@ -1376,6 +1376,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.scc_annotations[scc].max_nameable_universe() } + pub(crate) fn max_placeholder_universe_reached( + &self, + scc: ConstraintSccIndex, + ) -> UniverseIndex { + self.scc_annotations[scc].max_placeholder_universe_reached() + } + /// Checks the final value for the free region `fr` to see if it /// grew too large. In particular, examine what `end(X)` points /// wound up in `fr`'s final value; for each `end(X)` where `X != diff --git a/tests/ui/nll/member-constraints/non-root-universe-existential-1.rs b/tests/ui/nll/member-constraints/non-root-universe-existential-1.rs new file mode 100644 index 0000000000000..39dbfebce10aa --- /dev/null +++ b/tests/ui/nll/member-constraints/non-root-universe-existential-1.rs @@ -0,0 +1,29 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +trait Proj<'a> { + type Assoc; +} + +impl<'a, 'b, F: FnOnce() -> &'b ()> Proj<'a> for F { + type Assoc = (); +} + +fn is_proj Proj<'a>>(f: F) {} + +fn define<'a>() -> impl Sized + use<'a> { + // This defines the RPIT to `&'unconstrained_b ()`, an inference + // variable which is in a higher universe as gets created inside + // of the binder of `F: for<'a> Proj<'a>`. This previously caused + // us to not apply member constraints. + // + // This was unnecessary. It is totally acceptable for member regions + // to be able to name placeholders from higher universes, as long as + // they don't actually do so. + is_proj(define::<'a>); + &() +} + +fn main() {} diff --git a/tests/ui/nll/member-constraints/non-root-universe-existential-2.rs b/tests/ui/nll/member-constraints/non-root-universe-existential-2.rs new file mode 100644 index 0000000000000..c5ddde0d7d81b --- /dev/null +++ b/tests/ui/nll/member-constraints/non-root-universe-existential-2.rs @@ -0,0 +1,31 @@ +//@ check-pass + +// Unlike `non-root-universe-existential-1.rs` this previously +// compiled as it simply didn't define the hidden type of +// `impl Iterator` when projecting through it. We will do so +// with the new solver. Further minimizing this is challenging. + +struct Type(Vec); +enum TypeTreeValueIter<'a, T> { + Once(T), + Ref(&'a ()), +} + +impl<'a, T> Iterator for TypeTreeValueIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + loop {} + } +} + +fn item>(x: I) -> ::Item { + loop {} +} + +fn get_type_tree_values<'a>(ty: &'a Type) -> impl Iterator { + let _: &'a Type = item(std::iter::once(ty).map(get_type_tree_values)); + TypeTreeValueIter::<'a, &'a Type>::Once(ty) +} + +fn main() {} From 7af87d18d2ebe93f30221abd0d6de11ff8fcd5c1 Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 29 Jul 2025 11:51:43 -0500 Subject: [PATCH 033/252] editorconfig: don't trim trailing whitespace in tests --- .editorconfig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index ef8ed24c52a50..1b137cf4ebefd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,9 +7,18 @@ root = true [*] end_of_line = lf charset = utf-8 -trim_trailing_whitespace = true insert_final_newline = true +# some tests need trailing whitespace in output snapshots +[!tests/] +trim_trailing_whitespace = true +# for actual source code files of test, we still don't want trailing whitespace +[tests/**.{rs,js}] +trim_trailing_whitespace = true +# these specific source files need to have trailing whitespace. +[tests/ui/{frontmatter/frontmatter-whitespace-3.rs,parser/shebang/shebang-space.rs}] +trim_trailing_whitespace = false + [!src/llvm-project] indent_style = space indent_size = 4 From c503487a6f1402ed37051e435af0c410a3815b14 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 9 Aug 2025 11:53:30 -0700 Subject: [PATCH 034/252] Avoid abbreviating "numerator" as "numer", to allow catching typo "numer" elsewhere `typos.toml` has an exception for "numer", to avoid flagging its use as an abbreviation for "numerator". Remove the use of that abbrevation, spelling out "numerator" instead, and remove the exception, so that typo checks can find future instances of "numer" as a typo for "number". --- library/std/src/sys_common/mod.rs | 13 ++++++------- src/tools/miri/src/shims/time.rs | 4 ++-- typos.toml | 1 - 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index cce88d936b71b..24b6cff130974 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -51,17 +51,16 @@ pub trait FromInner { fn from_inner(inner: Inner) -> Self; } -// Computes (value*numer)/denom without overflow, as long as both -// (numer*denom) and the overall result fit into i64 (which is the case -// for our time conversions). +// Computes (value*numerator)/denom without overflow, as long as both (numerator*denom) and the +// overall result fit into i64 (which is the case for our time conversions). #[allow(dead_code)] // not used on all platforms -pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 { +pub fn mul_div_u64(value: u64, numerator: u64, denom: u64) -> u64 { let q = value / denom; let r = value % denom; // Decompose value as (value/denom*denom + value%denom), - // substitute into (value*numer)/denom and simplify. - // r < denom, so (denom*numer) is the upper bound of (r*numer) - q * numer + r * numer / denom + // substitute into (value*numerator)/denom and simplify. + // r < denom, so (denom*numerator) is the upper bound of (r*numerator) + q * numerator + r * numerator / denom } pub fn ignore_notfound(result: crate::io::Result) -> crate::io::Result<()> { diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index b5b35797fec2f..6e56fdfe35aef 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -322,8 +322,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Since our emulated ticks in `mach_absolute_time` *are* nanoseconds, // no scaling needs to happen. - let (numer, denom) = (1, 1); - this.write_int_fields(&[numer.into(), denom.into()], &info)?; + let (numerator, denom) = (1, 1); + this.write_int_fields(&[numerator.into(), denom.into()], &info)?; interp_ok(Scalar::from_i32(0)) // KERN_SUCCESS } diff --git a/typos.toml b/typos.toml index 4035f206a4663..317aafc861565 100644 --- a/typos.toml +++ b/typos.toml @@ -52,7 +52,6 @@ ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC = "ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC" ERROR_MCA_OCCURED = "ERROR_MCA_OCCURED" ERRNO_ACCES = "ERRNO_ACCES" tolen = "tolen" -numer = "numer" [default] extend-ignore-words-re = [ From a42833e0aae1a0c296609040f4a893f37e199525 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 10 Aug 2025 00:27:35 +0000 Subject: [PATCH 035/252] cargo update compiler & tools dependencies: Locking 18 packages to latest compatible versions Updating anstream v0.6.19 -> v0.6.20 Updating anstyle-query v1.1.3 -> v1.1.4 Updating anstyle-svg v0.1.9 -> v0.1.10 Updating anstyle-wincon v3.0.9 -> v3.0.10 Updating camino v1.1.10 -> v1.1.11 Updating clap v4.5.42 -> v4.5.43 Updating clap_builder v4.5.42 -> v4.5.43 Updating cxx v1.0.161 -> v1.0.166 Updating cxx-build v1.0.161 -> v1.0.166 Updating cxxbridge-cmd v1.0.161 -> v1.0.166 Updating cxxbridge-flags v1.0.161 -> v1.0.166 Updating cxxbridge-macro v1.0.161 -> v1.0.166 Updating derive-where v1.5.0 -> v1.6.0 Updating hashbrown v0.15.4 -> v0.15.5 Updating indenter v0.3.3 -> v0.3.4 Updating rustversion v1.0.21 -> v1.0.22 Updating scratch v1.0.8 -> v1.0.9 Updating zerovec v0.11.2 -> v0.11.4 note: pass `--verbose` to see 36 unchanged dependencies behind latest library dependencies: Locking 1 package to latest compatible version Updating hashbrown v0.15.4 -> v0.15.5 note: pass `--verbose` to see 2 unchanged dependencies behind latest rustbook dependencies: Locking 10 packages to latest compatible versions Updating anstream v0.6.19 -> v0.6.20 Updating anstyle-query v1.1.3 -> v1.1.4 Updating anstyle-wincon v3.0.9 -> v3.0.10 Updating cc v1.2.31 -> v1.2.32 Updating clap v4.5.42 -> v4.5.43 Updating clap_builder v4.5.42 -> v4.5.43 Updating clap_complete v4.5.55 -> v4.5.56 Updating hashbrown v0.15.4 -> v0.15.5 Updating rustversion v1.0.21 -> v1.0.22 Updating zerovec v0.11.2 -> v0.11.4 --- Cargo.lock | 90 +++++++++++++++++------------------ library/Cargo.lock | 4 +- src/tools/rustbook/Cargo.lock | 44 ++++++++--------- 3 files changed, 69 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbb76ada8377f..a69fa56f051bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,9 +80,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -119,18 +119,18 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-svg" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a43964079ef399480603125d5afae2b219aceffb77478956e25f17b9bc3435c" +checksum = "dc03a770ef506fe1396c0e476120ac0e6523cf14b74218dd5f18cd6833326fa9" dependencies = [ "anstyle", "anstyle-lossy", @@ -141,13 +141,13 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -353,9 +353,9 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "camino" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" +checksum = "5d07aa9a93b00c76f71bc35d598bed923f6d4f3a9ca5c24b7737ae1a292841c0" dependencies = [ "serde", ] @@ -518,9 +518,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.42" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" +checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" dependencies = [ "clap_builder", "clap_derive", @@ -538,9 +538,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.42" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" +checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" dependencies = [ "anstream", "anstyle", @@ -937,9 +937,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.161" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3523cc02ad831111491dd64b27ad999f1ae189986728e477604e61b81f828df" +checksum = "b5287274dfdf7e7eaa3d97d460eb2a94922539e6af214bda423f292105011ee2" dependencies = [ "cc", "cxxbridge-cmd", @@ -951,9 +951,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.161" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212b754247a6f07b10fa626628c157593f0abf640a3dd04cce2760eca970f909" +checksum = "65f3ce027a744135db10a1ebffa0863dab685aeef48f40a02c201f5e70c667d3" dependencies = [ "cc", "codespan-reporting", @@ -966,9 +966,9 @@ dependencies = [ [[package]] name = "cxxbridge-cmd" -version = "1.0.161" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f426a20413ec2e742520ba6837c9324b55ffac24ead47491a6e29f933c5b135a" +checksum = "a07dc23f2eea4774297f4c9a17ae4065fecb63127da556e6c9fadb0216d93595" dependencies = [ "clap", "codespan-reporting", @@ -980,15 +980,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.161" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258b6069020b4e5da6415df94a50ee4f586a6c38b037a180e940a43d06a070d" +checksum = "f7a4dbad6171f763c4066c83dcd27546b6e93c5c5ae2229f9813bda7233f571d" [[package]] name = "cxxbridge-macro" -version = "1.0.161" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dec184b52be5008d6eaf7e62fc1802caf1ad1227d11b3b7df2c409c7ffc3f4" +checksum = "a9be4b527950fc42db06163705e78e73eedc8fd723708e942afe3572a9a2c366" dependencies = [ "indexmap", "proc-macro2", @@ -1055,9 +1055,9 @@ version = "0.1.91" [[package]] name = "derive-where" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", @@ -1567,9 +1567,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", @@ -1688,7 +1688,7 @@ dependencies = [ "potential_utf", "yoke 0.8.0", "zerofrom", - "zerovec 0.11.2", + "zerovec 0.11.4", ] [[package]] @@ -1721,7 +1721,7 @@ dependencies = [ "litemap 0.8.0", "tinystr 0.8.1", "writeable 0.6.1", - "zerovec 0.11.2", + "zerovec 0.11.4", ] [[package]] @@ -1769,7 +1769,7 @@ dependencies = [ "icu_properties", "icu_provider 2.0.0", "smallvec", - "zerovec 0.11.2", + "zerovec 0.11.4", ] [[package]] @@ -1791,7 +1791,7 @@ dependencies = [ "icu_provider 2.0.0", "potential_utf", "zerotrie", - "zerovec 0.11.2", + "zerovec 0.11.4", ] [[package]] @@ -1831,7 +1831,7 @@ dependencies = [ "yoke 0.8.0", "zerofrom", "zerotrie", - "zerovec 0.11.2", + "zerovec 0.11.4", ] [[package]] @@ -1909,9 +1909,9 @@ dependencies = [ [[package]] name = "indenter" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" [[package]] name = "indexmap" @@ -2971,7 +2971,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" dependencies = [ - "zerovec 0.11.2", + "zerovec 0.11.4", ] [[package]] @@ -4918,9 +4918,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ruzstd" @@ -4978,9 +4978,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scratch" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52" +checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2" [[package]] name = "self_cell" @@ -5506,7 +5506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", - "zerovec 0.11.2", + "zerovec 0.11.4", ] [[package]] @@ -6852,9 +6852,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke 0.8.0", "zerofrom", diff --git a/library/Cargo.lock b/library/Cargo.lock index 09228825086ee..4b06f14c7eea7 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "rustc-std-workspace-alloc", "rustc-std-workspace-core", diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index d0eeab2206237..e42f266391e2f 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -77,22 +77,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -156,9 +156,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.31" +version = "1.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" +checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" dependencies = [ "shlex", ] @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.42" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882" +checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.42" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966" +checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" dependencies = [ "anstream", "anstyle", @@ -208,9 +208,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.55" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5abde44486daf70c5be8b8f8f1b66c49f86236edf6fa2abadb4d961c4c6229a" +checksum = "67e4efcbb5da11a92e8a609233aa1e8a7d91e38de0be865f016d14700d45a7fd" dependencies = [ "clap", ] @@ -564,9 +564,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" [[package]] name = "heck" @@ -1406,9 +1406,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -2183,9 +2183,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", From ba350ff9110de2c75dab1e9530b63898bdc10154 Mon Sep 17 00:00:00 2001 From: Lee ByeongJun Date: Sun, 10 Aug 2025 22:50:14 +0900 Subject: [PATCH 036/252] fix: re-enable self-assignment --- compiler/rustc_passes/src/dead.rs | 6 ++- tests/ui/lint/dead-code/self-assign.rs | 17 ++++----- tests/ui/lint/dead-code/self-assign.stderr | 44 ++++++++++++++++++++++ 3 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 tests/ui/lint/dead-code/self-assign.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index fa9d0c7b1b7d4..d5d7cc5dc2e1a 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -172,7 +172,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } - #[allow(dead_code)] // FIXME(81658): should be used + lint reinstated after #83171 relands. fn handle_assign(&mut self, expr: &'tcx hir::Expr<'tcx>) { if self .typeck_results() @@ -189,7 +188,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } } - #[allow(dead_code)] // FIXME(81658): should be used + lint reinstated after #83171 relands. fn check_for_self_assign(&mut self, assign: &'tcx hir::Expr<'tcx>) { fn check_for_self_assign_helper<'tcx>( typeck_results: &'tcx ty::TypeckResults<'tcx>, @@ -576,6 +574,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { hir::ExprKind::OffsetOf(..) => { self.handle_offset_of(expr); } + hir::ExprKind::Assign(ref lhs, ..) => { + self.handle_assign(lhs); + self.check_for_self_assign(expr); + } _ => (), } diff --git a/tests/ui/lint/dead-code/self-assign.rs b/tests/ui/lint/dead-code/self-assign.rs index 357846baf2212..ce91f53cbf1e1 100644 --- a/tests/ui/lint/dead-code/self-assign.rs +++ b/tests/ui/lint/dead-code/self-assign.rs @@ -7,23 +7,20 @@ //! - `dead_code` lint expansion for self-assignments was implemented in #87129. //! - Unfortunately implementation components of #87129 had to be disabled as part of reverts //! #86212, #83171 (to revert #81473) to address regressions #81626 and #81658. -//! - Consequently, none of the following warnings are emitted. +//! - Re-enabled in current version to properly detect self-assignments. //@ check-pass -// Implementation of self-assignment `dead_code` lint expansions disabled due to reverts. -//@ known-bug: #75356 - #![allow(unused_assignments)] #![warn(dead_code)] fn main() { let mut x = 0; x = x; - // FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself + //~^ WARNING: useless assignment of variable of type `i32` to itself x = (x); - // FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself + //~^ WARNING: useless assignment of variable of type `i32` to itself x = {x}; // block expressions don't count as self-assignments @@ -32,10 +29,10 @@ fn main() { struct S<'a> { f: &'a str } let mut s = S { f: "abc" }; s = s; - // FIXME ~^ WARNING: useless assignment of variable of type `S` to itself + //~^ WARNING: useless assignment of variable of type `S<'_>` to itself s.f = s.f; - // FIXME ~^ WARNING: useless assignment of field of type `&str` to itself + //~^ WARNING: useless assignment of field of type `&str` to itself struct N0 { x: Box } @@ -44,11 +41,11 @@ fn main() { struct N3 { n: N2 }; let mut n3 = N3 { n: N2(N1 { n: N0 { x: Box::new(42) } }) }; n3.n.0.n.x = n3.n.0.n.x; - // FIXME ~^ WARNING: useless assignment of field of type `Box` to itself + //~^ WARNING: useless assignment of field of type `Box` to itself let mut t = (1, ((2, 3, (4, 5)),)); t.1.0.2.1 = t.1.0.2.1; - // FIXME ~^ WARNING: useless assignment of field of type `i32` to itself + //~^ WARNING: useless assignment of field of type `i32` to itself let mut y = 0; diff --git a/tests/ui/lint/dead-code/self-assign.stderr b/tests/ui/lint/dead-code/self-assign.stderr new file mode 100644 index 0000000000000..408ebdb658b5a --- /dev/null +++ b/tests/ui/lint/dead-code/self-assign.stderr @@ -0,0 +1,44 @@ +warning: useless assignment of variable of type `i32` to itself + --> $DIR/self-assign.rs:19:5 + | +LL | x = x; + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/self-assign.rs:15:9 + | +LL | #![warn(dead_code)] + | ^^^^^^^^^ + +warning: useless assignment of variable of type `i32` to itself + --> $DIR/self-assign.rs:22:5 + | +LL | x = (x); + | ^^^^^^^ + +warning: useless assignment of variable of type `S<'_>` to itself + --> $DIR/self-assign.rs:31:5 + | +LL | s = s; + | ^^^^^ + +warning: useless assignment of field of type `&str` to itself + --> $DIR/self-assign.rs:34:5 + | +LL | s.f = s.f; + | ^^^^^^^^^ + +warning: useless assignment of field of type `Box` to itself + --> $DIR/self-assign.rs:43:5 + | +LL | n3.n.0.n.x = n3.n.0.n.x; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: useless assignment of field of type `i32` to itself + --> $DIR/self-assign.rs:47:5 + | +LL | t.1.0.2.1 = t.1.0.2.1; + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: 6 warnings emitted + From bc14ad38a394df0e74eb6e204d75038a8cf6ef99 Mon Sep 17 00:00:00 2001 From: Pierre Tardy Date: Wed, 6 Aug 2025 16:18:25 +0200 Subject: [PATCH 037/252] strip prefix of temporary file names when it exceeds filesystem name length limit When doing lto, rustc generates filenames that are concatenating many information. In the case of this testcase, it is concatenating crate name and rust file name, plus some hash, and the extension. In some other cases it will concatenate even more information reducing the maximum effective crate name to about 110 chars on linux filesystems where filename max length is 255 This commit is ensuring that the temporary file names are limited in size, while still reasonabily ensuring the unicity (with hashing of the stripped part) --- compiler/rustc_session/src/config.rs | 23 ++++++++++++++-- tests/run-make/lto-long-filenames/main.rs | 7 +++++ tests/run-make/lto-long-filenames/rmake.rs | 32 ++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 tests/run-make/lto-long-filenames/main.rs create mode 100644 tests/run-make/lto-long-filenames/rmake.rs diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index cfeadf3c7595a..ac6eeca300775 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -16,10 +16,11 @@ use std::{cmp, fmt, fs, iter}; use externs::{ExternOpt, split_extern_opt}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{StableHasher, StableOrd, ToStableHashKey}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagArgValue, DiagCtxtFlags, IntoDiagArg}; use rustc_feature::UnstableFeatures; +use rustc_hashes::Hash64; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; @@ -1198,7 +1199,25 @@ pub struct OutputFilenames { pub const RLINK_EXT: &str = "rlink"; pub const RUST_CGU_EXT: &str = "rcgu"; pub const DWARF_OBJECT_EXT: &str = "dwo"; +pub const MAX_FILENAME_LENGTH: usize = 143; // ecryptfs limits filenames to 143 bytes see #49914 +/// Ensure the filename is not too long, as some filesystems have a limit. +/// If the filename is too long, hash part of it and append the hash to the filename. +/// This is a workaround for long crate names generating overly long filenames. +fn maybe_strip_file_name(mut path: PathBuf) -> PathBuf { + if path.file_name().map_or(0, |name| name.len()) > MAX_FILENAME_LENGTH { + let filename = path.file_name().unwrap().to_string_lossy(); + let hash_len = 64 / 4; // Hash64 is 64 bits encoded in hex + let stripped_len = filename.len() - MAX_FILENAME_LENGTH + hash_len; + + let mut hasher = StableHasher::new(); + filename[..stripped_len].hash(&mut hasher); + let hash = hasher.finish::(); + + path.set_file_name(format!("{:x}-{}", hash, &filename[stripped_len..])); + } + path +} impl OutputFilenames { pub fn new( out_directory: PathBuf, @@ -1291,7 +1310,7 @@ impl OutputFilenames { } let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory); - self.with_directory_and_extension(temps_directory, &extension) + maybe_strip_file_name(self.with_directory_and_extension(temps_directory, &extension)) } pub fn temp_path_for_diagnostic(&self, ext: &str) -> PathBuf { diff --git a/tests/run-make/lto-long-filenames/main.rs b/tests/run-make/lto-long-filenames/main.rs new file mode 100644 index 0000000000000..daedff5c05fc1 --- /dev/null +++ b/tests/run-make/lto-long-filenames/main.rs @@ -0,0 +1,7 @@ +// This file has very long lines, but there is no way to avoid it as we are testing +// long crate names. so: +// ignore-tidy-linelength + +extern crate generated_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_crate_name; + +fn main() {} diff --git a/tests/run-make/lto-long-filenames/rmake.rs b/tests/run-make/lto-long-filenames/rmake.rs new file mode 100644 index 0000000000000..9e0ba63e9f5b8 --- /dev/null +++ b/tests/run-make/lto-long-filenames/rmake.rs @@ -0,0 +1,32 @@ +// This file has very long lines, but there is no way to avoid it as we are testing +// long crate names. so: +// ignore-tidy-linelength + +// A variant of the smoke test to check that link time optimization +// (LTO) is accepted by the compiler, and that +// passing its various flags still results in successful compilation, even for very long crate names. +// See https://github.com/rust-lang/rust/issues/49914 + +//@ ignore-cross-compile + +use std::fs; + +use run_make_support::{rfs, rustc}; + +// This test make sure we don't get such following error: +// error: could not write output to generated_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_crate_name.generated_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_crate_name.9384edb61bfd127c-cgu.0.rcgu.o: File name too long +// as reported in issue #49914 +fn main() { + let lto_flags = ["-Clto", "-Clto=yes", "-Clto=off", "-Clto=thin", "-Clto=fat"]; + let aux_file = "generated_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_large_crate_name.rs"; + // The auxiliary file is used to test long crate names. + // The file name is intentionally long to test the handling of long filenames. + // We don't commit it to avoid issues with Windows paths which have known limitations for the full path length. + // Posix usually only have a limit for the length of the file name. + rfs::write(aux_file, "#![crate_type = \"rlib\"]\n"); + + for flag in lto_flags { + rustc().input(aux_file).arg(flag).run(); + rustc().input("main.rs").arg(flag).run(); + } +} From de13718c66965852ba8970781908fa1eda9a54b9 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Sun, 10 Aug 2025 23:02:53 +0800 Subject: [PATCH 038/252] test: Add rustdoc test for enum negative overflow --- tests/rustdoc/enum/enum-variant-value.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/rustdoc/enum/enum-variant-value.rs b/tests/rustdoc/enum/enum-variant-value.rs index 1670de8a24f17..9cc85dfe10dca 100644 --- a/tests/rustdoc/enum/enum-variant-value.rs +++ b/tests/rustdoc/enum/enum-variant-value.rs @@ -189,3 +189,25 @@ pub use bar::P; //@ has - '//*[@id="variant.A"]/h3' 'A(u32)' //@ matches - '//*[@id="variant.B"]/h3' '^B$' pub use bar::Q; + +// Ensure signed implicit discriminants are rendered correctly after a negative explicit value. +//@ has 'foo/enum.R.html' +//@ has - '//*[@class="rust item-decl"]/code' 'A = -2,' +//@ has - '//*[@class="rust item-decl"]/code' 'B = -1,' +//@ matches - '//*[@id="variant.A"]/h3' '^A = -2$' +//@ matches - '//*[@id="variant.B"]/h3' '^B = -1$' +pub enum R { + A = -2, + B, +} + +// Also check that incrementing -1 yields 0 for the next implicit variant. +//@ has 'foo/enum.S.html' +//@ has - '//*[@class="rust item-decl"]/code' 'A = -1,' +//@ has - '//*[@class="rust item-decl"]/code' 'B = 0,' +//@ matches - '//*[@id="variant.A"]/h3' '^A = -1$' +//@ matches - '//*[@id="variant.B"]/h3' '^B = 0$' +pub enum S { + A = -1, + B, +} From 20a134f5f0fb5a68025143d0cd24cf4e4783819b Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Sun, 10 Aug 2025 23:33:23 +0800 Subject: [PATCH 039/252] rustdoc: Use `discr`s `Display` impl to render the value with the correct signedness --- src/librustdoc/html/render/print_item.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 02ee34aaac680..759f53974f573 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1656,11 +1656,9 @@ fn display_c_like_variant( } else if should_show_enum_discriminant { let adt_def = cx.tcx().adt_def(enum_def_id); let discr = adt_def.discriminant_for_variant(cx.tcx(), index); - if discr.ty.is_signed() { - write!(w, "{} = {}", name.as_str(), discr.val as i128)?; - } else { - write!(w, "{} = {}", name.as_str(), discr.val)?; - } + // Use `discr`'s `Display` impl to render the value with the correct + // signedness, including proper sign-extension for signed types. + write!(w, "{} = {}", name.as_str(), discr)?; } else { write!(w, "{name}")?; } From 38df15805ba5be78d70c515f1d585ee6be95e13b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 10 Aug 2025 16:17:26 -0700 Subject: [PATCH 040/252] cfg_select: Support unbraced expressions When operating on expressions, `cfg_select!` can now handle expressions without braces. (It still requires braces for other things, such as items.) Expand the test coverage and documentation accordingly. --- compiler/rustc_parse/src/parser/cfg_select.rs | 30 ++++++++++------ library/core/src/macros/mod.rs | 5 +-- tests/ui/macros/cfg_select.rs | 36 +++++++++++++++++-- tests/ui/macros/cfg_select.stderr | 14 +++----- 4 files changed, 60 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs index 2c6fb224d70d6..08a71db4de853 100644 --- a/compiler/rustc_parse/src/parser/cfg_select.rs +++ b/compiler/rustc_parse/src/parser/cfg_select.rs @@ -1,11 +1,12 @@ use rustc_ast::token::Token; use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::util::classify; use rustc_ast::{MetaItemInner, token}; use rustc_errors::PResult; use rustc_span::Span; use crate::exp; -use crate::parser::Parser; +use crate::parser::{AttrWrapper, ForceCollect, Parser, Restrictions, Trailing, UsePreAttrPos}; pub enum CfgSelectPredicate { Cfg(MetaItemInner), @@ -23,19 +24,26 @@ pub struct CfgSelectBranches { pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>, } -/// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where -/// the surrounding braces are stripped. +/// Parses a `TokenTree` consisting either of `{ /* ... */ }` (and strip the braces) or an +/// expression followed by a comma (and strip the comma). fn parse_token_tree<'a>(p: &mut Parser<'a>) -> PResult<'a, TokenStream> { - // Generate an error if the `=>` is not followed by `{`. - if p.token != token::OpenBrace { - p.expect(exp!(OpenBrace))?; + if p.token == token::OpenBrace { + // Strip the outer '{' and '}'. + match p.parse_token_tree() { + TokenTree::Token(..) => unreachable!("because of the expect above"), + TokenTree::Delimited(.., tts) => return Ok(tts), + } } - - // Strip the outer '{' and '}'. - match p.parse_token_tree() { - TokenTree::Token(..) => unreachable!("because of the expect above"), - TokenTree::Delimited(.., tts) => Ok(tts), + let expr = p.collect_tokens(None, AttrWrapper::empty(), ForceCollect::Yes, |p, _| { + p.parse_expr_res(Restrictions::STMT_EXPR, AttrWrapper::empty()) + .map(|(expr, _)| (expr, Trailing::No, UsePreAttrPos::No)) + })?; + if !classify::expr_is_complete(&expr) && p.token != token::CloseBrace && p.token != token::Eof { + p.expect(exp!(Comma))?; + } else { + let _ = p.eat(exp!(Comma)); } + Ok(TokenStream::from_ast(&expr)) } pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches> { diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index c59290a757b67..db8b527d59312 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -223,13 +223,14 @@ pub macro assert_matches { /// } /// ``` /// -/// The `cfg_select!` macro can also be used in expression position: +/// The `cfg_select!` macro can also be used in expression position, with or without braces on the +/// right-hand side: /// /// ``` /// #![feature(cfg_select)] /// /// let _some_string = cfg_select! { -/// unix => { "With great power comes great electricity bills" } +/// unix => "With great power comes great electricity bills", /// _ => { "Behind every successful diet is an unwatched pizza" } /// }; /// ``` diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index 461d2e0e8c1f5..9241141ef9a6c 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -8,10 +8,42 @@ fn print() { }); } -fn arm_rhs_must_be_in_braces() -> i32 { +fn print_2() { + println!(cfg_select! { + unix => "unix", + _ => "not unix", + }); +} + +fn arm_rhs_expr_1() -> i32 { cfg_select! { true => 1 - //~^ ERROR: expected `{`, found `1` + } +} + +fn arm_rhs_expr_2() -> i32 { + cfg_select! { + true => 1, + false => 2 + } +} + +fn arm_rhs_expr_3() -> i32 { + cfg_select! { + true => 1, + false => 2, + true => { 42 } + false => -1 as i32, + true => 2 + 2, + false => "", + true => if true { 42 } else { 84 } + false => if true { 42 } else { 84 }, + true => return 42, + false => loop {} + true => (1, 2), + false => (1, 2,), + true => todo!(), + false => println!("hello"), } } diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index 6c18a7c189dcc..7280f35c16f93 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -1,11 +1,5 @@ -error: expected `{`, found `1` - --> $DIR/cfg_select.rs:13:17 - | -LL | true => 1 - | ^ expected `{` - warning: unreachable predicate - --> $DIR/cfg_select.rs:20:5 + --> $DIR/cfg_select.rs:52:5 | LL | _ => {} | - always matches @@ -13,7 +7,7 @@ LL | true => {} | ^^^^ this predicate is never reached error: none of the predicates in this `cfg_select` evaluated to true - --> $DIR/cfg_select.rs:24:1 + --> $DIR/cfg_select.rs:56:1 | LL | / cfg_select! { LL | | @@ -22,10 +16,10 @@ LL | | } | |_^ error: none of the predicates in this `cfg_select` evaluated to true - --> $DIR/cfg_select.rs:29:1 + --> $DIR/cfg_select.rs:61:1 | LL | cfg_select! {} | ^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted From b5cee774acbc627e827caba71ec2d496798311c7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 11 Aug 2025 01:46:31 +0000 Subject: [PATCH 041/252] Remove unnecessary UnsatisfiedConst reporting logic --- .../traits/fulfillment_errors.rs | 26 +------------------ .../src/error_reporting/traits/mod.rs | 2 -- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 62859329de356..214a6e86d391a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -37,7 +37,6 @@ use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote}; use super::suggestions::get_explanation_based_on_obligation; use super::{ ArgKind, CandidateSimilarity, FindExprBySpan, GetSafeTransmuteErrorAndReason, ImplCandidate, - UnsatisfiedConst, }; use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::infer::TyCategory; @@ -374,13 +373,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - let UnsatisfiedConst(unsatisfied_const) = self - .maybe_add_note_for_unsatisfied_const( - leaf_trait_predicate, - &mut err, - span, - ); - if let Some((msg, span)) = type_def { err.span_label(span, msg); } @@ -506,7 +498,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, is_fn_trait, suggested, - unsatisfied_const, ); // Changing mutability doesn't make a difference to whether we have @@ -2716,7 +2707,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span: Span, is_fn_trait: bool, suggested: bool, - unsatisfied_const: bool, ) { let body_def_id = obligation.cause.body_id; let span = if let ObligationCauseCode::BinOp { rhs_span: Some(rhs_span), .. } = @@ -2763,10 +2753,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.tcx.def_span(trait_def_id), crate::fluent_generated::trait_selection_trait_has_no_impls, ); - } else if !suggested - && !unsatisfied_const - && trait_predicate.polarity() == ty::PredicatePolarity::Positive - { + } else if !suggested && trait_predicate.polarity() == ty::PredicatePolarity::Positive { // Can't show anything else useful, try to find similar impls. let impl_candidates = self.find_similar_impl_candidates(trait_predicate); if !self.report_similar_impl_candidates( @@ -2878,17 +2865,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn maybe_add_note_for_unsatisfied_const( - &self, - _trait_predicate: ty::PolyTraitPredicate<'tcx>, - _err: &mut Diag<'_>, - _span: Span, - ) -> UnsatisfiedConst { - let unsatisfied_const = UnsatisfiedConst(false); - // FIXME(const_trait_impl) - unsatisfied_const - } - fn report_closure_error( &self, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 1d8b934cef3f0..c8500b2d9d4ab 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -51,8 +51,6 @@ enum GetSafeTransmuteErrorAndReason { Error { err_msg: String, safe_transmute_explanation: Option }, } -struct UnsatisfiedConst(pub bool); - /// Crude way of getting back an `Expr` from a `Span`. pub struct FindExprBySpan<'hir> { pub span: Span, From 50323736ad4e7c7b52038ceb0e0fc540f3da4c29 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 11 Aug 2025 01:45:13 +0000 Subject: [PATCH 042/252] Remove unnecessary trait predicate eq function --- .../src/impl_wf_check/min_specialization.rs | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 0043f0c71176a..b38639ed8c624 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -390,45 +390,13 @@ fn check_predicates<'tcx>( let mut res = Ok(()); for (clause, span) in impl1_predicates { - if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(clause.as_predicate(), *pred2)) - { + if !impl2_predicates.iter().any(|&pred2| clause.as_predicate() == pred2) { res = res.and(check_specialization_on(tcx, clause, span)) } } res } -/// Checks if some predicate on the specializing impl (`predicate1`) is the same -/// as some predicate on the base impl (`predicate2`). -/// -/// This basically just checks syntactic equivalence, but is a little more -/// forgiving since we want to equate `T: Tr` with `T: [const] Tr` so this can work: -/// -/// ```ignore (illustrative) -/// #[rustc_specialization_trait] -/// trait Specialize { } -/// -/// impl Tr for T { } -/// impl const Tr for T { } -/// ``` -/// -/// However, we *don't* want to allow the reverse, i.e., when the bound on the -/// specializing impl is not as const as the bound on the base impl: -/// -/// ```ignore (illustrative) -/// impl const Tr for T { } -/// impl const Tr for T { } // should be T: [const] Bound -/// ``` -/// -/// So we make that check in this function and try to raise a helpful error message. -fn trait_predicates_eq<'tcx>( - predicate1: ty::Predicate<'tcx>, - predicate2: ty::Predicate<'tcx>, -) -> bool { - // FIXME(const_trait_impl) - predicate1 == predicate2 -} - #[instrument(level = "debug", skip(tcx))] fn check_specialization_on<'tcx>( tcx: TyCtxt<'tcx>, From 42475af2f9fd4a96ff9d97390e93b7fb8461cd8c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 11 Aug 2025 01:47:13 +0000 Subject: [PATCH 043/252] Remove unnecessary comment --- compiler/rustc_hir_typeck/src/callee.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 48bb45de53eb4..7afc555b5980e 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -910,7 +910,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // const stability checking here too, I guess. if self.tcx.is_conditionally_const(callee_did) { let q = self.tcx.const_conditions(callee_did); - // FIXME(const_trait_impl): Use this span with a better cause code. for (idx, (cond, pred_span)) in q.instantiate(self.tcx, callee_args).into_iter().enumerate() { From ebef9d7f6387fb0541a0dab48d1cd1f86556df04 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 8 Aug 2025 12:39:30 +0200 Subject: [PATCH 044/252] Set dead_on_return attribute for indirect arguments Set the dead_on_return attribute (added in LLVM 21) for arguments that are passed indirectly, but not byval. This indicates that the value of the argument on return does not matter, enabling additional dead store elimination. --- compiler/rustc_codegen_llvm/src/abi.rs | 12 ++++++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 7 +++++ tests/codegen-llvm/addr-of-mutate.rs | 6 ++-- tests/codegen-llvm/dead_on_return.rs | 31 +++++++++++++++++++ tests/codegen-llvm/function-arguments.rs | 2 +- .../loongarch-abi/loongarch64-lp64d-abi.rs | 2 +- 7 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 tests/codegen-llvm/dead_on_return.rs diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 009e7e2487b66..043123fcab2cb 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -24,6 +24,7 @@ use crate::attributes::{self, llfn_attrs_from_instance}; use crate::builder::Builder; use crate::context::CodegenCx; use crate::llvm::{self, Attribute, AttributePlace}; +use crate::llvm_util; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; @@ -500,7 +501,16 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } } PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => { - apply(attrs); + let i = apply(attrs); + if cx.sess().opts.optimize != config::OptLevel::No + && llvm_util::get_version() >= (21, 0, 0) + { + attributes::apply_to_llfn( + llfn, + llvm::AttributePlace::Argument(i), + &[llvm::AttributeKind::DeadOnReturn.create_attr(cx.llcx)], + ); + } } PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => { assert!(!on_stack); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 75d3d27f74e10..ad3c3d5932eef 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -249,6 +249,7 @@ pub(crate) enum AttributeKind { FnRetThunkExtern = 41, Writable = 42, DeadOnUnwind = 43, + DeadOnReturn = 44, } /// LLVMIntPredicate diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 588d867bbbf4e..cd4f80f808c65 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -277,6 +277,7 @@ enum class LLVMRustAttributeKind { FnRetThunkExtern = 41, Writable = 42, DeadOnUnwind = 43, + DeadOnReturn = 44, }; static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) { @@ -369,6 +370,12 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) { return Attribute::Writable; case LLVMRustAttributeKind::DeadOnUnwind: return Attribute::DeadOnUnwind; + case LLVMRustAttributeKind::DeadOnReturn: +#if LLVM_VERSION_GE(21, 0) + return Attribute::DeadOnReturn; +#else + report_fatal_error("DeadOnReturn attribute requires LLVM 21 or later"); +#endif } report_fatal_error("bad LLVMRustAttributeKind"); } diff --git a/tests/codegen-llvm/addr-of-mutate.rs b/tests/codegen-llvm/addr-of-mutate.rs index 14bc4b8ab28ce..7166906528939 100644 --- a/tests/codegen-llvm/addr-of-mutate.rs +++ b/tests/codegen-llvm/addr-of-mutate.rs @@ -5,7 +5,7 @@ // Test for the absence of `readonly` on the argument when it is mutated via `&raw const`. // See . -// CHECK: i8 @foo(ptr noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x) +// CHECK: i8 @foo(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x) #[no_mangle] pub fn foo(x: [u8; 128]) -> u8 { let ptr = core::ptr::addr_of!(x).cast_mut(); @@ -15,7 +15,7 @@ pub fn foo(x: [u8; 128]) -> u8 { x[0] } -// CHECK: i1 @second(ptr noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) +// CHECK: i1 @second(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) #[no_mangle] pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut(); @@ -24,7 +24,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { } // If going through a deref (and there are no other mutating accesses), then `readonly` is fine. -// CHECK: i1 @third(ptr noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) +// CHECK: i1 @third(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) #[no_mangle] pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut(); diff --git a/tests/codegen-llvm/dead_on_return.rs b/tests/codegen-llvm/dead_on_return.rs new file mode 100644 index 0000000000000..3c1940d6ba7c9 --- /dev/null +++ b/tests/codegen-llvm/dead_on_return.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -C opt-level=3 +//@ min-llvm-version: 21 + +#![crate_type = "lib"] +#![allow(unused_assignments, unused_variables)] + +// Check that the old string is deallocated, but a new one is not initialized. +#[unsafe(no_mangle)] +pub fn test_str_new(mut s: String) { + // CHECK-LABEL: @test_str_new + // CHECK: __rust_dealloc + // CHECK-NOT: store + s = String::new(); +} + +#[unsafe(no_mangle)] +pub fn test_str_take(mut x: String) -> String { + // CHECK-LABEL: @test_str_take + // CHECK-NEXT: {{.*}}: + // CHECK-NEXT: call void @llvm.memcpy + // CHECK-NEXT: ret + core::mem::take(&mut x) +} + +#[unsafe(no_mangle)] +pub fn test_array_store(mut x: [u32; 100]) { + // CHECK-LABEL: @test_array_store + // CHECK-NEXT: {{.*}}: + // CHECK-NEXT: ret + x[0] = 1; +} diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs index c8cd8526ae513..a3fafbe6f821c 100644 --- a/tests/codegen-llvm/function-arguments.rs +++ b/tests/codegen-llvm/function-arguments.rs @@ -134,7 +134,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {} #[no_mangle] pub fn notunpin_borrow(_: &NotUnpin) {} -// CHECK: @indirect_struct(ptr noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1) +// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1) #[no_mangle] pub fn indirect_struct(_: S) {} diff --git a/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs index 93c8d60930b75..4666342a16a31 100644 --- a/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs +++ b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs @@ -256,7 +256,7 @@ pub struct IntDoubleInt { c: i32, } -// CHECK: define void @f_int_double_int_s_arg(ptr noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a) +// CHECK: define void @f_int_double_int_s_arg(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a) #[no_mangle] pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} From 99769bc301d6e9187d0e7881bb36162fd48fd573 Mon Sep 17 00:00:00 2001 From: Stypox Date: Thu, 31 Jul 2025 12:16:18 +0200 Subject: [PATCH 045/252] Add tracing to resolve-related functions --- .../rustc_const_eval/src/interpret/call.rs | 23 ++++++++----- .../rustc_const_eval/src/interpret/cast.rs | 34 +++++++++++-------- .../src/interpret/eval_context.rs | 1 + .../rustc_const_eval/src/interpret/step.rs | 6 +++- src/tools/miri/src/helpers.rs | 2 ++ 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index a0160d1188d08..18c145db6afb1 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -736,13 +736,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); - let concrete_method = Instance::expect_resolve_for_vtable( - tcx, - self.typing_env, - def_id, - virtual_instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), - self.cur_span(), - ); + let concrete_method = { + let _trace = enter_trace_span!(M, resolve::expect_resolve_for_vtable, ?def_id); + Instance::expect_resolve_for_vtable( + tcx, + self.typing_env, + def_id, + virtual_instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), + self.cur_span(), + ) + }; assert_eq!(concrete_instance, concrete_method); } @@ -825,7 +828,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { place } }; - let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty); + let instance = { + let _trace = + enter_trace_span!(M, resolve::resolve_drop_in_place, ty = ?place.layout.ty); + ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty) + }; let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; let arg = self.mplace_to_ref(&place)?; diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index de4fbc7b4752e..e3afeda5b7c97 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -16,8 +16,8 @@ use super::{ FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, interp_ok, throw_ub, throw_ub_custom, }; -use crate::fluent_generated as fluent; use crate::interpret::Writeable; +use crate::{enter_trace_span, fluent_generated as fluent}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn cast( @@ -81,13 +81,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // The src operand does not matter, just its type match *src.layout.ty.kind() { ty::FnDef(def_id, args) => { - let instance = ty::Instance::resolve_for_fn_ptr( - *self.tcx, - self.typing_env, - def_id, - args, - ) - .ok_or_else(|| err_inval!(TooGeneric))?; + let instance = { + let _trace = enter_trace_span!(M, resolve::resolve_for_fn_ptr, ?def_id); + ty::Instance::resolve_for_fn_ptr( + *self.tcx, + self.typing_env, + def_id, + args, + ) + .ok_or_else(|| err_inval!(TooGeneric))? + }; let fn_ptr = self.fn_ptr(FnVal::Instance(instance)); self.write_pointer(fn_ptr, dest)?; @@ -114,12 +117,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // The src operand does not matter, just its type match *src.layout.ty.kind() { ty::Closure(def_id, args) => { - let instance = ty::Instance::resolve_closure( - *self.tcx, - def_id, - args, - ty::ClosureKind::FnOnce, - ); + let instance = { + let _trace = enter_trace_span!(M, resolve::resolve_closure, ?def_id); + ty::Instance::resolve_closure( + *self.tcx, + def_id, + args, + ty::ClosureKind::FnOnce, + ) + }; let fn_ptr = self.fn_ptr(FnVal::Instance(instance)); self.write_pointer(fn_ptr, dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index c4b705d7124ed..d0e9b5c71c6e2 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -344,6 +344,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { def: DefId, args: GenericArgsRef<'tcx>, ) -> InterpResult<'tcx, ty::Instance<'tcx>> { + let _trace = enter_trace_span!(M, resolve::try_resolve, def = ?def); trace!("resolve: {:?}, {:#?}", def, args); trace!("typing_env: {:#?}", self.typing_env); trace!("args: {:#?}", args); diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 9df49c0f4ccdf..04871faa3e621 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -560,7 +560,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { "Async Drop must be expanded or reset to sync in runtime MIR" ); let place = self.eval_place(place)?; - let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty); + let instance = { + let _trace = + enter_trace_span!(M, resolve::resolve_drop_in_place, ty = ?place.layout.ty); + Instance::resolve_drop_in_place(*self.tcx, place.layout.ty) + }; if let ty::InstanceKind::DropGlue(_, None) = instance.def { // This is the branch we enter if and only if the dropped type has no drop glue // whatsoever. This can happen as a result of monomorphizing a drop of a diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 43cb1c9ae053c..20b95f3b03490 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -32,6 +32,8 @@ pub enum AccessKind { /// /// A `None` namespace indicates we are looking for a module. fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option) -> Option { + let _trace = enter_trace_span!("try_resolve_did", ?path); + /// Yield all children of the given item, that have the given name. fn find_children<'tcx: 'a, 'a>( tcx: TyCtxt<'tcx>, From cd4676c40dad98fffb3910854454e58303370f0a Mon Sep 17 00:00:00 2001 From: Stypox Date: Mon, 11 Aug 2025 14:45:46 +0200 Subject: [PATCH 046/252] Turn _span into _trace as trace span name _span could possibly be confused with the Span type in rustc --- .../rustc_const_eval/src/interpret/call.rs | 4 ++-- .../src/interpret/eval_context.rs | 8 +++---- .../rustc_const_eval/src/interpret/operand.rs | 4 ++-- .../rustc_const_eval/src/interpret/place.rs | 2 +- .../rustc_const_eval/src/interpret/step.rs | 4 ++-- .../rustc_const_eval/src/interpret/util.rs | 14 +++++------ .../src/interpret/validity.rs | 2 +- src/tools/miri/src/borrow_tracker/mod.rs | 24 +++++++++---------- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index a0160d1188d08..b1cc0cc2878aa 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -346,7 +346,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { destination: &PlaceTy<'tcx, M::Provenance>, mut cont: ReturnContinuation, ) -> InterpResult<'tcx> { - let _span = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty); + let _trace = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty); // Compute callee information. // FIXME: for variadic support, do we have to somehow determine callee's extra_args? @@ -527,7 +527,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { target: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { - let _span = + let _trace = enter_trace_span!(M, step::init_fn_call, tracing_separate_thread = Empty, ?fn_val) .or_if_tracing_disabled(|| trace!("init_fn_call: {:#?}", fn_val)); diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index c4b705d7124ed..d4f2bb8257db0 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -113,7 +113,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// See [LayoutOf::layout_of] for the original documentation. #[inline(always)] pub fn layout_of(&self, ty: Ty<'tcx>) -> >::LayoutOfResult { - let _span = enter_trace_span!(M, layouting::layout_of, ty = ?ty.kind()); + let _trace = enter_trace_span!(M, layouting::layout_of, ty = ?ty.kind()); LayoutOf::layout_of(self, ty) } @@ -126,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List>, ) -> >::FnAbiOfResult { - let _span = enter_trace_span!(M, layouting::fn_abi_of_fn_ptr, ?sig, ?extra_args); + let _trace = enter_trace_span!(M, layouting::fn_abi_of_fn_ptr, ?sig, ?extra_args); FnAbiOf::fn_abi_of_fn_ptr(self, sig, extra_args) } @@ -139,7 +139,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List>, ) -> >::FnAbiOfResult { - let _span = enter_trace_span!(M, layouting::fn_abi_of_instance, ?instance, ?extra_args); + let _trace = enter_trace_span!(M, layouting::fn_abi_of_instance, ?instance, ?extra_args); FnAbiOf::fn_abi_of_instance(self, instance, extra_args) } } @@ -322,7 +322,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { frame: &Frame<'tcx, M::Provenance, M::FrameExtra>, value: T, ) -> Result { - let _span = enter_trace_span!( + let _trace = enter_trace_span!( M, "instantiate_from_frame_and_normalize_erasing_regions", "{}", diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 1454180907001..53a440b646b0b 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -773,7 +773,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { mir_place: mir::Place<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - let _span = enter_trace_span!( + let _trace = enter_trace_span!( M, step::eval_place_to_op, ?mir_place, @@ -823,7 +823,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { mir_op: &mir::Operand<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - let _span = + let _trace = enter_trace_span!(M, step::eval_operand, ?mir_op, tracing_separate_thread = Empty); use rustc_middle::mir::Operand::*; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 45c4edb850373..6ff50dc700fa0 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -526,7 +526,7 @@ where &self, mir_place: mir::Place<'tcx>, ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> { - let _span = + let _trace = enter_trace_span!(M, step::eval_place, ?mir_place, tracing_separate_thread = Empty); let mut place = self.local_to_place(mir_place.local)?; diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 9df49c0f4ccdf..76e470b69dce3 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -76,7 +76,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// /// This does NOT move the statement counter forward, the caller has to do that! pub fn eval_statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { - let _span = enter_trace_span!( + let _trace = enter_trace_span!( M, step::eval_statement, stmt = ?stmt.kind, @@ -465,7 +465,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { - let _span = enter_trace_span!( + let _trace = enter_trace_span!( M, step::eval_terminator, terminator = ?terminator.kind, diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 71800950faab2..72bee34540656 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -85,11 +85,11 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan { /// # let my_debug_var = String::new(); /// // logs a span named "hello" with a field named "arg" of value 42 (works only because /// // 42 implements the tracing::Value trait, otherwise use one of the options below) -/// let _span = enter_trace_span!(M, "hello", arg = 42); +/// let _trace = enter_trace_span!(M, "hello", arg = 42); /// // logs a field called "my_display_var" using the Display implementation -/// let _span = enter_trace_span!(M, "hello", %my_display_var); +/// let _trace = enter_trace_span!(M, "hello", %my_display_var); /// // logs a field called "my_debug_var" using the Debug implementation -/// let _span = enter_trace_span!(M, "hello", ?my_debug_var); +/// let _trace = enter_trace_span!(M, "hello", ?my_debug_var); /// ``` /// /// ### `NAME::SUBNAME` syntax @@ -107,8 +107,8 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan { /// # use rustc_const_eval::enter_trace_span; /// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>; /// // for example, the first will expand to the second -/// let _span = enter_trace_span!(M, borrow_tracker::on_stack_pop, /* ... */); -/// let _span = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_pop", /* ... */); +/// let _trace = enter_trace_span!(M, borrow_tracker::on_stack_pop, /* ... */); +/// let _trace = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_pop", /* ... */); /// ``` /// /// ### `tracing_separate_thread` parameter @@ -124,7 +124,7 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan { /// ```rust /// # use rustc_const_eval::enter_trace_span; /// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>; -/// let _span = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty); +/// let _trace = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty); /// ``` /// /// ### Executing something else when tracing is disabled @@ -136,7 +136,7 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan { /// # use rustc_const_eval::enter_trace_span; /// # use rustc_const_eval::interpret::EnteredTraceSpan; /// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>; -/// let _span = enter_trace_span!(M, step::eval_statement) +/// let _trace = enter_trace_span!(M, step::eval_statement) /// .or_if_tracing_disabled(|| tracing::info!("eval_statement")); /// ``` #[macro_export] diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index ed48f53c31056..ab0c0665d511c 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1415,7 +1415,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { recursive: bool, reset_provenance_and_padding: bool, ) -> InterpResult<'tcx> { - let _span = enter_trace_span!( + let _trace = enter_trace_span!( M, "validate_operand", "recursive={recursive}, reset_provenance_and_padding={reset_provenance_and_padding}, val={val:?}" diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index ec6c2c60ca9c6..89bd93edae127 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -260,7 +260,7 @@ impl GlobalStateInner { kind: MemoryKind, machine: &MiriMachine<'_>, ) -> AllocState { - let _span = enter_trace_span!(borrow_tracker::new_allocation, ?id, ?alloc_size, ?kind); + let _trace = enter_trace_span!(borrow_tracker::new_allocation, ?id, ?alloc_size, ?kind); match self.borrow_tracker_method { BorrowTrackerMethod::StackedBorrows => AllocState::StackedBorrows(Box::new(RefCell::new(Stacks::new_allocation( @@ -281,7 +281,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { kind: RetagKind, val: &ImmTy<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx>> { - let _span = enter_trace_span!(borrow_tracker::retag_ptr_value, ?kind, ?val.layout); + let _trace = enter_trace_span!(borrow_tracker::retag_ptr_value, ?kind, ?val.layout); let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -295,7 +295,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { kind: RetagKind, place: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { - let _span = enter_trace_span!(borrow_tracker::retag_place_contents, ?kind, ?place); + let _trace = enter_trace_span!(borrow_tracker::retag_place_contents, ?kind, ?place); let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -305,7 +305,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } fn protect_place(&mut self, place: &MPlaceTy<'tcx>) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - let _span = enter_trace_span!(borrow_tracker::protect_place, ?place); + let _trace = enter_trace_span!(borrow_tracker::protect_place, ?place); let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -315,7 +315,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } fn expose_tag(&self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> { - let _span = + let _trace = enter_trace_span!(borrow_tracker::expose_tag, alloc_id = alloc_id.0, tag = tag.0); let this = self.eval_context_ref(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; @@ -360,7 +360,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &self, frame: &Frame<'tcx, Provenance, FrameExtra<'tcx>>, ) -> InterpResult<'tcx> { - let _span = enter_trace_span!(borrow_tracker::on_stack_pop); + let _trace = enter_trace_span!(borrow_tracker::on_stack_pop); let this = self.eval_context_ref(); let borrow_tracker = this.machine.borrow_tracker.as_ref().unwrap(); // The body of this loop needs `borrow_tracker` immutably @@ -438,7 +438,7 @@ impl AllocState { range: AllocRange, machine: &MiriMachine<'tcx>, ) -> InterpResult<'tcx> { - let _span = enter_trace_span!(borrow_tracker::before_memory_read, alloc_id = alloc_id.0); + let _trace = enter_trace_span!(borrow_tracker::before_memory_read, alloc_id = alloc_id.0); match self { AllocState::StackedBorrows(sb) => sb.borrow_mut().before_memory_read(alloc_id, prov_extra, range, machine), @@ -460,7 +460,7 @@ impl AllocState { range: AllocRange, machine: &MiriMachine<'tcx>, ) -> InterpResult<'tcx> { - let _span = enter_trace_span!(borrow_tracker::before_memory_write, alloc_id = alloc_id.0); + let _trace = enter_trace_span!(borrow_tracker::before_memory_write, alloc_id = alloc_id.0); match self { AllocState::StackedBorrows(sb) => sb.get_mut().before_memory_write(alloc_id, prov_extra, range, machine), @@ -482,7 +482,7 @@ impl AllocState { size: Size, machine: &MiriMachine<'tcx>, ) -> InterpResult<'tcx> { - let _span = + let _trace = enter_trace_span!(borrow_tracker::before_memory_deallocation, alloc_id = alloc_id.0); match self { AllocState::StackedBorrows(sb) => @@ -493,7 +493,7 @@ impl AllocState { } pub fn remove_unreachable_tags(&self, tags: &FxHashSet) { - let _span = enter_trace_span!(borrow_tracker::remove_unreachable_tags); + let _trace = enter_trace_span!(borrow_tracker::remove_unreachable_tags); match self { AllocState::StackedBorrows(sb) => sb.borrow_mut().remove_unreachable_tags(tags), AllocState::TreeBorrows(tb) => tb.borrow_mut().remove_unreachable_tags(tags), @@ -508,7 +508,7 @@ impl AllocState { tag: BorTag, alloc_id: AllocId, // diagnostics ) -> InterpResult<'tcx> { - let _span = enter_trace_span!( + let _trace = enter_trace_span!( borrow_tracker::release_protector, alloc_id = alloc_id.0, tag = tag.0 @@ -523,7 +523,7 @@ impl AllocState { impl VisitProvenance for AllocState { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let _span = enter_trace_span!(borrow_tracker::visit_provenance); + let _trace = enter_trace_span!(borrow_tracker::visit_provenance); match self { AllocState::StackedBorrows(sb) => sb.visit_provenance(visit), AllocState::TreeBorrows(tb) => tb.visit_provenance(visit), From 6603fe1caa9aefea78aea19c587828cdcffc883d Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Sun, 3 Aug 2025 11:54:07 +0200 Subject: [PATCH 047/252] Port `#[allow_internal_unsafe]` to the new attribute system (attempt 2) --- .../src/attributes/macro_attrs.rs | 8 +++ compiler/rustc_attr_parsing/src/context.rs | 5 +- compiler/rustc_expand/src/base.rs | 5 +- .../rustc_hir/src/attrs/data_structures.rs | 3 ++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_hir/src/hir.rs | 1 + compiler/rustc_lint/src/builtin.rs | 20 +++++--- compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/check_attr.rs | 49 ++++++++++++++++--- compiler/rustc_passes/src/errors.rs | 4 +- tests/ui/attributes/malformed-attrs.stderr | 15 +++--- 11 files changed, 85 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 886f7a889d303..0779248e1a95e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -113,3 +113,11 @@ impl AttributeParser for MacroUseParser { Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state }) } } + +pub(crate) struct AllowInternalUnsafeParser; + +impl NoArgsAttributeParser for AllowInternalUnsafeParser { + const PATH: &[Symbol] = &[sym::allow_internal_unsafe]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; + const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span); +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 80dfdffdb5548..1420753a44ea2 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -33,7 +33,9 @@ use crate::attributes::lint_helpers::{ AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser, }; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; -use crate::attributes::macro_attrs::{MacroEscapeParser, MacroUseParser}; +use crate::attributes::macro_attrs::{ + AllowInternalUnsafeParser, MacroEscapeParser, MacroUseParser, +}; use crate::attributes::must_use::MustUseParser; use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser; use crate::attributes::non_exhaustive::NonExhaustiveParser; @@ -178,6 +180,7 @@ attribute_parsers!( Single, Single, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c234aa43c09c1..7da3bf27eb5c9 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -904,10 +904,7 @@ impl SyntaxExtension { find_attr!(attrs, AttributeKind::AllowInternalUnstable(i, _) => i) .map(|i| i.as_slice()) .unwrap_or_default(); - // FIXME(jdonszelman): allow_internal_unsafe isn't yet new-style - // let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe); - let allow_internal_unsafe = - ast::attr::find_by_name(attrs, sym::allow_internal_unsafe).is_some(); + let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe(_)); let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export) .and_then(|macro_export| macro_export.meta_item_list()) diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 5f4193154674a..e02edf5fe24db 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -249,6 +249,9 @@ pub enum AttributeKind { /// Represents `#[rustc_allow_incoherent_impl]`. AllowIncoherentImpl(Span), + /// Represents `#[allow_internal_unsafe]`. + AllowInternalUnsafe(Span), + /// Represents `#[allow_internal_unstable]`. AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index e3a7f0b97a8f0..7ce624dcc550a 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -16,6 +16,7 @@ impl AttributeKind { Align { .. } => No, AllowConstFnUnstable(..) => No, AllowIncoherentImpl(..) => No, + AllowInternalUnsafe(..) => Yes, AllowInternalUnstable(..) => Yes, AsPtr(..) => Yes, AutomaticallyDerived(..) => Yes, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 34db6f92d9288..0f63512b34c34 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1310,6 +1310,7 @@ impl AttributeExt for Attribute { Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span, Attribute::Parsed(AttributeKind::ShouldPanic { span, .. }) => *span, Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span, + Attribute::Parsed(AttributeKind::AllowInternalUnsafe(span)) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c893b7233755d..4ae0ef68534fd 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,6 +21,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::expr_to_string; +use rustc_attr_parsing::AttributeParser; use rustc_errors::{Applicability, LintDiagnostic}; use rustc_feature::GateIssue; use rustc_hir as hir; @@ -248,12 +249,6 @@ impl UnsafeCode { } impl EarlyLintPass for UnsafeCode { - fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { - if attr.has_name(sym::allow_internal_unsafe) { - self.report_unsafe(cx, attr.span, BuiltinUnsafe::AllowInternalUnsafe); - } - } - #[inline] fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { if let ast::ExprKind::Block(ref blk, _) = e.kind { @@ -312,6 +307,19 @@ impl EarlyLintPass for UnsafeCode { } } + ast::ItemKind::MacroDef(..) => { + if let Some(attr) = AttributeParser::parse_limited( + cx.builder.sess(), + &it.attrs, + sym::allow_internal_unsafe, + it.span, + DUMMY_NODE_ID, + Some(cx.builder.features()), + ) { + self.report_unsafe(cx, attr.span(), BuiltinUnsafe::AllowInternalUnsafe); + } + } + _ => {} } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6a28fe2617edf..4a1f01cc5c857 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -29,7 +29,7 @@ passes_allow_incoherent_impl = `rustc_allow_incoherent_impl` attribute should be applied to impl items .label = the only currently supported targets are inherent methods -passes_allow_internal_unstable = +passes_macro_only_attribute = attribute should be applied to a macro .label = not a macro diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 10c532b436aa1..d768aa6a8ddc3 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -207,6 +207,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => { self.check_const_continue(hir_id, *attr_span, target) } + Attribute::Parsed(AttributeKind::AllowInternalUnsafe(attr_span)) => { + self.check_allow_internal_unsafe(hir_id, *attr_span, span, target, attrs) + } Attribute::Parsed(AttributeKind::AllowInternalUnstable(_, first_span)) => { self.check_allow_internal_unstable(hir_id, *first_span, span, target, attrs) } @@ -413,7 +416,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // internal | sym::prelude_import | sym::panic_handler - | sym::allow_internal_unsafe | sym::lang | sym::needs_allocator | sym::default_lib_allocator @@ -2212,7 +2214,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. /// (Allows proc_macro functions) - // FIXME(jdonszelmann): if possible, move to attr parsing fn check_allow_internal_unstable( &self, hir_id: HirId, @@ -2220,6 +2221,42 @@ impl<'tcx> CheckAttrVisitor<'tcx> { span: Span, target: Target, attrs: &[Attribute], + ) { + self.check_macro_only_attr( + hir_id, + attr_span, + span, + target, + attrs, + "allow_internal_unstable", + ) + } + + /// Outputs an error for `#[allow_internal_unsafe]` which can only be applied to macros. + /// (Allows proc_macro functions) + fn check_allow_internal_unsafe( + &self, + hir_id: HirId, + attr_span: Span, + span: Span, + target: Target, + attrs: &[Attribute], + ) { + self.check_macro_only_attr(hir_id, attr_span, span, target, attrs, "allow_internal_unsafe") + } + + /// Outputs an error for attributes that can only be applied to macros, such as + /// `#[allow_internal_unsafe]` and `#[allow_internal_unstable]`. + /// (Allows proc_macro functions) + // FIXME(jdonszelmann): if possible, move to attr parsing + fn check_macro_only_attr( + &self, + hir_id: HirId, + attr_span: Span, + span: Span, + target: Target, + attrs: &[Attribute], + attr_name: &str, ) { match target { Target::Fn => { @@ -2238,18 +2275,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm => { - self.inline_attr_str_error_without_macro_def( - hir_id, - attr_span, - "allow_internal_unstable", - ); + self.inline_attr_str_error_without_macro_def(hir_id, attr_span, attr_name); return; } // otherwise continue out of the match _ => {} } - self.tcx.dcx().emit_err(errors::AllowInternalUnstable { attr_span, span }); + self.tcx.dcx().emit_err(errors::MacroOnlyAttribute { attr_span, span }); } /// Checks if the items on the `#[debugger_visualizer]` attribute are valid. diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index c6ab6b0d60179..10b30fbe8c94e 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -643,8 +643,8 @@ pub(crate) struct UsedStatic { } #[derive(Diagnostic)] -#[diag(passes_allow_internal_unstable)] -pub(crate) struct AllowInternalUnstable { +#[diag(passes_macro_only_attribute)] +pub(crate) struct MacroOnlyAttribute { #[primary_span] pub attr_span: Span, #[label] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index dd9dd3a6ce7fc..741101834504e 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -145,12 +145,6 @@ LL - #[macro_export = 18] LL + #[macro_export] | -error: malformed `allow_internal_unsafe` attribute input - --> $DIR/malformed-attrs.rs:213:1 - | -LL | #[allow_internal_unsafe = 1] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[allow_internal_unsafe]` - error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type --> $DIR/malformed-attrs.rs:96:1 | @@ -561,6 +555,15 @@ error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and ` LL | #[macro_use = 1] | ^^^^^^^^^^^^^^^^ +error[E0565]: malformed `allow_internal_unsafe` attribute input + --> $DIR/malformed-attrs.rs:213:1 + | +LL | #[allow_internal_unsafe = 1] + | ^^^^^^^^^^^^^^^^^^^^^^^^---^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[allow_internal_unsafe]` + error[E0565]: malformed `type_const` attribute input --> $DIR/malformed-attrs.rs:140:5 | From d523b9f3253b935ef3b293971bf9e7f911ff105f Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 11 Aug 2025 13:09:15 +0000 Subject: [PATCH 048/252] Support using #[unstable_feature_bound] on trait --- compiler/rustc_passes/src/check_attr.rs | 3 +- ...nstable_feature_bound_on_trait.fail.stderr | 18 ++++++++++ .../unstable_feature_bound_on_trait.rs | 33 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.fail.stderr create mode 100644 tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.rs diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 10c532b436aa1..48638bd1a8d7d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2294,7 +2294,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { // FIXME(staged_api): There's no reason we can't support more targets here. We're just // being conservative to begin with. - Target::Fn | Target::Impl { .. } => {} + Target::Fn | Target::Impl { .. } | Target::Trait => {} Target::ExternCrate | Target::Use | Target::Static @@ -2309,7 +2309,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::Struct | Target::Field | Target::Union - | Target::Trait | Target::TraitAlias | Target::Expression | Target::Statement diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.fail.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.fail.stderr new file mode 100644 index 0000000000000..69be101a40d2a --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.fail.stderr @@ -0,0 +1,18 @@ +error: unstable feature `foo` is used without being enabled. + --> $DIR/unstable_feature_bound_on_trait.rs:28:5 + | +LL | Foo::bar(); + | ^^^^^^^^^^ + | + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(foo)]` +note: required by a bound in `Bar::bar` + --> $DIR/unstable_feature_bound_on_trait.rs:16:1 + | +LL | #[unstable_feature_bound(foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Bar::bar` +... +LL | fn bar() {} + | --- required by a bound in this associated function + +error: aborting due to 1 previous error + diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.rs new file mode 100644 index 0000000000000..0ee00d5e7fb3f --- /dev/null +++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.rs @@ -0,0 +1,33 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +/// Test the behaviour of marking a trait with #[unstable_feature_bound]. +/// In this testcase, even though the trait method `bar` and the `struct Foo` are +/// both stable, #[unstable_feature_bound] is still needed at the call site of Foo::bar(). + +#[stable(feature = "a", since = "1.1.1" )] +struct Foo; + +#[unstable(feature = "foo", issue = "none" )] +#[unstable_feature_bound(foo)] +trait Bar { + #[stable(feature = "a", since = "1.1.1" )] + fn bar() {} +} + +#[unstable_feature_bound(foo)] +impl Bar for Foo { +} + +#[cfg_attr(pass, unstable_feature_bound(foo))] +fn moo() { + Foo::bar(); + //[fail]~^ ERROR: unstable feature `foo` is used without being enabled. +} + + +fn main() {} From 9a8facbe535e6197f4d2dfee03df11ccb902c73d Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 11 Aug 2025 13:17:45 +0000 Subject: [PATCH 049/252] Update rustc dev guide --- src/doc/rustc-dev-guide/src/stability.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/stability.md b/src/doc/rustc-dev-guide/src/stability.md index c26d34273d7ec..3c4c65fdd5a88 100644 --- a/src/doc/rustc-dev-guide/src/stability.md +++ b/src/doc/rustc-dev-guide/src/stability.md @@ -182,6 +182,11 @@ of the standard library raises it to a warning with `#![warn(deprecated_in_future)]`. ## unstable_feature_bound -The `#[unstable_feature_bound(foo)]` attribute can be used together with `#[unstable]` attribute to mark an `impl` of stable type and stable trait as unstable. In std/core, an item annotated with `#[unstable_feature_bound(foo)]` can only be used by another item that is also annotated with `#[unstable_feature_bound(foo)]`. Outside of std/core, using an item with `#[unstable_feature_bound(foo)]` requires the feature to be enabled with `#![feature(foo)]` attribute on the crate. Currently, only `impl`s and free functions can be annotated with `#[unstable_feature_bound]`. +The `#[unstable_feature_bound(foo)]` attribute can be used together with `#[unstable]` attribute to mark an `impl` of stable type and stable trait as unstable. In std/core, an item annotated with `#[unstable_feature_bound(foo)]` can only be used by another item that is also annotated with `#[unstable_feature_bound(foo)]`. Outside of std/core, using an item with `#[unstable_feature_bound(foo)]` requires the feature to be enabled with `#![feature(foo)]` attribute on the crate. + +Currently, the items that can be annotated with `#[unstable_feature_bound]` are: +- `impl` +- free function +- trait [blog]: https://www.ralfj.de/blog/2018/07/19/const.html From bcf87e4172416b96e24be998e18d81a8af183356 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 11 Aug 2025 13:27:46 +0000 Subject: [PATCH 050/252] Update error message --- compiler/rustc_passes/messages.ftl | 4 ++-- .../ui/unstable-feature-bound/unstable_inherent_method.rs | 4 ++-- .../unstable_inherent_method.stderr | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6a28fe2617edf..92e8dd32dd291 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -669,8 +669,8 @@ passes_rustc_std_internal_symbol = .label = not a function or static passes_rustc_unstable_feature_bound = - attribute should be applied to `impl` or free function outside of any `impl` or trait - .label = not an `impl` or free function + attribute should be applied to `impl`, trait or free function + .label = not an `impl`, trait or free function passes_should_be_applied_to_fn = attribute should be applied to a function definition diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.rs b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs index 5f3095430a806..0d6e4ebb4085f 100644 --- a/tests/ui/unstable-feature-bound/unstable_inherent_method.rs +++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs @@ -9,14 +9,14 @@ pub trait Trait { #[unstable(feature = "feat", issue = "none" )] #[unstable_feature_bound(foo)] - //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait + //~^ ERROR: attribute should be applied to `impl`, trait or free function fn foo(); } #[stable(feature = "a", since = "1.1.1" )] impl Trait for u8 { #[unstable_feature_bound(foo)] - //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait + //~^ ERROR: attribute should be applied to `impl`, trait or free function fn foo() {} } diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr index fa1c39db259a3..90cbb32df7c2f 100644 --- a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr +++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr @@ -1,20 +1,20 @@ -error: attribute should be applied to `impl` or free function outside of any `impl` or trait +error: attribute should be applied to `impl`, trait or free function --> $DIR/unstable_inherent_method.rs:11:5 | LL | #[unstable_feature_bound(foo)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | fn foo(); - | --------- not an `impl` or free function + | --------- not an `impl`, trait or free function -error: attribute should be applied to `impl` or free function outside of any `impl` or trait +error: attribute should be applied to `impl`, trait or free function --> $DIR/unstable_inherent_method.rs:18:5 | LL | #[unstable_feature_bound(foo)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | fn foo() {} - | ----------- not an `impl` or free function + | ----------- not an `impl`, trait or free function error: aborting due to 2 previous errors From 0ccbe8fc71173bf5d2e348e5b3ed6cb344db913b Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Mon, 14 Apr 2025 18:55:04 +0530 Subject: [PATCH 051/252] std: sys: pal: uefi: Overhaul Time Use a time representation with 1900-01-01-00:00:00 at timezone -1440 min as anchor. This is the earliest time supported in UEFI. Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/tests.rs | 3 + library/std/src/sys/pal/uefi/time.rs | 125 ++++++++++++++++++++++---- 2 files changed, 110 insertions(+), 18 deletions(-) diff --git a/library/std/src/sys/pal/uefi/tests.rs b/library/std/src/sys/pal/uefi/tests.rs index 49e75a1a70d7d..6a15c03184cf0 100644 --- a/library/std/src/sys/pal/uefi/tests.rs +++ b/library/std/src/sys/pal/uefi/tests.rs @@ -1,3 +1,6 @@ +//! These tests are not run automatically right now. Please run these tests manually by copying them +//! to a separate project when modifying any related code. + use super::alloc::*; use super::time::*; use crate::io::{IoSlice, IoSliceMut}; diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index eeb2c35ffbbc9..32c3cfd143c36 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -1,16 +1,28 @@ use crate::time::Duration; -const SECS_IN_MINUTE: u64 = 60; -const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60; -const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24; - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Duration); +/// When a Timezone is specified, the stored Duration is in UTC. If timezone is unspecified, then +/// the timezone is assumed to be in UTC. +/// +/// UEFI SystemTime is stored as Duration from 1900-01-01-00:00:00 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct SystemTime(Duration); -pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); +pub const UNIX_EPOCH: SystemTime = SystemTime::from_uefi(r_efi::efi::Time { + year: 1970, + month: 1, + day: 1, + hour: 0, + minute: 0, + second: 0, + nanosecond: 0, + timezone: 0, + daylight: 0, + pad1: 0, + pad2: 0, +}); impl Instant { pub fn now() -> Instant { @@ -40,6 +52,14 @@ impl Instant { } impl SystemTime { + pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Self { + Self(system_time_internal::from_uefi(&t)) + } + + pub(crate) const fn to_uefi(self, timezone: i16, daylight: u8) -> Option { + system_time_internal::to_uefi(&self.0, timezone, daylight) + } + pub fn now() -> SystemTime { system_time_internal::now() .unwrap_or_else(|| panic!("time not implemented on this platform")) @@ -50,11 +70,17 @@ impl SystemTime { } pub fn checked_add_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_add(*other)?)) + let temp = Self(self.0.checked_add(*other)?); + + // Check if can be represented in UEFI + if temp.to_uefi(0, 0).is_some() { Some(temp) } else { None } } pub fn checked_sub_duration(&self, other: &Duration) -> Option { - Some(SystemTime(self.0.checked_sub(*other)?)) + let temp = Self(self.0.checked_sub(*other)?); + + // Check if can be represented in UEFI + if temp.to_uefi(0, 0).is_some() { Some(temp) } else { None } } } @@ -66,51 +92,114 @@ pub(crate) mod system_time_internal { use crate::mem::MaybeUninit; use crate::ptr::NonNull; + const SECS_IN_MINUTE: u64 = 60; + const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60; + const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24; + const TIMEZONE_DELTA: u64 = 1440 * SECS_IN_MINUTE; + pub fn now() -> Option { let runtime_services: NonNull = helpers::runtime_services()?; let mut t: MaybeUninit Foo { .. }` or `impl Trait for Foo { .. }`. - Impl(Box), + Impl(Impl), /// A macro invocation. /// /// E.g., `foo!(..)`. @@ -3880,7 +3884,7 @@ impl ItemKind { | Self::Union(_, generics, _) | Self::Trait(box Trait { generics, .. }) | Self::TraitAlias(_, generics, _) - | Self::Impl(box Impl { generics, .. }) => Some(generics), + | Self::Impl(Impl { generics, .. }) => Some(generics), _ => None, } } @@ -4040,7 +4044,7 @@ mod size_asserts { static_assert_size!(GenericArg, 24); static_assert_size!(GenericBound, 88); static_assert_size!(Generics, 40); - static_assert_size!(Impl, 136); + static_assert_size!(Impl, 64); static_assert_size!(Item, 144); static_assert_size!(ItemKind, 80); static_assert_size!(LitKind, 24); @@ -4053,6 +4057,7 @@ mod size_asserts { static_assert_size!(PathSegment, 24); static_assert_size!(Stmt, 32); static_assert_size!(StmtKind, 16); + static_assert_size!(TraitImplHeader, 80); static_assert_size!(Ty, 64); static_assert_size!(TyKind, 40); // tidy-alphabetical-end diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 5fdce27db53e6..68b3d2b036865 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -929,8 +929,13 @@ macro_rules! common_visitor_and_walkers { } impl_walkable!(|&$($mut)? $($lt)? self: Impl, vis: &mut V| { - let Impl { defaultness, safety, generics, constness, polarity, of_trait, self_ty, items } = self; - visit_visitable!($($mut)? vis, defaultness, safety, generics, constness, polarity, of_trait, self_ty); + let Impl { generics, of_trait, self_ty, items } = self; + try_visit!(vis.visit_generics(generics)); + if let Some(box of_trait) = of_trait { + let TraitImplHeader { defaultness, safety, constness, polarity, trait_ref } = of_trait; + visit_visitable!($($mut)? vis, defaultness, safety, constness, polarity, trait_ref); + } + try_visit!(vis.visit_ty(self_ty)); visit_visitable_with!($($mut)? vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() }); V::Result::output() }); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ac6fac4c08e02..231752700ba09 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -340,13 +340,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::Union(ident, generics, vdata) } - ItemKind::Impl(box Impl { - safety, - polarity, - defaultness, - constness, + ItemKind::Impl(Impl { generics: ast_generics, - of_trait: trait_ref, + of_trait, self_ty: ty, items: impl_items, }) => { @@ -373,10 +369,10 @@ impl<'hir> LoweringContext<'_, 'hir> { polarity: BoundPolarity::Positive, }; - let trait_ref = trait_ref.as_ref().map(|trait_ref| { + let trait_ref = of_trait.as_ref().map(|of_trait| { this.lower_trait_ref( modifiers, - trait_ref, + &of_trait.trait_ref, ImplTraitContext::Disallowed(ImplTraitPosition::Trait), ) }); @@ -396,14 +392,35 @@ impl<'hir> LoweringContext<'_, 'hir> { // `defaultness.has_value()` is never called for an `impl`, always `true` in order // to not cause an assertion failure inside the `lower_defaultness` function. let has_val = true; - let (defaultness, defaultness_span) = self.lower_defaultness(*defaultness, has_val); - let polarity = match polarity { - ImplPolarity::Positive => ImplPolarity::Positive, - ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)), + let (constness, safety, polarity, defaultness, defaultness_span) = match *of_trait { + Some(box TraitImplHeader { + constness, + safety, + polarity, + defaultness, + trait_ref: _, + }) => { + let constness = self.lower_constness(constness); + let safety = self.lower_safety(safety, hir::Safety::Safe); + let polarity = match polarity { + ImplPolarity::Positive => ImplPolarity::Positive, + ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)), + }; + let (defaultness, defaultness_span) = + self.lower_defaultness(defaultness, has_val); + (constness, safety, polarity, defaultness, defaultness_span) + } + None => ( + hir::Constness::NotConst, + hir::Safety::Safe, + ImplPolarity::Positive, + hir::Defaultness::Final, + None, + ), }; hir::ItemKind::Impl(self.arena.alloc(hir::Impl { - constness: self.lower_constness(*constness), - safety: self.lower_safety(*safety, hir::Safety::Safe), + constness, + safety, polarity, defaultness, defaultness_span, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1fffb617c507a..dc2eb17589c66 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -954,13 +954,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } match &item.kind { - ItemKind::Impl(box Impl { - safety, - polarity, - defaultness: _, - constness, + ItemKind::Impl(Impl { generics, - of_trait: Some(t), + of_trait: + Some(box TraitImplHeader { + safety, + polarity, + defaultness: _, + constness, + trait_ref: t, + }), self_ty, items, }) => { @@ -992,16 +995,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true }); }); } - ItemKind::Impl(box Impl { - safety: _, - polarity: _, - defaultness: _, - constness: _, - generics, - of_trait: None, - self_ty, - items, - }) => { + ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items }) => { self.visit_attrs_vis(&item.attrs, &item.vis); self.visibility_not_permitted( &item.vis, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 662357ce88413..c9344a76a7b35 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -217,18 +217,18 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, of_trait, .. }) => { - if let &ast::ImplPolarity::Negative(span) = polarity { + ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) => { + if let ast::ImplPolarity::Negative(span) = of_trait.polarity { gate!( &self, negative_impls, - span.to(of_trait.as_ref().map_or(span, |t| t.path.span)), + span.to(of_trait.trait_ref.path.span), "negative trait bounds are not fully implemented; \ use marker types for now" ); } - if let ast::Defaultness::Default(_) = defaultness { + if let ast::Defaultness::Default(_) = of_trait.defaultness { gate!(&self, specialization, i.span, "specialization is unstable"); } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 6e34d1b61db43..ab402cbb8dc12 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -308,39 +308,41 @@ impl<'a> State<'a> { let (cb, ib) = self.head(visibility_qualified(&item.vis, "union")); self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib); } - ast::ItemKind::Impl(box ast::Impl { - safety, - polarity, - defaultness, - constness, - generics, - of_trait, - self_ty, - items, - }) => { + ast::ItemKind::Impl(ast::Impl { generics, of_trait, self_ty, items }) => { let (cb, ib) = self.head(""); self.print_visibility(&item.vis); - self.print_defaultness(*defaultness); - self.print_safety(*safety); - self.word("impl"); - - if generics.params.is_empty() { - self.nbsp(); - } else { - self.print_generic_params(&generics.params); - self.space(); - } - self.print_constness(*constness); + let impl_generics = |this: &mut Self| { + this.word("impl"); - if let ast::ImplPolarity::Negative(_) = polarity { - self.word("!"); - } - - if let Some(t) = of_trait { - self.print_trait_ref(t); + if generics.params.is_empty() { + this.nbsp(); + } else { + this.print_generic_params(&generics.params); + this.space(); + } + }; + + if let Some(box of_trait) = of_trait { + let ast::TraitImplHeader { + defaultness, + safety, + constness, + polarity, + ref trait_ref, + } = *of_trait; + self.print_defaultness(defaultness); + self.print_safety(safety); + impl_generics(self); + self.print_constness(constness); + if let ast::ImplPolarity::Negative(_) = polarity { + self.word("!"); + } + self.print_trait_ref(trait_ref); self.space(); self.word_space("for"); + } else { + impl_generics(self); } self.print_type(self_ty); diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 6082e376435a7..75db5d77783eb 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -108,11 +108,7 @@ pub(crate) fn expand_deriving_coerce_pointee( cx.item( span, attrs.clone(), - ast::ItemKind::Impl(Box::new(ast::Impl { - safety: ast::Safety::Default, - polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Final, - constness: ast::Const::No, + ast::ItemKind::Impl(ast::Impl { generics: Generics { params: generics .params @@ -137,10 +133,16 @@ pub(crate) fn expand_deriving_coerce_pointee( where_clause: generics.where_clause.clone(), span: generics.span, }, - of_trait: Some(trait_ref), + of_trait: Some(Box::new(ast::TraitImplHeader { + safety: ast::Safety::Default, + polarity: ast::ImplPolarity::Positive, + defaultness: ast::Defaultness::Final, + constness: ast::Const::No, + trait_ref, + })), self_ty: self_type.clone(), items: ThinVec::new(), - })), + }), ), )); } @@ -152,16 +154,18 @@ pub(crate) fn expand_deriving_coerce_pointee( let item = cx.item( span, attrs.clone(), - ast::ItemKind::Impl(Box::new(ast::Impl { - safety: ast::Safety::Default, - polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Final, - constness: ast::Const::No, + ast::ItemKind::Impl(ast::Impl { generics, - of_trait: Some(trait_ref), + of_trait: Some(Box::new(ast::TraitImplHeader { + safety: ast::Safety::Default, + polarity: ast::ImplPolarity::Positive, + defaultness: ast::Defaultness::Final, + constness: ast::Const::No, + trait_ref, + })), self_ty: self_type.clone(), items: ThinVec::new(), - })), + }), ); push(Annotatable::Item(item)); }; diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 3f4b47152c405..3fcf9da945070 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -826,21 +826,25 @@ impl<'a> TraitDef<'a> { ) } - let opt_trait_ref = Some(trait_ref); - cx.item( self.span, attrs, - ast::ItemKind::Impl(Box::new(ast::Impl { - safety: ast::Safety::Default, - polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Final, - constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No }, + ast::ItemKind::Impl(ast::Impl { generics: trait_generics, - of_trait: opt_trait_ref, + of_trait: Some(Box::new(ast::TraitImplHeader { + safety: ast::Safety::Default, + polarity: ast::ImplPolarity::Positive, + defaultness: ast::Defaultness::Final, + constness: if self.is_const { + ast::Const::Yes(DUMMY_SP) + } else { + ast::Const::No + }, + trait_ref, + })), self_ty: self_type, items: methods.into_iter().chain(associated_types).collect(), - })), + }), ) } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c893b7233755d..54769f9e097f7 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -270,7 +270,10 @@ impl EarlyLintPass for UnsafeCode { self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait); } - ast::ItemKind::Impl(box ast::Impl { safety: ast::Safety::Unsafe(_), .. }) => { + ast::ItemKind::Impl(ast::Impl { + of_trait: Some(box ast::TraitImplHeader { safety: ast::Safety::Unsafe(_), .. }), + .. + }) => { self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl); } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 7dafcc199a326..9f02f1f0df38e 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -411,11 +411,11 @@ declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]); impl EarlyLintPass for LintPassImpl { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind - && let Some(last) = lint_pass.path.segments.last() + if let ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) = &item.kind + && let Some(last) = of_trait.trait_ref.path.segments.last() && last.ident.name == sym::LintPass { - let expn_data = lint_pass.path.span.ctxt().outer_expn_data(); + let expn_data = of_trait.trait_ref.path.span.ctxt().outer_expn_data(); let call_site = expn_data.call_site; if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass) && call_site.ctxt().outer_expn_data().kind @@ -423,7 +423,7 @@ impl EarlyLintPass for LintPassImpl { { cx.emit_span_lint( LINT_PASS_IMPL_WITHOUT_MACRO, - lint_pass.path.span, + of_trait.trait_ref.path.span, LintPassByHand, ); } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 7e5f43ba77f43..8fafaa33d0c44 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -187,7 +187,7 @@ impl EarlyLintPass for NonCamelCaseTypes { // N.B. This check is only for inherent associated types, so that we don't lint against // trait impls where we should have warned for the trait definition already. - ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => { + ast::ItemKind::Impl(ast::Impl { of_trait: None, items, .. }) => { for it in items { // FIXME: this doesn't respect `#[allow(..)]` on the item itself. if let ast::AssocItemKind::Type(alias) = &it.kind { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 75cb103d5d63e..607adaf08294b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -663,7 +663,14 @@ impl<'a> Parser<'a> { }; let trait_ref = TraitRef { path, ref_id: ty_first.id }; - (Some(trait_ref), ty_second) + let of_trait = Some(Box::new(TraitImplHeader { + defaultness, + safety, + constness, + polarity, + trait_ref, + })); + (of_trait, ty_second) } None => { let self_ty = ty_first; @@ -692,16 +699,8 @@ impl<'a> Parser<'a> { (None, self_ty) } }; - Ok(ItemKind::Impl(Box::new(Impl { - safety, - polarity, - defaultness, - constness, - generics, - of_trait, - self_ty, - items: impl_items, - }))) + + Ok(ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items })) } fn parse_item_delegation(&mut self) -> PResult<'a, ItemKind> { @@ -1389,10 +1388,10 @@ impl<'a> Parser<'a> { }; match &mut item_kind { - ItemKind::Impl(box Impl { of_trait: Some(trai), constness, .. }) => { - *constness = Const::Yes(const_span); + ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }) => { + of_trait.constness = Const::Yes(const_span); - let before_trait = trai.path.span.shrink_to_lo(); + let before_trait = of_trait.trait_ref.path.span.shrink_to_lo(); let const_up_to_impl = const_span.with_hi(impl_span.lo()); err.with_multipart_suggestion( "you might have meant to write a const trait impl", diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d18d0fc16a8e4..3fee2ab6afe1e 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -11,7 +11,7 @@ use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; use rustc_ast::{ self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem, - ForeignItemKind, Impl, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias, + ForeignItemKind, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias, }; use rustc_attr_parsing as attr; use rustc_attr_parsing::AttributeParser; @@ -906,10 +906,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items do not add names to modules. - ItemKind::Impl(box Impl { of_trait: Some(..), .. }) - | ItemKind::Impl { .. } - | ItemKind::ForeignMod(..) - | ItemKind::GlobalAsm(..) => {} + ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {} ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => { unreachable!() diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 953b72fd72b8f..e52cbeb733ac0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2620,7 +2620,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.resolve_adt(item, generics); } - ItemKind::Impl(box Impl { + ItemKind::Impl(Impl { ref generics, ref of_trait, ref self_ty, @@ -2631,7 +2631,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.resolve_implementation( &item.attrs, generics, - of_trait, + of_trait.as_deref(), self_ty, item.id, impl_items, @@ -3177,7 +3177,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { &mut self, attrs: &[ast::Attribute], generics: &'ast Generics, - opt_trait_reference: &'ast Option, + of_trait: Option<&'ast ast::TraitImplHeader>, self_type: &'ast Ty, item_id: NodeId, impl_items: &'ast [Box], @@ -3201,7 +3201,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this| { // Resolve the trait reference, if necessary. this.with_optional_trait_ref( - opt_trait_reference.as_ref(), + of_trait.map(|t| &t.trait_ref), self_type, |this, trait_id| { this.resolve_doc_links(attrs, MaybeExported::Impl(trait_id)); @@ -3224,9 +3224,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { is_trait_impl: trait_id.is_some() }; this.with_self_rib(res, |this| { - if let Some(trait_ref) = opt_trait_reference.as_ref() { + if let Some(of_trait) = of_trait { // Resolve type arguments in the trait path. - visit::walk_trait_ref(this, trait_ref); + visit::walk_trait_ref(this, &of_trait.trait_ref); } // Resolve the self type. this.visit_ty(self_type); @@ -5183,7 +5183,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { | ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) | ItemKind::Union(_, generics, _) - | ItemKind::Impl(box Impl { generics, .. }) + | ItemKind::Impl(Impl { generics, .. }) | ItemKind::Trait(box Trait { generics, .. }) | ItemKind::TraitAlias(_, generics, _) => { if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 0312bf56e5979..24e017f7cf7de 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -473,33 +473,27 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) }, ( - Impl(box ast::Impl { - safety: lu, - polarity: lp, - defaultness: ld, - constness: lc, + Impl(ast::Impl { generics: lg, of_trait: lot, self_ty: lst, items: li, }), - Impl(box ast::Impl { - safety: ru, - polarity: rp, - defaultness: rd, - constness: rc, + Impl(ast::Impl { generics: rg, of_trait: rot, self_ty: rst, items: ri, }), ) => { - matches!(lu, Safety::Default) == matches!(ru, Safety::Default) - && matches!(lp, ImplPolarity::Positive) == matches!(rp, ImplPolarity::Positive) - && eq_defaultness(*ld, *rd) - && matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No) - && eq_generics(lg, rg) - && both(lot.as_ref(), rot.as_ref(), |l, r| eq_path(&l.path, &r.path)) + eq_generics(lg, rg) + && both(lot.as_deref(), rot.as_deref(), |l, r| { + matches!(l.safety, Safety::Default) == matches!(r.safety, Safety::Default) + && matches!(l.polarity, ImplPolarity::Positive) == matches!(r.polarity, ImplPolarity::Positive) + && eq_defaultness(l.defaultness, r.defaultness) + && matches!(l.constness, ast::Const::No) == matches!(r.constness, ast::Const::No) + && eq_path(&l.trait_ref.path, &r.trait_ref.path) + }) && eq_ty(lst, rst) && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind)) }, diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 57d4142ebe431..10df6f9670263 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -958,20 +958,19 @@ fn format_impl_ref_and_type( offset: Indent, ) -> Option { let ast::Impl { - safety, - polarity, - defaultness, - constness, - ref generics, - of_trait: ref trait_ref, - ref self_ty, - .. - } = *iimpl; + generics, + of_trait, + self_ty, + items: _, + } = iimpl; let mut result = String::with_capacity(128); result.push_str(&format_visibility(context, &item.vis)); - result.push_str(format_defaultness(defaultness)); - result.push_str(format_safety(safety)); + + if let Some(of_trait) = of_trait.as_deref() { + result.push_str(format_defaultness(of_trait.defaultness)); + result.push_str(format_safety(of_trait.safety)); + } let shape = if context.config.style_edition() >= StyleEdition::Edition2024 { Shape::indented(offset + last_line_width(&result), context.config) @@ -984,28 +983,24 @@ fn format_impl_ref_and_type( }; let generics_str = rewrite_generics(context, "impl", generics, shape).ok()?; result.push_str(&generics_str); - result.push_str(format_constness_right(constness)); - let polarity_str = match polarity { - ast::ImplPolarity::Negative(_) => "!", - ast::ImplPolarity::Positive => "", - }; - - let polarity_overhead; let trait_ref_overhead; - if let Some(ref trait_ref) = *trait_ref { + if let Some(of_trait) = of_trait.as_deref() { + result.push_str(format_constness_right(of_trait.constness)); + let polarity_str = match of_trait.polarity { + ast::ImplPolarity::Negative(_) => "!", + ast::ImplPolarity::Positive => "", + }; let result_len = last_line_width(&result); result.push_str(&rewrite_trait_ref( context, - trait_ref, + &of_trait.trait_ref, offset, polarity_str, result_len, )?); - polarity_overhead = 0; // already written trait_ref_overhead = " for".len(); } else { - polarity_overhead = polarity_str.len(); trait_ref_overhead = 0; } @@ -1020,17 +1015,15 @@ fn format_impl_ref_and_type( } else { 0 }; - let used_space = - last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead; + let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead; // 1 = space before the type. let budget = context.budget(used_space + 1); if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) { if !self_ty_str.contains('\n') { - if trait_ref.is_some() { + if of_trait.is_some() { result.push_str(" for "); } else { result.push(' '); - result.push_str(polarity_str); } result.push_str(&self_ty_str); return Some(result); @@ -1042,12 +1035,10 @@ fn format_impl_ref_and_type( // Add indentation of one additional tab. let new_line_offset = offset.block_indent(context.config); result.push_str(&new_line_offset.to_string(context.config)); - if trait_ref.is_some() { + if of_trait.is_some() { result.push_str("for "); - } else { - result.push_str(polarity_str); } - let budget = context.budget(last_line_width(&result) + polarity_overhead); + let budget = context.budget(last_line_width(&result)); let type_offset = match context.config.indent_style() { IndentStyle::Visual => new_line_offset + trait_ref_overhead, IndentStyle::Block => new_line_offset, diff --git a/src/tools/rustfmt/tests/source/negative-impl.rs b/src/tools/rustfmt/tests/source/negative-impl.rs index da242d4f3dca4..e8f9508e6563f 100644 --- a/src/tools/rustfmt/tests/source/negative-impl.rs +++ b/src/tools/rustfmt/tests/source/negative-impl.rs @@ -1,7 +1,3 @@ impl ! Display for JoinHandle { } -impl ! Box < JoinHandle > { } - impl ! std :: fmt :: Display for JoinHandle < T : std :: future :: Future + std :: marker :: Send + std :: marker :: Sync > { } - -impl ! JoinHandle < T : std :: future :: Future < Output > + std :: marker :: Send + std :: marker :: Sync + 'static > + 'static { } diff --git a/src/tools/rustfmt/tests/target/negative-impl.rs b/src/tools/rustfmt/tests/target/negative-impl.rs index 16ce7e26a99aa..bb53048dbc62b 100644 --- a/src/tools/rustfmt/tests/target/negative-impl.rs +++ b/src/tools/rustfmt/tests/target/negative-impl.rs @@ -1,14 +1,6 @@ impl !Display for JoinHandle {} -impl !Box {} - impl !std::fmt::Display for JoinHandle { } - -impl - !JoinHandle + std::marker::Send + std::marker::Sync + 'static> - + 'static -{ -} From bf266dc8341755f0f7ac6de1cfa474875f79b3d9 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 24 Jul 2025 09:32:58 -0500 Subject: [PATCH 093/252] Propagate TraitImplHeader to hir --- compiler/rustc_ast_lowering/src/item.rs | 99 +++++++++---------- compiler/rustc_hir/src/hir.rs | 27 ++--- compiler/rustc_hir/src/intravisit.rs | 26 ++--- .../rustc_hir_analysis/src/check/wfcheck.rs | 93 +++++++++-------- .../src/coherence/builtin.rs | 6 +- .../src/coherence/orphan.rs | 4 +- compiler/rustc_hir_analysis/src/collect.rs | 36 +++---- .../src/collect/predicates_of.rs | 4 +- .../src/collect/resolve_bound_vars.rs | 17 ++-- .../rustc_hir_analysis/src/collect/type_of.rs | 2 +- .../errors/wrong_number_of_generic_args.rs | 6 +- .../src/hir_ty_lowering/lint.rs | 6 +- .../src/hir_ty_lowering/mod.rs | 2 +- .../rustc_hir_analysis/src/hir_wf_check.rs | 5 +- compiler/rustc_hir_pretty/src/lib.rs | 61 ++++++------ .../src/fn_ctxt/suggestions.rs | 2 +- .../rustc_hir_typeck/src/method/suggest.rs | 10 +- .../src/deref_into_dyn_supertrait.rs | 4 +- compiler/rustc_lint/src/internal.rs | 4 +- compiler/rustc_lint/src/non_local_def.rs | 4 +- compiler/rustc_passes/src/check_attr.rs | 7 +- compiler/rustc_passes/src/stability.rs | 24 ++--- compiler/rustc_privacy/src/lib.rs | 3 +- .../src/error_reporting/traits/suggestions.rs | 8 +- compiler/rustc_ty_utils/src/assoc.rs | 4 +- compiler/rustc_ty_utils/src/implied_bounds.rs | 8 +- compiler/rustc_ty_utils/src/sig_types.rs | 2 +- compiler/rustc_ty_utils/src/ty.rs | 6 +- src/librustdoc/clean/mod.rs | 9 +- .../src/arbitrary_source_item_ordering.rs | 1 + .../clippy/clippy_lints/src/copy_iterator.rs | 4 +- .../clippy_lints/src/derivable_impls.rs | 4 +- src/tools/clippy/clippy_lints/src/derive.rs | 3 +- .../clippy/clippy_lints/src/empty_drop.rs | 4 +- .../clippy_lints/src/error_impl_error.rs | 2 +- .../clippy/clippy_lints/src/format_impl.rs | 4 +- .../clippy/clippy_lints/src/from_over_into.rs | 4 +- .../src/functions/impl_trait_in_params.rs | 3 +- .../src/functions/renamed_function_params.rs | 4 +- .../impl_hash_with_borrow_str_and_bytes.rs | 8 +- .../clippy_lints/src/infallible_try_from.rs | 4 +- .../src/iter_without_into_iter.rs | 5 +- .../clippy/clippy_lints/src/lifetimes.rs | 6 +- .../src/missing_fields_in_debug.rs | 4 +- .../clippy_lints/src/missing_trait_methods.rs | 4 +- .../clippy/clippy_lints/src/non_copy_const.rs | 2 +- .../src/non_send_fields_in_send_ty.rs | 6 +- .../clippy_lints/src/operators/op_ref.rs | 2 +- .../clippy_lints/src/partialeq_ne_impl.rs | 6 +- .../clippy_lints/src/same_name_method.rs | 4 +- .../clippy/clippy_lints/src/serde_api.rs | 6 +- .../clippy_lints/src/to_string_trait_impl.rs | 4 +- .../src/unconditional_recursion.rs | 8 +- .../src/undocumented_unsafe_blocks.rs | 6 +- src/tools/clippy/clippy_lints/src/write.rs | 4 +- .../clippy_utils/src/check_proc_macro.rs | 6 +- src/tools/clippy/clippy_utils/src/lib.rs | 3 +- src/tools/clippy/clippy_utils/src/visitors.rs | 3 +- tests/ui/unpretty/exhaustive.hir.stdout | 2 +- 59 files changed, 316 insertions(+), 299 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 231752700ba09..235573c96e450 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -360,75 +360,30 @@ impl<'hir> LoweringContext<'_, 'hir> { // lifetime to be added, but rather a reference to a // parent lifetime. let itctx = ImplTraitContext::Universal; - let (generics, (trait_ref, lowered_ty)) = + let (generics, (of_trait, lowered_ty)) = self.lower_generics(ast_generics, id, itctx, |this| { - let modifiers = TraitBoundModifiers { - constness: BoundConstness::Never, - asyncness: BoundAsyncness::Normal, - // we don't use this in bound lowering - polarity: BoundPolarity::Positive, - }; - - let trait_ref = of_trait.as_ref().map(|of_trait| { - this.lower_trait_ref( - modifiers, - &of_trait.trait_ref, - ImplTraitContext::Disallowed(ImplTraitPosition::Trait), - ) - }); + let of_trait = of_trait + .as_deref() + .map(|of_trait| this.lower_trait_impl_header(of_trait)); let lowered_ty = this.lower_ty( ty, ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf), ); - (trait_ref, lowered_ty) + (of_trait, lowered_ty) }); let new_impl_items = self .arena .alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item))); - // `defaultness.has_value()` is never called for an `impl`, always `true` in order - // to not cause an assertion failure inside the `lower_defaultness` function. - let has_val = true; - let (constness, safety, polarity, defaultness, defaultness_span) = match *of_trait { - Some(box TraitImplHeader { - constness, - safety, - polarity, - defaultness, - trait_ref: _, - }) => { - let constness = self.lower_constness(constness); - let safety = self.lower_safety(safety, hir::Safety::Safe); - let polarity = match polarity { - ImplPolarity::Positive => ImplPolarity::Positive, - ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)), - }; - let (defaultness, defaultness_span) = - self.lower_defaultness(defaultness, has_val); - (constness, safety, polarity, defaultness, defaultness_span) - } - None => ( - hir::Constness::NotConst, - hir::Safety::Safe, - ImplPolarity::Positive, - hir::Defaultness::Final, - None, - ), - }; - hir::ItemKind::Impl(self.arena.alloc(hir::Impl { - constness, - safety, - polarity, - defaultness, - defaultness_span, + hir::ItemKind::Impl(hir::Impl { generics, - of_trait: trait_ref, + of_trait, self_ty: lowered_ty, items: new_impl_items, - })) + }) } ItemKind::Trait(box Trait { constness, @@ -999,6 +954,44 @@ impl<'hir> LoweringContext<'_, 'hir> { self.expr(span, hir::ExprKind::Err(guar)) } + fn lower_trait_impl_header( + &mut self, + trait_impl_header: &TraitImplHeader, + ) -> &'hir hir::TraitImplHeader<'hir> { + let TraitImplHeader { constness, safety, polarity, defaultness, ref trait_ref } = + *trait_impl_header; + let constness = self.lower_constness(constness); + let safety = self.lower_safety(safety, hir::Safety::Safe); + let polarity = match polarity { + ImplPolarity::Positive => ImplPolarity::Positive, + ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)), + }; + // `defaultness.has_value()` is never called for an `impl`, always `true` in order + // to not cause an assertion failure inside the `lower_defaultness` function. + let has_val = true; + let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val); + let modifiers = TraitBoundModifiers { + constness: BoundConstness::Never, + asyncness: BoundAsyncness::Normal, + // we don't use this in bound lowering + polarity: BoundPolarity::Positive, + }; + let trait_ref = self.lower_trait_ref( + modifiers, + trait_ref, + ImplTraitContext::Disallowed(ImplTraitPosition::Trait), + ); + + self.arena.alloc(hir::TraitImplHeader { + constness, + safety, + polarity, + defaultness, + defaultness_span, + trait_ref, + }) + } + fn lower_impl_item( &mut self, i: &AssocItem, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 34db6f92d9288..d11ffce87cb37 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4194,7 +4194,7 @@ impl<'hir> Item<'hir> { expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>), ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds); - expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp; + expect_impl, &Impl<'hir>, ItemKind::Impl(imp), imp; } } @@ -4372,7 +4372,7 @@ pub enum ItemKind<'hir> { TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>), /// An implementation, e.g., `impl Trait for Foo { .. }`. - Impl(&'hir Impl<'hir>), + Impl(Impl<'hir>), } /// Represents an impl block declaration. @@ -4381,6 +4381,14 @@ pub enum ItemKind<'hir> { /// Refer to [`ImplItem`] for an associated item within an impl block. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Impl<'hir> { + pub generics: &'hir Generics<'hir>, + pub of_trait: Option<&'hir TraitImplHeader<'hir>>, + pub self_ty: &'hir Ty<'hir>, + pub items: &'hir [ImplItemId], +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct TraitImplHeader<'hir> { pub constness: Constness, pub safety: Safety, pub polarity: ImplPolarity, @@ -4388,13 +4396,7 @@ pub struct Impl<'hir> { // We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata // decoding as `Span`s cannot be decoded when a `Session` is not available. pub defaultness_span: Option, - pub generics: &'hir Generics<'hir>, - - /// The trait being implemented, if any. - pub of_trait: Option>, - - pub self_ty: &'hir Ty<'hir>, - pub items: &'hir [ImplItemId], + pub trait_ref: TraitRef<'hir>, } impl ItemKind<'_> { @@ -4756,8 +4758,8 @@ impl<'hir> Node<'hir> { /// Get a `hir::Impl` if the node is an impl block for the given `trait_def_id`. pub fn impl_block_of_trait(self, trait_def_id: DefId) -> Option<&'hir Impl<'hir>> { if let Node::Item(Item { kind: ItemKind::Impl(impl_block), .. }) = self - && let Some(trait_ref) = impl_block.of_trait - && let Some(trait_id) = trait_ref.trait_def_id() + && let Some(of_trait) = impl_block.of_trait + && let Some(trait_id) = of_trait.trait_ref.trait_def_id() && trait_id == trait_def_id { Some(impl_block) @@ -4952,7 +4954,7 @@ mod size_asserts { static_assert_size!(GenericArg<'_>, 16); static_assert_size!(GenericBound<'_>, 64); static_assert_size!(Generics<'_>, 56); - static_assert_size!(Impl<'_>, 80); + static_assert_size!(Impl<'_>, 40); static_assert_size!(ImplItem<'_>, 96); static_assert_size!(ImplItemKind<'_>, 40); static_assert_size!(Item<'_>, 88); @@ -4967,6 +4969,7 @@ mod size_asserts { static_assert_size!(Res, 12); static_assert_size!(Stmt<'_>, 32); static_assert_size!(StmtKind<'_>, 16); + static_assert_size!(TraitImplHeader<'_>, 48); static_assert_size!(TraitItem<'_>, 88); static_assert_size!(TraitItemKind<'_>, 48); static_assert_size!(Ty<'_>, 48); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 23fa466859a05..9b2f8ae75fa70 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -590,21 +590,21 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_enum_def(enum_definition)); } - ItemKind::Impl(Impl { - constness: _, - safety: _, - defaultness: _, - polarity: _, - defaultness_span: _, - generics, - of_trait, - self_ty, - items, - }) => { + ItemKind::Impl(Impl { generics, of_trait, self_ty, items }) => { try_visit!(visitor.visit_generics(generics)); - visit_opt!(visitor, visit_trait_ref, of_trait); + if let Some(TraitImplHeader { + constness: _, + safety: _, + polarity: _, + defaultness: _, + defaultness_span: _, + trait_ref, + }) = of_trait + { + try_visit!(visitor.visit_trait_ref(trait_ref)); + } try_visit!(visitor.visit_ty_unambig(self_ty)); - walk_list!(visitor, visit_impl_item_ref, *items); + walk_list!(visitor, visit_impl_item_ref, items); } ItemKind::Struct(ident, ref generics, ref struct_definition) | ItemKind::Union(ident, ref generics, ref struct_definition) => { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index a62efed13bc79..c642435b9893c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -244,48 +244,48 @@ pub(super) fn check_item<'tcx>( // // won't be allowed unless there's an *explicit* implementation of `Send` // for `T` - hir::ItemKind::Impl(impl_) => { - let header = tcx.impl_trait_header(def_id); - let is_auto = header - .is_some_and(|header| tcx.trait_is_auto(header.trait_ref.skip_binder().def_id)); - + hir::ItemKind::Impl(ref impl_) => { crate::impl_wf_check::check_impl_wf(tcx, def_id)?; let mut res = Ok(()); - if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) { - let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span); - res = Err(tcx - .dcx() - .struct_span_err(sp, "impls of auto traits cannot be default") - .with_span_labels(impl_.defaultness_span, "default because of this") - .with_span_label(sp, "auto trait") - .emit()); - } - // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span. - match header.map(|h| h.polarity) { - // `None` means this is an inherent impl - Some(ty::ImplPolarity::Positive) | None => { - res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait)); - } - Some(ty::ImplPolarity::Negative) => { - let ast::ImplPolarity::Negative(span) = impl_.polarity else { - bug!("impl_polarity query disagrees with impl's polarity in HIR"); - }; - // FIXME(#27579): what amount of WF checking do we need for neg impls? - if let hir::Defaultness::Default { .. } = impl_.defaultness { - let mut spans = vec![span]; - spans.extend(impl_.defaultness_span); - res = Err(struct_span_code_err!( - tcx.dcx(), - spans, - E0750, - "negative impls cannot be default impls" - ) + if let Some(of_trait) = impl_.of_trait { + let header = tcx.impl_trait_header(def_id).unwrap(); + let is_auto = tcx.trait_is_auto(header.trait_ref.skip_binder().def_id); + if let (hir::Defaultness::Default { .. }, true) = (of_trait.defaultness, is_auto) { + let sp = of_trait.trait_ref.path.span; + res = Err(tcx + .dcx() + .struct_span_err(sp, "impls of auto traits cannot be default") + .with_span_labels(of_trait.defaultness_span, "default because of this") + .with_span_label(sp, "auto trait") .emit()); - } } - Some(ty::ImplPolarity::Reservation) => { - // FIXME: what amount of WF checking do we need for reservation impls? + match header.polarity { + ty::ImplPolarity::Positive => { + res = res.and(check_impl(tcx, item, impl_)); + } + ty::ImplPolarity::Negative => { + let ast::ImplPolarity::Negative(span) = of_trait.polarity else { + bug!("impl_polarity query disagrees with impl's polarity in HIR"); + }; + // FIXME(#27579): what amount of WF checking do we need for neg impls? + if let hir::Defaultness::Default { .. } = of_trait.defaultness { + let mut spans = vec![span]; + spans.extend(of_trait.defaultness_span); + res = Err(struct_span_code_err!( + tcx.dcx(), + spans, + E0750, + "negative impls cannot be default impls" + ) + .emit()); + } + } + ty::ImplPolarity::Reservation => { + // FIXME: what amount of WF checking do we need for reservation impls? + } } + } else { + res = res.and(check_impl(tcx, item, impl_)); } res } @@ -1258,16 +1258,15 @@ pub(crate) fn check_const_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<() }) } -#[instrument(level = "debug", skip(tcx, hir_self_ty, hir_trait_ref))] +#[instrument(level = "debug", skip(tcx, impl_))] fn check_impl<'tcx>( tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>, - hir_self_ty: &hir::Ty<'_>, - hir_trait_ref: &Option>, + impl_: &hir::Impl<'_>, ) -> Result<(), ErrorGuaranteed> { enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| { - match hir_trait_ref { - Some(hir_trait_ref) => { + match impl_.of_trait { + Some(of_trait) => { // `#[rustc_reservation_impl]` impls are not real impls and // therefore don't need to be WF (the trait's `Self: Trait` predicate // won't hold). @@ -1275,7 +1274,7 @@ fn check_impl<'tcx>( // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. tcx.ensure_ok().coherent_trait(trait_ref.def_id)?; - let trait_span = hir_trait_ref.path.span; + let trait_span = of_trait.trait_ref.path.span; let trait_ref = wfcx.deeply_normalize( trait_span, Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), @@ -1299,12 +1298,12 @@ fn check_impl<'tcx>( if let Some(pred) = obligation.predicate.as_trait_clause() && pred.skip_binder().self_ty() == trait_ref.self_ty() { - obligation.cause.span = hir_self_ty.span; + obligation.cause.span = impl_.self_ty.span; } if let Some(pred) = obligation.predicate.as_projection_clause() && pred.skip_binder().self_ty() == trait_ref.self_ty() { - obligation.cause.span = hir_self_ty.span; + obligation.cause.span = impl_.self_ty.span; } } @@ -1321,7 +1320,7 @@ fn check_impl<'tcx>( wfcx.register_obligation(Obligation::new( tcx, ObligationCause::new( - hir_self_ty.span, + impl_.self_ty.span, wfcx.body_def_id, ObligationCauseCode::WellFormed(None), ), @@ -1342,7 +1341,7 @@ fn check_impl<'tcx>( self_ty, ); wfcx.register_wf_obligation( - hir_self_ty.span, + impl_.self_ty.span, Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), self_ty.into(), ); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 27948f50a4ad5..32b175611ceb5 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -531,8 +531,10 @@ pub(crate) fn coerce_unsized_info<'tcx>( })); } else if diff_fields.len() > 1 { let item = tcx.hir_expect_item(impl_did); - let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind { - t.path.span + let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) = + &item.kind + { + of_trait.trait_ref.path.span } else { tcx.def_span(impl_did) }; diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index c75fef9f716d6..f707196c81635 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -384,7 +384,7 @@ fn emit_orphan_check_error<'tcx>( traits::OrphanCheckErr::NonLocalInputType(tys) => { let item = tcx.hir_expect_item(impl_def_id); let impl_ = item.expect_impl(); - let hir_trait_ref = impl_.of_trait.as_ref().unwrap(); + let of_trait = impl_.of_trait.unwrap(); let span = tcx.def_span(impl_def_id); let mut diag = tcx.dcx().create_err(match trait_ref.self_ty().kind() { @@ -401,7 +401,7 @@ fn emit_orphan_check_error<'tcx>( impl_.self_ty.span } else { // Point at `C` in `impl for C in D` - hir_trait_ref.path.span + of_trait.trait_ref.path.span }; ty = tcx.erase_regions(ty); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8ccbfbbb3b498..b72e743f95b0f 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1295,18 +1295,22 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, - def_id: LocalDefId, - impl_: &hir::Impl<'_>, - span: Span, + of_trait: &hir::TraitImplHeader<'_>, + is_rustc_reservation: bool, ) -> ty::ImplPolarity { - let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl); - match &impl_ { - hir::Impl { polarity: hir::ImplPolarity::Negative(span), of_trait, .. } => { + match of_trait.polarity { + hir::ImplPolarity::Negative(span) => { if is_rustc_reservation { - let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span)); + let span = span.to(of_trait.trait_ref.path.span); tcx.dcx().span_err(span, "reservation impls can't be negative"); } ty::ImplPolarity::Negative } - hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: None, .. } => { - if is_rustc_reservation { - tcx.dcx().span_err(span, "reservation impls can't be inherent"); - } - ty::ImplPolarity::Positive - } - hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: Some(_), .. } => { + hir::ImplPolarity::Positive => { if is_rustc_reservation { ty::ImplPolarity::Reservation } else { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 8dd13da4fa7bc..b59dc4bd132f9 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -158,7 +158,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen if let Node::Item(item) = node { match item.kind { ItemKind::Impl(impl_) => { - if impl_.defaultness.is_default() { + if let Some(of_trait) = impl_.of_trait + && of_trait.defaultness.is_default() + { is_default_impl_trait = tcx .impl_trait_ref(def_id) .map(|t| ty::Binder::dummy(t.instantiate_identity())); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index eb3492f5de6e7..8133f9f68234b 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -604,13 +604,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - match &item.kind { - hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => { - if let Some(of_trait) = of_trait { - self.record_late_bound_vars(of_trait.hir_ref_id, Vec::default()); - } - } - _ => {} + if let hir::ItemKind::Impl(impl_) = item.kind + && let Some(of_trait) = impl_.of_trait + { + self.record_late_bound_vars(of_trait.trait_ref.hir_ref_id, Vec::default()); } match item.kind { hir::ItemKind::Fn { generics, .. } => { @@ -636,7 +633,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::Union(_, generics, _) | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::TraitAlias(_, generics, ..) - | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => { + | hir::ItemKind::Impl(hir::Impl { generics, .. }) => { // These kinds of items have only early-bound lifetime parameters. self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item)); } @@ -2106,7 +2103,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // If we have a self type alias (in an impl), try to resolve an // associated item from one of the supertraits of the impl's trait. Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. } => { - let hir::ItemKind::Impl(hir::Impl { of_trait: Some(trait_ref), .. }) = self + let hir::ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) = self .tcx .hir_node_by_def_id(impl_def_id.expect_local()) .expect_item() @@ -2114,7 +2111,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { else { return; }; - let Some(trait_def_id) = trait_ref.trait_def_id() else { + let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else { return; }; let Some((bound_vars, assoc_item)) = BoundVarContext::supertrait_hrtb_vars( diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 22fb02714dd79..62125c99d8021 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -251,7 +251,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ .emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () }); Ty::new_error(tcx, guar) } - _ => icx.lower_ty(*self_ty), + _ => icx.lower_ty(self_ty), }, ItemKind::Fn { .. } => { let args = ty::GenericArgs::identity_for_item(tcx, def_id); diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 835f8e8cdaeed..8a9f9130feacb 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -147,7 +147,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(hir::Impl { - of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }), + of_trait: + Some(hir::TraitImplHeader { + trait_ref: hir::TraitRef { hir_ref_id: id_in_of_trait, .. }, + .. + }), .. }), .. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 646ff3ca08d24..56998b5b53cc4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -200,7 +200,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) = tcx.hir_node_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id { - let Some(of_trait_ref) = of_trait else { + let Some(of_trait) = of_trait else { diag.span_suggestion_verbose( impl_self_ty.span.shrink_to_hi(), "you might have intended to implement this trait for a given type", @@ -209,10 +209,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); return; }; - if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) { + if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) { return; } - let of_trait_span = of_trait_ref.path.span; + let of_trait_span = of_trait.trait_ref.path.span; // make sure that we are not calling unwrap to abort during the compilation let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 1675aecd2b84f..c7b984d9b259c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2732,7 +2732,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let i = tcx.parent_hir_node(fn_hir_id).expect_item().expect_impl(); - let trait_ref = self.lower_impl_trait_ref(i.of_trait.as_ref()?, self.lower_ty(i.self_ty)); + let trait_ref = self.lower_impl_trait_ref(&i.of_trait?.trait_ref, self.lower_ty(i.self_ty)); let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind( tcx, diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 3fddaee8cef4d..d8578970adc94 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -154,8 +154,9 @@ pub(super) fn diagnostic_hir_wf_check<'tcx>( hir::ItemKind::TyAlias(_, _, ty) | hir::ItemKind::Static(_, _, ty, _) | hir::ItemKind::Const(_, _, ty, _) => vec![ty], - hir::ItemKind::Impl(impl_) => match &impl_.of_trait { - Some(t) => t + hir::ItemKind::Impl(impl_) => match impl_.of_trait { + Some(of_trait) => of_trait + .trait_ref .path .segments .last() diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 235eec96d74f5..be5859b57c5e0 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -690,39 +690,44 @@ impl<'a> State<'a> { let (cb, ib) = self.head("union"); self.print_struct(ident.name, generics, struct_def, item.span, true, cb, ib); } - hir::ItemKind::Impl(&hir::Impl { - constness, - safety, - polarity, - defaultness, - defaultness_span: _, - generics, - ref of_trait, - self_ty, - items, - }) => { + hir::ItemKind::Impl(hir::Impl { generics, of_trait, self_ty, items }) => { let (cb, ib) = self.head(""); - self.print_defaultness(defaultness); - self.print_safety(safety); - self.word_nbsp("impl"); - if let hir::Constness::Const = constness { - self.word_nbsp("const"); - } + let impl_generics = |this: &mut Self| { + this.word_nbsp("impl"); + if !generics.params.is_empty() { + this.print_generic_params(generics.params); + this.space(); + } + }; - if !generics.params.is_empty() { - self.print_generic_params(generics.params); - self.space(); - } + match of_trait { + None => impl_generics(self), + Some(&hir::TraitImplHeader { + constness, + safety, + polarity, + defaultness, + defaultness_span: _, + ref trait_ref, + }) => { + self.print_defaultness(defaultness); + self.print_safety(safety); + + impl_generics(self); + + if let hir::Constness::Const = constness { + self.word_nbsp("const"); + } - if let hir::ImplPolarity::Negative(_) = polarity { - self.word("!"); - } + if let hir::ImplPolarity::Negative(_) = polarity { + self.word("!"); + } - if let Some(t) = of_trait { - self.print_trait_ref(t); - self.space(); - self.word_space("for"); + self.print_trait_ref(trait_ref); + self.space(); + self.word_space("for"); + } } self.print_type(self_ty); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 2345cdab208e3..6013430e1ff3d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -936,7 +936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Node::ImplItem(item) => { // If it doesn't impl a trait, we can add a return type let Node::Item(&hir::Item { - kind: hir::ItemKind::Impl(&hir::Impl { of_trait, .. }), + kind: hir::ItemKind::Impl(hir::Impl { of_trait, .. }), .. }) = self.tcx.parent_hir_node(item.hir_id()) else { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index f7430f7af4e9a..824d592fa6c77 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1103,7 +1103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty.span.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _) ) || matches!( - of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind), + of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind), Some(ExpnKind::Macro(MacroKind::Derive, _)) ) => { @@ -1165,13 +1165,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { entry.0.insert(cause_span); entry.1.insert((cause_span, "unsatisfied trait bound introduced here")); } else { - if let Some(trait_ref) = of_trait { - entry.0.insert(trait_ref.path.span); + if let Some(of_trait) = of_trait { + entry.0.insert(of_trait.trait_ref.path.span); } entry.0.insert(self_ty.span); }; - if let Some(trait_ref) = of_trait { - entry.1.insert((trait_ref.path.span, "")); + if let Some(of_trait) = of_trait { + entry.1.insert((of_trait.trait_ref.path.span, "")); } entry.1.insert((self_ty.span, "")); } diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index dd16117db1c5e..943fcc0801b1e 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -61,8 +61,8 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { // `Deref` is being implemented for `t` if let hir::ItemKind::Impl(impl_) = item.kind // the trait is a `Deref` implementation - && let Some(trait_) = &impl_.of_trait - && let Some(did) = trait_.trait_def_id() + && let Some(of_trait) = &impl_.of_trait + && let Some(did) = of_trait.trait_ref.trait_def_id() && tcx.is_lang_item(did, LangItem::Deref) // the self type is `dyn t_principal` && let self_ty = tcx.type_of(item.owner_id).instantiate_identity() diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 9f02f1f0df38e..016ff17f5d7ea 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -582,8 +582,8 @@ impl Diagnostics { for (_hir_id, parent) in cx.tcx.hir_parent_iter(current_id) { debug!(?parent); if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) = parent - && let hir::Impl { of_trait: Some(of_trait), .. } = impl_ - && let Some(def_id) = of_trait.trait_def_id() + && let Some(of_trait) = impl_.of_trait + && let Some(def_id) = of_trait.trait_ref.trait_def_id() && let Some(name) = cx.tcx.get_diagnostic_name(def_id) && matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic) { diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index b877f909fc029..2dd3425e66cf4 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -129,8 +129,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { // of the `impl` definition let mut collector = PathCollector { paths: Vec::new() }; collector.visit_ty_unambig(&impl_.self_ty); - if let Some(of_trait) = &impl_.of_trait { - collector.visit_trait_ref(of_trait); + if let Some(of_trait) = impl_.of_trait { + collector.visit_trait_ref(&of_trait.trait_ref); } // 1.5. Remove any path that doesn't resolve to a `DefId` or if it resolve to a diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 10c532b436aa1..dbdc8a3dbf5ca 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1155,8 +1155,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let is_valid = doc_fake_variadic_is_allowed_self_ty(i.self_ty) || if let Some(&[hir::GenericArg::Type(ty)]) = i .of_trait - .as_ref() - .and_then(|trait_ref| trait_ref.path.segments.last()) + .and_then(|of_trait| of_trait.trait_ref.path.segments.last()) .map(|last_segment| last_segment.args().args) { matches!(&ty.kind, hir::TyKind::Tup([_])) @@ -1646,8 +1645,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { && let parent_hir_id = self.tcx.parent_hir_id(hir_id) && let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id) && let hir::ItemKind::Impl(impl_) = item.kind - && let Some(trait_) = impl_.of_trait - && let Some(def_id) = trait_.trait_def_id() + && let Some(of_trait) = impl_.of_trait + && let Some(def_id) = of_trait.trait_ref.trait_def_id() && self.tcx.is_lang_item(def_id, hir::LangItem::Drop) { return; diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index e2f223325dfdf..71650c6b9b937 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -590,9 +590,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemKind::Impl(hir::Impl { - of_trait: Some(t), self_ty, items, constness, .. - }) => { + hir::ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), self_ty, items, .. }) => { let features = self.tcx.features(); if features.staged_api() { let attrs = self.tcx.hir_attrs(item.hir_id()); @@ -628,7 +626,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { { let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true }; c.visit_ty_unambig(self_ty); - c.visit_trait_ref(t); + c.visit_trait_ref(&of_trait.trait_ref); // Skip the lint if the impl is marked as unstable using // #[unstable_feature_bound(..)] @@ -641,7 +639,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // do not lint when the trait isn't resolved, since resolution error should // be fixed first - if t.path.res != Res::Err + if of_trait.trait_ref.path.res != Res::Err && c.fully_stable && !unstable_feature_bound_in_effect { @@ -655,7 +653,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } if features.const_trait_impl() - && let hir::Constness::Const = constness + && let hir::Constness::Const = of_trait.constness { let stable_or_implied_stable = match const_stab { None => true, @@ -671,7 +669,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { Some(_) => false, }; - if let Some(trait_id) = t.trait_def_id() + if let Some(trait_id) = of_trait.trait_ref.trait_def_id() && let Some(const_stab) = self.tcx.lookup_const_stability(trait_id) { // the const stability of a trait impl must match the const stability on the trait. @@ -699,14 +697,18 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } } - if let hir::Constness::Const = constness - && let Some(def_id) = t.trait_def_id() + if let hir::Constness::Const = of_trait.constness + && let Some(def_id) = of_trait.trait_ref.trait_def_id() { // FIXME(const_trait_impl): Improve the span here. - self.tcx.check_const_stability(def_id, t.path.span, t.path.span); + self.tcx.check_const_stability( + def_id, + of_trait.trait_ref.path.span, + of_trait.trait_ref.path.span, + ); } - for impl_item_ref in *items { + for impl_item_ref in items { let impl_item = self.tcx.associated_item(impl_item_ref.owner_id); if let Some(def_id) = impl_item.trait_item_def_id { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 5d02c02b23c2f..1bddbd03cc3d3 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1779,7 +1779,8 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { if let DefKind::Impl { of_trait: true } = tcx.def_kind(def_id) { let trait_ref = tcx.impl_trait_ref(def_id).unwrap(); let trait_ref = trait_ref.instantiate_identity(); - visitor.span = tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().path.span; + visitor.span = + tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().trait_ref.path.span; let _ = visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path()); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index ae72178c052e4..bc8c8a444058d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3471,8 +3471,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .. })) => { let mut spans = Vec::with_capacity(2); - if let Some(trait_ref) = of_trait { - spans.push(trait_ref.path.span); + if let Some(of_trait) = of_trait { + spans.push(of_trait.trait_ref.path.span); } spans.push(self_ty.span); let mut spans: MultiSpan = spans.into(); @@ -3480,7 +3480,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self_ty.span.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _) ) || matches!( - of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind), + of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind), Some(ExpnKind::Macro(MacroKind::Derive, _)) ) { spans.push_span_label( @@ -3592,7 +3592,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .. })) => { let mut spans = vec![self_ty.span]; - spans.extend(of_trait.as_ref().map(|t| t.path.span)); + spans.extend(of_trait.map(|t| t.trait_ref.path.span)); let mut spans: MultiSpan = spans.into(); spans.push_span_label(data.span, "unsatisfied trait bound introduced here"); err.span_note(spans, msg); diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 37cb64511c7a2..e9629e31482a2 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -174,10 +174,10 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( }) .collect(), ItemKind::Impl(impl_) => { - let Some(trait_ref) = impl_.of_trait else { + let Some(of_trait) = impl_.of_trait else { return Default::default(); }; - let Some(trait_def_id) = trait_ref.trait_def_id() else { + let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else { return Default::default(); }; let in_trait_def = tcx.associated_types_for_impl_traits_in_trait_or_impl(trait_def_id); diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 6fa763f18ef19..cdfb93c4e7d56 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -172,10 +172,12 @@ fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator let trait_args = impl_ .of_trait .into_iter() - .flat_map(|trait_ref| trait_ref.path.segments.last().unwrap().args().args) + .flat_map(|of_trait| of_trait.trait_ref.path.segments.last().unwrap().args().args) .map(|arg| arg.span()); - let dummy_spans_for_default_args = - impl_.of_trait.into_iter().flat_map(|trait_ref| iter::repeat(trait_ref.path.span)); + let dummy_spans_for_default_args = impl_ + .of_trait + .into_iter() + .flat_map(|of_trait| iter::repeat(of_trait.trait_ref.path.span)); iter::once(impl_.self_ty.span).chain(trait_args).chain(dummy_spans_for_default_args) } else { bug!("unexpected item for impl {def_id:?}: {item:?}") diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index dc6009116ac57..d95660810e5ff 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -87,7 +87,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( DefKind::InlineConst | DefKind::Closure | DefKind::SyntheticCoroutineBody => {} DefKind::Impl { of_trait } => { if of_trait { - let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span; + let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().trait_ref.path.span; let args = &tcx.impl_trait_ref(item).unwrap().instantiate_identity().args[1..]; try_visit!(visitor.visit(span, args)); } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 2e0b16d922763..b22c326b9f2ab 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -81,7 +81,11 @@ fn sizedness_constraint_for_ty<'tcx>( fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { match tcx.hir_node_by_def_id(def_id) { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { defaultness, of_trait: Some(_), .. }), + kind: + hir::ItemKind::Impl(hir::Impl { + of_trait: Some(hir::TraitImplHeader { defaultness, .. }), + .. + }), .. }) | hir::Node::ImplItem(hir::ImplItem { defaultness, .. }) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7194c2fcededa..890bfaced6cd6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2768,7 +2768,7 @@ fn clean_maybe_renamed_item<'tcx>( // These kinds of item either don't need a `name` or accept a `None` one so we handle them // before. match item.kind { - ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx), + ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.owner_id.def_id, cx), ItemKind::Use(path, kind) => { return clean_use_statement( item, @@ -2896,7 +2896,7 @@ fn clean_impl<'tcx>( ) -> Vec { let tcx = cx.tcx; let mut ret = Vec::new(); - let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx)); + let trait_ = impl_.of_trait.map(|t| clean_trait_ref(&t.trait_ref, cx)); let items = impl_ .items .iter() @@ -2922,7 +2922,10 @@ fn clean_impl<'tcx>( }); let mut make_item = |trait_: Option, for_: Type, items: Vec| { let kind = ImplItem(Box::new(Impl { - safety: impl_.safety, + safety: match impl_.of_trait { + Some(of_trait) => of_trait.safety, + None => hir::Safety::Safe, + }, generics: clean_generics(impl_.generics, cx), trait_, for_, diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index d6469d32931d9..36498adff502e 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -534,6 +534,7 @@ fn get_item_name(item: &Item<'_>) -> Option { if let Some(of_trait) = im.of_trait { let mut trait_segs: Vec = of_trait + .trait_ref .path .segments .iter() diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs index 4ecf3e41611b1..51aebd8b0cfba 100644 --- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs @@ -37,12 +37,12 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]); impl<'tcx> LateLintPass<'tcx> for CopyIterator { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Impl(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), .. }) = item.kind && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && is_copy(cx, ty) - && let Some(trait_id) = trait_ref.trait_def_id() + && let Some(trait_id) = of_trait.trait_ref.trait_def_id() && cx.tcx.is_diagnostic_item(sym::Iterator, trait_id) { span_lint_and_note( diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index 0a481ddcd12e4..7580d6cab66d4 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -183,14 +183,14 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex impl<'tcx> LateLintPass<'tcx> for DerivableImpls { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Impl(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), items: [child], self_ty, .. }) = item.kind && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) && !item.span.from_expansion() - && let Some(def_id) = trait_ref.trait_def_id() + && let Some(def_id) = of_trait.trait_ref.trait_def_id() && cx.tcx.is_diagnostic_item(sym::Default, def_id) && let impl_item_hir = child.hir_id() && let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir) diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 49dd1bb09c61c..c53a957f6a8b7 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -201,10 +201,11 @@ declare_lint_pass!(Derive => [ impl<'tcx> LateLintPass<'tcx> for Derive { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Impl(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), .. }) = item.kind { + let trait_ref = &of_trait.trait_ref; let ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id()); diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs index 4e948701da4ff..2b8221884344f 100644 --- a/src/tools/clippy/clippy_lints/src/empty_drop.rs +++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs @@ -36,11 +36,11 @@ declare_lint_pass!(EmptyDrop => [EMPTY_DROP]); impl LateLintPass<'_> for EmptyDrop { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Impl(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), items: [child], .. }) = item.kind - && trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait() + && of_trait.trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait() && let impl_item_hir = child.hir_id() && let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir) && let ImplItemKind::Fn(_, b) = &impl_item.kind diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs index 6525648efb1e9..3018e1f127347 100644 --- a/src/tools/clippy/clippy_lints/src/error_impl_error.rs +++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { ); }, ItemKind::Impl(imp) - if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id()) + if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_ref.trait_def_id()) && let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) && error_def_id == trait_def_id && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local) diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index 0535ecf5240f9..416aea51ea195 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -254,10 +254,10 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio if impl_item.ident.name == sym::fmt && let ImplItemKind::Fn(_, body_id) = impl_item.kind && let Some(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), .. }) = get_parent_as_impl(cx.tcx, impl_item.hir_id()) - && let Some(did) = trait_ref.trait_def_id() + && let Some(did) = of_trait.trait_ref.trait_def_id() && let Some(name) = cx.tcx.get_diagnostic_name(did) && matches!(name, sym::Debug | sym::Display) { diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index 1da6952eb64c4..e3bb5ee10db7c 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -67,12 +67,12 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]); impl<'tcx> LateLintPass<'tcx> for FromOverInto { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Impl(Impl { - of_trait: Some(hir_trait_ref), + of_trait: Some(of_trait), self_ty, items: [impl_item_ref], .. }) = item.kind - && let Some(into_trait_seg) = hir_trait_ref.path.segments.last() + && let Some(into_trait_seg) = of_trait.trait_ref.path.segments.last() // `impl Into for self_ty` && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args && span_is_local(item.span) diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs index cb83b1395d260..3105e303ae31f 100644 --- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs @@ -54,8 +54,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { if let ImplItemKind::Fn(_, body_id) = impl_item.kind && let hir::Node::Item(item) = cx.tcx.parent_hir_node(impl_item.hir_id()) && let hir::ItemKind::Impl(impl_) = item.kind - && let hir::Impl { of_trait, .. } = *impl_ - && of_trait.is_none() + && let hir::Impl { of_trait: None, .. } = impl_ && let body = cx.tcx.hir_body(body_id) && cx.tcx.visibility(cx.tcx.hir_body_owner_def_id(body.id())).is_public() && !is_in_test(cx.tcx, impl_item.hir_id()) diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs index 0d6191f2c9715..0a7c6e9d5f8e1 100644 --- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs @@ -15,11 +15,11 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored && let parent_node = cx.tcx.parent_hir_node(item.hir_id()) && let Node::Item(parent_item) = parent_node && let ItemKind::Impl(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), .. }) = &parent_item.kind && let Some(did) = trait_item_def_id_of_impl(cx, item.owner_id) - && !is_from_ignored_trait(trait_ref, ignored_traits) + && !is_from_ignored_trait(&of_trait.trait_ref, ignored_traits) { let mut param_idents_iter = cx.tcx.hir_body_param_idents(body_id); let mut default_param_idents_iter = cx.tcx.fn_arg_idents(did).iter().copied(); diff --git a/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs b/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs index 940adbae428e8..f73182d3af0d2 100644 --- a/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Item, ItemKind, Path, TraitRef}; +use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::declare_lint_pass; @@ -76,10 +76,10 @@ impl LateLintPass<'_> for ImplHashWithBorrowStrBytes { /// three of `Hash`, `Borrow` and `Borrow<[u8]>`. fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if let ItemKind::Impl(imp) = item.kind - && let Some(TraitRef {path: Path {span, res, ..}, ..}) = imp.of_trait + && let Some(of_trait) = imp.of_trait && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let Some(hash_id) = cx.tcx.get_diagnostic_item(sym::Hash) - && Res::Def(DefKind::Trait, hash_id) == *res + && Res::Def(DefKind::Trait, hash_id) == of_trait.trait_ref.path.res && let Some(borrow_id) = cx.tcx.get_diagnostic_item(sym::Borrow) // since we are in the `Hash` impl, we don't need to check for that. // we need only to check for `Borrow` and `Borrow<[u8]>` @@ -89,7 +89,7 @@ impl LateLintPass<'_> for ImplHashWithBorrowStrBytes { span_lint_and_then( cx, IMPL_HASH_BORROW_WITH_STR_AND_BYTES, - *span, + of_trait.trait_ref.path.span, "the semantics of `Borrow` around `Hash` can't be satisfied when both `Borrow` and `Borrow<[u8]>` are implemented", |diag| { diag.note("the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow"); diff --git a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs index 589c294a678a2..36df07a437058 100644 --- a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs +++ b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs @@ -45,8 +45,8 @@ declare_lint_pass!(InfallibleTryFrom => [INFALLIBLE_TRY_FROM]); impl<'tcx> LateLintPass<'tcx> for InfallibleTryFrom { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { let ItemKind::Impl(imp) = item.kind else { return }; - let Some(r#trait) = imp.of_trait else { return }; - let Some(trait_def_id) = r#trait.trait_def_id() else { + let Some(of_trait) = imp.of_trait else { return }; + let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else { return; }; if !cx.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) { diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index b89f91f7255fb..645e0f981f27e 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -125,8 +125,9 @@ impl LateLintPass<'_> for IterWithoutIntoIter { fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) { if let ItemKind::Impl(imp) = item.kind && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind - && let Some(trait_ref) = imp.of_trait - && trait_ref + && let Some(of_trait) = imp.of_trait + && of_trait + .trait_ref .trait_def_id() .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) && !item.span.in_external_macro(cx.sess().source_map()) diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 35c9d2fd4eb86..149ae5e710c1f 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { } = item.kind { check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv); - } else if let ItemKind::Impl(impl_) = item.kind + } else if let ItemKind::Impl(impl_) = &item.kind && !item.span.from_expansion() { report_extra_impl_lifetimes(cx, impl_); @@ -712,8 +712,8 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<' let mut checker = LifetimeChecker::::new(cx, impl_.generics); walk_generics(&mut checker, impl_.generics); - if let Some(ref trait_ref) = impl_.of_trait { - walk_trait_ref(&mut checker, trait_ref); + if let Some(of_trait) = impl_.of_trait { + walk_trait_ref(&mut checker, &of_trait.trait_ref); } walk_unambig_ty(&mut checker, impl_.self_ty); for &item in impl_.items { diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index 18e2b384a463d..8822b32b1c3d6 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs @@ -198,8 +198,8 @@ fn check_struct<'tcx>( impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { // is this an `impl Debug for X` block? - if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, .. }) = item.kind - && let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res + if let ItemKind::Impl(Impl { of_trait: Some(of_trait), self_ty, .. }) = item.kind + && let Res::Def(DefKind::Trait, trait_def_id) = of_trait.trait_ref.path.res && let TyKind::Path(QPath::Resolved(_, self_path)) = &self_ty.kind // make sure that the self type is either a struct, an enum or a union // this prevents ICEs such as when self is a type parameter or a primitive type diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 399bf4e18064c..9cc93bf06531a 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -61,10 +61,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { if !is_lint_allowed(cx, MISSING_TRAIT_METHODS, item.hir_id()) && span_is_local(item.span) && let ItemKind::Impl(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), .. }) = item.kind - && let Some(trait_id) = trait_ref.trait_def_id() + && let Some(trait_id) = of_trait.trait_ref.trait_def_id() { let trait_item_ids: DefIdSet = cx .tcx diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 388c029c9ef45..8a5a6f4a4dc1e 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -778,7 +778,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { if let Node::Item(parent_item) = cx.tcx.parent_hir_node(item.hir_id()) && let ItemKind::Impl(impl_block) = parent_item.kind && let Some(of_trait) = impl_block.of_trait - && let Some(trait_id) = of_trait.trait_def_id() + && let Some(trait_id) = of_trait.trait_ref.trait_def_id() { // Replace all instances of `::AssocType` with the // unit type and check again. If the result is the same then the diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs index 8ff78ec7c580d..b810bc01fbdcb 100644 --- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -83,10 +83,10 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { if !item.span.in_external_macro(cx.tcx.sess.source_map()) && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send) && let ItemKind::Impl(hir_impl) = &item.kind - && let Some(trait_ref) = &hir_impl.of_trait - && let Some(trait_id) = trait_ref.trait_def_id() + && let Some(of_trait) = &hir_impl.of_trait + && let Some(trait_id) = of_trait.trait_ref.trait_def_id() && send_trait == trait_id - && hir_impl.polarity == ImplPolarity::Positive + && of_trait.polarity == ImplPolarity::Positive && let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id) && let self_ty = ty_trait_ref.instantiate_identity().self_ty() && let ty::Adt(adt_def, impl_trait_args) = self_ty.kind() diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs index 0a1f2625f4cfc..9c160ff680ec8 100644 --- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs +++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs @@ -183,7 +183,7 @@ fn in_impl<'tcx>( && let item = cx.tcx.hir_expect_item(impl_def_id.expect_local()) && let ItemKind::Impl(item) = &item.kind && let Some(of_trait) = &item.of_trait - && let Some(seg) = of_trait.path.segments.last() + && let Some(seg) = of_trait.trait_ref.path.segments.last() && let Res::Def(_, trait_id) = seg.res && trait_id == bin_op && let Some(generic_args) = seg.args diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs index 301b2cd4bf2fc..77751e75a8e14 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs @@ -34,15 +34,15 @@ declare_lint_pass!(PartialEqNeImpl => [PARTIALEQ_NE_IMPL]); impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Impl(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), items: impl_items, .. }) = item.kind && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) && let Some(eq_trait) = cx.tcx.lang_items().eq_trait() - && trait_ref.path.res.def_id() == eq_trait + && of_trait.trait_ref.path.res.def_id() == eq_trait { - for impl_item in *impl_items { + for impl_item in impl_items { if cx.tcx.item_name(impl_item.owner_id) == sym::ne { span_lint_hir( cx, diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs index 67eb71f7d0747..b87751f498643 100644 --- a/src/tools/clippy/clippy_lints/src/same_name_method.rs +++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs @@ -68,9 +68,9 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { let existing_name = map.get_mut(res).unwrap(); match of_trait { - Some(trait_ref) => { + Some(of_trait) => { let mut methods_in_trait: BTreeSet = if let Node::TraitRef(TraitRef { path, .. }) = - cx.tcx.hir_node(trait_ref.hir_ref_id) + cx.tcx.hir_node(of_trait.trait_ref.hir_ref_id) && let Res::Def(DefKind::Trait, did) = path.res { // FIXME: if diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs index 2de22e4b6a360..01c7f394b9adc 100644 --- a/src/tools/clippy/clippy_lints/src/serde_api.rs +++ b/src/tools/clippy/clippy_lints/src/serde_api.rs @@ -26,16 +26,16 @@ declare_lint_pass!(SerdeApi => [SERDE_API_MISUSE]); impl<'tcx> LateLintPass<'tcx> for SerdeApi { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { if let ItemKind::Impl(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), items, .. }) = item.kind { - let did = trait_ref.path.res.def_id(); + let did = of_trait.trait_ref.path.res.def_id(); if paths::SERDE_DE_VISITOR.matches(cx, did) { let mut seen_str = None; let mut seen_string = None; - for item in *items { + for item in items { match cx.tcx.item_name(item.owner_id) { sym::visit_str => seen_str = Some(cx.tcx.def_span(item.owner_id)), sym::visit_string => seen_string = Some(cx.tcx.def_span(item.owner_id)), diff --git a/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs b/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs index 9596b85664b34..303f6028bd51f 100644 --- a/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs +++ b/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs @@ -48,10 +48,10 @@ declare_lint_pass!(ToStringTraitImpl => [TO_STRING_TRAIT_IMPL]); impl<'tcx> LateLintPass<'tcx> for ToStringTraitImpl { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'tcx>) { if let ItemKind::Impl(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), .. }) = it.kind - && let Some(trait_did) = trait_ref.trait_def_id() + && let Some(trait_did) = of_trait.trait_ref.trait_def_id() && cx.tcx.is_diagnostic_item(sym::ToString, trait_did) { span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs index dcddff557d1c7..e843e169113e7 100644 --- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs @@ -137,9 +137,9 @@ fn get_impl_trait_def_id(cx: &LateContext<'_>, method_def_id: LocalDefId) -> Opt // We exclude `impl` blocks generated from rustc's proc macros. && !cx.tcx.is_automatically_derived(owner_id.to_def_id()) // It is a implementation of a trait. - && let Some(trait_) = impl_.of_trait + && let Some(of_trait) = impl_.of_trait { - trait_.trait_def_id() + of_trait.trait_ref.trait_def_id() } else { None } @@ -242,8 +242,8 @@ fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: Local // We exclude `impl` blocks generated from rustc's proc macros. && !cx.tcx.is_automatically_derived(owner_id.to_def_id()) // It is a implementation of a trait. - && let Some(trait_) = impl_.of_trait - && let Some(trait_def_id) = trait_.trait_def_id() + && let Some(of_trait) = impl_.of_trait + && let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() // The trait is `ToString`. && cx.tcx.is_diagnostic_item(sym::ToString, trait_def_id) { diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index cf603c6190ba1..1c52de52619ef 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -8,7 +8,7 @@ use clippy_utils::source::walk_span_to_context; use clippy_utils::visitors::{Descend, for_each_expr}; use hir::HirId; use rustc_hir as hir; -use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; +use rustc_hir::{Block, BlockCheckMode, Impl, ItemKind, Node, UnsafeSource}; use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; @@ -204,7 +204,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { let item_has_safety_comment = item_has_safety_comment(cx, item); match (&item.kind, item_has_safety_comment) { // lint unsafe impl without safety comment - (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.safety.is_unsafe() => { + (ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::No) if of_trait.safety.is_unsafe() => { if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id()) && !is_unsafe_from_proc_macro(cx, item.span) { @@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { } }, // lint safe impl with unnecessary safety comment - (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.safety.is_safe() => { + (ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::Yes(pos)) if of_trait.safety.is_safe() => { if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { let (span, help_span) = mk_spans(pos); diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index d9a007635cae1..a15e4e42e71df 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -347,10 +347,10 @@ impl<'tcx> LateLintPass<'tcx> for Write { fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { if let ItemKind::Impl(Impl { - of_trait: Some(trait_ref), + of_trait: Some(of_trait), .. }) = &item.kind - && let Some(trait_id) = trait_ref.trait_def_id() + && let Some(trait_id) = of_trait.trait_ref.trait_def_id() { cx.tcx.is_diagnostic_item(sym::Debug, trait_id) } else { diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index dc31ed08fb712..e0c1b9d445a2a 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -19,8 +19,8 @@ use rustc_ast::token::CommentKind; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, - ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety, - TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, + ImplItem, ImplItemKind, TraitImplHeader, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, + QPath, Safety, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, }; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -254,7 +254,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), ItemKind::Trait(_, _, Safety::Unsafe, ..) | ItemKind::Impl(Impl { - safety: Safety::Unsafe, .. + of_trait: Some(TraitImplHeader { safety: Safety::Unsafe, .. }), .. }) => (Pat::Str("unsafe"), Pat::Str("}")), ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index fc716d86fc629..fcc120656e3e9 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -528,8 +528,9 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx> pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, owner: OwnerId) -> Option<&'tcx TraitRef<'tcx>> { if let Node::Item(item) = cx.tcx.hir_node(cx.tcx.hir_owner_parent(owner)) && let ItemKind::Impl(impl_) = &item.kind + && let Some(of_trait) = impl_.of_trait { - return impl_.of_trait.as_ref(); + return Some(&of_trait.trait_ref); } None } diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index ba5cbc738361f..c9f5401ebe776 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -460,7 +460,8 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { } fn visit_nested_item(&mut self, id: ItemId) -> Self::Result { if let ItemKind::Impl(i) = &self.cx.tcx.hir_item(id).kind - && i.safety.is_unsafe() + && let Some(of_trait) = i.of_trait + && of_trait.safety.is_unsafe() { ControlFlow::Break(()) } else { diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 9cfa65f580126..e9823c9575bc9 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -509,7 +509,7 @@ mod items { impl () { } impl () { } impl Default for () { } - impl const Default for () { } + impl const Default for () { } } /// ItemKind::MacCall mod item_mac_call { } From f336cc777b84c29776e8cc1b148cf1065b9fae2d Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Tue, 12 Aug 2025 08:26:11 +0700 Subject: [PATCH 094/252] Make I-miscompile imply I-prioritize Since I-unsound already implies I-prioritize, it makes sense that I-miscompile should do the same. --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 71f1ed0fda3f2..6f6e95c5b50e9 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -207,6 +207,7 @@ trigger_labels = [ "regression-from-stable-to-beta", "regression-from-stable-to-nightly", "I-unsound", + "I-miscompile", ] exclude_labels = [ "P-*", From 57901fe09242582608dfbaa047ea006cf0c984a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=91=E6=80=95?= Date: Tue, 5 Aug 2025 16:40:46 +0800 Subject: [PATCH 095/252] E0793: Clarify that it applies to unions as well --- .../src/error_codes/E0793.md | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0793.md b/compiler/rustc_error_codes/src/error_codes/E0793.md index ccd1b43bd194a..2722dac104b7f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0793.md +++ b/compiler/rustc_error_codes/src/error_codes/E0793.md @@ -1,4 +1,9 @@ -An unaligned reference to a field of a [packed] struct got created. +An unaligned reference to a field of a [packed] `struct` or `union` was created. + +The `#[repr(packed)]` attribute removes padding between fields, which can +cause fields to be stored at unaligned memory addresses. Creating references +to such fields violates Rust's memory safety guarantees and can lead to +undefined behavior in optimized code. Erroneous code example: @@ -45,9 +50,36 @@ unsafe { // For formatting, we can create a copy to avoid the direct reference. let copy = foo.field1; println!("{}", copy); + // Creating a copy can be written in a single line with curly braces. // (This is equivalent to the two lines above.) println!("{}", { foo.field1 }); + + // A reference to a field that will always be sufficiently aligned is safe: + println!("{}", foo.field2); +} +``` + +### Unions + +Although creating a reference to a `union` field is `unsafe`, this error +will still be triggered if the referenced field is not sufficiently +aligned. Use `addr_of!` and raw pointers in the same way as for struct fields. + +```compile_fail,E0793 +#[repr(packed)] +pub union Foo { + field1: u64, + field2: u8, +} + +unsafe { + let foo = Foo { field1: 0 }; + // Accessing the field directly is fine. + let val = foo.field1; + + // A reference to a packed union field causes an error. + let val = &foo.field1; // ERROR } ``` From 1ce4b370e44fbac89b75438c8e75b26bff18d496 Mon Sep 17 00:00:00 2001 From: SabrinaJewson Date: Tue, 12 Aug 2025 05:12:34 +0100 Subject: [PATCH 096/252] Handle the `capacity == 0` case --- library/alloc/src/vec/mod.rs | 61 ++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index e02265dcafca3..8001faf9d20a5 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -51,19 +51,20 @@ //! //! # Memory layout //! -//! For non-zero-sized types, [`Vec`] uses the [`Global`] allocator for its allocation. It is -//! valid to convert both ways between a [`Vec`] and a raw pointer allocated with the [`Global`] -//! allocator, provided that the [`Layout`] used with the allocator is correct for a sequence of -//! `capacity` elements of the type, and the first `len` values pointed to by the raw pointer are -//! valid. More precisely, a `ptr: *mut T` that has been allocated with the [`Global`] allocator -//! with [`Layout::array::(capacity)`][Layout::array] may be converted into a vec using -//! [`Vec::::from_raw_parts(ptr, len, capacity)`](Vec::from_raw_parts). -//! Conversely, the memory backing a `value: *mut T` obtained from [`Vec::::as_mut_ptr`] may be -//! deallocated using the [`Global`] allocator with the same layout. +//! When the type is non-zero-sized and the capacity is nonzero, [`Vec`] uses the [`Global`] +//! allocator for its allocation. It is valid to convert both ways between such a [`Vec`] and a raw +//! pointer allocated with the [`Global`] allocator, provided that the [`Layout`] used with the +//! allocator is correct for a sequence of `capacity` elements of the type, and the first `len` +//! values pointed to by the raw pointer are valid. More precisely, a `ptr: *mut T` that has been +//! allocated with the [`Global`] allocator with [`Layout::array::(capacity)`][Layout::array] may +//! be converted into a vec using +//! [`Vec::::from_raw_parts(ptr, len, capacity)`](Vec::from_raw_parts). Conversely, the memory +//! backing a `value: *mut T` obtained from [`Vec::::as_mut_ptr`] may be deallocated using the +//! [`Global`] allocator with the same layout. //! -//! For zero-sized types (ZSTs), the `Vec` pointer must be non-null and sufficiently aligned. -//! The recommended way to build a `Vec` of ZSTs if [`vec!`] cannot be used is to use -//! [`ptr::NonNull::dangling`]. +//! For zero-sized types (ZSTs), or when the capacity is zero, the `Vec` pointer must be non-null +//! and sufficiently aligned. The recommended way to build a `Vec` of ZSTs if [`vec!`] cannot be +//! used is to use [`ptr::NonNull::dangling`]. //! //! [`push`]: Vec::push //! [`ptr::NonNull::dangling`]: NonNull::dangling @@ -542,18 +543,23 @@ impl Vec { /// This is highly unsafe, due to the number of invariants that aren't /// checked: /// - /// * `ptr` must have been allocated using the global allocator, such as via - /// the [`alloc::alloc`] function. - /// * `T` needs to have the same alignment as what `ptr` was allocated with. + /// * If `T` is not a zero-sized type and the capacity is nonzero, `ptr` must have + /// been allocated using the global allocator, such as via the [`alloc::alloc`] + /// function. If `T` is a zero-sized type or the capacity is zero, `ptr` need + /// only be non-null and aligned. + /// * `T` needs to have the same alignment as what `ptr` was allocated with, + /// if the pointer is required to be allocated. /// (`T` having a less strict alignment is not sufficient, the alignment really /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be /// allocated and deallocated with the same layout.) - /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs - /// to be the same size as the pointer was allocated with. (Because similar to - /// alignment, [`dealloc`] must be called with the same layout `size`.) + /// * The size of `T` times the `capacity` (ie. the allocated size in bytes), if + /// nonzero, needs to be the same size as the pointer was allocated with. + /// (Because similar to alignment, [`dealloc`] must be called with the same + /// layout `size`.) /// * `length` needs to be less than or equal to `capacity`. /// * The first `length` values must be properly initialized values of type `T`. - /// * `capacity` needs to be the capacity that the pointer was allocated with. + /// * `capacity` needs to be the capacity that the pointer was allocated with, + /// if the pointer is required to be allocated. /// * The allocated size in bytes must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// @@ -792,9 +798,10 @@ impl Vec { /// memory previously managed by the `Vec`. Most often, one does /// this by converting the raw pointer, length, and capacity back /// into a `Vec` with the [`from_raw_parts`] function; more generally, - /// if `T` is non-zero-sized one may use any method that calls - /// [`dealloc`] with a layout of `Layout::array::(capacity)`, - /// and if `T` is zero-sized nothing needs to be done. + /// if `T` is non-zero-sized and the capacity is nonzero, one may use + /// any method that calls [`dealloc`] with a layout of + /// `Layout::array::(capacity)`; if `T` is zero-sized or the + /// capacity is zero, nothing needs to be done. /// /// [`from_raw_parts`]: Vec::from_raw_parts /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc @@ -1777,11 +1784,11 @@ impl Vec { /// may still invalidate this pointer. /// See the second example below for how this guarantee can be used. /// - /// The method also guarantees that, as long as `T` is not zero-sized, the pointer may be - /// passed into [`dealloc`] with a layout of `Layout::array::(capacity)` in order to - /// deallocate the backing memory. If this is done, be careful not to run the destructor - /// of the `Vec`, as dropping it will result in double-frees. Wrapping the `Vec` in a - /// [`ManuallyDrop`] is the typical way to achieve this. + /// The method also guarantees that, as long as `T` is not zero-sized and the capacity is + /// nonzero, the pointer may be passed into [`dealloc`] with a layout of + /// `Layout::array::(capacity)` in order to deallocate the backing memory. If this is done, + /// be careful not to run the destructor of the `Vec`, as dropping it will result in + /// double-frees. Wrapping the `Vec` in a [`ManuallyDrop`] is the typical way to achieve this. /// /// # Examples /// From 2563e4a7ffe47e93c69283c14e6d660b08834cf1 Mon Sep 17 00:00:00 2001 From: Tom Vijlbrief Date: Mon, 11 Aug 2025 11:19:47 +0200 Subject: [PATCH 097/252] [AVR] Changed data_layout --- compiler/rustc_codegen_llvm/src/context.rs | 6 ++++++ compiler/rustc_target/src/spec/targets/avr_none.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ee77774c68832..27ae729a53110 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -213,6 +213,12 @@ pub(crate) unsafe fn create_module<'ll>( target_data_layout = target_data_layout.replace("p8:128:128:128:48", "p8:128:128") } } + if llvm_version < (22, 0, 0) { + if sess.target.arch == "avr" { + // LLVM 22.0 updated the default layout on avr: https://github.com/llvm/llvm-project/pull/153010 + target_data_layout = target_data_layout.replace("n8:16", "n8") + } + } // Ensure the data-layout values hardcoded remain the defaults. { diff --git a/compiler/rustc_target/src/spec/targets/avr_none.rs b/compiler/rustc_target/src/spec/targets/avr_none.rs index 07ed2a37803fb..ad056d0232670 100644 --- a/compiler/rustc_target/src/spec/targets/avr_none.rs +++ b/compiler/rustc_target/src/spec/targets/avr_none.rs @@ -9,7 +9,7 @@ pub(crate) fn target() -> Target { host_tools: None, std: None, }, - data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(), + data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8".into(), llvm_target: "avr-unknown-unknown".into(), pointer_width: 16, options: TargetOptions { From e4540224229d10a9a537519cad8a64f01060c0ea Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 12 Aug 2025 17:11:58 +1000 Subject: [PATCH 098/252] bootstrap: Only warn about `rust.debug-assertions` if downloading rustc --- src/bootstrap/src/core/config/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index c505cacadb5d2..a656927b1f64d 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -955,7 +955,7 @@ impl Config { config.download_rustc_commit = download_ci_rustc_commit(dwn_ctx, rust_download_rustc, config.llvm_assertions); - if debug_assertions_requested { + if debug_assertions_requested && config.download_rustc_commit.is_some() { eprintln!( "WARN: `rust.debug-assertions = true` will prevent downloading CI rustc as alt CI \ rustc is not currently built with debug assertions." From 5e4f465655157365c016834dd3db6045d649483c Mon Sep 17 00:00:00 2001 From: Ada Alakbarova <58857108+ada4a@users.noreply.github.com> Date: Tue, 12 Aug 2025 09:43:17 +0200 Subject: [PATCH 099/252] fix typo --- library/core/src/ops/range.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index f33a33e6b752f..95d1e2069ac94 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -853,7 +853,7 @@ pub trait RangeBounds { /// assert!( RangeBounds::is_empty(&(f32::NAN..5.0))); /// ``` /// - /// But never empty is either side is unbounded: + /// But never empty if either side is unbounded: /// /// ``` /// #![feature(range_bounds_is_empty)] From a279ba4349d26062ef24cdc7d90ae09437b97a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 5 Aug 2025 17:46:56 +0200 Subject: [PATCH 100/252] Consolidate stageN directories in the build directory Now stageN-X corresponds to stage N X, as it should. --- src/bootstrap/src/bin/rustc.rs | 2 +- src/bootstrap/src/bin/rustdoc.rs | 4 ++-- src/bootstrap/src/core/build_steps/clean.rs | 2 +- src/bootstrap/src/core/build_steps/tool.rs | 6 +++--- src/bootstrap/src/lib.rs | 23 +++++++++++++-------- src/bootstrap/src/utils/shared_helpers.rs | 5 +++-- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 0364c664ba512..5865df67b669a 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -258,7 +258,7 @@ fn main() { eprintln!("{prefix} libdir: {libdir:?}"); } - maybe_dump(format!("stage{stage}-rustc"), &cmd); + maybe_dump(format!("stage{}-rustc", stage + 1), &cmd); let start = Instant::now(); let (child, status) = { diff --git a/src/bootstrap/src/bin/rustdoc.rs b/src/bootstrap/src/bin/rustdoc.rs index a338b9c808013..efb51bdce1e0e 100644 --- a/src/bootstrap/src/bin/rustdoc.rs +++ b/src/bootstrap/src/bin/rustdoc.rs @@ -56,11 +56,11 @@ fn main() { // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`. // We also declare that the flag is expected, which we need to do to not // get warnings about it being unexpected. - if stage == "0" { + if stage == 0 { cmd.arg("--cfg=bootstrap"); } - maybe_dump(format!("stage{stage}-rustdoc"), &cmd); + maybe_dump(format!("stage{}-rustdoc", stage + 1), &cmd); if verbose > 1 { eprintln!( diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index f67569d148607..8712aeb81eb88 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -129,7 +129,7 @@ fn clean_specific_stage(build: &Build, stage: u32) { for entry in entries { let entry = t!(entry); - let stage_prefix = format!("stage{stage}"); + let stage_prefix = format!("stage{}", stage + 1); // if current entry is not related with the target stage, continue if !entry.file_name().to_str().unwrap_or("").contains(&stage_prefix) { diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 42f59f00e5a19..5e4ebb2755da0 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -380,13 +380,13 @@ pub(crate) fn get_tool_target_compiler( /// tools directory. fn copy_link_tool_bin( builder: &Builder<'_>, - compiler: Compiler, + build_compiler: Compiler, target: TargetSelection, mode: Mode, name: &str, ) -> PathBuf { - let cargo_out = builder.cargo_out(compiler, mode, target).join(exe(name, target)); - let bin = builder.tools_dir(compiler).join(exe(name, target)); + let cargo_out = builder.cargo_out(build_compiler, mode, target).join(exe(name, target)); + let bin = builder.tools_dir(build_compiler).join(exe(name, target)); builder.copy_link(&cargo_out, &bin, FileType::Executable); bin } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 4abf386e5de61..341ddf8da4f44 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -859,14 +859,17 @@ impl Build { if self.config.rust_optimize.is_release() { "release" } else { "debug" } } - fn tools_dir(&self, compiler: Compiler) -> PathBuf { - let out = self.out.join(compiler.host).join(format!("stage{}-tools-bin", compiler.stage)); + fn tools_dir(&self, build_compiler: Compiler) -> PathBuf { + let out = self + .out + .join(build_compiler.host) + .join(format!("stage{}-tools-bin", build_compiler.stage + 1)); t!(fs::create_dir_all(&out)); out } /// Returns the root directory for all output generated in a particular - /// stage when running with a particular host compiler. + /// stage when being built with a particular build compiler. /// /// The mode indicates what the root directory is for. fn stage_out(&self, build_compiler: Compiler, mode: Mode) -> PathBuf { @@ -876,15 +879,17 @@ impl Build { (None, "bootstrap-tools") } fn staged_tool(build_compiler: Compiler) -> (Option, &'static str) { - (Some(build_compiler.stage), "tools") + (Some(build_compiler.stage + 1), "tools") } let (stage, suffix) = match mode { + // Std is special, stage N std is built with stage N rustc Mode::Std => (Some(build_compiler.stage), "std"), - Mode::Rustc => (Some(build_compiler.stage), "rustc"), - Mode::Codegen => (Some(build_compiler.stage), "codegen"), + // The rest of things are built with stage N-1 rustc + Mode::Rustc => (Some(build_compiler.stage + 1), "rustc"), + Mode::Codegen => (Some(build_compiler.stage + 1), "codegen"), Mode::ToolBootstrap => bootstrap_tool(), - Mode::ToolStd | Mode::ToolRustc => (Some(build_compiler.stage), "tools"), + Mode::ToolStd | Mode::ToolRustc => (Some(build_compiler.stage + 1), "tools"), Mode::ToolTarget => { // If we're not cross-compiling (the common case), share the target directory with // bootstrap tools to reuse the build cache. @@ -907,8 +912,8 @@ impl Build { /// Returns the root output directory for all Cargo output in a given stage, /// running a particular compiler, whether or not we're building the /// standard library, and targeting the specified architecture. - fn cargo_out(&self, compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf { - self.stage_out(compiler, mode).join(target).join(self.cargo_dir()) + fn cargo_out(&self, build_compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf { + self.stage_out(build_compiler, mode).join(target).join(self.cargo_dir()) } /// Root output directory of LLVM for `target` diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs index 9428e221f4122..d620cc4bbb6b4 100644 --- a/src/bootstrap/src/utils/shared_helpers.rs +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -81,10 +81,11 @@ pub fn parse_rustc_verbose() -> usize { } /// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`. +/// This is the stage of the *build compiler*, which we are wrapping using a rustc/rustdoc wrapper. /// /// If "RUSTC_STAGE" was not set, the program will be terminated with 101. -pub fn parse_rustc_stage() -> String { - env::var("RUSTC_STAGE").unwrap_or_else(|_| { +pub fn parse_rustc_stage() -> u32 { + env::var("RUSTC_STAGE").ok().and_then(|v| v.parse().ok()).unwrap_or_else(|| { // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead. eprintln!("rustc shim: FATAL: RUSTC_STAGE was not set"); eprintln!("rustc shim: NOTE: use `x.py build -vvv` to see all environment variables set by bootstrap"); From db1a64c93b087c1209a2f1f6d29059f3134ba8e3 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 5 Aug 2025 15:28:25 +0200 Subject: [PATCH 101/252] simplify stack handling, be completely lazy --- .../rustc_type_ir/src/search_graph/mod.rs | 141 +++++++++++------- .../rustc_type_ir/src/search_graph/stack.rs | 22 +-- 2 files changed, 95 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index daacb4a3e446e..24094eeea8d47 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -12,10 +12,11 @@ //! The global cache has to be completely unobservable, while the per-cycle cache may impact //! behavior as long as the resulting behavior is still correct. use std::cmp::Ordering; -use std::collections::BTreeMap; use std::collections::hash_map::Entry; +use std::collections::{BTreeMap, btree_map}; use std::fmt::Debug; use std::hash::Hash; +use std::iter; use std::marker::PhantomData; use derive_where::derive_where; @@ -230,13 +231,19 @@ impl AvailableDepth { } } +#[derive(Clone, Copy, Debug)] +struct CycleHead { + paths_to_head: PathsToNested, + usage_kind: UsageKind, +} + /// All cycle heads a given goal depends on, ordered by their stack depth. /// /// We also track all paths from this goal to that head. This is necessary /// when rebasing provisional cache results. #[derive(Clone, Debug, Default)] struct CycleHeads { - heads: BTreeMap, + heads: BTreeMap, } impl CycleHeads { @@ -256,32 +263,32 @@ impl CycleHeads { self.heads.first_key_value().map(|(k, _)| *k) } - fn remove_highest_cycle_head(&mut self) -> PathsToNested { + fn remove_highest_cycle_head(&mut self) -> CycleHead { let last = self.heads.pop_last(); last.unwrap().1 } - fn insert(&mut self, head: StackDepth, path_from_entry: impl Into + Copy) { - *self.heads.entry(head).or_insert(path_from_entry.into()) |= path_from_entry.into(); + fn insert( + &mut self, + head_index: StackDepth, + path_from_entry: impl Into + Copy, + usage_kind: UsageKind, + ) { + match self.heads.entry(head_index) { + btree_map::Entry::Vacant(entry) => { + entry.insert(CycleHead { paths_to_head: path_from_entry.into(), usage_kind }); + } + btree_map::Entry::Occupied(entry) => { + let head = entry.into_mut(); + head.paths_to_head |= path_from_entry.into(); + head.usage_kind = head.usage_kind.merge(usage_kind); + } + } } - fn iter(&self) -> impl Iterator + '_ { + fn iter(&self) -> impl Iterator + '_ { self.heads.iter().map(|(k, v)| (*k, *v)) } - - /// Update the cycle heads of a goal at depth `this` given the cycle heads - /// of a nested goal. This merges the heads after filtering the parent goal - /// itself. - fn extend_from_child(&mut self, this: StackDepth, step_kind: PathKind, child: &CycleHeads) { - for (&head, &path_from_entry) in child.heads.iter() { - match head.cmp(&this) { - Ordering::Less => {} - Ordering::Equal => continue, - Ordering::Greater => unreachable!(), - } - self.insert(head, path_from_entry.extend_with(step_kind)); - } - } } bitflags::bitflags! { @@ -487,9 +494,6 @@ impl EvaluationResult { pub struct SearchGraph, X: Cx = ::Cx> { root_depth: AvailableDepth, - /// The stack of goals currently being computed. - /// - /// An element is *deeper* in the stack if its index is *lower*. stack: Stack, /// The provisional cache contains entries for already computed goals which /// still depend on goals higher-up in the stack. We don't move them to the @@ -511,6 +515,7 @@ pub struct SearchGraph, X: Cx = ::Cx> { /// cache entry. enum UpdateParentGoalCtxt<'a, X: Cx> { Ordinary(&'a NestedGoals), + CycleOnStack(X::Input), ProvisionalCacheHit, } @@ -532,21 +537,42 @@ impl, X: Cx> SearchGraph { stack: &mut Stack, step_kind_from_parent: PathKind, required_depth_for_nested: usize, - heads: &CycleHeads, + heads: impl Iterator, encountered_overflow: bool, context: UpdateParentGoalCtxt<'_, X>, ) { - if let Some(parent_index) = stack.last_index() { - let parent = &mut stack[parent_index]; + if let Some((parent_index, parent)) = stack.last_mut_with_index() { parent.required_depth = parent.required_depth.max(required_depth_for_nested + 1); parent.encountered_overflow |= encountered_overflow; - parent.heads.extend_from_child(parent_index, step_kind_from_parent, heads); + for (head_index, head) in heads { + match head_index.cmp(&parent_index) { + Ordering::Less => parent.heads.insert( + head_index, + head.paths_to_head.extend_with(step_kind_from_parent), + head.usage_kind, + ), + Ordering::Equal => { + let usage_kind = parent + .has_been_used + .map_or(head.usage_kind, |prev| prev.merge(head.usage_kind)); + parent.has_been_used = Some(usage_kind); + } + Ordering::Greater => unreachable!(), + } + } let parent_depends_on_cycle = match context { UpdateParentGoalCtxt::Ordinary(nested_goals) => { parent.nested_goals.extend_from_child(step_kind_from_parent, nested_goals); !nested_goals.is_empty() } + UpdateParentGoalCtxt::CycleOnStack(head) => { + // We lookup provisional cache entries before detecting cycles. + // We therefore can't use a global cache entry if it contains a cycle + // whose head is in the provisional cache. + parent.nested_goals.insert(head, step_kind_from_parent.into()); + true + } UpdateParentGoalCtxt::ProvisionalCacheHit => true, }; // Once we've got goals which encountered overflow or a cycle, @@ -674,7 +700,7 @@ impl, X: Cx> SearchGraph { &mut self.stack, step_kind_from_parent, evaluation_result.required_depth, - &evaluation_result.heads, + evaluation_result.heads.iter(), evaluation_result.encountered_overflow, UpdateParentGoalCtxt::Ordinary(&evaluation_result.nested_goals), ); @@ -772,7 +798,7 @@ impl, X: Cx> SearchGraph { stack_entry: &StackEntry, mut mutate_result: impl FnMut(X::Input, X::Result) -> X::Result, ) { - let popped_head = self.stack.next_index(); + let popped_head_index = self.stack.next_index(); #[allow(rustc::potential_query_instability)] self.provisional_cache.retain(|&input, entries| { entries.retain_mut(|entry| { @@ -782,7 +808,7 @@ impl, X: Cx> SearchGraph { path_from_head, result, } = entry; - let ep = if heads.highest_cycle_head() == popped_head { + let popped_head = if heads.highest_cycle_head() == popped_head_index { heads.remove_highest_cycle_head() } else { return true; @@ -795,9 +821,14 @@ impl, X: Cx> SearchGraph { // // After rebasing the cycles `hph` will go through `e`. We need to make // sure that forall possible paths `hep`, `heph` is equal to `hph.` - for (h, ph) in stack_entry.heads.iter() { - let hp = - Self::cycle_path_kind(&self.stack, stack_entry.step_kind_from_parent, h); + let ep = popped_head.paths_to_head; + for (head_index, head) in stack_entry.heads.iter() { + let ph = head.paths_to_head; + let hp = Self::cycle_path_kind( + &self.stack, + stack_entry.step_kind_from_parent, + head_index, + ); // We first validate that all cycles while computing `p` would stay // the same if we were to recompute it as a nested goal of `e`. @@ -817,7 +848,7 @@ impl, X: Cx> SearchGraph { // the heads of `e` to make sure that rebasing `e` again also considers // them. let eph = ep.extend_with_paths(ph); - heads.insert(h, eph); + heads.insert(head_index, eph, head.usage_kind); } let Some(head) = heads.opt_highest_cycle_head() else { @@ -877,11 +908,10 @@ impl, X: Cx> SearchGraph { &mut self.stack, step_kind_from_parent, 0, - heads, + heads.iter(), encountered_overflow, UpdateParentGoalCtxt::ProvisionalCacheHit, ); - debug_assert!(self.stack[head].has_been_used.is_some()); debug!(?head, ?path_from_head, "provisional cache hit"); return Some(result); } @@ -993,12 +1023,12 @@ impl, X: Cx> SearchGraph { // We don't move cycle participants to the global cache, so the // cycle heads are always empty. - let heads = Default::default(); + let heads = iter::empty(); Self::update_parent_goal( &mut self.stack, step_kind_from_parent, required_depth, - &heads, + heads, encountered_overflow, UpdateParentGoalCtxt::Ordinary(nested_goals), ); @@ -1014,34 +1044,31 @@ impl, X: Cx> SearchGraph { input: X::Input, step_kind_from_parent: PathKind, ) -> Option { - let head = self.stack.find(input)?; + let head_index = self.stack.find(input)?; // We have a nested goal which directly relies on a goal deeper in the stack. // // We start by tagging all cycle participants, as that's necessary for caching. // // Finally we can return either the provisional response or the initial response // in case we're in the first fixpoint iteration for this goal. - let path_kind = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head); - debug!(?path_kind, "encountered cycle with depth {head:?}"); - let usage_kind = UsageKind::Single(path_kind); - self.stack[head].has_been_used = - Some(self.stack[head].has_been_used.map_or(usage_kind, |prev| prev.merge(usage_kind))); - - // Subtle: when encountering a cyclic goal, we still first checked for overflow, - // so we have to update the reached depth. - let last_index = self.stack.last_index().unwrap(); - let last = &mut self.stack[last_index]; - last.required_depth = last.required_depth.max(1); - - last.nested_goals.insert(input, step_kind_from_parent.into()); - last.nested_goals.insert(last.input, PathsToNested::EMPTY); - if last_index != head { - last.heads.insert(head, step_kind_from_parent); - } + let path_kind = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head_index); + debug!(?path_kind, "encountered cycle with depth {head_index:?}"); + let head = CycleHead { + paths_to_head: step_kind_from_parent.into(), + usage_kind: UsageKind::Single(path_kind), + }; + Self::update_parent_goal( + &mut self.stack, + step_kind_from_parent, + 0, + iter::once((head_index, head)), + false, + UpdateParentGoalCtxt::CycleOnStack(input), + ); // Return the provisional result or, if we're in the first iteration, // start with no constraints. - if let Some(result) = self.stack[head].provisional_result { + if let Some(result) = self.stack[head_index].provisional_result { Some(result) } else { Some(D::initial_provisional_result(cx, path_kind, input)) diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs index a58cd82b02303..ea99dc6e7fd28 100644 --- a/compiler/rustc_type_ir/src/search_graph/stack.rs +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -1,4 +1,4 @@ -use std::ops::{Index, IndexMut}; +use std::ops::Index; use derive_where::derive_where; use rustc_index::IndexVec; @@ -48,6 +48,12 @@ pub(super) struct StackEntry { pub nested_goals: NestedGoals, } +/// The stack of goals currently being computed. +/// +/// An element is *deeper* in the stack if its index is *lower*. +/// +/// Only the last entry of the stack is mutable. All other entries get +/// lazily updated in `update_parent_goal`. #[derive_where(Default; X: Cx)] pub(super) struct Stack { entries: IndexVec>, @@ -62,10 +68,6 @@ impl Stack { self.entries.len() } - pub(super) fn last_index(&self) -> Option { - self.entries.last_index() - } - pub(super) fn last(&self) -> Option<&StackEntry> { self.entries.raw.last() } @@ -74,6 +76,10 @@ impl Stack { self.entries.raw.last_mut() } + pub(super) fn last_mut_with_index(&mut self) -> Option<(StackDepth, &mut StackEntry)> { + self.entries.last_index().map(|idx| (idx, &mut self.entries[idx])) + } + pub(super) fn next_index(&self) -> StackDepth { self.entries.next_index() } @@ -108,9 +114,3 @@ impl Index for Stack { &self.entries[index] } } - -impl IndexMut for Stack { - fn index_mut(&mut self, index: StackDepth) -> &mut Self::Output { - &mut self.entries[index] - } -} From fbfcfa6bcebe939a89670baea09ef8b56f2dcf1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 10:15:16 +0200 Subject: [PATCH 102/252] Unify all groups in bootstrap to use `Builder::msg` --- src/bootstrap/src/core/build_steps/check.rs | 38 +++--- src/bootstrap/src/core/build_steps/clippy.rs | 57 +++++---- src/bootstrap/src/core/build_steps/compile.rs | 74 ++++++------ src/bootstrap/src/core/build_steps/doc.rs | 33 +++--- src/bootstrap/src/core/build_steps/install.rs | 8 +- src/bootstrap/src/core/build_steps/test.rs | 90 ++++++-------- src/bootstrap/src/core/build_steps/tool.rs | 34 +----- src/bootstrap/src/lib.rs | 111 ++++++++---------- 8 files changed, 206 insertions(+), 239 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index f931aae3c2e04..0cbf8f55e9933 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -72,7 +72,6 @@ impl Step for Std { fn run(self, builder: &Builder<'_>) { let build_compiler = self.build_compiler; - let stage = build_compiler.stage; let target = self.target; let mut cargo = builder::Cargo::new( @@ -94,10 +93,12 @@ impl Step for Std { cargo.arg("-p").arg(krate); } - let _guard = builder.msg_check( + let _guard = builder.msg( + Kind::Check, format_args!("library artifacts{}", crate_description(&self.crates)), + Mode::Std, + self.build_compiler, target, - Some(stage), ); let stamp = build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check"); @@ -136,7 +137,13 @@ impl Step for Std { let stamp = build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check-test"); - let _guard = builder.msg_check("library test/bench/example targets", target, Some(stage)); + let _guard = builder.msg( + Kind::Check, + "library test/bench/example targets", + Mode::Std, + self.build_compiler, + target, + ); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } @@ -227,10 +234,12 @@ impl Step for Rustc { cargo.arg("-p").arg(krate); } - let _guard = builder.msg_check( + let _guard = builder.msg( + Kind::Check, format_args!("compiler artifacts{}", crate_description(&self.crates)), + Mode::Rustc, + self.build_compiler, target, - None, ); let stamp = @@ -357,7 +366,13 @@ impl Step for CodegenBackend { .arg(builder.src.join(format!("compiler/{}/Cargo.toml", backend.crate_name()))); rustc_cargo_env(builder, &mut cargo, target); - let _guard = builder.msg_check(backend.crate_name(), target, None); + let _guard = builder.msg( + Kind::Check, + backend.crate_name(), + Mode::Codegen, + self.build_compiler, + target, + ); let stamp = build_stamp::codegen_backend_stamp(builder, build_compiler, target, &backend) .with_prefix("check"); @@ -482,14 +497,7 @@ fn run_tool_check_step( let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, mode, target)) .with_prefix(&format!("{display_name}-check")); - let stage = match mode { - // Mode::ToolRustc is included here because of how msg_sysroot_tool prints stages - Mode::Std | Mode::ToolRustc => build_compiler.stage, - _ => build_compiler.stage + 1, - }; - - let _guard = - builder.msg_tool(builder.kind, mode, display_name, stage, &build_compiler.host, &target); + let _guard = builder.msg(builder.kind, display_name, mode, build_compiler, target); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 93c767bdd253d..4d734fe5c667d 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -143,11 +143,11 @@ impl Step for Std { fn run(self, builder: &Builder<'_>) { let target = self.target; - let compiler = builder.compiler(builder.top_stage, builder.config.host_target); + let build_compiler = builder.compiler(builder.top_stage, builder.config.host_target); let mut cargo = builder::Cargo::new( builder, - compiler, + build_compiler, Mode::Std, SourceType::InTree, target, @@ -160,14 +160,19 @@ impl Step for Std { cargo.arg("-p").arg(krate); } - let _guard = - builder.msg_clippy(format_args!("library{}", crate_description(&self.crates)), target); + let _guard = builder.msg( + Kind::Clippy, + format_args!("library{}", crate_description(&self.crates)), + Mode::Std, + build_compiler, + target, + ); run_cargo( builder, cargo, lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC), - &build_stamp::libstd_stamp(builder, compiler, target), + &build_stamp::libstd_stamp(builder, build_compiler, target), vec![], true, false, @@ -203,33 +208,33 @@ impl Step for Rustc { /// This will lint the compiler for a particular stage of the build using /// the `compiler` targeting the `target` architecture. fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(builder.top_stage, builder.config.host_target); + let build_compiler = builder.compiler(builder.top_stage, builder.config.host_target); let target = self.target; if !builder.download_rustc() { - if compiler.stage != 0 { + if build_compiler.stage != 0 { // If we're not in stage 0, then we won't have a std from the beta // compiler around. That means we need to make sure there's one in // the sysroot for the compiler to find. Otherwise, we're going to // fail when building crates that need to generate code (e.g., build // scripts and their dependencies). - builder.std(compiler, compiler.host); - builder.std(compiler, target); + builder.std(build_compiler, build_compiler.host); + builder.std(build_compiler, target); } else { - builder.ensure(check::Std::new(compiler, target)); + builder.ensure(check::Std::new(build_compiler, target)); } } let mut cargo = builder::Cargo::new( builder, - compiler, + build_compiler, Mode::Rustc, SourceType::InTree, target, Kind::Clippy, ); - rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); + rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates); // Explicitly pass -p for all compiler crates -- this will force cargo // to also lint the tests/benches/examples for these crates, rather @@ -238,14 +243,19 @@ impl Step for Rustc { cargo.arg("-p").arg(krate); } - let _guard = - builder.msg_clippy(format_args!("compiler{}", crate_description(&self.crates)), target); + let _guard = builder.msg( + Kind::Clippy, + format_args!("compiler{}", crate_description(&self.crates)), + Mode::Rustc, + build_compiler, + target, + ); run_cargo( builder, cargo, lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC), - &build_stamp::librustc_stamp(builder, compiler, target), + &build_stamp::librustc_stamp(builder, build_compiler, target), vec![], true, false, @@ -284,16 +294,16 @@ macro_rules! lint_any { } fn run(self, builder: &Builder<'_>) -> Self::Output { - let compiler = builder.compiler(builder.top_stage, builder.config.host_target); + let build_compiler = builder.compiler(builder.top_stage, builder.config.host_target); let target = self.target; if !builder.download_rustc() { - builder.ensure(check::Rustc::new(builder, compiler, target)); + builder.ensure(check::Rustc::new(builder, build_compiler, target)); }; let cargo = prepare_tool_cargo( builder, - compiler, + build_compiler, Mode::ToolRustc, target, Kind::Clippy, @@ -302,17 +312,16 @@ macro_rules! lint_any { &[], ); - let _guard = builder.msg_tool( + let _guard = builder.msg( Kind::Clippy, - Mode::ToolRustc, $readable_name, - compiler.stage, - &compiler.host, - &target, + Mode::ToolRustc, + build_compiler, + target, ); let stringified_name = stringify!($name).to_lowercase(); - let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target)) + let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, Mode::ToolRustc, target)) .with_prefix(&format!("{}-check", stringified_name)); run_cargo( diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 4519731ada7f3..c04f080356525 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -159,7 +159,7 @@ impl Step for Std { return; } - let compiler = if builder.download_rustc() && self.force_recompile { + let build_compiler = if builder.download_rustc() && self.force_recompile { // When there are changes in the library tree with CI-rustc, we want to build // the stageN library and that requires using stageN-1 compiler. builder.compiler(self.compiler.stage.saturating_sub(1), builder.config.host_target) @@ -173,7 +173,8 @@ impl Step for Std { && builder.config.is_host_target(target) && !self.force_recompile { - let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false }); + let sysroot = + builder.ensure(Sysroot { compiler: build_compiler, force_recompile: false }); cp_rustc_component_to_ci_sysroot( builder, &sysroot, @@ -182,53 +183,58 @@ impl Step for Std { return; } - if builder.config.keep_stage.contains(&compiler.stage) - || builder.config.keep_stage_std.contains(&compiler.stage) + if builder.config.keep_stage.contains(&build_compiler.stage) + || builder.config.keep_stage_std.contains(&build_compiler.stage) { trace!(keep_stage = ?builder.config.keep_stage); trace!(keep_stage_std = ?builder.config.keep_stage_std); builder.info("WARNING: Using a potentially old libstd. This may not behave well."); - builder.ensure(StartupObjects { compiler, target }); + builder.ensure(StartupObjects { compiler: build_compiler, target }); - self.copy_extra_objects(builder, &compiler, target); + self.copy_extra_objects(builder, &build_compiler, target); - builder.ensure(StdLink::from_std(self, compiler)); + builder.ensure(StdLink::from_std(self, build_compiler)); return; } - let mut target_deps = builder.ensure(StartupObjects { compiler, target }); + let mut target_deps = builder.ensure(StartupObjects { compiler: build_compiler, target }); - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); + let compiler_to_use = + builder.compiler_for(build_compiler.stage, build_compiler.host, target); trace!(?compiler_to_use); - if compiler_to_use != compiler + if compiler_to_use != build_compiler // Never uplift std unless we have compiled stage 1; if stage 1 is compiled, // uplift it from there. // // FIXME: improve `fn compiler_for` to avoid adding stage condition here. - && compiler.stage > 1 + && build_compiler.stage > 1 { - trace!(?compiler_to_use, ?compiler, "compiler != compiler_to_use, uplifting library"); + trace!( + ?compiler_to_use, + ?build_compiler, + "compiler != compiler_to_use, uplifting library" + ); builder.std(compiler_to_use, target); let msg = if compiler_to_use.host == target { format!( "Uplifting library (stage{} -> stage{})", - compiler_to_use.stage, compiler.stage + compiler_to_use.stage, build_compiler.stage ) } else { format!( "Uplifting library (stage{}:{} -> stage{}:{})", - compiler_to_use.stage, compiler_to_use.host, compiler.stage, target + compiler_to_use.stage, compiler_to_use.host, build_compiler.stage, target ) }; builder.info(&msg); // Even if we're not building std this stage, the new sysroot must // still contain the third party objects needed by various targets. - self.copy_extra_objects(builder, &compiler, target); + self.copy_extra_objects(builder, &build_compiler, target); builder.ensure(StdLink::from_std(self, compiler_to_use)); return; @@ -236,11 +242,11 @@ impl Step for Std { trace!( ?compiler_to_use, - ?compiler, + ?build_compiler, "compiler == compiler_to_use, handling not-cross-compile scenario" ); - target_deps.extend(self.copy_extra_objects(builder, &compiler, target)); + target_deps.extend(self.copy_extra_objects(builder, &build_compiler, target)); // We build a sysroot for mir-opt tests using the same trick that Miri does: A check build // with -Zalways-encode-mir. This frees us from the need to have a target linker, and the @@ -249,7 +255,7 @@ impl Step for Std { trace!("building special sysroot for mir-opt tests"); let mut cargo = builder::Cargo::new_for_mir_opt_tests( builder, - compiler, + build_compiler, Mode::Std, SourceType::InTree, target, @@ -262,7 +268,7 @@ impl Step for Std { trace!("building regular sysroot"); let mut cargo = builder::Cargo::new( builder, - compiler, + build_compiler, Mode::Std, SourceType::InTree, target, @@ -285,16 +291,16 @@ impl Step for Std { let _guard = builder.msg( Kind::Build, - compiler.stage, format_args!("library artifacts{}", crate_description(&self.crates)), - compiler.host, + Mode::Std, + build_compiler, target, ); run_cargo( builder, cargo, vec![], - &build_stamp::libstd_stamp(builder, compiler, target), + &build_stamp::libstd_stamp(builder, build_compiler, target), target_deps, self.is_for_mir_opt_tests, // is_check false, @@ -302,7 +308,7 @@ impl Step for Std { builder.ensure(StdLink::from_std( self, - builder.compiler(compiler.stage, builder.config.host_target), + builder.compiler(build_compiler.stage, builder.config.host_target), )); } @@ -1126,11 +1132,11 @@ impl Step for Rustc { cargo.env("RUSTC_BOLT_LINK_FLAGS", "1"); } - let _guard = builder.msg_rustc_tool( + let _guard = builder.msg( Kind::Build, - build_compiler.stage, format_args!("compiler artifacts{}", crate_description(&self.crates)), - build_compiler.host, + Mode::Rustc, + build_compiler, target, ); let stamp = build_stamp::librustc_stamp(builder, build_compiler, target); @@ -1603,11 +1609,11 @@ impl Step for GccCodegenBackend { let gcc = builder.ensure(Gcc { target }); add_cg_gcc_cargo_flags(&mut cargo, &gcc); - let _guard = builder.msg_rustc_tool( + let _guard = builder.msg( Kind::Build, - build_compiler.stage, - "codegen backend gcc", - build_compiler.host, + format_args!("codegen backend gcc"), + Mode::Codegen, + build_compiler, target, ); let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); @@ -1687,11 +1693,11 @@ impl Step for CraneliftCodegenBackend { .arg(builder.src.join("compiler/rustc_codegen_cranelift/Cargo.toml")); rustc_cargo_env(builder, &mut cargo, target); - let _guard = builder.msg_rustc_tool( + let _guard = builder.msg( Kind::Build, - build_compiler.stage, - "codegen backend cranelift", - build_compiler.host, + format_args!("codegen backend cranelift"), + Mode::Codegen, + build_compiler, target, ); let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index ca7a6dc8e07ed..6f0d5203d1176 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -239,7 +239,7 @@ impl Step for TheBook { fn run(self, builder: &Builder<'_>) { builder.require_submodule("src/doc/book", None); - let compiler = self.build_compiler; + let build_compiler = self.build_compiler; let target = self.target; let absolute_path = builder.src.join("src/doc/book"); @@ -273,20 +273,20 @@ impl Step for TheBook { let shared_assets = builder.ensure(SharedAssets { target }); // build the redirect pages - let _guard = builder.msg_doc(compiler, "book redirect pages", target); + let _guard = builder.msg(Kind::Doc, "book redirect pages", None, build_compiler, target); for file in t!(fs::read_dir(redirect_path)) { let file = t!(file); let path = file.path(); let path = path.to_str().unwrap(); - invoke_rustdoc(builder, compiler, &shared_assets, target, path); + invoke_rustdoc(builder, build_compiler, &shared_assets, target, path); } } } fn invoke_rustdoc( builder: &Builder<'_>, - compiler: Compiler, + build_compiler: Compiler, shared_assets: &SharedAssetsPaths, target: TargetSelection, markdown: &str, @@ -298,7 +298,7 @@ fn invoke_rustdoc( let header = builder.src.join("src/doc/redirect.inc"); let footer = builder.src.join("src/doc/footer.inc"); - let mut cmd = builder.rustdoc_cmd(compiler); + let mut cmd = builder.rustdoc_cmd(build_compiler); let out = out.join("book"); @@ -362,7 +362,7 @@ impl Step for Standalone { fn run(self, builder: &Builder<'_>) { let target = self.target; let build_compiler = self.build_compiler; - let _guard = builder.msg_doc(build_compiler, "standalone", target); + let _guard = builder.msg(Kind::Doc, "standalone", None, build_compiler, target); let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); @@ -469,7 +469,7 @@ impl Step for Releases { fn run(self, builder: &Builder<'_>) { let target = self.target; let build_compiler = self.build_compiler; - let _guard = builder.msg_doc(build_compiler, "releases", target); + let _guard = builder.msg(Kind::Doc, "releases", None, build_compiler, target); let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); @@ -784,7 +784,7 @@ fn doc_std( let description = format!("library{} in {} format", crate_description(requested_crates), format.as_str()); - let _guard = builder.msg_doc(build_compiler, description, target); + let _guard = builder.msg(Kind::Doc, description, None, build_compiler, target); cargo.into_cmd().run(builder); builder.cp_link_r(&out_dir, out); @@ -861,11 +861,11 @@ impl Step for Rustc { let build_compiler = self.build_compiler; builder.std(build_compiler, builder.config.host_target); - let _guard = builder.msg_rustc_tool( + let _guard = builder.msg( Kind::Doc, - build_compiler.stage, format!("compiler{}", crate_description(&self.crates)), - build_compiler.host, + Mode::Rustc, + build_compiler, target, ); @@ -1059,7 +1059,7 @@ macro_rules! tool_doc { let proc_macro_out_dir = builder.stage_out(build_compiler, mode).join("doc"); symlink_dir_force(&builder.config, &out, &proc_macro_out_dir); - let _guard = builder.msg_doc(build_compiler, stringify!($tool).to_lowercase(), target); + let _guard = builder.msg(Kind::Doc, stringify!($tool).to_lowercase(), None, build_compiler, target); cargo.into_cmd().run(builder); if !builder.config.dry_run() { @@ -1314,13 +1314,8 @@ impl Step for RustcBook { // bootstrap.toml), then this needs to explicitly update the dylib search // path. builder.add_rustc_lib_path(self.build_compiler, &mut cmd); - let doc_generator_guard = builder.msg( - Kind::Run, - self.build_compiler.stage, - "lint-docs", - self.build_compiler.host, - self.target, - ); + let doc_generator_guard = + builder.msg(Kind::Run, "lint-docs", None, self.build_compiler, self.target); cmd.run(builder); drop(doc_generator_guard); diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index acee78dcf59b9..6d09e41e646cb 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -68,7 +68,13 @@ fn install_sh( host: Option, tarball: &GeneratedTarball, ) { - let _guard = builder.msg(Kind::Install, stage, package, host, host); + let _guard = builder.msg( + Kind::Install, + package, + None, + (host.unwrap_or(builder.host_target), stage), + host, + ); let prefix = default_path(&builder.config.prefix, "/usr/local"); let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc")); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 2f933baa4a4cd..fa72e93f503c4 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -161,8 +161,7 @@ You can skip linkcheck with --skip src/tools/linkchecker" let linkchecker = builder.tool_cmd(Tool::Linkchecker); // Run the linkchecker. - let _guard = - builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host); + let _guard = builder.msg(Kind::Test, "Linkcheck", None, compiler, bootstrap_host); let _time = helpers::timeit(builder); linkchecker.delay_failure().arg(builder.out.join(host).join("doc")).run(builder); } @@ -541,8 +540,7 @@ impl Miri { cargo.env("MIRI_SYSROOT", &miri_sysroot); let mut cargo = BootstrapCommand::from(cargo); - let _guard = - builder.msg(Kind::Build, compiler.stage, "miri sysroot", compiler.host, target); + let _guard = builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustc, compiler, target); cargo.run(builder); // # Determine where Miri put its sysroot. @@ -643,7 +641,8 @@ impl Step for Miri { cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg()); { - let _guard = builder.msg_rustc_tool(Kind::Test, stage, "miri", host, target); + let _guard = + builder.msg(Kind::Test, "miri", Mode::ToolRustc, miri.build_compiler, target); let _time = helpers::timeit(builder); cargo.run(builder); } @@ -659,11 +658,11 @@ impl Step for Miri { cargo.args(["tests/pass", "tests/panic"]); { - let _guard = builder.msg_rustc_tool( + let _guard = builder.msg( Kind::Test, - stage, "miri (mir-opt-level 4)", - host, + Mode::ToolRustc, + miri.build_compiler, target, ); let _time = helpers::timeit(builder); @@ -703,7 +702,7 @@ impl Step for CargoMiri { } // This compiler runs on the host, we'll just use it for the target. - let compiler = builder.compiler(stage, host); + let build_compiler = builder.compiler(stage, host); // Run `cargo miri test`. // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures @@ -711,7 +710,7 @@ impl Step for CargoMiri { // itself executes properly under Miri, and that all the logic in `cargo-miri` does not explode. let mut cargo = tool::prepare_tool_cargo( builder, - compiler, + build_compiler, Mode::ToolStd, // it's unclear what to use here, we're not building anything just doing a smoke test! target, Kind::MiriTest, @@ -736,7 +735,8 @@ impl Step for CargoMiri { // Finally, run everything. let mut cargo = BootstrapCommand::from(cargo); { - let _guard = builder.msg_rustc_tool(Kind::Test, stage, "cargo-miri", host, target); + let _guard = + builder.msg(Kind::Test, "cargo-miri", Mode::ToolRustc, (host, stage), target); let _time = helpers::timeit(builder); cargo.run(builder); } @@ -830,7 +830,7 @@ impl Step for Clippy { /// Runs `cargo test` for clippy. fn run(self, builder: &Builder<'_>) { - let host = self.compilers.target(); + let target = self.compilers.target(); // We need to carefully distinguish the compiler that builds clippy, and the compiler // that is linked into the clippy being tested. `target_compiler` is the latter, @@ -844,7 +844,7 @@ impl Step for Clippy { builder, build_compiler, Mode::ToolRustc, - host, + target, Kind::Test, "src/tools/clippy", SourceType::InTree, @@ -858,7 +858,7 @@ impl Step for Clippy { cargo.env("HOST_LIBS", host_libs); // Build the standard library that the tests can use. - builder.std(target_compiler, host); + builder.std(target_compiler, target); cargo.env("TEST_SYSROOT", builder.sysroot(target_compiler)); cargo.env("TEST_RUSTC", builder.rustc(target_compiler)); cargo.env("TEST_RUSTC_LIB", builder.rustc_libdir(target_compiler)); @@ -881,9 +881,9 @@ impl Step for Clippy { } cargo.add_rustc_lib_path(builder); - let cargo = prepare_cargo_test(cargo, &[], &[], host, builder); + let cargo = prepare_cargo_test(cargo, &[], &[], target, builder); - let _guard = builder.msg_rustc_tool(Kind::Test, build_compiler.stage, "clippy", host, host); + let _guard = builder.msg(Kind::Test, "clippy", Mode::ToolRustc, build_compiler, target); // Clippy reports errors if it blessed the outputs if cargo.allow_failure().run(builder) { @@ -990,9 +990,9 @@ impl Step for RustdocJSStd { )); let _guard = builder.msg( Kind::Test, - builder.top_stage, "rustdoc-js-std", - builder.config.host_target, + None, + (builder.config.host_target, builder.top_stage), self.target, ); command.run(builder); @@ -1141,13 +1141,7 @@ impl Step for RustdocGUI { } let _time = helpers::timeit(builder); - let _guard = builder.msg_rustc_tool( - Kind::Test, - self.compiler.stage, - "rustdoc-gui", - self.compiler.host, - self.target, - ); + let _guard = builder.msg(Kind::Test, "rustdoc-gui", None, self.compiler, self.target); try_run_tests(builder, &mut cmd, true); } } @@ -2237,9 +2231,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let _group = builder.msg( Kind::Test, - compiler.stage, format!("compiletest suite={suite} mode={mode}"), - compiler.host, + Mode::ToolBootstrap, + compiler, target, ); try_run_tests(builder, &mut cmd, false); @@ -2381,9 +2375,9 @@ impl BookTest { builder.add_rust_test_threads(&mut rustbook_cmd); let _guard = builder.msg( Kind::Test, - compiler.stage, format_args!("mdbook {}", self.path.display()), - compiler.host, + None, + compiler, compiler.host, ); let _time = helpers::timeit(builder); @@ -2402,8 +2396,7 @@ impl BookTest { builder.std(compiler, host); - let _guard = - builder.msg(Kind::Test, compiler.stage, format!("book {}", self.name), host, host); + let _guard = builder.msg(Kind::Test, format!("book {}", self.name), None, compiler, host); // Do a breadth-first traversal of the `src/doc` directory and just run // tests for all files that end in `*.md` @@ -2547,9 +2540,9 @@ impl Step for ErrorIndex { let guard = builder.msg( Kind::Test, - target_compiler.stage, "error-index", - target_compiler.host, + None, + self.compilers.build_compiler(), target_compiler.host, ); let _time = helpers::timeit(builder); @@ -2650,9 +2643,8 @@ fn run_cargo_test<'a>( let compiler = cargo.compiler(); let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder); let _time = helpers::timeit(builder); - let _group = description.into().and_then(|what| { - builder.msg_rustc_tool(Kind::Test, compiler.stage, what, compiler.host, target) - }); + let _group = + description.into().and_then(|what| builder.msg(Kind::Test, what, None, compiler, target)); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( @@ -3176,8 +3168,9 @@ impl Step for Bootstrap { /// Tests the build system itself. fn run(self, builder: &Builder<'_>) { let host = builder.config.host_target; - let compiler = builder.compiler(0, host); - let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host); + let build_compiler = builder.compiler(0, host); + let _guard = + builder.msg(Kind::Test, "bootstrap", Mode::ToolBootstrap, build_compiler, host); // Some tests require cargo submodule to be present. builder.build.require_submodule("src/tools/cargo", None); @@ -3196,7 +3189,7 @@ impl Step for Bootstrap { let mut cargo = tool::prepare_tool_cargo( builder, - compiler, + build_compiler, Mode::ToolBootstrap, host, Kind::Test, @@ -3276,9 +3269,9 @@ impl Step for TierCheck { let _guard = builder.msg( Kind::Test, - self.compiler.stage, "platform support check", - self.compiler.host, + None, + self.compiler, self.compiler.host, ); BootstrapCommand::from(cargo).delay_failure().run(builder); @@ -3326,10 +3319,10 @@ impl Step for RustInstaller { /// Ensure the version placeholder replacement tool builds fn run(self, builder: &Builder<'_>) { let bootstrap_host = builder.config.host_target; - let compiler = builder.compiler(0, bootstrap_host); + let build_compiler = builder.compiler(0, bootstrap_host); let cargo = tool::prepare_tool_cargo( builder, - compiler, + build_compiler, Mode::ToolBootstrap, bootstrap_host, Kind::Test, @@ -3338,13 +3331,8 @@ impl Step for RustInstaller { &[], ); - let _guard = builder.msg( - Kind::Test, - compiler.stage, - "rust-installer", - bootstrap_host, - bootstrap_host, - ); + let _guard = + builder.msg(Kind::Test, "rust-installer", None, build_compiler, bootstrap_host); run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder); // We currently don't support running the test.sh script outside linux(?) environments. @@ -3355,7 +3343,7 @@ impl Step for RustInstaller { } let mut cmd = command(builder.src.join("src/tools/rust-installer/test.sh")); - let tmpdir = testdir(builder, compiler.host).join("rust-installer"); + let tmpdir = testdir(builder, build_compiler.host).join("rust-installer"); let _ = std::fs::remove_dir_all(&tmpdir); let _ = std::fs::create_dir_all(&tmpdir); cmd.current_dir(&tmpdir); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 5e4ebb2755da0..793e6b629c991 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -26,7 +26,7 @@ use crate::core::builder::{ use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection}; use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{add_dylib_path, exe, t}; -use crate::{Compiler, FileType, Kind, Mode, gha}; +use crate::{Compiler, FileType, Kind, Mode}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum SourceType { @@ -58,28 +58,6 @@ struct ToolBuild { artifact_kind: ToolArtifactKind, } -impl Builder<'_> { - #[track_caller] - pub(crate) fn msg_tool( - &self, - kind: Kind, - mode: Mode, - tool: &str, - build_stage: u32, - host: &TargetSelection, - target: &TargetSelection, - ) -> Option { - match mode { - // depends on compiler stage, different to host compiler - Mode::ToolRustc => { - self.msg_rustc_tool(kind, build_stage, format_args!("tool {tool}"), *host, *target) - } - // doesn't depend on compiler, same as host compiler - _ => self.msg(kind, build_stage, format_args!("tool {tool}"), *host, *target), - } - } -} - /// Result of the tool build process. Each `Step` in this module is responsible /// for using this type as `type Output = ToolBuildResult;` #[derive(Clone)] @@ -166,14 +144,8 @@ impl Step for ToolBuild { cargo.args(self.cargo_args); - let _guard = builder.msg_tool( - Kind::Build, - self.mode, - self.tool, - self.build_compiler.stage, - &self.build_compiler.host, - &self.target, - ); + let _guard = + builder.msg(Kind::Build, self.tool, self.mode, self.build_compiler, self.target); // we check this below let build_success = compile::stream_cargo(builder, cargo, vec![], &mut |_| {}); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 341ddf8da4f44..24ba4b12264c4 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -410,6 +410,25 @@ forward! { download_rustc() -> bool, } +/// A mostly temporary helper struct before we can migrate everything in bootstrap to use +/// the concept of a build compiler. +struct HostAndStage { + host: TargetSelection, + stage: u32, +} + +impl From<(TargetSelection, u32)> for HostAndStage { + fn from((host, stage): (TargetSelection, u32)) -> Self { + Self { host, stage } + } +} + +impl From for HostAndStage { + fn from(compiler: Compiler) -> Self { + Self { host: compiler.host, stage: compiler.stage } + } +} + impl Build { /// Creates a new set of build configuration from the `flags` on the command /// line and the filesystem `config`. @@ -1072,45 +1091,14 @@ impl Build { } } - #[must_use = "Groups should not be dropped until the Step finishes running"] - #[track_caller] - fn msg_clippy( - &self, - what: impl Display, - target: impl Into>, - ) -> Option { - self.msg(Kind::Clippy, self.config.stage, what, self.config.host_target, target) - } - - #[must_use = "Groups should not be dropped until the Step finishes running"] - #[track_caller] - fn msg_check( - &self, - what: impl Display, - target: impl Into>, - custom_stage: Option, - ) -> Option { - self.msg( - Kind::Check, - custom_stage.unwrap_or(self.config.stage), - what, - self.config.host_target, - target, - ) - } - - #[must_use = "Groups should not be dropped until the Step finishes running"] - #[track_caller] - fn msg_doc( - &self, - compiler: Compiler, - what: impl Display, - target: impl Into> + Copy, - ) -> Option { - self.msg(Kind::Doc, compiler.stage, what, compiler.host, target.into()) - } - - /// Return a `Group` guard for a [`Step`] that is built for each `--stage`. + /// Return a `Group` guard for a [`Step`] that: + /// - Performs `action` + /// - On `what` + /// - Where `what` possibly corresponds to a `mode` + /// - `action` is performed using the given build compiler (`host_and_stage`). + /// - Since some steps do not use the concept of a build compiler yet, it is also possible + /// to pass the host and stage explicitly. + /// - With a given `target`. /// /// [`Step`]: crate::core::builder::Step #[must_use = "Groups should not be dropped until the Step finishes running"] @@ -1118,15 +1106,31 @@ impl Build { fn msg( &self, action: impl Into, - stage: u32, what: impl Display, - host: impl Into>, + mode: impl Into>, + host_and_stage: impl Into, target: impl Into>, ) -> Option { + let host_and_stage = host_and_stage.into(); + let actual_stage = match mode.into() { + // Std has the same stage as the compiler that builds it + Some(Mode::Std) => host_and_stage.stage, + // Other things have stage corresponding to their build compiler + 1 + Some( + Mode::Rustc + | Mode::Codegen + | Mode::ToolBootstrap + | Mode::ToolTarget + | Mode::ToolStd + | Mode::ToolRustc, + ) + | None => host_and_stage.stage + 1, + }; + let action = action.into().description(); - let msg = |fmt| format!("{action} stage{stage} {what}{fmt}"); + let msg = |fmt| format!("{action} stage{actual_stage} {what}{fmt}"); let msg = if let Some(target) = target.into() { - let host = host.into().unwrap(); + let host = host_and_stage.host; if host == target { msg(format_args!(" ({target})")) } else { @@ -1154,27 +1158,6 @@ impl Build { self.group(&msg) } - #[must_use = "Groups should not be dropped until the Step finishes running"] - #[track_caller] - fn msg_rustc_tool( - &self, - action: impl Into, - build_stage: u32, - what: impl Display, - host: TargetSelection, - target: TargetSelection, - ) -> Option { - let action = action.into().description(); - let msg = |fmt| format!("{action} {what} {fmt}"); - - let msg = if host == target { - msg(format_args!("(stage{build_stage} -> stage{}, {target})", build_stage + 1)) - } else { - msg(format_args!("(stage{build_stage}:{host} -> stage{}:{target})", build_stage + 1)) - }; - self.group(&msg) - } - #[track_caller] fn group(&self, msg: &str) -> Option { match self.config.get_dry_run() { From df2da84a619afcc8e0adfff142cb28af0ada6abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 10:42:14 +0200 Subject: [PATCH 103/252] Change format of messages in `Builder::fmt` --- src/bootstrap/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 24ba4b12264c4..0b65ebc067189 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1130,11 +1130,12 @@ impl Build { let action = action.into().description(); let msg = |fmt| format!("{action} stage{actual_stage} {what}{fmt}"); let msg = if let Some(target) = target.into() { + let build_stage = host_and_stage.stage; let host = host_and_stage.host; if host == target { - msg(format_args!(" ({target})")) + msg(format_args!(" (stage{build_stage} -> stage{actual_stage}, {target})")) } else { - msg(format_args!(" ({host} -> {target})")) + msg(format_args!(" (stage{build_stage}:{host} -> stage{actual_stage}:{target})")) } } else { msg(format_args!("")) From 3fb4be20c1f41b32697224abd10be814102466ed Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Tue, 12 Aug 2025 12:01:55 +0200 Subject: [PATCH 104/252] Update to LLVM 21.1.0 rc3 --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index d35840afa50d2..9a1f898064f52 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit d35840afa50d2615835d6a836f1967c57008188a +Subproject commit 9a1f898064f52269bc94675dcbd620b46d45d173 From 7aa8707639ede0605d7182bc13047b6e4549e5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 29 Jul 2025 20:51:46 +0200 Subject: [PATCH 105/252] make no_mangle explicit on foreign items --- .../src/back/symbol_export.rs | 2 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 21 +++++++ .../src/middle/codegen_fn_attrs.rs | 7 ++- compiler/rustc_middle/src/mir/mono.rs | 2 +- .../src/cross_crate_inline.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 36 ++++++------ compiler/rustc_passes/src/dead.rs | 2 +- compiler/rustc_passes/src/reachable.rs | 5 +- compiler/rustc_symbol_mangling/src/lib.rs | 55 ++++++++++--------- .../clippy/clippy_lints/src/missing_inline.rs | 2 +- src/tools/miri/src/bin/miri.rs | 2 +- src/tools/miri/src/helpers.rs | 2 +- tests/run-make/wasm-panic-small/rmake.rs | 2 +- 13 files changed, 85 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 7e124f65324a5..0494666bda923 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -569,7 +569,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel // core/std/allocators/etc. For example symbols used to hook up allocation // are not considered for export let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id); - let is_extern = codegen_fn_attrs.contains_extern_indicator(); + let is_extern = codegen_fn_attrs.contains_extern_indicator(tcx, sym_def_id); let std_internal = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 7f54a47327af8..287787eb3d1ff 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -443,6 +443,27 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code if tcx.should_inherit_track_caller(did) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } + + // Foreign items by default use no mangling for their symbol name. + if tcx.is_foreign_item(did) { + // There's a few exceptions to this rule though: + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { + // * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way + // both for exports and imports through foreign items. This is handled further, + // during symbol mangling logic. + } else if codegen_fn_attrs.link_name.is_some() { + // * This can be overridden with the `#[link_name]` attribute + } else { + // NOTE: there's one more exception that we cannot apply here. On wasm, + // some items cannot be `no_mangle`. + // However, we don't have enough information here to determine that. + // As such, no_mangle foreign items on wasm that have the same defid as some + // import will *still* be mangled despite this. + // + // if none of the exceptions apply; apply no_mangle + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + } + } } fn check_result( diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 94384e64afd15..52341df074085 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use rustc_abi::Align; use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; @@ -193,7 +194,11 @@ impl CodegenFnAttrs { /// * `#[linkage]` is present /// /// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint. - pub fn contains_extern_indicator(&self) -> bool { + pub fn contains_extern_indicator(&self, tcx: TyCtxt<'_>, did: DefId) -> bool { + if tcx.is_foreign_item(did) { + return false; + } + self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) || self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) || self.export_name.is_some() diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index e5864660575c5..3afd946b30a2a 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -151,7 +151,7 @@ impl<'tcx> MonoItem<'tcx> { // instantiation: // We emit an unused_attributes lint for this case, which should be kept in sync if possible. let codegen_fn_attrs = tcx.codegen_instance_attrs(instance.def); - if codegen_fn_attrs.contains_extern_indicator() + if codegen_fn_attrs.contains_extern_indicator(tcx, instance.def.def_id()) || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { return InstantiationMode::GloballyShared { may_conflict: false }; diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index b186c2bd7758f..03fdf9fbac538 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -18,7 +18,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); // If this has an extern indicator, then this function is globally shared and thus will not // generate cgu-internal copies which would make it cross-crate inlinable. - if codegen_fn_attrs.contains_extern_indicator() { + if codegen_fn_attrs.contains_extern_indicator(tcx, def_id.into()) { return false; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 10c532b436aa1..22e2a887b61a2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -561,7 +561,24 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Fn | Target::Closure - | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {} + | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { + // `#[inline]` is ignored if the symbol must be codegened upstream because it's exported. + if let Some(did) = hir_id.as_owner() + && self.tcx.def_kind(did).has_codegen_attrs() + && kind != &InlineAttr::Never + { + let attrs = self.tcx.codegen_fn_attrs(did); + // Not checking naked as `#[inline]` is forbidden for naked functions anyways. + if attrs.contains_extern_indicator(self.tcx, did.into()) { + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr_span, + errors::InlineIgnoredForExported {}, + ); + } + } + } Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, @@ -588,23 +605,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::InlineNotFnOrClosure { attr_span, defn_span }); } } - - // `#[inline]` is ignored if the symbol must be codegened upstream because it's exported. - if let Some(did) = hir_id.as_owner() - && self.tcx.def_kind(did).has_codegen_attrs() - && kind != &InlineAttr::Never - { - let attrs = self.tcx.codegen_fn_attrs(did); - // Not checking naked as `#[inline]` is forbidden for naked functions anyways. - if attrs.contains_extern_indicator() { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::InlineIgnoredForExported {}, - ); - } - } } /// Checks that `#[coverage(..)]` is applied to a function/closure/method, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index fa9d0c7b1b7d4..1c76e4e7166d7 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -701,7 +701,7 @@ fn has_allow_dead_code_or_lang_attr( // #[used], #[no_mangle], #[export_name], etc also keeps the item alive // forcefully, e.g., for placing it in a specific section. - cg_attrs.contains_extern_indicator() + cg_attrs.contains_extern_indicator(tcx, def_id.into()) || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 2f78c22c7483b..6cd8a54ecf434 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -183,7 +183,7 @@ impl<'tcx> ReachableContext<'tcx> { } else { CodegenFnAttrs::EMPTY }; - let is_extern = codegen_attrs.contains_extern_indicator(); + let is_extern = codegen_attrs.contains_extern_indicator(self.tcx, search_item.into()); if is_extern { self.reachable_symbols.insert(search_item); } @@ -423,8 +423,9 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { if !tcx.def_kind(def_id).has_codegen_attrs() { return false; } + let codegen_attrs = tcx.codegen_fn_attrs(def_id); - codegen_attrs.contains_extern_indicator() + codegen_attrs.contains_extern_indicator(tcx, def_id.into()) // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs. diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 6bcb7f6e093c4..f3c96f641902e 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -218,32 +218,33 @@ fn compute_symbol_name<'tcx>( } } - // Foreign items by default use no mangling for their symbol name. There's a - // few exceptions to this rule though: - // - // * This can be overridden with the `#[link_name]` attribute - // - // * On the wasm32 targets there is a bug (or feature) in LLD [1] where the - // same-named symbol when imported from different wasm modules will get - // hooked up incorrectly. As a result foreign symbols, on the wasm target, - // with a wasm import module, get mangled. Additionally our codegen will - // deduplicate symbols based purely on the symbol name, but for wasm this - // isn't quite right because the same-named symbol on wasm can come from - // different modules. For these reasons if `#[link(wasm_import_module)]` - // is present we mangle everything on wasm because the demangled form will - // show up in the `wasm-import-name` custom attribute in LLVM IR. - // - // * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way - // both for exports and imports through foreign items. This is handled above. - // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316 - if tcx.is_foreign_item(def_id) - && (!tcx.sess.target.is_like_wasm - || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)) + let wasm_import_module_exception_force_mangling = { + // * On the wasm32 targets there is a bug (or feature) in LLD [1] where the + // same-named symbol when imported from different wasm modules will get + // hooked up incorrectly. As a result foreign symbols, on the wasm target, + // with a wasm import module, get mangled. Additionally our codegen will + // deduplicate symbols based purely on the symbol name, but for wasm this + // isn't quite right because the same-named symbol on wasm can come from + // different modules. For these reasons if `#[link(wasm_import_module)]` + // is present we mangle everything on wasm because the demangled form will + // show up in the `wasm-import-name` custom attribute in LLVM IR. + // + // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316 + // + // So, on wasm if a foreign item loses its `#[no_mangle]`, it might *still* + // be mangled if we're forced to. Note: I don't like this. + // These kinds of exceptions should be added during the `codegen_attrs` query. + // However, we don't have the wasm import module map there yet. + tcx.is_foreign_item(def_id) + && tcx.sess.target.is_like_wasm + && tcx.wasm_import_module_map(LOCAL_CRATE).contains_key(&def_id.into()) + }; + + if let Some(name) = attrs.link_name + && !wasm_import_module_exception_force_mangling { - if let Some(name) = attrs.link_name { - return name.to_string(); - } - return tcx.item_name(def_id).to_string(); + // Use provided name + return name.to_string(); } if let Some(name) = attrs.export_name { @@ -251,7 +252,9 @@ fn compute_symbol_name<'tcx>( return name.to_string(); } - if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { + if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) + && !wasm_import_module_exception_force_mangling + { // Don't mangle return tcx.item_name(def_id).to_string(); } diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index d02952eb48702..b16924babd1c5 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -190,5 +190,5 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { /// and a rustc warning would be triggered, see #15301 fn fn_is_externally_exported(cx: &LateContext<'_>, def_id: DefId) -> bool { let attrs = cx.tcx.codegen_fn_attrs(def_id); - attrs.contains_extern_indicator() + attrs.contains_extern_indicator(cx.tcx, def_id) } diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index ae1b25f8857a0..d9e374c414cad 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -279,7 +279,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { return None; } let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id); - if codegen_fn_attrs.contains_extern_indicator() + if codegen_fn_attrs.contains_extern_indicator(tcx, local_def_id.into()) || codegen_fn_attrs .flags .contains(CodegenFnAttrFlags::USED_COMPILER) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 43cb1c9ae053c..a8e2151afe610 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -132,7 +132,7 @@ pub fn iter_exported_symbols<'tcx>( for def_id in crate_items.definitions() { let exported = tcx.def_kind(def_id).has_codegen_attrs() && { let codegen_attrs = tcx.codegen_fn_attrs(def_id); - codegen_attrs.contains_extern_indicator() + codegen_attrs.contains_extern_indicator(tcx, def_id.into()) || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER) || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs index e69fbac96356a..ea0b6faf037c5 100644 --- a/tests/run-make/wasm-panic-small/rmake.rs +++ b/tests/run-make/wasm-panic-small/rmake.rs @@ -24,5 +24,5 @@ fn test(cfg: &str) { let bytes = rfs::read("foo.wasm"); println!("{}", bytes.len()); - assert!(bytes.len() < 40_000); + assert!(bytes.len() < 40_000, "bytes len was: {}", bytes.len()); } From bd44d855f5a2c989b5cc5bef517978c47ddc6779 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 12 Aug 2025 12:50:48 +0200 Subject: [PATCH 106/252] Link to payload_as_str() from payload(). --- library/std/src/panic.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index cff4f20b5a812..5e8d2f8e78ec7 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -60,6 +60,7 @@ impl<'a> PanicHookInfo<'a> { /// Returns the payload associated with the panic. /// /// This will commonly, but not always, be a `&'static str` or [`String`]. + /// If you only care about such payloads, use [`payload_as_str`] instead. /// /// A invocation of the `panic!()` macro in Rust 2021 or later will always result in a /// panic payload of type `&'static str` or `String`. @@ -69,6 +70,7 @@ impl<'a> PanicHookInfo<'a> { /// can result in a panic payload other than a `&'static str` or `String`. /// /// [`String`]: ../../std/string/struct.String.html + /// [`payload_as_str`]: PanicHookInfo::payload_as_str /// /// # Examples /// From 08acba30718281a068ab978f8feded9b871ec9db Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 12 Aug 2025 12:52:39 +0200 Subject: [PATCH 107/252] Revert "Partially outline code inside the panic! macro". Without any tests/benchmarks that show some improvement, it's hard to know whether the change had any positive effect at all. (And if it did, whether that effect is still achieved today.) --- .../src/check_consts/check.rs | 6 +-- .../src/const_eval/machine.rs | 2 +- compiler/rustc_feature/src/builtin_attrs.rs | 4 -- compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_span/src/symbol.rs | 2 +- library/core/src/panic.rs | 45 ------------------- library/core/src/panicking.rs | 11 +---- src/tools/clippy/clippy_utils/src/macros.rs | 7 +-- src/tools/clippy/clippy_utils/src/sym.rs | 3 -- 9 files changed, 8 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 8e2c138282af3..ca707b50d50d9 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -827,7 +827,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // At this point, we are calling a function, `callee`, whose `DefId` is known... - // `begin_panic` and `#[rustc_const_panic_str]` functions accept generic + // `begin_panic` and `panic_display` functions accept generic // types other than str. Check to enforce that only str can be used in // const-eval. @@ -841,8 +841,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { return; } - // const-eval of `#[rustc_const_panic_str]` functions assumes the argument is `&&str` - if tcx.has_attr(callee, sym::rustc_const_panic_str) { + // const-eval of `panic_display` assumes the argument is `&&str` + if tcx.is_lang_item(callee, LangItem::PanicDisplay) { match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() { ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) => {} diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index a18ae79f318df..da954cf4ed740 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -237,7 +237,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { ) -> InterpResult<'tcx, Option>> { let def_id = instance.def_id(); - if self.tcx.has_attr(def_id, sym::rustc_const_panic_str) + if self.tcx.is_lang_item(def_id, LangItem::PanicDisplay) || self.tcx.is_lang_item(def_id, LangItem::BeginPanic) { let args = self.copy_fn_args(args); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5c63d4808db2f..5c1f3a3756351 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -929,10 +929,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body", ), - rustc_attr!( - rustc_const_panic_str, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::Yes, "`#[rustc_const_panic_str]` ensures the argument to this function is &&str during const-check", - ), rustc_attr!( rustc_const_stable_indirect, Normal, template!(Word), diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 75c04b23ed6e8..905b84a8cbeb6 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -286,6 +286,7 @@ language_item_table! { Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::Exact(0); PanicNounwind, sym::panic_nounwind, panic_nounwind, Target::Fn, GenericRequirement::Exact(0); PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None; + PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None; ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None; PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0); PanicMisalignedPointerDereference, sym::panic_misaligned_pointer_dereference, panic_misaligned_pointer_dereference_fn, Target::Fn, GenericRequirement::Exact(0); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index acbed7a9eed81..b02d9359c3abe 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1583,6 +1583,7 @@ symbols! { panic_const_shl_overflow, panic_const_shr_overflow, panic_const_sub_overflow, + panic_display, panic_fmt, panic_handler, panic_impl, @@ -1828,7 +1829,6 @@ symbols! { rustc_coherence_is_core, rustc_coinductive, rustc_confusables, - rustc_const_panic_str, rustc_const_stable, rustc_const_stable_indirect, rustc_const_unstable, diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 5fa340a6147f6..7a42b3d0fc780 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -48,7 +48,6 @@ pub macro panic_2015 { #[allow_internal_unstable(panic_internals, const_format_args)] #[rustc_diagnostic_item = "core_panic_2021_macro"] #[rustc_macro_transparency = "semitransparent"] -#[cfg(feature = "panic_immediate_abort")] pub macro panic_2021 { () => ( $crate::panicking::panic("explicit panic") @@ -64,50 +63,6 @@ pub macro panic_2021 { }), } -#[doc(hidden)] -#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable( - panic_internals, - core_intrinsics, - const_dispatch, - const_eval_select, - const_format_args, - rustc_attrs -)] -#[rustc_diagnostic_item = "core_panic_2021_macro"] -#[rustc_macro_transparency = "semitransparent"] -#[cfg(not(feature = "panic_immediate_abort"))] -pub macro panic_2021 { - () => ({ - // Create a function so that the argument for `track_caller` - // can be moved inside if possible. - #[cold] - #[track_caller] - #[inline(never)] - const fn panic_cold_explicit() -> ! { - $crate::panicking::panic_explicit() - } - panic_cold_explicit(); - }), - // Special-case the single-argument case for const_panic. - ("{}", $arg:expr $(,)?) => ({ - #[cold] - #[track_caller] - #[inline(never)] - #[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval - #[rustc_do_not_const_check] // hooked by const-eval - const fn panic_cold_display(arg: &T) -> ! { - $crate::panicking::panic_display(arg) - } - panic_cold_display(&$arg); - }), - ($($t:tt)+) => ({ - // Semicolon to prevent temporaries inside the formatting machinery from - // being considered alive in the caller after the panic_fmt call. - $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)); - }), -} - #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")] #[allow_internal_unstable(panic_internals)] diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 812bc5e614572..804a12ee477bb 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -233,14 +233,6 @@ pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ true); } -#[track_caller] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] -#[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable -pub const fn panic_explicit() -> ! { - panic_display(&"explicit panic"); -} - #[inline] #[track_caller] #[rustc_diagnostic_item = "unreachable_display"] // needed for `non-fmt-panics` lint @@ -260,9 +252,8 @@ pub const fn panic_str_2015(expr: &str) -> ! { #[inline] #[track_caller] +#[lang = "panic_display"] // needed for const-evaluated panics #[rustc_do_not_const_check] // hooked by const-eval -// enforce a &&str argument in const-check and hook this by const-eval -#[rustc_const_panic_str] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn panic_display(x: &T) -> ! { panic_fmt(format_args!("{}", *x)); diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 60473a26493d0..7cd5a16f5b46d 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -250,18 +250,13 @@ impl<'a> PanicExpn<'a> { }; let name = path.segments.last().unwrap().ident.name; - // This has no argument - if name == sym::panic_cold_explicit { - return Some(Self::Empty); - } - let [arg, rest @ ..] = args else { return None; }; let result = match name { sym::panic if arg.span.eq_ctxt(expr.span) => Self::Empty, sym::panic | sym::panic_str => Self::Str(arg), - sym::panic_display | sym::panic_cold_display => { + sym::panic_display => { let ExprKind::AddrOf(_, _, e) = &arg.kind else { return None; }; diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index ce7cc9348fbd9..278101ac27f96 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -241,9 +241,6 @@ generate! { or_insert, or_insert_with, outer_expn, - panic_cold_display, - panic_cold_explicit, - panic_display, panic_str, parse, partition, From 427be23b22573699f396431e48970a5659389b27 Mon Sep 17 00:00:00 2001 From: Sacha Ayoun Date: Tue, 12 Aug 2025 13:18:48 +0100 Subject: [PATCH 108/252] Address dangling doc Signed-off-by: Sacha Ayoun --- library/core/src/alloc/layout.rs | 8 ++++---- library/core/src/ptr/mod.rs | 16 ++++++++-------- library/core/src/ptr/non_null.rs | 8 ++++---- library/core/src/ptr/unique.rs | 8 ++++---- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 49275975f046f..cd5fd77f86597 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -226,10 +226,10 @@ impl Layout { /// Creates a `NonNull` that is dangling, but well-aligned for this Layout. /// - /// Note that the pointer value may potentially represent a valid pointer, - /// which means this must not be used as a "not yet initialized" - /// sentinel value. Types that lazily allocate must track initialization by - /// some other means. + /// Note that the address of the returned pointer may potentially + /// be that of a valid pointer, which means this must not be used + /// as a "not yet initialized" sentinel value. + /// Types that lazily allocate must track initialization by some other means. #[unstable(feature = "alloc_layout_extra", issue = "55724")] #[must_use] #[inline] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 1a2a5182567b4..b2607e453245a 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -885,10 +885,10 @@ pub const fn without_provenance(addr: usize) -> *const T { /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. /// -/// Note that the pointer value may potentially represent a valid pointer to -/// a `T`, which means this must not be used as a "not yet initialized" -/// sentinel value. Types that lazily allocate must track initialization by -/// some other means. +/// Note that the address of the returned pointer may potentially +/// be that of a valid pointer, which means this must not be used +/// as a "not yet initialized" sentinel value. +/// Types that lazily allocate must track initialization by some other means. #[inline(always)] #[must_use] #[stable(feature = "strict_provenance", since = "1.84.0")] @@ -928,10 +928,10 @@ pub const fn without_provenance_mut(addr: usize) -> *mut T { /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. /// -/// Note that the pointer value may potentially represent a valid pointer to -/// a `T`, which means this must not be used as a "not yet initialized" -/// sentinel value. Types that lazily allocate must track initialization by -/// some other means. +/// Note that the address of the returned pointer may potentially +/// be that of a valid pointer, which means this must not be used +/// as a "not yet initialized" sentinel value. +/// Types that lazily allocate must track initialization by some other means. #[inline(always)] #[must_use] #[stable(feature = "strict_provenance", since = "1.84.0")] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 8667361fecc74..e72aa1da2cbe3 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -109,10 +109,10 @@ impl NonNull { /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. /// - /// Note that the pointer value may potentially represent a valid pointer to - /// a `T`, which means this must not be used as a "not yet initialized" - /// sentinel value. Types that lazily allocate must track initialization by - /// some other means. + /// Note that the address of the returned pointer may potentially + /// be that of a valid pointer, which means this must not be used + /// as a "not yet initialized" sentinel value. + /// Types that lazily allocate must track initialization by some other means. /// /// # Examples /// diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index e9e13f9e97f84..4302c1b1e4451 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -63,10 +63,10 @@ impl Unique { /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. /// - /// Note that the pointer value may potentially represent a valid pointer to - /// a `T`, which means this must not be used as a "not yet initialized" - /// sentinel value. Types that lazily allocate must track initialization by - /// some other means. + /// Note that the address of the returned pointer may potentially + /// be that of a valid pointer, which means this must not be used + /// as a "not yet initialized" sentinel value. + /// Types that lazily allocate must track initialization by some other means. #[must_use] #[inline] pub const fn dangling() -> Self { From 0d723234b37ed1eceb92abd6e3814ea06aafaac7 Mon Sep 17 00:00:00 2001 From: Rej Ect Date: Tue, 12 Aug 2025 08:21:00 +0300 Subject: [PATCH 109/252] chore(ci): upgrade checkout to v5 chore(ci): upgrade checkout to v5 --- .github/workflows/ci.yml | 6 +++--- .github/workflows/dependencies.yml | 4 ++-- .github/workflows/ghcr.yml | 2 +- .github/workflows/post-merge.yml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ce543071d841..df5dda76eb70a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,7 @@ jobs: run_type: ${{ steps.jobs.outputs.run_type }} steps: - name: Checkout the source code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Test citool # Only test citool on the auto branch, to reduce latency of the calculate matrix job # on PR/try builds. @@ -113,7 +113,7 @@ jobs: run: git config --global core.autocrlf false - name: checkout the source code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 2 @@ -313,7 +313,7 @@ jobs: if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }} steps: - name: checkout the source code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 2 # Calculate the exit status of the whole CI workflow. diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 9d4b6192d6eae..80ffd67e04e1a 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -51,7 +51,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: checkout the source code - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: recursive - name: install the bootstrap toolchain @@ -101,7 +101,7 @@ jobs: pull-requests: write steps: - name: checkout the source code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: download Cargo.lock from update job uses: actions/download-artifact@v4 diff --git a/.github/workflows/ghcr.yml b/.github/workflows/ghcr.yml index 6d050d98cb2e5..a89867efe666b 100644 --- a/.github/workflows/ghcr.yml +++ b/.github/workflows/ghcr.yml @@ -29,7 +29,7 @@ jobs: # Needed to write to the ghcr.io registry packages: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: persist-credentials: false diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index ca088ba31fdf9..12ff4be4f1e8c 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -15,7 +15,7 @@ jobs: permissions: pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: # Make sure that we have enough commits to find the parent merge commit. # Since all merges should be through merge commits, fetching two commits From f7defc0fe5ea6270de7be2159f91b4cc7afabf47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 15:01:33 +0200 Subject: [PATCH 110/252] Resolve review remarks --- src/bootstrap/src/core/build_steps/compile.rs | 13 ++++--------- src/bootstrap/src/core/build_steps/test.rs | 1 + 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index c04f080356525..c8feba48d84b2 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -215,7 +215,7 @@ impl Step for Std { trace!( ?compiler_to_use, ?build_compiler, - "compiler != compiler_to_use, uplifting library" + "build_compiler != compiler_to_use, uplifting library" ); builder.std(compiler_to_use, target); @@ -1609,13 +1609,8 @@ impl Step for GccCodegenBackend { let gcc = builder.ensure(Gcc { target }); add_cg_gcc_cargo_flags(&mut cargo, &gcc); - let _guard = builder.msg( - Kind::Build, - format_args!("codegen backend gcc"), - Mode::Codegen, - build_compiler, - target, - ); + let _guard = + builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, target); let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); write_codegen_backend_stamp(stamp, files, builder.config.dry_run()) } @@ -1695,7 +1690,7 @@ impl Step for CraneliftCodegenBackend { let _guard = builder.msg( Kind::Build, - format_args!("codegen backend cranelift"), + "codegen backend cranelift", Mode::Codegen, build_compiler, target, diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index fa72e93f503c4..f1be0af31837b 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2232,6 +2232,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let _group = builder.msg( Kind::Test, format!("compiletest suite={suite} mode={mode}"), + // FIXME: compiletest sometimes behaves as ToolStd, we could expose that difference here Mode::ToolBootstrap, compiler, target, From 0b8c6ad2b7863d34bfe5a55714039d2039a0ede5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 17:39:07 +0200 Subject: [PATCH 111/252] Remove one dependency from tracing bootstrap build --- src/bootstrap/Cargo.lock | 130 --------------------------------------- src/bootstrap/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 131 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index f5d04c39d3f33..605ac687ab814 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -11,21 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anstyle" version = "1.0.10" @@ -109,12 +94,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - [[package]] name = "cc" version = "1.2.23" @@ -136,12 +115,7 @@ version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", "num-traits", - "wasm-bindgen", - "windows-link", ] [[package]] @@ -212,12 +186,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - [[package]] name = "cpufeatures" version = "0.2.15" @@ -373,30 +341,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "ignore" version = "0.4.23" @@ -430,16 +374,6 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - [[package]] name = "junction" version = "1.2.0" @@ -701,12 +635,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - [[package]] name = "ryu" version = "1.0.18" @@ -996,64 +924,6 @@ dependencies = [ "wit-bindgen-rt", ] -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index ae5a5d798e57c..eb9cfaff31b38 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -61,7 +61,7 @@ xz2 = "0.1" sysinfo = { version = "0.36.0", default-features = false, optional = true, features = ["system"] } # Dependencies needed by the `tracing` feature -chrono = { version = "0.4", optional = true } +chrono = { version = "0.4", default-features = false, optional = true, features = ["now", "std"] } tracing = { version = "0.1", optional = true, features = ["attributes"] } tracing-chrome = { version = "0.7", optional = true } tracing-subscriber = { version = "0.3", optional = true, features = ["env-filter", "fmt", "registry", "std"] } From 0b855bcdc9b0fafa5a4a4330e10655105daf27cb Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 7 Aug 2025 19:21:16 -0700 Subject: [PATCH 112/252] Switch to a bitflags `MacroKinds` to support macros with more than one kind Review everything that uses `MacroKind`, and switch anything that could refer to more than one kind to use `MacroKinds`. Add a new `SyntaxExtensionKind::MacroRules` for `macro_rules!` macros, using the concrete `MacroRulesMacroExpander` type, and have it track which kinds it can handle. Eliminate the separate optional `attr_ext`, now that a `SyntaxExtension` can handle multiple macro kinds. This also avoids the need to downcast when calling methods on `MacroRulesMacroExpander`, such as `get_unused_rule`. Integrate macro kind checking into name resolution's `sub_namespace_match`, so that we only find a macro if it's the right type, and eliminate the special-case hack for attributes. --- Cargo.lock | 1 + compiler/rustc_ast_lowering/src/item.rs | 4 +- compiler/rustc_expand/src/base.rs | 46 +++++++++++++-- compiler/rustc_expand/src/expand.rs | 27 ++++----- compiler/rustc_expand/src/mbe/macro_rules.rs | 26 ++++---- compiler/rustc_hir/Cargo.toml | 1 + compiler/rustc_hir/src/def.rs | 59 +++++++++++++++++-- compiler/rustc_hir/src/hir.rs | 7 +-- compiler/rustc_lint/src/non_local_def.rs | 4 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_metadata/src/rmeta/table.rs | 26 ++++++-- .../rustc_resolve/src/build_reduced_graph.rs | 3 +- compiler/rustc_resolve/src/def_collector.rs | 4 +- compiler/rustc_resolve/src/diagnostics.rs | 28 ++++++--- compiler/rustc_resolve/src/ident.rs | 16 +---- .../rustc_resolve/src/late/diagnostics.rs | 9 ++- compiler/rustc_resolve/src/lib.rs | 10 ++-- compiler/rustc_resolve/src/macros.rs | 56 ++++++++---------- 19 files changed, 212 insertions(+), 119 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dbb76ada8377f..62ee27e4cca50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3889,6 +3889,7 @@ dependencies = [ name = "rustc_hir" version = "0.0.0" dependencies = [ + "bitflags", "odht", "rustc_abi", "rustc_arena", diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index ac6fac4c08e02..599e9ce7c257b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -464,14 +464,14 @@ impl<'hir> LoweringContext<'_, 'hir> { let body = Box::new(self.lower_delim_args(body)); let def_id = self.local_def_id(id); let def_kind = self.tcx.def_kind(def_id); - let DefKind::Macro(macro_kind) = def_kind else { + let DefKind::Macro(macro_kinds) = def_kind else { unreachable!( "expected DefKind::Macro for macro item, found {}", def_kind.descr(def_id.to_def_id()) ); }; let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules }); - hir::ItemKind::Macro(ident, macro_def, macro_kind) + hir::ItemKind::Macro(ident, macro_def, macro_kinds) } ItemKind::Delegation(box delegation) => { let delegation_results = self.lower_delegation(delegation, id, false); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c234aa43c09c1..c47c076e56ef9 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -17,6 +17,7 @@ use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation}; +use rustc_hir::def::MacroKinds; use rustc_hir::{Stability, find_attr}; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; use rustc_parse::MACRO_ARGUMENTS; @@ -718,6 +719,9 @@ impl MacResult for DummyResult { /// A syntax extension kind. #[derive(Clone)] pub enum SyntaxExtensionKind { + /// A `macro_rules!` macro that can work as any `MacroKind` + MacroRules(Arc), + /// A token-based function-like macro. Bang( /// An expander with signature TokenStream -> TokenStream. @@ -775,6 +779,34 @@ pub enum SyntaxExtensionKind { GlobDelegation(Arc), } +impl SyntaxExtensionKind { + /// Returns `Some(expander)` for a macro usable as a `LegacyBang`; otherwise returns `None` + /// + /// This includes a `MacroRules` with function-like rules. + pub fn as_legacy_bang(&self) -> Option<&(dyn TTMacroExpander + sync::DynSync + sync::DynSend)> { + match self { + SyntaxExtensionKind::LegacyBang(exp) => Some(exp.as_ref()), + SyntaxExtensionKind::MacroRules(exp) if exp.kinds().contains(MacroKinds::BANG) => { + Some(exp.as_ref()) + } + _ => None, + } + } + + /// Returns `Some(expander)` for a macro usable as an `Attr`; otherwise returns `None` + /// + /// This includes a `MacroRules` with `attr` rules. + pub fn as_attr(&self) -> Option<&(dyn AttrProcMacro + sync::DynSync + sync::DynSend)> { + match self { + SyntaxExtensionKind::Attr(exp) => Some(exp.as_ref()), + SyntaxExtensionKind::MacroRules(exp) if exp.kinds().contains(MacroKinds::ATTR) => { + Some(exp.as_ref()) + } + _ => None, + } + } +} + /// A struct representing a macro definition in "lowered" form ready for expansion. pub struct SyntaxExtension { /// A syntax extension kind. @@ -804,18 +836,19 @@ pub struct SyntaxExtension { } impl SyntaxExtension { - /// Returns which kind of macro calls this syntax extension. - pub fn macro_kind(&self) -> MacroKind { + /// Returns which kinds of macro call this syntax extension. + pub fn macro_kinds(&self) -> MacroKinds { match self.kind { SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) - | SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang, + | SyntaxExtensionKind::GlobDelegation(..) => MacroKinds::BANG, SyntaxExtensionKind::Attr(..) | SyntaxExtensionKind::LegacyAttr(..) - | SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr, + | SyntaxExtensionKind::NonMacroAttr => MacroKinds::ATTR, SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => { - MacroKind::Derive + MacroKinds::DERIVE } + SyntaxExtensionKind::MacroRules(ref m) => m.kinds(), } } @@ -1027,11 +1060,12 @@ impl SyntaxExtension { parent: LocalExpnId, call_site: Span, descr: Symbol, + kind: MacroKind, macro_def_id: Option, parent_module: Option, ) -> ExpnData { ExpnData::new( - ExpnKind::Macro(self.macro_kind(), descr), + ExpnKind::Macro(kind, descr), parent.to_expn_id(), call_site, self.span, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index e7ae44169688d..f675541e0793f 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -736,8 +736,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); ExpandResult::Ready(match invoc.kind { - InvocationKind::Bang { mac, span } => match ext { - SyntaxExtensionKind::Bang(expander) => { + InvocationKind::Bang { mac, span } => { + if let SyntaxExtensionKind::Bang(expander) = ext { match expander.expand(self.cx, span, mac.args.tokens.clone()) { Ok(tok_result) => { let fragment = @@ -755,8 +755,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } - } - SyntaxExtensionKind::LegacyBang(expander) => { + } else if let Some(expander) = ext.as_legacy_bang() { let tok_result = match expander.expand(self.cx, span, mac.args.tokens.clone()) { ExpandResult::Ready(tok_result) => tok_result, ExpandResult::Retry(_) => { @@ -776,11 +775,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span); fragment_kind.dummy(span, guar) } + } else { + unreachable!(); } - _ => unreachable!(), - }, - InvocationKind::Attr { attr, pos, mut item, derives } => match ext { - SyntaxExtensionKind::Attr(expander) => { + } + InvocationKind::Attr { attr, pos, mut item, derives } => { + if let Some(expander) = ext.as_attr() { self.gate_proc_macro_input(&item); self.gate_proc_macro_attr_item(span, &item); let tokens = match &item { @@ -835,8 +835,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } - } - SyntaxExtensionKind::LegacyAttr(expander) => { + } else if let SyntaxExtensionKind::LegacyAttr(expander) = ext { match validate_attr::parse_meta(&self.cx.sess.psess, &attr) { Ok(meta) => { let item_clone = macro_stats.then(|| item.clone()); @@ -878,15 +877,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fragment_kind.expect_from_annotatables(iter::once(item)) } } - } - SyntaxExtensionKind::NonMacroAttr => { + } else if let SyntaxExtensionKind::NonMacroAttr = ext { // `-Zmacro-stats` ignores these because they don't do any real expansion. self.cx.expanded_inert_attrs.mark(&attr); item.visit_attrs(|attrs| attrs.insert(pos, attr)); fragment_kind.expect_from_annotatables(iter::once(item)) + } else { + unreachable!(); } - _ => unreachable!(), - }, + } InvocationKind::Derive { path, item, is_const } => match ext { SyntaxExtensionKind::Derive(expander) | SyntaxExtensionKind::LegacyDerive(expander) => { diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 08b0efb74a05f..334f57f9d6259 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -15,6 +15,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; +use rustc_hir::def::MacroKinds; use rustc_hir::find_attr; use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::{ @@ -144,6 +145,7 @@ pub struct MacroRulesMacroExpander { name: Ident, span: Span, transparency: Transparency, + kinds: MacroKinds, rules: Vec, } @@ -158,6 +160,10 @@ impl MacroRulesMacroExpander { }; if has_compile_error_macro(rhs) { None } else { Some((&self.name, span)) } } + + pub fn kinds(&self) -> MacroKinds { + self.kinds + } } impl TTMacroExpander for MacroRulesMacroExpander { @@ -540,13 +546,13 @@ pub fn compile_declarative_macro( span: Span, node_id: NodeId, edition: Edition, -) -> (SyntaxExtension, Option>, usize) { +) -> (SyntaxExtension, usize) { let mk_syn_ext = |kind| { let is_local = is_defined_in_current_crate(node_id); SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local) }; - let mk_bang_ext = |expander| mk_syn_ext(SyntaxExtensionKind::LegacyBang(expander)); - let dummy_syn_ext = |guar| (mk_bang_ext(Arc::new(DummyExpander(guar))), None, 0); + let dummy_syn_ext = + |guar| (mk_syn_ext(SyntaxExtensionKind::LegacyBang(Arc::new(DummyExpander(guar)))), 0); let macro_rules = macro_def.macro_rules; let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) }; @@ -559,12 +565,12 @@ pub fn compile_declarative_macro( let mut guar = None; let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err()); - let mut has_attr_rules = false; + let mut kinds = MacroKinds::empty(); let mut rules = Vec::new(); while p.token != token::Eof { let args = if p.eat_keyword_noexpect(sym::attr) { - has_attr_rules = true; + kinds |= MacroKinds::ATTR; if !features.macro_attr() { feature_err(sess, sym::macro_attr, span, "`macro_rules!` attributes are unstable") .emit(); @@ -581,6 +587,7 @@ pub fn compile_declarative_macro( } Some(args) } else { + kinds |= MacroKinds::BANG; None }; let lhs_tt = p.parse_token_tree(); @@ -627,6 +634,7 @@ pub fn compile_declarative_macro( let guar = sess.dcx().span_err(span, "macros must contain at least one rule"); return dummy_syn_ext(guar); } + assert!(!kinds.is_empty()); let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x) .unwrap_or(Transparency::fallback(macro_rules)); @@ -640,12 +648,8 @@ pub fn compile_declarative_macro( // Return the number of rules for unused rule linting, if this is a local macro. let nrules = if is_defined_in_current_crate(node_id) { rules.len() } else { 0 }; - let exp = Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules }); - let opt_attr_ext = has_attr_rules.then(|| { - let exp = Arc::clone(&exp); - Arc::new(mk_syn_ext(SyntaxExtensionKind::Attr(exp))) - }); - (mk_bang_ext(exp), opt_attr_ext, nrules) + let exp = MacroRulesMacroExpander { name: ident, kinds, span, node_id, transparency, rules }; + (mk_syn_ext(SyntaxExtensionKind::MacroRules(Arc::new(exp))), nrules) } fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option { diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 539d2e6f0b179..71496b7ec324a 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +bitflags = "2.9.1" odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 339d4e2eab7fa..79319e2426603 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -31,6 +31,53 @@ pub enum CtorKind { Const, } +/// A set of macro kinds, for macros that can have more than one kind +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Hash, Debug)] +#[derive(HashStable_Generic)] +pub struct MacroKinds(u8); +bitflags::bitflags! { + impl MacroKinds: u8 { + const BANG = 1 << 0; + const ATTR = 1 << 1; + const DERIVE = 1 << 2; + } +} + +impl From for MacroKinds { + fn from(kind: MacroKind) -> Self { + match kind { + MacroKind::Bang => Self::BANG, + MacroKind::Attr => Self::ATTR, + MacroKind::Derive => Self::DERIVE, + } + } +} + +impl MacroKinds { + /// Convert the MacroKinds to a static string. + /// + /// This hardcodes all the possibilities, in order to return a static string. + pub fn descr(self) -> &'static str { + match self { + // FIXME: change this to "function-like macro" and fix all tests + Self::BANG => "macro", + Self::ATTR => "attribute macro", + Self::DERIVE => "derive macro", + _ if self == (Self::ATTR | Self::BANG) => "attribute/function macro", + _ if self == (Self::DERIVE | Self::BANG) => "derive/function macro", + _ if self == (Self::ATTR | Self::DERIVE) => "attribute/derive macro", + _ if self.is_all() => "attribute/derive/function macro", + _ if self.is_empty() => "useless macro", + _ => unreachable!(), + } + } + + /// Return an indefinite article (a/an) for use with `descr()` + pub fn article(self) -> &'static str { + if self.contains(Self::ATTR) { "an" } else { "a" } + } +} + /// An attribute that is not a macro; e.g., `#[inline]` or `#[rustfmt::skip]`. #[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)] pub enum NonMacroAttrKind { @@ -101,7 +148,7 @@ pub enum DefKind { AssocConst, // Macro namespace - Macro(MacroKind), + Macro(MacroKinds), // Not namespaced (or they are, but we don't treat them so) ExternCrate, @@ -177,7 +224,7 @@ impl DefKind { DefKind::AssocConst => "associated constant", DefKind::TyParam => "type parameter", DefKind::ConstParam => "const parameter", - DefKind::Macro(macro_kind) => macro_kind.descr(), + DefKind::Macro(kinds) => kinds.descr(), DefKind::LifetimeParam => "lifetime parameter", DefKind::Use => "import", DefKind::ForeignMod => "foreign module", @@ -208,7 +255,7 @@ impl DefKind { | DefKind::Use | DefKind::InlineConst | DefKind::ExternCrate => "an", - DefKind::Macro(macro_kind) => macro_kind.article(), + DefKind::Macro(kinds) => kinds.article(), _ => "a", } } @@ -845,10 +892,10 @@ impl Res { ) } - pub fn macro_kind(self) -> Option { + pub fn macro_kinds(self) -> Option { match self { - Res::Def(DefKind::Macro(kind), _) => Some(kind), - Res::NonMacroAttr(..) => Some(MacroKind::Attr), + Res::Def(DefKind::Macro(kinds), _) => Some(kinds), + Res::NonMacroAttr(..) => Some(MacroKinds::ATTR), _ => None, } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 34db6f92d9288..8358a11e586ad 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -20,7 +20,6 @@ use rustc_data_structures::tagged_ptr::TaggedRef; use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::def_id::LocalDefId; -use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -30,7 +29,7 @@ use tracing::debug; use crate::LangItem; use crate::attrs::AttributeKind; -use crate::def::{CtorKind, DefKind, PerNS, Res}; +use crate::def::{CtorKind, DefKind, MacroKinds, PerNS, Res}; use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::{FnKind, VisitorExt}; @@ -4156,7 +4155,7 @@ impl<'hir> Item<'hir> { expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId), ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body); - expect_macro, (Ident, &ast::MacroDef, MacroKind), + expect_macro, (Ident, &ast::MacroDef, MacroKinds), ItemKind::Macro(ident, def, mk), (*ident, def, *mk); expect_mod, (Ident, &'hir Mod<'hir>), ItemKind::Mod(ident, m), (*ident, m); @@ -4335,7 +4334,7 @@ pub enum ItemKind<'hir> { has_body: bool, }, /// A MBE macro definition (`macro_rules!` or `macro`). - Macro(Ident, &'hir ast::MacroDef, MacroKind), + Macro(Ident, &'hir ast::MacroDef, MacroKinds), /// A module. Mod(Ident, &'hir Mod<'hir>), /// An external module, e.g. `extern { .. }`. diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index b877f909fc029..e6507fe6149f3 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -5,7 +5,7 @@ use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind}; use rustc_middle::ty::TyCtxt; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::def_id::{DefId, LOCAL_CRATE}; -use rustc_span::{ExpnKind, MacroKind, Span, kw, sym}; +use rustc_span::{ExpnKind, Span, kw, sym}; use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag}; use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; @@ -240,7 +240,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { }, ) } - ItemKind::Macro(_, _macro, MacroKind::Bang) + ItemKind::Macro(_, _macro, _kinds) if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) => { cx.emit_span_lint( diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d42c8b947a48a..a7e7e9985f4d4 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1981,7 +1981,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { def_key.disambiguated_data.data = DefPathData::MacroNs(name); let def_id = id.to_def_id(); - self.tables.def_kind.set_some(def_id.index, DefKind::Macro(macro_kind)); + self.tables.def_kind.set_some(def_id.index, DefKind::Macro(macro_kind.into())); self.tables.proc_macro.set_some(def_id.index, macro_kind); self.encode_attrs(id); record!(self.tables.def_keys[def_id] <- def_key); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 99174e4ad2fd9..1f7d142d33000 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -11,7 +11,7 @@ use rustc_abi::{FieldIdx, ReprOptions, VariantIdx}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; use rustc_hir::attrs::StrippedCfgItem; -use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap}; +use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap, MacroKinds}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; use rustc_hir::lang_items::LangItem; diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 0671aa203993a..2cb07a28a8ad2 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -81,7 +81,7 @@ impl FixedSizeEncoding for u64 { } macro_rules! fixed_size_enum { - ($ty:ty { $(($($pat:tt)*))* }) => { + ($ty:ty { $(($($pat:tt)*))* } $( unreachable { $(($($upat:tt)*))+ } )?) => { impl FixedSizeEncoding for Option<$ty> { type ByteArray = [u8;1]; @@ -103,12 +103,24 @@ macro_rules! fixed_size_enum { b[0] = match self { None => unreachable!(), $(Some($($pat)*) => 1 + ${index()},)* + $(Some($($($upat)*)|+) => unreachable!(),)? } } } } } +// Workaround; need const traits to construct bitflags in a const +macro_rules! const_macro_kinds { + ($($name:ident),+$(,)?) => (MacroKinds::from_bits_truncate($(MacroKinds::$name.bits())|+)) +} +const MACRO_KINDS_ATTR_BANG: MacroKinds = const_macro_kinds!(ATTR, BANG); +const MACRO_KINDS_DERIVE_BANG: MacroKinds = const_macro_kinds!(DERIVE, BANG); +const MACRO_KINDS_DERIVE_ATTR: MacroKinds = const_macro_kinds!(DERIVE, ATTR); +const MACRO_KINDS_DERIVE_ATTR_BANG: MacroKinds = const_macro_kinds!(DERIVE, ATTR, BANG); +// Ensure that we get a compilation error if MacroKinds gets extended without updating metadata. +const _: () = assert!(MACRO_KINDS_DERIVE_ATTR_BANG.is_all()); + fixed_size_enum! { DefKind { ( Mod ) @@ -151,10 +163,16 @@ fixed_size_enum! { ( Ctor(CtorOf::Struct, CtorKind::Const) ) ( Ctor(CtorOf::Variant, CtorKind::Fn) ) ( Ctor(CtorOf::Variant, CtorKind::Const) ) - ( Macro(MacroKind::Bang) ) - ( Macro(MacroKind::Attr) ) - ( Macro(MacroKind::Derive) ) + ( Macro(MacroKinds::BANG) ) + ( Macro(MacroKinds::ATTR) ) + ( Macro(MacroKinds::DERIVE) ) + ( Macro(MACRO_KINDS_ATTR_BANG) ) + ( Macro(MACRO_KINDS_DERIVE_ATTR) ) + ( Macro(MACRO_KINDS_DERIVE_BANG) ) + ( Macro(MACRO_KINDS_DERIVE_ATTR_BANG) ) ( SyntheticCoroutineBody ) + } unreachable { + ( Macro(_) ) } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d18d0fc16a8e4..07395b68c7d4c 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1235,7 +1235,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ItemKind::Fn(box ast::Fn { ident: fn_ident, .. }) => { match self.proc_macro_stub(item, *fn_ident) { Some((macro_kind, ident, span)) => { - let res = Res::Def(DefKind::Macro(macro_kind), def_id.to_def_id()); + let macro_kinds = macro_kind.into(); + let res = Res::Def(DefKind::Macro(macro_kinds), def_id.to_def_id()); let macro_data = MacroData::new(self.r.dummy_ext(macro_kind)); self.r.new_local_macro(def_id, macro_data); self.r.proc_macro_stubs.insert(def_id); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 7d51fef28d3ba..1e4513eb78707 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -149,9 +149,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let macro_data = self.resolver.compile_macro(def, *ident, &attrs, i.span, i.id, edition); - let macro_kind = macro_data.ext.macro_kind(); + let macro_kinds = macro_data.ext.macro_kinds(); opt_macro_data = Some(macro_data); - DefKind::Macro(macro_kind) + DefKind::Macro(macro_kinds) } ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::Use(use_tree) => { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 210ab72678c56..217be7be1780a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -13,7 +13,7 @@ use rustc_errors::{ use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem}; use rustc_hir::def::Namespace::{self, *}; -use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS}; +use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds, NonMacroAttrKind, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::{PrimTy, Stability, StabilityLevel, find_attr}; use rustc_middle::bug; @@ -1491,11 +1491,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Some(binding) = resolution.borrow().best_binding() else { continue; }; - let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) = - binding.res() - else { + let Res::Def(DefKind::Macro(kinds), def_id) = binding.res() else { continue; }; + if !kinds.intersects(MacroKinds::ATTR | MacroKinds::DERIVE) { + continue; + } // By doing this all *imported* macros get added to the `macro_map` even if they // are *unused*, which makes the later suggestions find them and work. let _ = this.get_macro_by_def_id(def_id); @@ -1504,7 +1505,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ); - let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind); + let is_expected = + &|res: Res| res.macro_kinds().is_some_and(|k| k.contains(macro_kind.into())); let suggestion = self.early_lookup_typo_candidate( ScopeSet::Macro(macro_kind), parent_scope, @@ -1601,13 +1603,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let desc = match binding.res() { - Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(), - Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => { + Res::Def(DefKind::Macro(MacroKinds::BANG), _) => { + "a function-like macro".to_string() + } + Res::Def(DefKind::Macro(MacroKinds::ATTR), _) | Res::NonMacroAttr(..) => { format!("an attribute: `#[{ident}]`") } - Res::Def(DefKind::Macro(MacroKind::Derive), _) => { + Res::Def(DefKind::Macro(MacroKinds::DERIVE), _) => { format!("a derive macro: `#[derive({ident})]`") } + Res::Def(DefKind::Macro(kinds), _) => { + format!("{} {}", kinds.article(), kinds.descr()) + } Res::ToolMod => { // Don't confuse the user with tool modules. continue; @@ -2748,9 +2755,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let binding_key = BindingKey::new(ident, MacroNS); let binding = self.resolution(crate_module, binding_key)?.binding()?; - let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else { + let Res::Def(DefKind::Macro(kinds), _) = binding.res() else { return None; }; + if !kinds.contains(MacroKinds::BANG) { + return None; + } let module_name = crate_module.kind.name().unwrap_or(kw::Crate); let import_snippet = match import.kind { ImportKind::Single { source, target, .. } if source != target => { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 9efcef695b7b4..87b3fc76c9671 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -2,7 +2,7 @@ use Determinacy::*; use Namespace::*; use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; -use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS}; +use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS}; use rustc_middle::bug; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; @@ -259,7 +259,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { { let ext = &self.get_macro_by_def_id(def_id).ext; if ext.builtin_name.is_none() - && ext.macro_kind() == MacroKind::Derive + && ext.macro_kinds() == MacroKinds::DERIVE && parent.expansion.outer_expn_is_descendant_of(*ctxt) { return Some((parent, derive_fallback_lint_id)); @@ -632,17 +632,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match result { Ok((binding, flags)) => { - let binding_macro_kind = binding.macro_kind(); - // If we're looking for an attribute, that might be supported by a - // `macro_rules!` macro. - // FIXME: Replace this with tracking multiple macro kinds for one Def. - if !(sub_namespace_match(binding_macro_kind, macro_kind) - || (binding_macro_kind == Some(MacroKind::Bang) - && macro_kind == Some(MacroKind::Attr) - && this - .get_macro(binding.res()) - .is_some_and(|macro_data| macro_data.attr_ext.is_some()))) - { + if !sub_namespace_match(binding.macro_kinds(), macro_kind) { return None; } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index aca251da71d39..c8cab5a0fe9a1 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -19,14 +19,13 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::def::Namespace::{self, *}; -use rustc_hir::def::{self, CtorKind, CtorOf, DefKind}; +use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::{MissingLifetimeKind, PrimTy}; use rustc_middle::ty; use rustc_session::{Session, lint}; use rustc_span::edit_distance::{edit_distance, find_best_match_for_name}; use rustc_span::edition::Edition; -use rustc_span::hygiene::MacroKind; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use thin_vec::ThinVec; use tracing::debug; @@ -1850,12 +1849,12 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { match (res, source) { ( - Res::Def(DefKind::Macro(MacroKind::Bang), def_id), + Res::Def(DefKind::Macro(kinds), def_id), PathSource::Expr(Some(Expr { kind: ExprKind::Index(..) | ExprKind::Call(..), .. })) | PathSource::Struct(_), - ) => { + ) if kinds.contains(MacroKinds::BANG) => { // Don't suggest macro if it's unstable. let suggestable = def_id.is_local() || self.r.tcx.lookup_stability(def_id).is_none_or(|s| s.is_stable()); @@ -1880,7 +1879,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { err.note("if you want the `try` keyword, you need Rust 2018 or later"); } } - (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => { + (Res::Def(DefKind::Macro(kinds), _), _) if kinds.contains(MacroKinds::BANG) => { err.span_label(span, fallback_label.to_string()); } (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b43f71913d9ba..797f4f619e31d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -53,7 +53,8 @@ use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::attrs::StrippedCfgItem; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{ - self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS, + self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, MacroKinds, NonMacroAttrKind, PartialRes, + PerNS, }; use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; use rustc_hir::definitions::DisambiguatorState; @@ -969,8 +970,8 @@ impl<'ra> NameBindingData<'ra> { matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _)) } - fn macro_kind(&self) -> Option { - self.res().macro_kind() + fn macro_kinds(&self) -> Option { + self.res().macro_kinds() } // Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding` @@ -1030,14 +1031,13 @@ struct DeriveData { struct MacroData { ext: Arc, - attr_ext: Option>, nrules: usize, macro_rules: bool, } impl MacroData { fn new(ext: Arc) -> MacroData { - MacroData { ext, attr_ext: None, nrules: 0, macro_rules: false } + MacroData { ext, nrules: 0, macro_rules: false } } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 9173d0d3ea5ec..f3617cf1eb32c 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1,7 +1,6 @@ //! A bunch of methods and structures more or less related to resolving macros and //! interface provided by `Resolver` to macro expander. -use std::any::Any; use std::cell::Cell; use std::mem; use std::sync::Arc; @@ -13,13 +12,13 @@ use rustc_expand::base::{ Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind, }; +use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{ AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion, }; -use rustc_expand::{MacroRulesMacroExpander, compile_declarative_macro}; use rustc_hir::StabilityLevel; use rustc_hir::attrs::{CfgEntry, StrippedCfgItem}; -use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind}; +use rustc_hir::def::{self, DefKind, MacroKinds, Namespace, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_middle::middle::stability; use rustc_middle::ty::{RegisteredTools, TyCtxt}; @@ -86,22 +85,19 @@ pub(crate) type MacroRulesScopeRef<'ra> = &'ra Cell>; /// one for attribute-like macros (attributes, derives). /// We ignore resolutions from one sub-namespace when searching names in scope for another. pub(crate) fn sub_namespace_match( - candidate: Option, + candidate: Option, requirement: Option, ) -> bool { - #[derive(PartialEq)] - enum SubNS { - Bang, - AttrLike, - } - let sub_ns = |kind| match kind { - MacroKind::Bang => SubNS::Bang, - MacroKind::Attr | MacroKind::Derive => SubNS::AttrLike, - }; - let candidate = candidate.map(sub_ns); - let requirement = requirement.map(sub_ns); // "No specific sub-namespace" means "matches anything" for both requirements and candidates. - candidate.is_none() || requirement.is_none() || candidate == requirement + let (Some(candidate), Some(requirement)) = (candidate, requirement) else { + return true; + }; + match requirement { + MacroKind::Bang => candidate.contains(MacroKinds::BANG), + MacroKind::Attr | MacroKind::Derive => { + candidate.intersects(MacroKinds::ATTR | MacroKinds::DERIVE) + } + } } // We don't want to format a path using pretty-printing, @@ -323,6 +319,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { parent_scope.expansion, span, fast_print_path(path), + kind, def_id, def_id.map(|def_id| self.macro_def_scope(def_id).nearest_parent_mod()), ), @@ -356,11 +353,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } let def_id = self.local_def_id(node_id); let m = &self.local_macro_map[&def_id]; - let SyntaxExtensionKind::LegacyBang(ref ext) = m.ext.kind else { - continue; - }; - let ext: &dyn Any = ext.as_ref(); - let Some(m) = ext.downcast_ref::() else { + let SyntaxExtensionKind::MacroRules(ref m) = m.ext.kind else { continue; }; for arm_i in unused_arms.iter() { @@ -633,7 +626,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.check_stability_and_deprecation(&ext, path, node_id); - let unexpected_res = if ext.macro_kind() != kind { + let unexpected_res = if !ext.macro_kinds().contains(kind.into()) { Some((kind.article(), kind.descr_expected())) } else if matches!(res, Res::Def(..)) { match supports_macro_expansion { @@ -665,7 +658,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Suggest moving the macro out of the derive() if the macro isn't Derive if !path.span.from_expansion() && kind == MacroKind::Derive - && ext.macro_kind() != MacroKind::Derive + && !ext.macro_kinds().contains(MacroKinds::DERIVE) { err.remove_surrounding_derive = Some(RemoveSurroundingDerive { span: path.span }); err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str }); @@ -842,10 +835,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } _ => None, }, - None => self.get_macro(res).map(|macro_data| match kind { - Some(MacroKind::Attr) if let Some(ref ext) = macro_data.attr_ext => Arc::clone(ext), - _ => Arc::clone(¯o_data.ext), - }), + None => self.get_macro(res).map(|macro_data| Arc::clone(¯o_data.ext)), }; Ok((ext, res)) } @@ -1114,7 +1104,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && let Some(binding) = binding // This is a `macro_rules` itself, not some import. && let NameBindingKind::Res(res) = binding.kind - && let Res::Def(DefKind::Macro(MacroKind::Bang), def_id) = res + && let Res::Def(DefKind::Macro(kinds), def_id) = res + && kinds.contains(MacroKinds::BANG) // And the `macro_rules` is defined inside the attribute's module, // so it cannot be in scope unless imported. && self.tcx.is_descendant_of(def_id, mod_def_id.to_def_id()) @@ -1161,8 +1152,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. if ident.name == sym::cfg || ident.name == sym::cfg_attr { - let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind()); - if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) { + let macro_kinds = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kinds()); + if macro_kinds.is_some() && sub_namespace_match(macro_kinds, Some(MacroKind::Attr)) { self.dcx() .emit_err(errors::NameReservedInAttributeNamespace { span: ident.span, ident }); } @@ -1181,7 +1172,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { node_id: NodeId, edition: Edition, ) -> MacroData { - let (mut ext, mut attr_ext, mut nrules) = compile_declarative_macro( + let (mut ext, mut nrules) = compile_declarative_macro( self.tcx.sess, self.tcx.features(), macro_def, @@ -1198,14 +1189,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. ext.kind = builtin_ext_kind.clone(); - attr_ext = None; nrules = 0; } else { self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident }); } } - MacroData { ext: Arc::new(ext), attr_ext, nrules, macro_rules: macro_def.macro_rules } + MacroData { ext: Arc::new(ext), nrules, macro_rules: macro_def.macro_rules } } fn path_accessible( From d7b30bef7ea482a3ded64b3ab41246ad363ee73d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 8 Aug 2025 23:03:34 -0700 Subject: [PATCH 113/252] Expand documentation of `GlobDelegation` I discovered this via research through the git log, and I want to leave additional guidance for future macro spelunkers. --- compiler/rustc_expand/src/base.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c47c076e56ef9..205aa47c1a02e 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -776,6 +776,8 @@ pub enum SyntaxExtensionKind { ), /// A glob delegation. + /// + /// This is for delegated function implementations, and has nothing to do with glob imports. GlobDelegation(Arc), } From c81fcaca1c4f2e9b39fc8bc3d03a3f19b475d366 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 8 Aug 2025 21:36:17 -0700 Subject: [PATCH 114/252] Only suggest changing `#[derive(mymacro)]` to `#[mymacro]` for attribute macros --- compiler/rustc_resolve/src/macros.rs | 1 + tests/ui/proc-macro/macro-namespace-reserved-2.stderr | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f3617cf1eb32c..9f25635f1fd1a 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -659,6 +659,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !path.span.from_expansion() && kind == MacroKind::Derive && !ext.macro_kinds().contains(MacroKinds::DERIVE) + && ext.macro_kinds().contains(MacroKinds::ATTR) { err.remove_surrounding_derive = Some(RemoveSurroundingDerive { span: path.span }); err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str }); diff --git a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr index 0471124061ef4..c8a7cc3ba9135 100644 --- a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -95,14 +95,6 @@ error: expected derive macro, found macro `crate::my_macro` | LL | #[derive(crate::my_macro)] | ^^^^^^^^^^^^^^^ not a derive macro - | -help: remove from the surrounding `derive()` - --> $DIR/macro-namespace-reserved-2.rs:50:10 - | -LL | #[derive(crate::my_macro)] - | ^^^^^^^^^^^^^^^ - = help: add as non-Derive macro - `#[crate::my_macro]` error: cannot find macro `my_macro_attr` in this scope --> $DIR/macro-namespace-reserved-2.rs:28:5 From ba231db3f33381f417a94566f043738dcaf60fc3 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 8 Aug 2025 22:49:57 -0700 Subject: [PATCH 115/252] Detect and report macro kind mismatches early, and more precisely This eliminates the case in `failed_to_match_macro` to check for a function-like invocation of a macro with no function-like rules. Instead, macro kind mismatches now result in an unresolved macro, and we detect this case in `unresolved_macro_suggestions`, which now carefully distinguishes between a kind mismatch and other errors. This also handles cases of forward-referenced attributes and cyclic attributes. Expand test coverage to include all of these cases. --- compiler/rustc_expand/src/mbe/diagnostics.rs | 12 ---- compiler/rustc_resolve/messages.ftl | 3 + compiler/rustc_resolve/src/diagnostics.rs | 22 +++++--- compiler/rustc_resolve/src/errors.rs | 6 ++ tests/ui/macros/macro-rules-attr-error.rs | 39 ++++++++++++- tests/ui/macros/macro-rules-attr-error.stderr | 55 ++++++++++++++++--- 6 files changed, 108 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 5b9d56ee2bc32..80433b7be9103 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -58,18 +58,6 @@ pub(super) fn failed_to_match_macro( let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure else { - // FIXME: we should report this at macro resolution time, as we do for - // `resolve_macro_cannot_use_as_attr`. We can do that once we track multiple macro kinds for a - // Def. - if attr_args.is_none() && !rules.iter().any(|rule| matches!(rule, MacroRule::Func { .. })) { - let msg = format!("macro has no rules for function-like invocation `{name}!`"); - let mut err = psess.dcx().struct_span_err(sp, msg); - if !def_head_span.is_dummy() { - let msg = "this macro has no rules for function-like invocation"; - err.span_label(def_head_span, msg); - } - return (sp, err.emit()); - } return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro")); }; diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index ceef558c0cf95..d5ff8a4b60970 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -242,6 +242,9 @@ resolve_lowercase_self = attempt to use a non-constant value in a constant .suggestion = try using `Self` +resolve_macro_cannot_use_as_fn_like = + `{$ident}` exists, but has no rules for function-like invocation + resolve_macro_cannot_use_as_attr = `{$ident}` exists, but has no `attr` rules diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 217be7be1780a..a78cf0287954c 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1555,11 +1555,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some((def_id, unused_ident)) = unused_macro { let scope = self.local_macro_def_scopes[&def_id]; let parent_nearest = parent_scope.module.nearest_parent_mod(); - if Some(parent_nearest) == scope.opt_def_id() { + let unused_macro_kinds = self.local_macro_map[def_id].ext.macro_kinds(); + if !unused_macro_kinds.contains(macro_kind.into()) { match macro_kind { MacroKind::Bang => { - err.subdiagnostic(MacroDefinedLater { span: unused_ident.span }); - err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident }); + err.subdiagnostic(MacroRulesNot::Func { span: unused_ident.span, ident }); } MacroKind::Attr => { err.subdiagnostic(MacroRulesNot::Attr { span: unused_ident.span, ident }); @@ -1568,14 +1568,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(MacroRulesNot::Derive { span: unused_ident.span, ident }); } } - return; } - } - - if self.macro_names.contains(&ident.normalize_to_macros_2_0()) { - err.subdiagnostic(AddedMacroUse); - return; + if Some(parent_nearest) == scope.opt_def_id() { + err.subdiagnostic(MacroDefinedLater { span: unused_ident.span }); + err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident }); + return; + } } if ident.name == kw::Default @@ -1651,6 +1650,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(note); return; } + + if self.macro_names.contains(&ident.normalize_to_macros_2_0()) { + err.subdiagnostic(AddedMacroUse); + return; + } } /// Given an attribute macro that failed to be resolved, look for `derive` macros that could diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 2747ba135ed0d..a1d62ba7a6834 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -672,6 +672,12 @@ pub(crate) struct MacroSuggMovePosition { #[derive(Subdiagnostic)] pub(crate) enum MacroRulesNot { + #[label(resolve_macro_cannot_use_as_fn_like)] + Func { + #[primary_span] + span: Span, + ident: Ident, + }, #[label(resolve_macro_cannot_use_as_attr)] Attr { #[primary_span] diff --git a/tests/ui/macros/macro-rules-attr-error.rs b/tests/ui/macros/macro-rules-attr-error.rs index 1c8bb251e20e1..81eadb6692f22 100644 --- a/tests/ui/macros/macro-rules-attr-error.rs +++ b/tests/ui/macros/macro-rules-attr-error.rs @@ -7,9 +7,46 @@ macro_rules! local_attr { //~^^ ERROR: local_attr } +//~v NOTE: `fn_only` exists, but has no `attr` rules +macro_rules! fn_only { + {} => {} +} + +//~v NOTE: `attr_only` exists, but has no rules for function-like invocation +macro_rules! attr_only { + attr() {} => {} +} + fn main() { + //~v NOTE: in this expansion of #[local_attr] #[local_attr] struct S; - local_attr!(arg); //~ ERROR: macro has no rules for function-like invocation + //~vv ERROR: cannot find macro `local_attr` in this scope + //~| NOTE: `local_attr` is in scope, but it is an attribute + local_attr!(arg); + + //~v ERROR: cannot find attribute `fn_only` in this scope + #[fn_only] + struct S; + + attr_only!(); //~ ERROR: cannot find macro `attr_only` in this scope +} + +//~vv ERROR: cannot find attribute `forward_referenced_attr` in this scope +//~| NOTE: consider moving the definition of `forward_referenced_attr` before this call +#[forward_referenced_attr] +struct S; + +//~v NOTE: a macro with the same name exists, but it appears later +macro_rules! forward_referenced_attr { + attr() {} => {} +} + +//~vv ERROR: cannot find attribute `cyclic_attr` in this scope +//~| NOTE: consider moving the definition of `cyclic_attr` before this call +#[cyclic_attr] +//~v NOTE: a macro with the same name exists, but it appears later +macro_rules! cyclic_attr { + attr() {} => {} } diff --git a/tests/ui/macros/macro-rules-attr-error.stderr b/tests/ui/macros/macro-rules-attr-error.stderr index 177b700938409..674d35091b68d 100644 --- a/tests/ui/macros/macro-rules-attr-error.stderr +++ b/tests/ui/macros/macro-rules-attr-error.stderr @@ -9,14 +9,55 @@ LL | #[local_attr] | = note: this error originates in the attribute macro `local_attr` (in Nightly builds, run with -Z macro-backtrace for more info) -error: macro has no rules for function-like invocation `local_attr!` - --> $DIR/macro-rules-attr-error.rs:14:5 +error: cannot find macro `local_attr` in this scope + --> $DIR/macro-rules-attr-error.rs:27:5 | -LL | macro_rules! local_attr { - | ----------------------- this macro has no rules for function-like invocation -... LL | local_attr!(arg); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ + | + = note: `local_attr` is in scope, but it is an attribute: `#[local_attr]` + +error: cannot find attribute `fn_only` in this scope + --> $DIR/macro-rules-attr-error.rs:30:7 + | +LL | macro_rules! fn_only { + | ------- `fn_only` exists, but has no `attr` rules +... +LL | #[fn_only] + | ^^^^^^^ + +error: cannot find macro `attr_only` in this scope + --> $DIR/macro-rules-attr-error.rs:33:5 + | +LL | macro_rules! attr_only { + | --------- `attr_only` exists, but has no rules for function-like invocation +... +LL | attr_only!(); + | ^^^^^^^^^ + +error: cannot find attribute `forward_referenced_attr` in this scope + --> $DIR/macro-rules-attr-error.rs:38:3 + | +LL | #[forward_referenced_attr] + | ^^^^^^^^^^^^^^^^^^^^^^^ consider moving the definition of `forward_referenced_attr` before this call + | +note: a macro with the same name exists, but it appears later + --> $DIR/macro-rules-attr-error.rs:42:14 + | +LL | macro_rules! forward_referenced_attr { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: cannot find attribute `cyclic_attr` in this scope + --> $DIR/macro-rules-attr-error.rs:48:3 + | +LL | #[cyclic_attr] + | ^^^^^^^^^^^ consider moving the definition of `cyclic_attr` before this call + | +note: a macro with the same name exists, but it appears later + --> $DIR/macro-rules-attr-error.rs:50:14 + | +LL | macro_rules! cyclic_attr { + | ^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 6 previous errors From b74e1cb769d11b37d29490f9ab63a3af19c509fc Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 8 Aug 2025 23:25:37 -0700 Subject: [PATCH 116/252] mbe: Rename macro parsing state names to use `Bang` instead of `Not` The use of `Not` to describe the `!` in `macro_rules!` reads confusingly, and also results in search collisions with the diagnostic structure `MacroRulesNot` elsewhere in the compiler. Rename it to use the more conventional `Bang` for `!`. --- compiler/rustc_expand/src/mbe/macro_check.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 25987a5036635..faeae1f494e65 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -357,10 +357,10 @@ enum NestedMacroState { /// The token `macro_rules` was processed. MacroRules, /// The tokens `macro_rules!` were processed. - MacroRulesNot, + MacroRulesBang, /// The tokens `macro_rules!` followed by a name were processed. The name may be either directly /// an identifier or a meta-variable (that hopefully would be instantiated by an identifier). - MacroRulesNotName, + MacroRulesBangName, /// The keyword `macro` was processed. Macro, /// The keyword `macro` followed by a name was processed. @@ -408,24 +408,24 @@ fn check_nested_occurrences( NestedMacroState::MacroRules, &TokenTree::Token(Token { kind: TokenKind::Bang, .. }), ) => { - state = NestedMacroState::MacroRulesNot; + state = NestedMacroState::MacroRulesBang; } ( - NestedMacroState::MacroRulesNot, + NestedMacroState::MacroRulesBang, &TokenTree::Token(Token { kind: TokenKind::Ident(..), .. }), ) => { - state = NestedMacroState::MacroRulesNotName; + state = NestedMacroState::MacroRulesBangName; } - (NestedMacroState::MacroRulesNot, &TokenTree::MetaVar(..)) => { - state = NestedMacroState::MacroRulesNotName; + (NestedMacroState::MacroRulesBang, &TokenTree::MetaVar(..)) => { + state = NestedMacroState::MacroRulesBangName; // We check that the meta-variable is correctly used. check_occurrences(psess, node_id, tt, macros, binders, ops, guar); } - (NestedMacroState::MacroRulesNotName, TokenTree::Delimited(.., del)) + (NestedMacroState::MacroRulesBangName, TokenTree::Delimited(.., del)) | (NestedMacroState::MacroName, TokenTree::Delimited(.., del)) if del.delim == Delimiter::Brace => { - let macro_rules = state == NestedMacroState::MacroRulesNotName; + let macro_rules = state == NestedMacroState::MacroRulesBangName; state = NestedMacroState::Empty; let rest = check_nested_macro(psess, node_id, macro_rules, &del.tts, &nested_macros, guar); From 33ba4a2f119e23b5d92ba6fac833b532abab82ee Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 9 Aug 2025 01:37:03 -0700 Subject: [PATCH 117/252] clippy: Update for switch to `MacroKinds` This updates two clippy lints which had exceptions for `MacroKind::Bang` macros to extend those exceptions to any macro, now that a macro_rules macro can be any kind of macro. --- src/tools/clippy/clippy_lints/src/item_name_repetitions.rs | 5 ++--- src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 95e16aae40f9a..945bb84708f85 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -8,7 +8,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, QPath, TyKind, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::MacroKind; use rustc_span::symbol::Symbol; declare_clippy_lint! { @@ -503,8 +502,8 @@ impl LateLintPass<'_> for ItemNameRepetitions { ); } - let is_macro_rule = matches!(item.kind, ItemKind::Macro(_, _, MacroKind::Bang)); - if both_are_public && item_camel.len() > mod_camel.len() && !is_macro_rule { + let is_macro = matches!(item.kind, ItemKind::Macro(_, _, _)); + if both_are_public && item_camel.len() > mod_camel.len() && !is_macro { let matching = count_match_start(mod_camel, &item_camel); let rmatching = count_match_end(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index 3828aff4164e8..902e8af7ec48d 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -7,7 +7,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::hygiene::MacroKind; declare_clippy_lint! { /// ### What it does @@ -89,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { // We ignore macro exports. And `ListStem` uses, which aren't interesting. fn is_ignorable_export<'tcx>(item: &'tcx Item<'tcx>) -> bool { if let ItemKind::Use(path, kind) = item.kind { - let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(MacroKind::Bang), _))) + let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _))) || kind == UseKind::ListStem; if ignore { return true; From e1fc89af5bb657acb45097cae15873de78210065 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 9 Aug 2025 00:20:07 -0700 Subject: [PATCH 118/252] rustdoc: Minimal fixes to compile with `MacroKinds` This makes the minimal fixes necessary for rustdoc to compile and pass existing tests with the switch to `MacroKinds`. It only works for macros that don't actually have multiple kinds, and will panic (with a `todo!`) if it encounters a macro with multiple kinds. rustdoc needs further fixes to handle macros with multiple kinds, and to handle attributes and derive macros that aren't proc macros. --- src/librustdoc/clean/inline.rs | 53 ++++++++++++------- src/librustdoc/clean/mod.rs | 14 +++-- src/librustdoc/formats/item_type.rs | 9 ++-- .../passes/collect_intra_doc_links.rs | 28 +++++----- src/librustdoc/visit_ast.rs | 7 ++- 5 files changed, 70 insertions(+), 41 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 8c0f897c9926c..0d98c64bbde5f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::Mutability; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LocalModDefId}; use rustc_metadata::creader::{CStore, LoadedMacro}; use rustc_middle::ty::fast_reject::SimplifiedType; @@ -137,13 +137,16 @@ pub(crate) fn try_inline( clean::ConstantItem(Box::new(ct)) }) } - Res::Def(DefKind::Macro(kind), did) => { - let mac = build_macro(cx, did, name, kind); - - let type_kind = match kind { - MacroKind::Bang => ItemType::Macro, - MacroKind::Attr => ItemType::ProcAttribute, - MacroKind::Derive => ItemType::ProcDerive, + Res::Def(DefKind::Macro(kinds), did) => { + let mac = build_macro(cx, did, name, kinds); + + // FIXME: handle attributes and derives that aren't proc macros, and macros with + // multiple kinds + let type_kind = match kinds { + MacroKinds::BANG => ItemType::Macro, + MacroKinds::ATTR => ItemType::ProcAttribute, + MacroKinds::DERIVE => ItemType::ProcDerive, + _ => todo!("Handle macros with multiple kinds"), }; record_extern_fqn(cx, did, type_kind); mac @@ -749,22 +752,36 @@ fn build_macro( cx: &mut DocContext<'_>, def_id: DefId, name: Symbol, - macro_kind: MacroKind, + macro_kinds: MacroKinds, ) -> clean::ItemKind { match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) { - LoadedMacro::MacroDef { def, .. } => match macro_kind { - MacroKind::Bang => clean::MacroItem(clean::Macro { + // FIXME: handle attributes and derives that aren't proc macros, and macros with multiple + // kinds + LoadedMacro::MacroDef { def, .. } => match macro_kinds { + MacroKinds::BANG => clean::MacroItem(clean::Macro { source: utils::display_macro_source(cx, name, &def), macro_rules: def.macro_rules, }), - MacroKind::Derive | MacroKind::Attr => { - clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() }) - } + MacroKinds::DERIVE => clean::ProcMacroItem(clean::ProcMacro { + kind: MacroKind::Derive, + helpers: Vec::new(), + }), + MacroKinds::ATTR => clean::ProcMacroItem(clean::ProcMacro { + kind: MacroKind::Attr, + helpers: Vec::new(), + }), + _ => todo!("Handle macros with multiple kinds"), }, - LoadedMacro::ProcMacro(ext) => clean::ProcMacroItem(clean::ProcMacro { - kind: ext.macro_kind(), - helpers: ext.helper_attrs, - }), + LoadedMacro::ProcMacro(ext) => { + // Proc macros can only have a single kind + let kind = match ext.macro_kinds() { + MacroKinds::BANG => MacroKind::Bang, + MacroKinds::ATTR => MacroKind::Attr, + MacroKinds::DERIVE => MacroKind::Derive, + _ => unreachable!(), + }; + clean::ProcMacroItem(clean::ProcMacro { kind, helpers: ext.helper_attrs }) + } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7194c2fcededa..5003857330da0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -40,7 +40,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, In use rustc_errors::codes::*; use rustc_errors::{FatalError, struct_span_code_err}; use rustc_hir::attrs::AttributeKind; -use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; use rustc_hir::{LangItem, PredicateOrigin, find_attr}; use rustc_hir_analysis::hir_ty_lowering::FeedConstTy; @@ -2845,11 +2845,19 @@ fn clean_maybe_renamed_item<'tcx>( generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), - ItemKind::Macro(_, macro_def, MacroKind::Bang) => MacroItem(Macro { + // FIXME: handle attributes and derives that aren't proc macros, and macros with + // multiple kinds + ItemKind::Macro(_, macro_def, MacroKinds::BANG) => MacroItem(Macro { source: display_macro_source(cx, name, macro_def), macro_rules: macro_def.macro_rules, }), - ItemKind::Macro(_, _, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx), + ItemKind::Macro(_, _, MacroKinds::ATTR) => { + clean_proc_macro(item, &mut name, MacroKind::Attr, cx) + } + ItemKind::Macro(_, _, MacroKinds::DERIVE) => { + clean_proc_macro(item, &mut name, MacroKind::Derive, cx) + } + ItemKind::Macro(_, _, _) => todo!("Handle macros with multiple kinds"), // proc macros can have a name set by attributes ItemKind::Fn { ref sig, generics, body: body_id, .. } => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 3aba7a370adb2..1dba84aa44cc1 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -2,7 +2,7 @@ use std::fmt; -use rustc_hir::def::{CtorOf, DefKind}; +use rustc_hir::def::{CtorOf, DefKind, MacroKinds}; use rustc_span::hygiene::MacroKind; use serde::{Serialize, Serializer}; @@ -134,9 +134,10 @@ impl ItemType { DefKind::Trait => Self::Trait, DefKind::TyAlias => Self::TypeAlias, DefKind::TraitAlias => Self::TraitAlias, - DefKind::Macro(MacroKind::Bang) => ItemType::Macro, - DefKind::Macro(MacroKind::Attr) => ItemType::ProcAttribute, - DefKind::Macro(MacroKind::Derive) => ItemType::ProcDerive, + DefKind::Macro(MacroKinds::BANG) => ItemType::Macro, + DefKind::Macro(MacroKinds::ATTR) => ItemType::ProcAttribute, + DefKind::Macro(MacroKinds::DERIVE) => ItemType::ProcDerive, + DefKind::Macro(_) => todo!("Handle macros with multiple kinds"), DefKind::ForeignTy => Self::ForeignType, DefKind::Variant => Self::Variant, DefKind::Field => Self::StructField, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index bcb676cd1f17e..2616a47e5292f 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -13,7 +13,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, Diag, DiagMessage}; use rustc_hir::def::Namespace::*; -use rustc_hir::def::{DefKind, Namespace, PerNS}; +use rustc_hir::def::{DefKind, MacroKinds, Namespace, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE}; use rustc_hir::{Mutability, Safety}; use rustc_middle::ty::{Ty, TyCtxt}; @@ -25,7 +25,6 @@ use rustc_resolve::rustdoc::{ use rustc_session::config::CrateType; use rustc_session::lint::Lint; use rustc_span::BytePos; -use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{Ident, Symbol, sym}; use smallvec::{SmallVec, smallvec}; use tracing::{debug, info, instrument, trace}; @@ -115,9 +114,11 @@ impl Res { let prefix = match kind { DefKind::Fn | DefKind::AssocFn => return Suggestion::Function, - DefKind::Macro(MacroKind::Bang) => return Suggestion::Macro, + // FIXME: handle macros with multiple kinds, and attribute/derive macros that aren't + // proc macros + DefKind::Macro(MacroKinds::BANG) => return Suggestion::Macro, - DefKind::Macro(MacroKind::Derive) => "derive", + DefKind::Macro(MacroKinds::DERIVE) => "derive", DefKind::Struct => "struct", DefKind::Enum => "enum", DefKind::Trait => "trait", @@ -881,9 +882,12 @@ fn trait_impls_for<'a>( fn is_derive_trait_collision(ns: &PerNS, ResolutionFailure<'_>>>) -> bool { if let (Ok(type_ns), Ok(macro_ns)) = (&ns.type_ns, &ns.macro_ns) { type_ns.iter().any(|(res, _)| matches!(res, Res::Def(DefKind::Trait, _))) - && macro_ns - .iter() - .any(|(res, _)| matches!(res, Res::Def(DefKind::Macro(MacroKind::Derive), _))) + && macro_ns.iter().any(|(res, _)| { + matches!( + res, + Res::Def(DefKind::Macro(kinds), _) if kinds.contains(MacroKinds::DERIVE) + ) + }) } else { false } @@ -1662,11 +1666,11 @@ impl Disambiguator { let suffixes = [ // If you update this list, please also update the relevant rustdoc book section! - ("!()", DefKind::Macro(MacroKind::Bang)), - ("!{}", DefKind::Macro(MacroKind::Bang)), - ("![]", DefKind::Macro(MacroKind::Bang)), + ("!()", DefKind::Macro(MacroKinds::BANG)), + ("!{}", DefKind::Macro(MacroKinds::BANG)), + ("![]", DefKind::Macro(MacroKinds::BANG)), ("()", DefKind::Fn), - ("!", DefKind::Macro(MacroKind::Bang)), + ("!", DefKind::Macro(MacroKinds::BANG)), ]; if let Some(idx) = link.find('@') { @@ -1685,7 +1689,7 @@ impl Disambiguator { safety: Safety::Safe, }), "function" | "fn" | "method" => Kind(DefKind::Fn), - "derive" => Kind(DefKind::Macro(MacroKind::Derive)), + "derive" => Kind(DefKind::Macro(MacroKinds::DERIVE)), "field" => Kind(DefKind::Field), "variant" => Kind(DefKind::Variant), "type" => NS(Namespace::TypeNS), diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 9058277d72eea..b2e4b59437504 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -5,7 +5,7 @@ use std::mem; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{DefKind, MacroKinds, Res}; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet}; use rustc_hir::intravisit::{Visitor, walk_body, walk_item}; use rustc_hir::{CRATE_HIR_ID, Node}; @@ -13,7 +13,6 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{Symbol, kw, sym}; use tracing::debug; @@ -325,7 +324,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let is_bang_macro = matches!( item, - Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, _, MacroKind::Bang), .. }) + Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, _, kinds), .. }) if kinds.contains(MacroKinds::BANG) ); if !self.view_item_stack.insert(res_did) && !is_bang_macro { @@ -406,7 +405,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // attribute can still be visible. || match item.kind { hir::ItemKind::Impl(..) => true, - hir::ItemKind::Macro(_, _, MacroKind::Bang) => { + hir::ItemKind::Macro(_, _, _) => { self.cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) } _ => false, From c439a59dbd275aef9bc24c7172e2111ccc3794c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Mar 2024 20:46:36 +0000 Subject: [PATCH 119/252] Change the desugaring of `assert!` for better error output In the desugaring of `assert!`, we now expand to a `match` expression instead of `if !cond {..}`. The span of incorrect conditions will point only at the expression, and not the whole `assert!` invocation. ``` error[E0308]: mismatched types --> $DIR/issue-14091.rs:2:13 | LL | assert!(1,1); | ^ expected `bool`, found integer ``` We no longer mention the expression needing to implement the `Not` trait. ``` error[E0308]: mismatched types --> $DIR/issue-14091-2.rs:15:13 | LL | assert!(x, x); | ^ expected `bool`, found `BytePos` ``` `assert!(val)` now desugars to: ```rust match val { true => {}, _ => $crate::panic::panic_2021!(), } ``` Fix #122159. We make some minor changes to some diagnostics to avoid span overlap on type mismatch or inverted "expected"/"found" on type errors. We remove some unnecessary parens from core, alloc and miri. address review comments --- compiler/rustc_builtin_macros/src/assert.rs | 35 +++++++++------- .../src/error_reporting/infer/mod.rs | 40 +++++++++++++++++-- .../src/missing_asserts_for_indexing.rs | 12 +++--- src/tools/clippy/tests/ui/const_is_empty.rs | 1 + .../clippy/tests/ui/const_is_empty.stderr | 10 ++++- .../clippy/tests/ui/incompatible_msrv.rs | 2 +- tests/ui/codemap_tests/issue-28308.rs | 16 +++++++- tests/ui/codemap_tests/issue-28308.stderr | 28 ++++++++++--- tests/ui/consts/control-flow/assert.stderr | 4 +- ...st_monomorphization_error_backtrace.stderr | 8 ++-- .../const-expr-generic-err.stderr | 4 +- tests/ui/macros/assert-macro-lifetimes.rs | 8 ++++ .../ui/simd/const-err-trumps-simd-err.stderr | 4 +- tests/ui/transmutability/uninhabited.stderr | 12 +++--- 14 files changed, 134 insertions(+), 50 deletions(-) create mode 100644 tests/ui/macros/assert-macro-lifetimes.rs diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 855da5caa312c..013258a1b4efa 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -1,8 +1,8 @@ mod context; -use rustc_ast::token::Delimiter; +use rustc_ast::token::{self, Delimiter}; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token}; +use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment}; use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; @@ -29,7 +29,7 @@ pub(crate) fn expand_assert<'cx>( // `core::panic` and `std::panic` are different macros, so we use call-site // context to pick up whichever is currently in scope. - let call_site_span = cx.with_call_site_ctxt(span); + let call_site_span = cx.with_call_site_ctxt(cond_expr.span); let panic_path = || { if use_panic_2021(span) { @@ -63,7 +63,7 @@ pub(crate) fn expand_assert<'cx>( }), })), ); - expr_if_not(cx, call_site_span, cond_expr, then, None) + assert_cond_check(cx, call_site_span, cond_expr, then) } // If `generic_assert` is enabled, generates rich captured outputs // @@ -88,26 +88,33 @@ pub(crate) fn expand_assert<'cx>( )), )], ); - expr_if_not(cx, call_site_span, cond_expr, then, None) + assert_cond_check(cx, call_site_span, cond_expr, then) }; ExpandResult::Ready(MacEager::expr(expr)) } +/// `assert!($cond_expr, $custom_message)` struct Assert { cond_expr: Box, custom_message: Option, } -// if !{ ... } { ... } else { ... } -fn expr_if_not( - cx: &ExtCtxt<'_>, - span: Span, - cond: Box, - then: Box, - els: Option>, -) -> Box { - cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els) +/// `match { true => {} _ => }` +fn assert_cond_check(cx: &ExtCtxt<'_>, span: Span, cond: Box, then: Box) -> Box { + // Instead of expanding to `if ! { }`, we expand to + // `match { true => {} _ => }`. + // This allows us to always complain about mismatched types instead of "cannot apply unary + // operator `!` to type `X`" when passing an invalid ``, while also allowing `` to + // be `&true`. + let els = cx.expr_block(cx.block(span, thin_vec![])); + let mut arms = thin_vec![]; + arms.push(cx.arm(span, cx.pat_lit(span, cx.expr_bool(span, true)), els)); + arms.push(cx.arm(span, cx.pat_wild(span), then)); + + // We wrap the `match` in a statement to limit the length of any borrows introduced in the + // condition. + cx.expr_block(cx.block(span, [cx.stmt_expr(cx.expr_match(span, cond, arms))].into())) } fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 8551780bcd5f4..4c7a7e93648a5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1620,8 +1620,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { let e = self.tcx.erase_regions(e); let f = self.tcx.erase_regions(f); - let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx)); - let found = with_forced_trimmed_paths!(f.sort_string(self.tcx)); + let mut expected = with_forced_trimmed_paths!(e.sort_string(self.tcx)); + let mut found = with_forced_trimmed_paths!(f.sort_string(self.tcx)); + if let ObligationCauseCode::Pattern { span, .. } = cause.code() + && let Some(span) = span + && !span.from_expansion() + && cause.span.from_expansion() + { + // When the type error comes from a macro like `assert!()`, and we are pointing at + // code the user wrote the cause and effect are reversed as the expected value is + // what the macro expanded to. + (found, expected) = (expected, found); + } if expected == found { label_or_note(span, terr.to_string(self.tcx)); } else { @@ -2144,7 +2154,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> Option<(DiagStyledString, DiagStyledString)> { match values { ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found), - ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, long_ty_path), + ValuePairs::Terms(exp_found) => { + self.expected_found_str_term(cause, exp_found, long_ty_path) + } ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), @@ -2183,6 +2195,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn expected_found_str_term( &self, + cause: &ObligationCause<'tcx>, exp_found: ty::error::ExpectedFound>, long_ty_path: &mut Option, ) -> Option<(DiagStyledString, DiagStyledString)> { @@ -2190,8 +2203,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if exp_found.references_error() { return None; } + let (mut expected, mut found) = (exp_found.expected, exp_found.found); + + if let ObligationCauseCode::Pattern { span, .. } = cause.code() + && let Some(span) = span + && !span.from_expansion() + && cause.span.from_expansion() + { + // When the type error comes from a macro like `assert!()`, and we are pointing at + // code the user wrote, the cause and effect are reversed as the expected value is + // what the macro expanded to. So if the user provided a `Type` when the macro is + // written in such a way that a `bool` was expected, we want to print: + // = note: expected `bool` + // found `Type`" + // but as far as the compiler is concerned, after expansion what was expected was `Type` + // = note: expected `Type` + // found `bool`" + // so we reverse them here to match user expectation. + (expected, found) = (found, expected); + } - Some(match (exp_found.expected.kind(), exp_found.found.kind()) { + Some(match (expected.kind(), found.kind()) { (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => { let (mut exp, mut fnd) = self.cmp(expected, found); // Use the terminal width as the basis to determine when to compress the printed diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index cf0c85990b150..788a04357b1e2 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -11,7 +11,7 @@ use rustc_ast::{BinOpKind, LitKind, RangeLimits}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnindexMap; use rustc_errors::{Applicability, Diag}; -use rustc_hir::{Block, Body, Expr, ExprKind, UnOp}; +use rustc_hir::{Body, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; @@ -135,12 +135,12 @@ fn assert_len_expr<'hir>( cx: &LateContext<'_>, expr: &'hir Expr<'hir>, ) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> { - let (cmp, asserted_len, slice_len) = if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr) - && let ExprKind::Unary(UnOp::Not, condition) = &cond.kind - && let ExprKind::Binary(bin_op, left, right) = &condition.kind + let (cmp, asserted_len, slice_len) = if let Some( + higher::IfLetOrMatch::Match(cond, [_, then], _) + ) = higher::IfLetOrMatch::parse(cx, expr) + && let ExprKind::Binary(bin_op, left, right) = &cond.kind // check if `then` block has a never type expression - && let ExprKind::Block(Block { expr: Some(then_expr), .. }, _) = then.kind - && cx.typeck_results().expr_ty(then_expr).is_never() + && cx.typeck_results().expr_ty(then.body).is_never() { len_comparison(bin_op.node, left, right)? } else if let Some((macro_call, bin_op)) = first_node_macro_backtrace(cx, expr).find_map(|macro_call| { diff --git a/src/tools/clippy/tests/ui/const_is_empty.rs b/src/tools/clippy/tests/ui/const_is_empty.rs index 8bb4f0e5d9750..63c6342a323ce 100644 --- a/src/tools/clippy/tests/ui/const_is_empty.rs +++ b/src/tools/clippy/tests/ui/const_is_empty.rs @@ -196,6 +196,7 @@ fn issue_13106() { const { assert!(EMPTY_STR.is_empty()); + //~^ const_is_empty } const { diff --git a/src/tools/clippy/tests/ui/const_is_empty.stderr b/src/tools/clippy/tests/ui/const_is_empty.stderr index 2ba189058e832..9a42518698e39 100644 --- a/src/tools/clippy/tests/ui/const_is_empty.stderr +++ b/src/tools/clippy/tests/ui/const_is_empty.stderr @@ -158,10 +158,16 @@ LL | let _ = val.is_empty(); | ^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:202:9 + --> tests/ui/const_is_empty.rs:198:17 + | +LL | assert!(EMPTY_STR.is_empty()); + | ^^^^^^^^^^^^^^^^^^^^ + +error: this expression always evaluates to true + --> tests/ui/const_is_empty.rs:203:9 | LL | EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 27 previous errors +error: aborting due to 28 previous errors diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.rs b/src/tools/clippy/tests/ui/incompatible_msrv.rs index f7f21e1850d0a..882f909e30c97 100644 --- a/src/tools/clippy/tests/ui/incompatible_msrv.rs +++ b/src/tools/clippy/tests/ui/incompatible_msrv.rs @@ -1,6 +1,6 @@ #![warn(clippy::incompatible_msrv)] #![feature(custom_inner_attributes)] -#![allow(stable_features)] +#![allow(stable_features, clippy::diverging_sub_expression)] #![feature(strict_provenance)] // For use in test #![clippy::msrv = "1.3.0"] diff --git a/tests/ui/codemap_tests/issue-28308.rs b/tests/ui/codemap_tests/issue-28308.rs index 81493f8c45311..b0e04d0f1f6b1 100644 --- a/tests/ui/codemap_tests/issue-28308.rs +++ b/tests/ui/codemap_tests/issue-28308.rs @@ -1,4 +1,16 @@ fn main() { - assert!("foo"); - //~^ ERROR cannot apply unary operator `!` + assert!("foo"); //~ ERROR mismatched types + //~^ NOTE expected `bool`, found `str` + //~| NOTE in this expansion of assert! + let x = Some(&1); + assert!(x); //~ ERROR mismatched types + //~^ NOTE expected `bool`, found `Option<&{integer}>` + //~| NOTE expected enum `bool` + //~| NOTE in this expansion of assert! + //~| NOTE in this expansion of assert! + assert!(x, ""); //~ ERROR mismatched types + //~^ NOTE expected `bool`, found `Option<&{integer}>` + //~| NOTE expected enum `bool` + //~| NOTE in this expansion of assert! + //~| NOTE in this expansion of assert! } diff --git a/tests/ui/codemap_tests/issue-28308.stderr b/tests/ui/codemap_tests/issue-28308.stderr index 7bc9e05dfc024..e84ceb44aacba 100644 --- a/tests/ui/codemap_tests/issue-28308.stderr +++ b/tests/ui/codemap_tests/issue-28308.stderr @@ -1,9 +1,27 @@ -error[E0600]: cannot apply unary operator `!` to type `&'static str` - --> $DIR/issue-28308.rs:2:5 +error[E0308]: mismatched types + --> $DIR/issue-28308.rs:2:13 | LL | assert!("foo"); - | ^^^^^^^^^^^^^^ cannot apply unary operator `!` + | ^^^^^ expected `bool`, found `str` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/issue-28308.rs:6:13 + | +LL | assert!(x); + | ^ expected `bool`, found `Option<&{integer}>` + | + = note: expected enum `bool` + found type `Option<&{integer}>` + +error[E0308]: mismatched types + --> $DIR/issue-28308.rs:11:13 + | +LL | assert!(x, ""); + | ^ expected `bool`, found `Option<&{integer}>` + | + = note: expected enum `bool` + found type `Option<&{integer}>` + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0600`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/control-flow/assert.stderr b/tests/ui/consts/control-flow/assert.stderr index 026097a6ba0e1..deaad6abbccf6 100644 --- a/tests/ui/consts/control-flow/assert.stderr +++ b/tests/ui/consts/control-flow/assert.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation panicked: assertion failed: false - --> $DIR/assert.rs:5:15 + --> $DIR/assert.rs:5:23 | LL | const _: () = assert!(false); - | ^^^^^^^^^^^^^^ evaluation of `_` failed here + | ^^^^^ evaluation of `_` failed here error: aborting due to 1 previous error diff --git a/tests/ui/generics/post_monomorphization_error_backtrace.stderr b/tests/ui/generics/post_monomorphization_error_backtrace.stderr index 6953414f0c235..92c7df73638f5 100644 --- a/tests/ui/generics/post_monomorphization_error_backtrace.stderr +++ b/tests/ui/generics/post_monomorphization_error_backtrace.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::() == 0 - --> $DIR/post_monomorphization_error_backtrace.rs:6:23 + --> $DIR/post_monomorphization_error_backtrace.rs:6:31 | LL | const V: () = assert!(std::mem::size_of::() == 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::::V` failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::::V` failed here note: erroneous constant encountered --> $DIR/post_monomorphization_error_backtrace.rs:14:5 @@ -17,10 +17,10 @@ LL | assert_zst::() | ^^^^^^^^^^^^^^^^^ error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::() == 0 - --> $DIR/post_monomorphization_error_backtrace.rs:6:23 + --> $DIR/post_monomorphization_error_backtrace.rs:6:31 | LL | const V: () = assert!(std::mem::size_of::() == 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::::V` failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::::V` failed here note: erroneous constant encountered --> $DIR/post_monomorphization_error_backtrace.rs:14:5 diff --git a/tests/ui/inline-const/const-expr-generic-err.stderr b/tests/ui/inline-const/const-expr-generic-err.stderr index 26039ba6d4449..e053e88db172f 100644 --- a/tests/ui/inline-const/const-expr-generic-err.stderr +++ b/tests/ui/inline-const/const-expr-generic-err.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::() == 0 - --> $DIR/const-expr-generic-err.rs:4:13 + --> $DIR/const-expr-generic-err.rs:4:21 | LL | const { assert!(std::mem::size_of::() == 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::::{constant#0}` failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::::{constant#0}` failed here note: erroneous constant encountered --> $DIR/const-expr-generic-err.rs:4:5 diff --git a/tests/ui/macros/assert-macro-lifetimes.rs b/tests/ui/macros/assert-macro-lifetimes.rs new file mode 100644 index 0000000000000..cc25928320477 --- /dev/null +++ b/tests/ui/macros/assert-macro-lifetimes.rs @@ -0,0 +1,8 @@ +//@ check-pass +#[derive(PartialEq, Eq, Hash)] +struct S; +fn main() { + let foo = std::rc::Rc::new(std::cell::RefCell::new(std::collections::HashMap::::new())); + // Ensure that the lifetimes of the borrow do not leak past the end of `main`. + assert!(matches!(foo.borrow().get(&S).unwrap(), S)) +} diff --git a/tests/ui/simd/const-err-trumps-simd-err.stderr b/tests/ui/simd/const-err-trumps-simd-err.stderr index 93d1fce637f2f..6d25a28c92c5c 100644 --- a/tests/ui/simd/const-err-trumps-simd-err.stderr +++ b/tests/ui/simd/const-err-trumps-simd-err.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation panicked: assertion failed: LANE < 4 - --> $DIR/const-err-trumps-simd-err.rs:17:13 + --> $DIR/const-err-trumps-simd-err.rs:17:21 | LL | const { assert!(LANE < 4); } // the error should be here... - | ^^^^^^^^^^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed here + | ^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed here note: erroneous constant encountered --> $DIR/const-err-trumps-simd-err.rs:17:5 diff --git a/tests/ui/transmutability/uninhabited.stderr b/tests/ui/transmutability/uninhabited.stderr index 4757daec9978a..9f289852809c2 100644 --- a/tests/ui/transmutability/uninhabited.stderr +++ b/tests/ui/transmutability/uninhabited.stderr @@ -41,10 +41,10 @@ LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` error[E0080]: evaluation panicked: assertion failed: false - --> $DIR/uninhabited.rs:41:9 + --> $DIR/uninhabited.rs:41:17 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation of `yawning_void_struct::_` failed here + | ^^^^^ evaluation of `yawning_void_struct::_` failed here error[E0277]: `()` cannot be safely transmuted into `yawning_void_enum::Void` --> $DIR/uninhabited.rs:71:41 @@ -68,10 +68,10 @@ LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` error[E0080]: evaluation panicked: assertion failed: false - --> $DIR/uninhabited.rs:63:9 + --> $DIR/uninhabited.rs:63:17 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation of `yawning_void_enum::_` failed here + | ^^^^^ evaluation of `yawning_void_enum::_` failed here error[E0277]: `u128` cannot be safely transmuted into `DistantVoid` --> $DIR/uninhabited.rs:92:43 @@ -95,10 +95,10 @@ LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` error[E0080]: evaluation panicked: assertion failed: false - --> $DIR/uninhabited.rs:87:9 + --> $DIR/uninhabited.rs:87:17 | LL | assert!(false); - | ^^^^^^^^^^^^^^ evaluation of `distant_void::_` failed here + | ^^^^^ evaluation of `distant_void::_` failed here error[E0277]: `Src` cannot be safely transmuted into `issue_126267::Error` --> $DIR/uninhabited.rs:108:42 From 72b606db89c7d2ce76ea41ea80ec92e6320bf20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 18:39:09 +0200 Subject: [PATCH 120/252] Replace `stage0-tools-bin` with `stage1-tools-bin` --- src/bootstrap/src/core/builder/mod.rs | 2 +- src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile | 2 +- src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh | 2 +- src/ci/github-actions/jobs.yml | 2 +- src/doc/rustc-dev-guide/src/building/optimized-build.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 163a498d4b48c..de4b941ac9082 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1597,7 +1597,7 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s cmd.env("CARGO", &self.initial_cargo); // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler` // in `tool::ToolBuild` step, so they match the Miri we just built. However this means they - // are actually living one stage up, i.e. we are running `stage0-tools-bin/miri` with the + // are actually living one stage up, i.e. we are running `stage1-tools-bin/miri` with the // libraries in `stage1/lib`. This is an unfortunate off-by-1 caused (possibly) by the fact // that Miri doesn't have an "assemble" step like rustc does that would cross the stage boundary. // We can't use `add_rustc_lib_path` as that's a NOP on Windows but we do need these libraries diff --git a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile index 2b8a3f829c608..e726329753f24 100644 --- a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile +++ b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile @@ -96,7 +96,7 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.codegen-units=1 ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \ - ./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ + ./build/$HOSTS/stage1-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ --host $HOSTS --target $HOSTS --include-default-paths build-manifest bootstrap ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=clang diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh index 924bdbc761505..4c95d4a401e5e 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh @@ -4,7 +4,7 @@ set -eux python3 ../x.py build --set rust.debug=true opt-dist -./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ +./build/$HOSTS/stage1-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ build-manifest bootstrap diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 48c570bfa11aa..ae13d14c38053 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -656,7 +656,7 @@ auto: --enable-full-tools --enable-profiler --set rust.codegen-units=1 - SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths + SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage1-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows-8c diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md index 863ed9749fb7e..46def66d17823 100644 --- a/src/doc/rustc-dev-guide/src/building/optimized-build.md +++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md @@ -118,7 +118,7 @@ Here is an example of how can `opt-dist` be used locally (outside of CI): ``` 3. Run the tool with the `local` mode and provide necessary parameters: ```bash - ./build/host/stage0-tools-bin/opt-dist local \ + ./build/host/stage1-tools-bin/opt-dist local \ --target-triple \ # select target, e.g. "x86_64-unknown-linux-gnu" --checkout-dir \ # path to rust checkout, e.g. "." --llvm-dir \ # path to built LLVM toolchain, e.g. "/foo/bar/llvm/install" From 4360c52c4fafb38bd5514220ee2cd2b8c260c286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 18:40:42 +0200 Subject: [PATCH 121/252] Add change tracker entry --- 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 091956e7e5f3e..cd7fba39a8458 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -496,4 +496,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "It is no longer possible to `x doc` with stage 0. All doc commands have to be on stage 1+.", }, + ChangeInfo { + change_id: 145295, + severity: ChangeSeverity::Warning, + summary: "The names of stageN directories in the build directory have been consolidated with the new (post-stage-0-redesign) staging scheme. Some tools and binaries might be located in a different build directory than before.", + }, ]; From 7ce620dd7c6fc3371290b40a1ea28146f0d37031 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sat, 26 Jul 2025 18:51:13 -0400 Subject: [PATCH 122/252] Constify SystemTime methods --- library/std/src/lib.rs | 6 ++++ library/std/src/sys/pal/hermit/time.rs | 32 ++++++++++++++------- library/std/src/sys/pal/sgx/time.rs | 15 +++++++--- library/std/src/sys/pal/solid/time.rs | 9 ++++-- library/std/src/sys/pal/uefi/time.rs | 27 ++++++++++++----- library/std/src/sys/pal/unix/time.rs | 30 +++++++++++++------ library/std/src/sys/pal/unsupported/time.rs | 15 +++++++--- library/std/src/sys/pal/wasi/time.rs | 25 +++++++++++----- library/std/src/sys/pal/windows/time.rs | 30 ++++++++++++------- library/std/src/sys/pal/xous/time.rs | 15 +++++++--- library/std/src/time.rs | 30 +++++++++++++------ 11 files changed, 166 insertions(+), 68 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0c53753064724..25355efd20ece 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -281,9 +281,11 @@ #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(char_max_len)] +#![feature(const_trait_impl)] #![feature(core_float_math)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] +#![feature(derive_const)] #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(doc_masked)] @@ -329,6 +331,10 @@ #![feature(bstr_internals)] #![feature(char_internals)] #![feature(clone_to_uninit)] +#![feature(const_cmp)] +#![feature(const_ops)] +#![feature(const_option_ops)] +#![feature(const_try)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(drop_guard)] diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index f76a5f96c8750..89a427ab88ba9 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -25,8 +25,15 @@ impl Timespec { Timespec { t: timespec { tv_sec, tv_nsec } } } - fn sub_timespec(&self, other: &Timespec) -> Result { - if self >= other { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + const fn sub_timespec(&self, other: &Timespec) -> Result { + // FIXME: const PartialOrd + let mut cmp = self.t.tv_sec - other.t.tv_sec; + if cmp == 0 { + cmp = self.t.tv_nsec as i64 - other.t.tv_nsec as i64; + } + + if cmp >= 0 { Ok(if self.t.tv_nsec >= other.t.tv_nsec { Duration::new( (self.t.tv_sec - other.t.tv_sec) as u64, @@ -46,20 +53,22 @@ impl Timespec { } } - fn checked_add_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + const fn checked_add_duration(&self, other: &Duration) -> Option { let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?; // Nano calculations can't overflow because nanos are <1B which fit // in a u32. - let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap(); - if nsec >= NSEC_PER_SEC.try_into().unwrap() { - nsec -= u32::try_from(NSEC_PER_SEC).unwrap(); + let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; + if nsec >= NSEC_PER_SEC as u32 { + nsec -= NSEC_PER_SEC as u32; secs = secs.checked_add(1)?; } Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) } - fn checked_sub_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + const fn checked_sub_duration(&self, other: &Duration) -> Option { let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?; // Similar to above, nanos can't overflow. @@ -213,15 +222,18 @@ impl SystemTime { SystemTime(time) } - pub fn sub_time(&self, other: &SystemTime) -> Result { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result { self.0.sub_timespec(&other.0) } - pub fn checked_add_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_add_duration(other)?)) } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_sub_duration(other)?)) } } diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/pal/sgx/time.rs index db4cf2804bf13..603dae952abd2 100644 --- a/library/std/src/sys/pal/sgx/time.rs +++ b/library/std/src/sys/pal/sgx/time.rs @@ -32,15 +32,22 @@ impl SystemTime { SystemTime(usercalls::insecure_time()) } - pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result { + // FIXME: ok_or_else with const closures + match self.0.checked_sub(other.0) { + Some(duration) => Ok(duration), + None => Err(other.0 - self.0), + } } - pub fn checked_add_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_add(*other)?)) } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs index c39d715c6a6f6..e35e60df1a0ad 100644 --- a/library/std/src/sys/pal/solid/time.rs +++ b/library/std/src/sys/pal/solid/time.rs @@ -39,7 +39,8 @@ impl SystemTime { Self(t) } - pub fn sub_time(&self, other: &SystemTime) -> Result { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result { if self.0 >= other.0 { Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64))) } else { @@ -47,11 +48,13 @@ impl SystemTime { } } - pub fn checked_add_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_add_unsigned(other.as_secs())?)) } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_sub_unsigned(other.as_secs())?)) } } diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index a5ab76903274d..df5611b2dddc1 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -80,19 +80,32 @@ impl SystemTime { .unwrap_or_else(|| panic!("time not implemented on this platform")) } - pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result { + // FIXME: ok_or_else with const closures + match self.0.checked_sub(other.0) { + Some(duration) => Ok(duration), + None => Err(other.0 - self.0), + } } - pub fn checked_add_duration(&self, other: &Duration) -> Option { - let temp = Self(self.0.checked_add(*other)?); + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option { + let temp = self.0.checked_add(*other)?; // Check if can be represented in UEFI - if temp <= MAX_UEFI_TIME { Some(temp) } else { None } + // FIXME: const PartialOrd + let mut cmp = temp.as_secs() - MAX_UEFI_TIME.0.as_secs(); + if cmp == 0 { + cmp = temp.subsec_nanos() as u64 - MAX_UEFI_TIME.0.subsec_nanos() as u64; + } + + if cmp <= 0 { Some(SystemTime(temp)) } else { None } } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - self.0.checked_sub(*other).map(Self) + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index bd7f74fea6a9c..328fe0bc9603f 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -38,15 +38,18 @@ impl SystemTime { SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) } } - pub fn sub_time(&self, other: &SystemTime) -> Result { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result { self.t.sub_timespec(&other.t) } - pub fn checked_add_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option { Some(SystemTime { t: self.t.checked_add_duration(other)? }) } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option { Some(SystemTime { t: self.t.checked_sub_duration(other)? }) } } @@ -133,8 +136,15 @@ impl Timespec { Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap() } - pub fn sub_timespec(&self, other: &Timespec) -> Result { - if self >= other { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_timespec(&self, other: &Timespec) -> Result { + // FIXME: const PartialOrd + let mut cmp = self.tv_sec - other.tv_sec; + if cmp == 0 { + cmp = self.tv_nsec.as_inner() as i64 - other.tv_nsec.as_inner() as i64; + } + + if cmp >= 0 { // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM // to optimize it into a branchless form (see also #75545): // @@ -169,7 +179,8 @@ impl Timespec { } } - pub fn checked_add_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option { let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?; // Nano calculations can't overflow because nanos are <1B which fit @@ -179,10 +190,11 @@ impl Timespec { nsec -= NSEC_PER_SEC as u32; secs = secs.checked_add(1)?; } - Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) }) + Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) }) } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option { let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?; // Similar to above, nanos can't overflow. @@ -191,7 +203,7 @@ impl Timespec { nsec += NSEC_PER_SEC as i32; secs = secs.checked_sub(1)?; } - Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) }) + Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) }) } #[allow(dead_code)] diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/pal/unsupported/time.rs index 6d67b538a96bf..0c38791704407 100644 --- a/library/std/src/sys/pal/unsupported/time.rs +++ b/library/std/src/sys/pal/unsupported/time.rs @@ -31,15 +31,22 @@ impl SystemTime { panic!("time not implemented on this platform") } - pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result { + // FIXME: ok_or_else with const closures + match self.0.checked_sub(other.0) { + Some(duration) => Ok(duration), + None => Err(other.0 - self.0), + } } - pub fn checked_add_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_add(*other)?)) } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/library/std/src/sys/pal/wasi/time.rs b/library/std/src/sys/pal/wasi/time.rs index 0d8d0b59ac14a..892661b312b2f 100644 --- a/library/std/src/sys/pal/wasi/time.rs +++ b/library/std/src/sys/pal/wasi/time.rs @@ -43,23 +43,34 @@ impl SystemTime { SystemTime(current_time(wasi::CLOCKID_REALTIME)) } - pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { SystemTime(Duration::from_nanos(ts)) } - pub fn to_wasi_timestamp(&self) -> Option { - self.0.as_nanos().try_into().ok() + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn to_wasi_timestamp(&self) -> Option { + // FIXME: const TryInto + let ns = self.0.as_nanos(); + if ns <= u64::MAX as u128 { Some(ns as u64) } else { None } } - pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result { + // FIXME: ok_or_else with const closures + match self.0.checked_sub(other.0) { + Some(duration) => Ok(duration), + None => Err(other.0 - self.0), + } } - pub fn checked_add_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_add(*other)?)) } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index 68126bd8d2fa0..a948c07e0a31e 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -72,7 +72,8 @@ impl SystemTime { } } - fn from_intervals(intervals: i64) -> SystemTime { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + const fn from_intervals(intervals: i64) -> SystemTime { SystemTime { t: c::FILETIME { dwLowDateTime: intervals as u32, @@ -81,11 +82,13 @@ impl SystemTime { } } - fn intervals(&self) -> i64 { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + const fn intervals(&self) -> i64 { (self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32) } - pub fn sub_time(&self, other: &SystemTime) -> Result { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result { let me = self.intervals(); let other = other.intervals(); if me >= other { @@ -95,12 +98,14 @@ impl SystemTime { } } - pub fn checked_add_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option { let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?; Some(SystemTime::from_intervals(intervals)) } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option { let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?; Some(SystemTime::from_intervals(intervals)) } @@ -150,15 +155,18 @@ impl Hash for SystemTime { } } -fn checked_dur2intervals(dur: &Duration) -> Option { - dur.as_secs() +#[rustc_const_unstable(feature = "const_system_time", issue = "144517")] +const fn checked_dur2intervals(dur: &Duration) -> Option { + // FIXME: const TryInto + let secs = dur + .as_secs() .checked_mul(INTERVALS_PER_SEC)? - .checked_add(dur.subsec_nanos() as u64 / 100)? - .try_into() - .ok() + .checked_add(dur.subsec_nanos() as u64 / 100)?; + if secs <= i64::MAX as u64 { Some(secs.cast_signed()) } else { None } } -fn intervals2dur(intervals: u64) -> Duration { +#[rustc_const_unstable(feature = "const_system_time", issue = "144517")] +const fn intervals2dur(intervals: u64) -> Duration { Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32) } diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/pal/xous/time.rs index ae8be81c0b7c5..d737416436e68 100644 --- a/library/std/src/sys/pal/xous/time.rs +++ b/library/std/src/sys/pal/xous/time.rs @@ -43,15 +43,22 @@ impl SystemTime { SystemTime { 0: Duration::from_millis((upper as u64) << 32 | lower as u64) } } - pub fn sub_time(&self, other: &SystemTime) -> Result { - self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn sub_time(&self, other: &SystemTime) -> Result { + // FIXME: ok_or_else with const closures + match self.0.checked_sub(other.0) { + Some(duration) => Ok(duration), + None => Err(other.0 - self.0), + } } - pub fn checked_add_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_add(*other)?)) } - pub fn checked_sub_duration(&self, other: &Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub_duration(&self, other: &Duration) -> Option { Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/library/std/src/time.rs b/library/std/src/time.rs index cd0683f44c998..07bb41f14961b 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -551,8 +551,13 @@ impl SystemTime { /// println!("{difference:?}"); /// ``` #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: SystemTime) -> Result { - self.0.sub_time(&earlier.0).map_err(SystemTimeError) + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn duration_since(&self, earlier: SystemTime) -> Result { + // FIXME: map_err in const + match self.0.sub_time(&earlier.0) { + Ok(time) => Ok(time), + Err(err) => Err(SystemTimeError(err)), + } } /// Returns the difference from this system time to the @@ -589,7 +594,8 @@ impl SystemTime { /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` /// otherwise. #[stable(feature = "time_checked_add", since = "1.34.0")] - pub fn checked_add(&self, duration: Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_add(&self, duration: Duration) -> Option { self.0.checked_add_duration(&duration).map(SystemTime) } @@ -597,13 +603,15 @@ impl SystemTime { /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` /// otherwise. #[stable(feature = "time_checked_add", since = "1.34.0")] - pub fn checked_sub(&self, duration: Duration) -> Option { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn checked_sub(&self, duration: Duration) -> Option { self.0.checked_sub_duration(&duration).map(SystemTime) } } #[stable(feature = "time2", since = "1.8.0")] -impl Add for SystemTime { +#[rustc_const_unstable(feature = "const_ops", issue = "143802")] +impl const Add for SystemTime { type Output = SystemTime; /// # Panics @@ -616,14 +624,16 @@ impl Add for SystemTime { } #[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl AddAssign for SystemTime { +#[rustc_const_unstable(feature = "const_ops", issue = "143802")] +impl const AddAssign for SystemTime { fn add_assign(&mut self, other: Duration) { *self = *self + other; } } #[stable(feature = "time2", since = "1.8.0")] -impl Sub for SystemTime { +#[rustc_const_unstable(feature = "const_ops", issue = "143802")] +impl const Sub for SystemTime { type Output = SystemTime; fn sub(self, dur: Duration) -> SystemTime { @@ -632,7 +642,8 @@ impl Sub for SystemTime { } #[stable(feature = "time_augmented_assignment", since = "1.9.0")] -impl SubAssign for SystemTime { +#[rustc_const_unstable(feature = "const_ops", issue = "143802")] +impl const SubAssign for SystemTime { fn sub_assign(&mut self, other: Duration) { *self = *self - other; } @@ -699,7 +710,8 @@ impl SystemTimeError { /// ``` #[must_use] #[stable(feature = "time2", since = "1.8.0")] - pub fn duration(&self) -> Duration { + #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] + pub const fn duration(&self) -> Duration { self.0 } } From 614364c68107c21c417f5363553229a14c7e11c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 20:23:35 +0200 Subject: [PATCH 123/252] Allow cross-compiling the Cranelift dist component --- src/bootstrap/src/core/build_steps/dist.rs | 5 ++++- src/bootstrap/src/core/build_steps/install.rs | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index f9cb300b68ea1..e63f9e14efece 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1410,6 +1410,7 @@ impl Step for Miri { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct CraneliftCodegenBackend { pub build_compiler: Compiler, + pub target: TargetSelection, } impl Step for CraneliftCodegenBackend { @@ -1437,6 +1438,7 @@ impl Step for CraneliftCodegenBackend { run.builder.config.host_target, run.target, ), + target: run.target, }); } @@ -1448,7 +1450,7 @@ impl Step for CraneliftCodegenBackend { return None; } - let target = self.build_compiler.host; + let target = self.target; let compilers = RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, target); if !target_supports_cranelift_backend(target) { @@ -1608,6 +1610,7 @@ impl Step for Extended { add_component!("analysis" => Analysis { compiler, target }); add_component!("rustc-codegen-cranelift" => CraneliftCodegenBackend { build_compiler: compiler, + target }); add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker { build_compiler: compiler, diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index acee78dcf59b9..32eec8cefab43 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -276,6 +276,7 @@ install!((self, builder, _config), RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), only_hosts: true, { if let Some(tarball) = builder.ensure(dist::CraneliftCodegenBackend { build_compiler: self.compiler, + target: self.target }) { install_sh(builder, "rustc-codegen-cranelift", self.compiler.stage, Some(self.target), &tarball); } else { From 2c0409c7e838ef3f9910a6812c085f971e8bbae6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 11 Aug 2025 21:38:46 +0000 Subject: [PATCH 124/252] Remove unused must_use --- compiler/rustc_expand/src/expand.rs | 1 + compiler/rustc_lint/messages.ftl | 1 + compiler/rustc_lint/src/early/diagnostics.rs | 10 +- compiler/rustc_lint/src/lints.rs | 3 +- compiler/rustc_lint_defs/src/lib.rs | 1 + compiler/rustc_passes/messages.ftl | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/errors.rs | 2 + .../issue-43106-gating-of-builtin-attrs.rs | 5 + ...issue-43106-gating-of-builtin-attrs.stderr | 324 +++++++++--------- .../unused/unused_attributes-must_use.fixed | 139 ++++++++ .../lint/unused/unused_attributes-must_use.rs | 3 + .../unused/unused_attributes-must_use.stderr | 64 ++-- 13 files changed, 358 insertions(+), 198 deletions(-) create mode 100644 tests/ui/lint/unused/unused_attributes-must_use.fixed diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index f02aa6c120f91..5504fff519ccb 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -2157,6 +2157,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr_name, macro_name: pprust::path_to_string(&call.path), invoc_span: call.path.span, + attr_span: attr.span, }, ); } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 4d0c0c94a8138..6a47e23604774 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -982,6 +982,7 @@ lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead lint_unused_builtin_attribute = unused attribute `{$attr_name}` .note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}` + .suggestion = remove the attribute lint_unused_closure = unused {$pre}{$count -> diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index f0fbf5bc81e9b..59e806e56d17a 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -205,8 +205,14 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => { - lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }.decorate_lint(diag); + BuiltinLintDiag::UnusedBuiltinAttribute { + attr_name, + macro_name, + invoc_span, + attr_span, + } => { + lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name, attr_span } + .decorate_lint(diag); } BuiltinLintDiag::TrailingMacro(is_trailing, name) => { lints::TrailingMacro { is_trailing, name }.decorate_lint(diag); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 73e69a1791a4d..f1d3d0d19dad6 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2935,9 +2935,10 @@ pub(crate) struct RawPrefix { pub(crate) struct UnusedBuiltinAttribute { #[note] pub invoc_span: Span, - pub attr_name: Symbol, pub macro_name: String, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub attr_span: Span, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index fe068d96b7424..7bd6078fa1057 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -647,6 +647,7 @@ pub enum BuiltinLintDiag { attr_name: Symbol, macro_name: String, invoc_span: Span, + attr_span: Span, }, PatternsInFnsWithoutBody { span: Span, diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6a28fe2617edf..5654f8f5efc4f 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -510,6 +510,7 @@ passes_must_not_suspend = passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} + .suggestion = remove the attribute passes_no_link = attribute should be applied to an `extern crate` item diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 10c532b436aa1..ef9c8dc8b1391 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1621,7 +1621,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { UNUSED_ATTRIBUTES, hir_id, attr_span, - errors::MustUseNoEffect { article, target }, + errors::MustUseNoEffect { article, target, attr_span }, ); } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index c6ab6b0d60179..e47181e0931d6 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -469,6 +469,8 @@ pub(crate) struct FfiConstInvalidTarget { pub(crate) struct MustUseNoEffect { pub article: &'static str, pub target: rustc_hir::Target, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub attr_span: Span, } #[derive(Diagnostic)] 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 b93cb2ea006de..c91fd600068cd 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 @@ -71,6 +71,7 @@ //~^^ WARN this was previously accepted by the compiler #![must_use] //~^ WARN `#[must_use]` has no effect +//~| HELP remove the attribute // see issue-43106-gating-of-stable.rs // see issue-43106-gating-of-unstable.rs // see issue-43106-gating-of-deprecated.rs @@ -599,16 +600,20 @@ mod deprecated { } #[must_use] //~ WARN `#[must_use]` has no effect +//~^ HELP remove the attribute mod must_use { mod inner { #![must_use] } //~ WARN `#[must_use]` has no effect + //~^ HELP remove the attribute #[must_use] fn f() { } #[must_use] struct S; #[must_use] type T = S; //~ WARN `#[must_use]` has no effect + //~^ HELP remove the attribute #[must_use] impl S { } //~ WARN `#[must_use]` has no effect + //~^ HELP remove the attribute } #[windows_subsystem = "windows"] 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 f2ae50b75a348..e0ea5382faa95 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 @@ -1,5 +1,5 @@ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:397:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | mod inner { #![macro_escape] } = help: try an outer attribute: `#[macro_use]` warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ @@ -43,151 +43,151 @@ LL | #![deny(x5100)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:97:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:99:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:100:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:102:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:103:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:106:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:108:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:115:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:118:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:121:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:134:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:137:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:140:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:153:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:156:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:159:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:189:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:1 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ @@ -199,13 +199,13 @@ LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:281:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:282:1 | LL | #[no_mangle] | ^^^^^^^^^^^^ @@ -220,31 +220,31 @@ 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: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:321:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:322:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:339:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:340:1 | LL | #[ignore] | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:375:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:415:1 | LL | #[no_std] | ^^^^^^^^^ warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:451:1 | LL | #[cold] | ^^^^^^^ @@ -260,7 +260,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: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:1 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -276,7 +276,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: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:518:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:1 | LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,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: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:550:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:1 | LL | #[link()] | ^^^^^^^^^ @@ -308,55 +308,55 @@ 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: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:602:1 | LL | #[must_use] | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:1 | LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:678:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:1 | LL | #[no_builtins] | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -418,7 +418,7 @@ 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! warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:85:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:86:12 | LL | #![feature(rust1)] | ^^^^^ @@ -426,121 +426,121 @@ LL | #![feature(rust1)] = note: `#[warn(stable_features)]` on by default warning: `#[macro_use]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:5 | LL | #[macro_use] fn f() { } | ^^^^^^^^^^^^ warning: `#[macro_use]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:180:5 | LL | #[macro_use] struct S; | ^^^^^^^^^^^^ warning: `#[macro_use]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:183:5 | LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ warning: `#[macro_use]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:186:5 | LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:192:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:17 | LL | mod inner { #![macro_export] } | ^^^^^^^^^^^^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:195:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:5 | LL | #[macro_export] fn f() { } | ^^^^^^^^^^^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:199:5 | LL | #[macro_export] struct S; | ^^^^^^^^^^^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5 | LL | #[macro_export] type T = S; | ^^^^^^^^^^^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:5 | LL | #[macro_export] impl S { } | ^^^^^^^^^^^^^^^ warning: `#[path]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:244:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ warning: `#[path]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:247:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ warning: `#[path]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:250:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ warning: `#[path]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:253:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:254:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:264:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:267:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:270:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:273:5 | LL | #[automatically_derived] trait W { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:276:5 | LL | #[automatically_derived] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:286:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:287:17 | LL | mod inner { #![no_mangle] } | ------------^^^^^^^^^^^^^-- not a free function, impl method or static @@ -548,7 +548,7 @@ LL | mod inner { #![no_mangle] } = 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 a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:293:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:294:5 | LL | #[no_mangle] struct S; | ^^^^^^^^^^^^ --------- not a free function, impl method or static @@ -556,7 +556,7 @@ LL | #[no_mangle] 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 a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:298:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:299:5 | LL | #[no_mangle] type T = S; | ^^^^^^^^^^^^ ----------- not a free function, impl method or static @@ -564,7 +564,7 @@ LL | #[no_mangle] 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 a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:303:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:304:5 | LL | #[no_mangle] impl S { } | ^^^^^^^^^^^^ ---------- not a free function, impl method or static @@ -572,7 +572,7 @@ LL | #[no_mangle] 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 a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:309:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:310:9 | LL | #[no_mangle] fn foo(); | ^^^^^^^^^^^^ --------- not a free function, impl method or static @@ -580,7 +580,7 @@ LL | #[no_mangle] fn foo(); = 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 a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:315:9 | LL | #[no_mangle] fn bar() {} | ^^^^^^^^^^^^ ----------- not a free function, impl method or static @@ -588,163 +588,163 @@ LL | #[no_mangle] fn bar() {} = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:330:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:336:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:343:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:348:5 | LL | #[ignore] struct S; | ^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:354:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:362:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:365:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:368:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:371:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:378:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:381:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:384:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:390:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:410:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:418:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:457:17 | LL | mod inner { #![cold] } | ------------^^^^^^^^-- not a function definition @@ -752,7 +752,7 @@ LL | mod inner { #![cold] } = 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 a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:5 | LL | #[cold] struct S; | ^^^^^^^ --------- not a function definition @@ -760,7 +760,7 @@ LL | #[cold] 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 a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:5 | LL | #[cold] type T = S; | ^^^^^^^ ----------- not a function definition @@ -768,7 +768,7 @@ LL | #[cold] 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 a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 | LL | #[cold] impl S { } | ^^^^^^^ ---------- not a function definition @@ -776,7 +776,7 @@ LL | #[cold] 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 a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ @@ -786,13 +786,13 @@ LL | extern "C" { } | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! help: try `#[link(name = "1900")]` instead - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 | LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:17 | LL | mod inner { #![link_name="1900"] } | ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static @@ -800,7 +800,7 @@ LL | mod inner { #![link_name="1900"] } = 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 a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:498:5 | LL | #[link_name = "1900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static @@ -808,7 +808,7 @@ LL | #[link_name = "1900"] 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 a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:5 | LL | #[link_name = "1900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static @@ -816,7 +816,7 @@ LL | #[link_name = "1900"] 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 a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:5 | LL | #[link_name = "1900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static @@ -824,7 +824,7 @@ LL | #[link_name = "1900"] 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 a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:513:5 | LL | #[link_name = "1900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static @@ -832,7 +832,7 @@ LL | #[link_name = "1900"] 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 a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:524:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:525:17 | LL | mod inner { #![link_section="1800"] } | ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static @@ -840,7 +840,7 @@ LL | mod inner { #![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! warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:531:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:5 | LL | #[link_section = "1800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static @@ -848,7 +848,7 @@ LL | #[link_section = "1800"] 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 a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:537:5 | LL | #[link_section = "1800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static @@ -856,7 +856,7 @@ LL | #[link_section = "1800"] 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 a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:542:5 | LL | #[link_section = "1800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static @@ -864,7 +864,7 @@ LL | #[link_section = "1800"] 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:556:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:557:17 | LL | mod inner { #![link()] } | ------------^^^^^^^^^^-- not an `extern` block @@ -872,7 +872,7 @@ LL | mod inner { #![link()] } = 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:561:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:562:5 | LL | #[link()] fn f() { } | ^^^^^^^^^ ---------- not an `extern` block @@ -880,7 +880,7 @@ LL | #[link()] 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:566:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:567:5 | LL | #[link()] struct S; | ^^^^^^^^^ --------- not an `extern` block @@ -888,7 +888,7 @@ LL | #[link()] 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:571:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:572:5 | LL | #[link()] type T = S; | ^^^^^^^^^ ----------- not an `extern` block @@ -896,7 +896,7 @@ LL | #[link()] 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:576:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:5 | LL | #[link()] impl S { } | ^^^^^^^^^ ---------- not an `extern` block @@ -904,7 +904,7 @@ LL | #[link()] 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:581:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:582:5 | LL | #[link()] extern "Rust" {} | ^^^^^^^^^ @@ -912,259 +912,259 @@ LL | #[link()] 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: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:605:17 | LL | mod inner { #![must_use] } | ^^^^^^^^^^^^ warning: `#[must_use]` has no effect when applied to a type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:612:5 | LL | #[must_use] type T = S; | ^^^^^^^^^^^ warning: `#[must_use]` has no effect when applied to an inherent implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:5 | LL | #[must_use] impl S { } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:622:17 | LL | mod inner { #![windows_subsystem="windows"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:625:5 | LL | #[windows_subsystem = "windows"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:628:5 | LL | #[windows_subsystem = "windows"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:5 | LL | #[windows_subsystem = "windows"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:5 | LL | #[windows_subsystem = "windows"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:662:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:666:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:674:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17 | LL | mod inner { #![no_builtins] } | ^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5 | LL | #[no_builtins] fn f() { } | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 | LL | #[no_builtins] struct S; | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 | LL | #[no_builtins] type T = S; | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 | LL | #[no_builtins] impl S { } | ^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/unused/unused_attributes-must_use.fixed b/tests/ui/lint/unused/unused_attributes-must_use.fixed new file mode 100644 index 0000000000000..80d488296eaa2 --- /dev/null +++ b/tests/ui/lint/unused/unused_attributes-must_use.fixed @@ -0,0 +1,139 @@ +//@ run-rustfix + +#![allow(dead_code, path_statements)] +#![deny(unused_attributes, unused_must_use)] +#![feature(asm_experimental_arch, stmt_expr_attributes, trait_alias)] + + //~ ERROR `#[must_use]` has no effect +extern crate std as std2; + + //~ ERROR `#[must_use]` has no effect +mod test_mod {} + + //~ ERROR `#[must_use]` has no effect +use std::arch::global_asm; + + //~ ERROR `#[must_use]` has no effect +const CONST: usize = 4; + //~ ERROR `#[must_use]` has no effect +#[no_mangle] +static STATIC: usize = 4; + +#[must_use] +struct X; + +#[must_use] +enum Y { + Z, +} + +#[must_use] +union U { + unit: (), +} + + //~ ERROR `#[must_use]` has no effect +impl U { + #[must_use] + fn method() -> i32 { + 4 + } +} + +#[must_use] +#[no_mangle] +fn foo() -> i64 { + 4 +} + + //~ ERROR `#[must_use]` has no effect +extern "Rust" { + #[link_name = "STATIC"] + //~ ERROR `#[must_use]` has no effect + static FOREIGN_STATIC: usize; + + #[link_name = "foo"] + #[must_use] + fn foreign_foo() -> i64; +} + + //~ ERROR unused attribute +global_asm!(""); + + //~ ERROR `#[must_use]` has no effect +type UseMe = (); + +fn qux< T>(_: T) {} //~ ERROR `#[must_use]` has no effect + +#[must_use] +trait Use { + //~ ERROR `#[must_use]` has no effect + const ASSOC_CONST: usize = 4; + //~ ERROR `#[must_use]` has no effect + type AssocTy; + + #[must_use] + fn get_four(&self) -> usize { + 4 + } +} + + //~ ERROR `#[must_use]` has no effect +impl Use for () { + type AssocTy = (); + + //~ ERROR `#[must_use]` has no effect + fn get_four(&self) -> usize { + 4 + } +} + + //~ ERROR `#[must_use]` has no effect +trait Alias = Use; + + //~ ERROR `#[must_use]` has no effect +macro_rules! cool_macro { + () => { + 4 + }; +} + +fn main() { + //~ ERROR `#[must_use]` has no effect + let x = || {}; + x(); + + let x = //~ ERROR `#[must_use]` has no effect + || {}; + x(); + + let _ = X; //~ ERROR that must be used + let _ = Y::Z; //~ ERROR that must be used + let _ = U { unit: () }; //~ ERROR that must be used + let _ = U::method(); //~ ERROR that must be used + let _ = foo(); //~ ERROR that must be used + + unsafe { + let _ = foreign_foo(); //~ ERROR that must be used + }; + + CONST; + STATIC; + unsafe { FOREIGN_STATIC }; + cool_macro!(); + qux(4); + let _ = ().get_four(); //~ ERROR that must be used + + match Some(4) { + //~ ERROR `#[must_use]` has no effect + Some(res) => res, + None => 0, + }; + + struct PatternField { + foo: i32, + } + let s = PatternField { foo: 123 }; //~ ERROR `#[must_use]` has no effect + let PatternField { foo } = s; //~ ERROR `#[must_use]` has no effect + let _ = foo; +} diff --git a/tests/ui/lint/unused/unused_attributes-must_use.rs b/tests/ui/lint/unused/unused_attributes-must_use.rs index 860fc5046d103..edefe8ed65ec7 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.rs +++ b/tests/ui/lint/unused/unused_attributes-must_use.rs @@ -1,3 +1,5 @@ +//@ run-rustfix + #![allow(dead_code, path_statements)] #![deny(unused_attributes, unused_must_use)] #![feature(asm_experimental_arch, stmt_expr_attributes, trait_alias)] @@ -133,4 +135,5 @@ fn main() { } let s = PatternField { #[must_use] foo: 123 }; //~ ERROR `#[must_use]` has no effect let PatternField { #[must_use] foo } = s; //~ ERROR `#[must_use]` has no effect + let _ = foo; } diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 862ffa42d8083..27927cf37e92a 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -1,154 +1,154 @@ error: unused attribute `must_use` - --> $DIR/unused_attributes-must_use.rs:58:1 + --> $DIR/unused_attributes-must_use.rs:60:1 | LL | #[must_use] | ^^^^^^^^^^^ | note: the built-in attribute `must_use` will be ignored, since it's applied to the macro invocation `global_asm` - --> $DIR/unused_attributes-must_use.rs:59:1 + --> $DIR/unused_attributes-must_use.rs:61:1 | LL | global_asm!(""); | ^^^^^^^^^^ note: the lint level is defined here - --> $DIR/unused_attributes-must_use.rs:2:9 + --> $DIR/unused_attributes-must_use.rs:4:9 | LL | #![deny(unused_attributes, unused_must_use)] | ^^^^^^^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to an extern crate - --> $DIR/unused_attributes-must_use.rs:5:1 + --> $DIR/unused_attributes-must_use.rs:7:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a module - --> $DIR/unused_attributes-must_use.rs:8:1 + --> $DIR/unused_attributes-must_use.rs:10:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a use - --> $DIR/unused_attributes-must_use.rs:11:1 + --> $DIR/unused_attributes-must_use.rs:13:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a constant item - --> $DIR/unused_attributes-must_use.rs:14:1 + --> $DIR/unused_attributes-must_use.rs:16:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a static item - --> $DIR/unused_attributes-must_use.rs:16:1 + --> $DIR/unused_attributes-must_use.rs:18:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to an inherent implementation block - --> $DIR/unused_attributes-must_use.rs:33:1 + --> $DIR/unused_attributes-must_use.rs:35:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a foreign module - --> $DIR/unused_attributes-must_use.rs:47:1 + --> $DIR/unused_attributes-must_use.rs:49:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a type alias - --> $DIR/unused_attributes-must_use.rs:61:1 + --> $DIR/unused_attributes-must_use.rs:63:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a type parameter - --> $DIR/unused_attributes-must_use.rs:64:8 + --> $DIR/unused_attributes-must_use.rs:66:8 | LL | fn qux<#[must_use] T>(_: T) {} | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to an trait implementation block - --> $DIR/unused_attributes-must_use.rs:79:1 + --> $DIR/unused_attributes-must_use.rs:81:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a trait alias - --> $DIR/unused_attributes-must_use.rs:89:1 + --> $DIR/unused_attributes-must_use.rs:91:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a macro def - --> $DIR/unused_attributes-must_use.rs:92:1 + --> $DIR/unused_attributes-must_use.rs:94:1 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a statement - --> $DIR/unused_attributes-must_use.rs:100:5 + --> $DIR/unused_attributes-must_use.rs:102:5 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a closure - --> $DIR/unused_attributes-must_use.rs:104:13 + --> $DIR/unused_attributes-must_use.rs:106:13 | LL | let x = #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to an match arm - --> $DIR/unused_attributes-must_use.rs:126:9 + --> $DIR/unused_attributes-must_use.rs:128:9 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a struct field - --> $DIR/unused_attributes-must_use.rs:134:28 + --> $DIR/unused_attributes-must_use.rs:136:28 | LL | let s = PatternField { #[must_use] foo: 123 }; | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a pattern field - --> $DIR/unused_attributes-must_use.rs:135:24 + --> $DIR/unused_attributes-must_use.rs:137:24 | LL | let PatternField { #[must_use] foo } = s; | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to an associated const - --> $DIR/unused_attributes-must_use.rs:68:5 + --> $DIR/unused_attributes-must_use.rs:70:5 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to an associated type - --> $DIR/unused_attributes-must_use.rs:70:5 + --> $DIR/unused_attributes-must_use.rs:72:5 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a provided trait method - --> $DIR/unused_attributes-must_use.rs:83:5 + --> $DIR/unused_attributes-must_use.rs:85:5 | LL | #[must_use] | ^^^^^^^^^^^ error: `#[must_use]` has no effect when applied to a foreign static item - --> $DIR/unused_attributes-must_use.rs:50:5 + --> $DIR/unused_attributes-must_use.rs:52:5 | LL | #[must_use] | ^^^^^^^^^^^ error: unused `X` that must be used - --> $DIR/unused_attributes-must_use.rs:108:5 + --> $DIR/unused_attributes-must_use.rs:110:5 | LL | X; | ^ | note: the lint level is defined here - --> $DIR/unused_attributes-must_use.rs:2:28 + --> $DIR/unused_attributes-must_use.rs:4:28 | LL | #![deny(unused_attributes, unused_must_use)] | ^^^^^^^^^^^^^^^ @@ -158,7 +158,7 @@ LL | let _ = X; | +++++++ error: unused `Y` that must be used - --> $DIR/unused_attributes-must_use.rs:109:5 + --> $DIR/unused_attributes-must_use.rs:111:5 | LL | Y::Z; | ^^^^ @@ -169,7 +169,7 @@ LL | let _ = Y::Z; | +++++++ error: unused `U` that must be used - --> $DIR/unused_attributes-must_use.rs:110:5 + --> $DIR/unused_attributes-must_use.rs:112:5 | LL | U { unit: () }; | ^^^^^^^^^^^^^^ @@ -180,7 +180,7 @@ LL | let _ = U { unit: () }; | +++++++ error: unused return value of `U::method` that must be used - --> $DIR/unused_attributes-must_use.rs:111:5 + --> $DIR/unused_attributes-must_use.rs:113:5 | LL | U::method(); | ^^^^^^^^^^^ @@ -191,7 +191,7 @@ LL | let _ = U::method(); | +++++++ error: unused return value of `foo` that must be used - --> $DIR/unused_attributes-must_use.rs:112:5 + --> $DIR/unused_attributes-must_use.rs:114:5 | LL | foo(); | ^^^^^ @@ -202,7 +202,7 @@ LL | let _ = foo(); | +++++++ error: unused return value of `foreign_foo` that must be used - --> $DIR/unused_attributes-must_use.rs:115:9 + --> $DIR/unused_attributes-must_use.rs:117:9 | LL | foreign_foo(); | ^^^^^^^^^^^^^ @@ -213,7 +213,7 @@ LL | let _ = foreign_foo(); | +++++++ error: unused return value of `Use::get_four` that must be used - --> $DIR/unused_attributes-must_use.rs:123:5 + --> $DIR/unused_attributes-must_use.rs:125:5 | LL | ().get_four(); | ^^^^^^^^^^^^^ From d6945f6d8c15bd692000cd7f8d76d171ae27b8c9 Mon Sep 17 00:00:00 2001 From: ltdk Date: Thu, 17 Jul 2025 23:28:24 -0400 Subject: [PATCH 125/252] Add cast_init and cast_uninit methods for pointers --- library/alloc/src/lib.rs | 1 + library/alloc/src/vec/mod.rs | 2 +- library/core/src/iter/adapters/map_windows.rs | 2 +- library/core/src/ptr/const_ptr.rs | 22 ++++++++++++++++ library/core/src/ptr/mut_ptr.rs | 25 +++++++++++++++++++ library/core/src/ptr/non_null.rs | 22 ++++++++++++++++ library/std/src/lib.rs | 1 + library/std/src/sys/fs/windows.rs | 2 +- 8 files changed, 74 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index c091e496c5090..639c5d4c9309f 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -102,6 +102,7 @@ #![feature(async_iterator)] #![feature(bstr)] #![feature(bstr_internals)] +#![feature(cast_maybe_uninit)] #![feature(char_internals)] #![feature(char_max_len)] #![feature(clone_to_uninit)] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 8001faf9d20a5..2e40227a058af 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3176,7 +3176,7 @@ impl Vec { // - but the allocation extends out to `self.buf.capacity()` elements, possibly // uninitialized let spare_ptr = unsafe { ptr.add(self.len) }; - let spare_ptr = spare_ptr.cast::>(); + let spare_ptr = spare_ptr.cast_uninit(); let spare_len = self.buf.capacity() - self.len; // SAFETY: diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs index a9c07fee2a91e..0dada9eb6aacf 100644 --- a/library/core/src/iter/adapters/map_windows.rs +++ b/library/core/src/iter/adapters/map_windows.rs @@ -195,7 +195,7 @@ impl Buffer { // SAFETY: the index is valid and this is element `a` in the // diagram above and has not been dropped yet. - unsafe { ptr::drop_in_place(to_drop.cast::()) }; + unsafe { ptr::drop_in_place(to_drop.cast_init()) }; } } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 8b3703bd4b321..6546dde39ac27 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1430,6 +1430,28 @@ impl *const T { } } +impl *const T { + /// Casts from a type to its maybe-uninitialized version. + #[must_use] + #[inline(always)] + #[unstable(feature = "cast_maybe_uninit", issue = "145036")] + pub const fn cast_uninit(self) -> *const MaybeUninit { + self as _ + } +} +impl *const MaybeUninit { + /// Casts from a maybe-uninitialized type to its initialized version. + /// + /// This is always safe, since UB can only occur if the pointer is read + /// before being initialized. + #[must_use] + #[inline(always)] + #[unstable(feature = "cast_maybe_uninit", issue = "145036")] + pub const fn cast_init(self) -> *const T { + self as _ + } +} + impl *const [T] { /// Returns the length of a raw slice. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index af39ec86d7ac8..4add964141ae5 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1687,6 +1687,31 @@ impl *mut T { } } +impl *mut T { + /// Casts from a type to its maybe-uninitialized version. + /// + /// This is always safe, since UB can only occur if the pointer is read + /// before being initialized. + #[must_use] + #[inline(always)] + #[unstable(feature = "cast_maybe_uninit", issue = "145036")] + pub const fn cast_uninit(self) -> *mut MaybeUninit { + self as _ + } +} +impl *mut MaybeUninit { + /// Casts from a maybe-uninitialized type to its initialized version. + /// + /// This is always safe, since UB can only occur if the pointer is read + /// before being initialized. + #[must_use] + #[inline(always)] + #[unstable(feature = "cast_maybe_uninit", issue = "145036")] + pub const fn cast_init(self) -> *mut T { + self as _ + } +} + impl *mut [T] { /// Returns the length of a raw slice. /// diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 8667361fecc74..294184ae8e07f 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1357,6 +1357,28 @@ impl NonNull { } } +impl NonNull { + /// Casts from a type to its maybe-uninitialized version. + #[must_use] + #[inline(always)] + #[unstable(feature = "cast_maybe_uninit", issue = "145036")] + pub const fn cast_uninit(self) -> NonNull> { + self.cast() + } +} +impl NonNull> { + /// Casts from a maybe-uninitialized type to its initialized version. + /// + /// This is always safe, since UB can only occur if the pointer is read + /// before being initialized. + #[must_use] + #[inline(always)] + #[unstable(feature = "cast_maybe_uninit", issue = "145036")] + pub const fn cast_init(self) -> NonNull { + self.cast() + } +} + impl NonNull<[T]> { /// Creates a non-null raw slice from a thin pointer and a length. /// diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0c53753064724..66d3f71e0ba2b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -327,6 +327,7 @@ // tidy-alphabetical-start #![feature(bstr)] #![feature(bstr_internals)] +#![feature(cast_maybe_uninit)] #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(core_intrinsics)] diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 09feddd0be9a1..bb3e4bc30ca95 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -1606,7 +1606,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { }; unsafe { let ptr = header.PathBuffer.as_mut_ptr(); - ptr.copy_from(abs_path.as_ptr().cast::>(), abs_path.len()); + ptr.copy_from(abs_path.as_ptr().cast_uninit(), abs_path.len()); let mut ret = 0; cvt(c::DeviceIoControl( From 85d1c89e0fe2c9db253c6e4e53a19302584a2dfd Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sun, 3 Aug 2025 17:03:25 +0200 Subject: [PATCH 126/252] fix tail calls to `#[track_caller]` functions --- Cargo.lock | 1 + compiler/rustc_codegen_ssa/Cargo.toml | 1 + compiler/rustc_codegen_ssa/src/mir/block.rs | 32 +++++++++++++++--- compiler/rustc_lint_defs/src/builtin.rs | 33 +++++++++++++++++++ compiler/rustc_monomorphize/src/collector.rs | 30 ++++++++++++++++- .../callee_is_track_caller.rs | 5 +-- .../callee_is_track_caller.stderr | 10 ++++++ .../callee_is_track_caller_polymorphic.rs | 20 +++++++++++ .../callee_is_track_caller_polymorphic.stderr | 10 ++++++ 9 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 tests/ui/explicit-tail-calls/callee_is_track_caller.stderr create mode 100644 tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.rs create mode 100644 tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.stderr diff --git a/Cargo.lock b/Cargo.lock index 5a3906c470f77..8aa4196d6a87d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3622,6 +3622,7 @@ dependencies = [ "rustc_hir", "rustc_incremental", "rustc_index", + "rustc_lint_defs", "rustc_macros", "rustc_metadata", "rustc_middle", diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 30956fd185579..6a8971de7461e 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -26,6 +26,7 @@ rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } rustc_incremental = { path = "../rustc_incremental" } rustc_index = { path = "../rustc_index" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e96590441fa42..f151e24947e11 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -5,6 +5,7 @@ use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_data_structures::packed::Pu128; use rustc_hir::lang_items::LangItem; +use rustc_lint_defs::builtin::TAIL_CALL_TRACK_CALLER; use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; @@ -906,7 +907,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_span, ); - let instance = match instance.def { + match instance.def { // We don't need AsyncDropGlueCtorShim here because it is not `noop func`, // it is `func returning noop future` ty::InstanceKind::DropGlue(_, None) => { @@ -995,14 +996,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { intrinsic.name, ); } - instance + (Some(instance), None) } } } - _ => instance, - }; - (Some(instance), None) + _ if kind == CallKind::Tail + && instance.def.requires_caller_location(bx.tcx()) => + { + if let Some(hir_id) = + terminator.source_info.scope.lint_root(&self.mir.source_scopes) + { + let msg = "tail calling a function marked with `#[track_caller]` has no special effect"; + bx.tcx().node_lint(TAIL_CALL_TRACK_CALLER, hir_id, |d| { + _ = d.primary_message(msg).span(fn_span) + }); + } + + let instance = ty::Instance::resolve_for_fn_ptr( + bx.tcx(), + bx.typing_env(), + def_id, + generic_args, + ) + .unwrap(); + + (None, Some(bx.get_fn_addr(instance))) + } + _ => (Some(instance), None), + } } ty::FnPtr(..) => (None, Some(callee.immediate())), _ => bug!("{} is not callable", callee.layout.ty), diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 3b84c6b611016..a258d26c817ff 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -5100,3 +5100,36 @@ declare_lint! { report_in_deps: true, }; } + +declare_lint! { + /// The `tail_call_track_caller` lint detects usage of `become` attempting to tail call + /// a function marked with `#[track_caller]`. + /// + /// ### Example + /// + /// ```rust + /// #![feature(explicit_tail_calls)] + /// #![expect(incomplete_features)] + /// + /// #[track_caller] + /// fn f() {} + /// + /// fn g() { + /// become f(); + /// } + /// + /// g(); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Due to implementation details of tail calls and `#[track_caller]` attribute, calls to + /// functions marked with `#[track_caller]` cannot become tail calls. As such using `become` + /// is no different than a normal call (except for changes in drop order). + pub TAIL_CALL_TRACK_CALLER, + Warn, + "detects tail calls of functions marked with `#[track_caller]`", + @feature_gate = explicit_tail_calls; +} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 35b80a9b96f4d..5c94242b450b8 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -788,7 +788,35 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { // *Before* monomorphizing, record that we already handled this mention. self.used_mentioned_items.insert(MentionedItem::Fn(callee_ty)); let callee_ty = self.monomorphize(callee_ty); - visit_fn_use(self.tcx, callee_ty, true, source, &mut self.used_items) + + // HACK(explicit_tail_calls): collect tail calls to `#[track_caller]` functions as indirect, + // because we later call them as such, to prevent issues with ABI incompatibility. + // Ideally we'd replace such tail calls with normal call + return, but this requires + // post-mono MIR optimizations, which we don't yet have. + let force_indirect_call = + if matches!(terminator.kind, mir::TerminatorKind::TailCall { .. }) + && let &ty::FnDef(def_id, args) = callee_ty.kind() + && let instance = ty::Instance::expect_resolve( + self.tcx, + ty::TypingEnv::fully_monomorphized(), + def_id, + args, + source, + ) + && instance.def.requires_caller_location(self.tcx) + { + true + } else { + false + }; + + visit_fn_use( + self.tcx, + callee_ty, + !force_indirect_call, + source, + &mut self.used_items, + ) } mir::TerminatorKind::Drop { ref place, .. } => { let ty = place.ty(self.body, self.tcx).ty; diff --git a/tests/ui/explicit-tail-calls/callee_is_track_caller.rs b/tests/ui/explicit-tail-calls/callee_is_track_caller.rs index bcb93fda8c856..b85b335844b02 100644 --- a/tests/ui/explicit-tail-calls/callee_is_track_caller.rs +++ b/tests/ui/explicit-tail-calls/callee_is_track_caller.rs @@ -1,10 +1,11 @@ -//@ check-pass -// FIXME(explicit_tail_calls): make this run-pass, once tail calls are properly implemented +//@ run-pass +//@ ignore-pass #![expect(incomplete_features)] #![feature(explicit_tail_calls)] fn a(x: u32) -> u32 { become b(x); + //~^ warning: tail calling a function marked with `#[track_caller]` has no special effect } #[track_caller] diff --git a/tests/ui/explicit-tail-calls/callee_is_track_caller.stderr b/tests/ui/explicit-tail-calls/callee_is_track_caller.stderr new file mode 100644 index 0000000000000..e1a251d156f76 --- /dev/null +++ b/tests/ui/explicit-tail-calls/callee_is_track_caller.stderr @@ -0,0 +1,10 @@ +warning: tail calling a function marked with `#[track_caller]` has no special effect + --> $DIR/callee_is_track_caller.rs:7:12 + | +LL | become b(x); + | ^^^^ + | + = note: `#[warn(tail_call_track_caller)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.rs b/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.rs new file mode 100644 index 0000000000000..33384de83eb74 --- /dev/null +++ b/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.rs @@ -0,0 +1,20 @@ +//@ run-pass +//@ ignore-pass +#![expect(incomplete_features)] +#![feature(explicit_tail_calls)] + +fn c() { + become T::f(); + //~^ warning: tail calling a function marked with `#[track_caller]` has no special effect +} + +trait Trait { + #[track_caller] + fn f() {} +} + +impl Trait for () {} + +fn main() { + c::<()>(); +} diff --git a/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.stderr b/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.stderr new file mode 100644 index 0000000000000..5a1c40509ad3a --- /dev/null +++ b/tests/ui/explicit-tail-calls/callee_is_track_caller_polymorphic.stderr @@ -0,0 +1,10 @@ +warning: tail calling a function marked with `#[track_caller]` has no special effect + --> $DIR/callee_is_track_caller_polymorphic.rs:7:12 + | +LL | become T::f(); + | ^^^^^^ + | + = note: `#[warn(tail_call_track_caller)]` on by default + +warning: 1 warning emitted + From 075ce31bd39c68b911edda233f0af3f40113212b Mon Sep 17 00:00:00 2001 From: ywxt Date: Wed, 30 Jul 2025 17:33:17 +0800 Subject: [PATCH 127/252] Fix parallel rustc not being reproducible due to unstable sorting of items. --- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_middle/src/mir/mono.rs | 67 +++++++------- compiler/rustc_session/src/options.rs | 2 + .../compiler-flags/codegen-source-order.md | 12 +++ src/tools/compiletest/src/runtest.rs | 4 + .../bad-intrinsic-monomorphization.stderr | 16 ++-- tests/ui/intrinsics/non-integer-atomic.stderr | 88 +++++++++---------- 7 files changed, 107 insertions(+), 83 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/codegen-source-order.md diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 16474b231e042..0a764808f9538 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -689,6 +689,7 @@ fn test_unstable_options_tracking_hash() { // Make sure that changing an [UNTRACKED] option leaves the hash unchanged. // tidy-alphabetical-start untracked!(assert_incr_state, Some(String::from("loaded"))); + untracked!(codegen_source_order, true); untracked!(deduplicate_diagnostics, false); untracked!(dump_dep_graph, true); untracked!(dump_mir, Some(String::from("abc"))); diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 3afd946b30a2a..0d98e055d9563 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -12,7 +12,6 @@ use rustc_hashes::Hash128; use rustc_hir::ItemId; use rustc_hir::attrs::InlineAttr; use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE}; -use rustc_index::Idx; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; use rustc_session::config::OptLevel; @@ -526,44 +525,50 @@ impl<'tcx> CodegenUnit<'tcx> { tcx: TyCtxt<'tcx>, ) -> Vec<(MonoItem<'tcx>, MonoItemData)> { // The codegen tests rely on items being process in the same order as - // they appear in the file, so for local items, we sort by node_id first + // they appear in the file, so for local items, we sort by span first #[derive(PartialEq, Eq, PartialOrd, Ord)] - struct ItemSortKey<'tcx>(Option, SymbolName<'tcx>); - + struct ItemSortKey<'tcx>(Option, SymbolName<'tcx>); + + // We only want to take HirIds of user-defines instances into account. + // The others don't matter for the codegen tests and can even make item + // order unstable. + fn local_item_id<'tcx>(item: MonoItem<'tcx>) -> Option { + match item { + MonoItem::Fn(ref instance) => match instance.def { + InstanceKind::Item(def) => def.as_local().map(|_| def), + InstanceKind::VTableShim(..) + | InstanceKind::ReifyShim(..) + | InstanceKind::Intrinsic(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::Virtual(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::CloneShim(..) + | InstanceKind::ThreadLocalShim(..) + | InstanceKind::FnPtrAddrShim(..) + | InstanceKind::AsyncDropGlue(..) + | InstanceKind::FutureDropPollShim(..) + | InstanceKind::AsyncDropGlueCtorShim(..) => None, + }, + MonoItem::Static(def_id) => def_id.as_local().map(|_| def_id), + MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id.to_def_id()), + } + } fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey<'tcx> { ItemSortKey( - match item { - MonoItem::Fn(ref instance) => { - match instance.def { - // We only want to take HirIds of user-defined - // instances into account. The others don't matter for - // the codegen tests and can even make item order - // unstable. - InstanceKind::Item(def) => def.as_local().map(Idx::index), - InstanceKind::VTableShim(..) - | InstanceKind::ReifyShim(..) - | InstanceKind::Intrinsic(..) - | InstanceKind::FnPtrShim(..) - | InstanceKind::Virtual(..) - | InstanceKind::ClosureOnceShim { .. } - | InstanceKind::ConstructCoroutineInClosureShim { .. } - | InstanceKind::DropGlue(..) - | InstanceKind::CloneShim(..) - | InstanceKind::ThreadLocalShim(..) - | InstanceKind::FnPtrAddrShim(..) - | InstanceKind::AsyncDropGlue(..) - | InstanceKind::FutureDropPollShim(..) - | InstanceKind::AsyncDropGlueCtorShim(..) => None, - } - } - MonoItem::Static(def_id) => def_id.as_local().map(Idx::index), - MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id.index()), - }, + local_item_id(item) + .map(|def_id| tcx.def_span(def_id).find_ancestor_not_from_macro()) + .flatten(), item.symbol_name(tcx), ) } let mut items: Vec<_> = self.items().iter().map(|(&i, &data)| (i, data)).collect(); + if !tcx.sess.opts.unstable_opts.codegen_source_order { + // It's already deterministic, so we can just use it. + return items; + } items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i)); items } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7c18fd8909808..0e112edc73316 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2165,6 +2165,8 @@ options! { "hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), + codegen_source_order: bool = (false, parse_bool, [UNTRACKED], + "emit mono items in the order of spans in source files (default: no)"), contract_checks: Option = (None, parse_opt_bool, [TRACKED], "emit runtime checks for contract pre- and post-conditions (default: no)"), coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED], diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-source-order.md b/src/doc/unstable-book/src/compiler-flags/codegen-source-order.md new file mode 100644 index 0000000000000..cb019fe0176cb --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/codegen-source-order.md @@ -0,0 +1,12 @@ +# `codegen-source-order` + +--- + +This feature allows you to have a predictive and +deterministic order for items after codegen, which +is the same as in source code. + +For every `CodegenUnit`, local `MonoItem`s would +be sorted by `(Span, SymbolName)`, which +makes codegen tests rely on the order of items in +source files work. diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index debf67e2741dd..be4663fffbe36 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1695,6 +1695,10 @@ impl<'test> TestCx<'test> { } TestMode::Assembly | TestMode::Codegen => { rustc.arg("-Cdebug-assertions=no"); + // For assembly and codegen tests, we want to use the same order + // of the items of a codegen unit as the source order, so that + // we can compare the output with the source code through filecheck. + rustc.arg("-Zcodegen-source-order"); } TestMode::Crashes => { set_mir_dump_dir(&mut rustc); diff --git a/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr b/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr index f49d95e9cfcbe..51ef71c9e2988 100644 --- a/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr +++ b/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr @@ -1,8 +1,8 @@ -error[E0511]: invalid monomorphization of `cttz` intrinsic: expected basic integer type, found `Foo` - --> $DIR/bad-intrinsic-monomorphization.rs:16:5 +error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `Foo` + --> $DIR/bad-intrinsic-monomorphization.rs:26:5 | -LL | intrinsics::cttz(v) - | ^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::simd::simd_add(a, b) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `fadd_fast` intrinsic: expected basic float type, found `Foo` --> $DIR/bad-intrinsic-monomorphization.rs:21:5 @@ -10,11 +10,11 @@ error[E0511]: invalid monomorphization of `fadd_fast` intrinsic: expected basic LL | intrinsics::fadd_fast(a, b) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `Foo` - --> $DIR/bad-intrinsic-monomorphization.rs:26:5 +error[E0511]: invalid monomorphization of `cttz` intrinsic: expected basic integer type, found `Foo` + --> $DIR/bad-intrinsic-monomorphization.rs:16:5 | -LL | intrinsics::simd::simd_add(a, b) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::cttz(v) + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/intrinsics/non-integer-atomic.stderr b/tests/ui/intrinsics/non-integer-atomic.stderr index b96ee7ba84688..330d313639dd1 100644 --- a/tests/ui/intrinsics/non-integer-atomic.stderr +++ b/tests/ui/intrinsics/non-integer-atomic.stderr @@ -1,59 +1,53 @@ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `bool` - --> $DIR/non-integer-atomic.rs:15:5 +error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` + --> $DIR/non-integer-atomic.rs:55:5 | LL | intrinsics::atomic_load::<_, { SeqCst }>(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `bool` - --> $DIR/non-integer-atomic.rs:20:5 +error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `Foo` + --> $DIR/non-integer-atomic.rs:35:5 + | +LL | intrinsics::atomic_load::<_, { SeqCst }>(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` + --> $DIR/non-integer-atomic.rs:60:5 | LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `bool` - --> $DIR/non-integer-atomic.rs:25:5 +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` + --> $DIR/non-integer-atomic.rs:85:5 | LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `bool` - --> $DIR/non-integer-atomic.rs:30:5 +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` + --> $DIR/non-integer-atomic.rs:70:5 | LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `Foo` - --> $DIR/non-integer-atomic.rs:35:5 - | -LL | intrinsics::atomic_load::<_, { SeqCst }>(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `Foo` --> $DIR/non-integer-atomic.rs:40:5 | LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `Foo` - --> $DIR/non-integer-atomic.rs:45:5 - | -LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `Foo` - --> $DIR/non-integer-atomic.rs:50:5 +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` + --> $DIR/non-integer-atomic.rs:90:5 | LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` - --> $DIR/non-integer-atomic.rs:55:5 +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `[u8; 100]` + --> $DIR/non-integer-atomic.rs:80:5 | -LL | intrinsics::atomic_load::<_, { SeqCst }>(p); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` - --> $DIR/non-integer-atomic.rs:60:5 +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `bool` + --> $DIR/non-integer-atomic.rs:20:5 | LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,36 +58,42 @@ error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basi LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` - --> $DIR/non-integer-atomic.rs:70:5 - | -LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:75:5 | LL | intrinsics::atomic_load::<_, { SeqCst }>(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `[u8; 100]` - --> $DIR/non-integer-atomic.rs:80:5 +error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `bool` + --> $DIR/non-integer-atomic.rs:15:5 | -LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_load::<_, { SeqCst }>(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` - --> $DIR/non-integer-atomic.rs:85:5 +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `bool` + --> $DIR/non-integer-atomic.rs:30:5 | -LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` - --> $DIR/non-integer-atomic.rs:90:5 +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `Foo` + --> $DIR/non-integer-atomic.rs:50:5 | LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `Foo` + --> $DIR/non-integer-atomic.rs:45:5 + | +LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `bool` + --> $DIR/non-integer-atomic.rs:25:5 + | +LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0511`. From bc8a52161950a59cc1d8f118d1fb10ab5890e84e Mon Sep 17 00:00:00 2001 From: ywxt Date: Wed, 13 Aug 2025 09:23:41 +0800 Subject: [PATCH 128/252] Fix pgo tests --- .../run-make-support/src/external_deps/rustc.rs | 6 ++++++ tests/run-make/pgo-branch-weights/rmake.rs | 11 +++++++++-- tests/run-make/pgo-indirect-call-promotion/rmake.rs | 13 ++++++++++--- tests/run-make/pgo-use/rmake.rs | 2 ++ 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index 60d3366ee98c8..b74b1d5e166fc 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -405,6 +405,12 @@ impl Rustc { }; self } + + /// Make that the generated LLVM IR is in source order. + pub fn codegen_source_order(&mut self) -> &mut Self { + self.cmd.arg("-Zcodegen-source-order"); + self + } } /// Query the sysroot path corresponding `rustc --print=sysroot`. diff --git a/tests/run-make/pgo-branch-weights/rmake.rs b/tests/run-make/pgo-branch-weights/rmake.rs index 1893248e3077a..e74eabc187542 100644 --- a/tests/run-make/pgo-branch-weights/rmake.rs +++ b/tests/run-make/pgo-branch-weights/rmake.rs @@ -17,15 +17,21 @@ use run_make_support::{llvm_filecheck, llvm_profdata, rfs, run_with_args, rustc} fn main() { let path_prof_data_dir = Path::new("prof_data_dir"); let path_merged_profdata = path_prof_data_dir.join("merged.profdata"); - rustc().input("opaque.rs").run(); + rustc().input("opaque.rs").codegen_source_order().run(); rfs::create_dir_all(&path_prof_data_dir); rustc() .input("interesting.rs") .profile_generate(&path_prof_data_dir) .opt() .codegen_units(1) + .codegen_source_order() + .run(); + rustc() + .input("main.rs") + .profile_generate(&path_prof_data_dir) + .opt() + .codegen_source_order() .run(); - rustc().input("main.rs").profile_generate(&path_prof_data_dir).opt().run(); run_with_args("main", &["aaaaaaaaaaaa2bbbbbbbbbbbb2bbbbbbbbbbbbbbbbcc"]); llvm_profdata().merge().output(&path_merged_profdata).input(path_prof_data_dir).run(); rustc() @@ -34,6 +40,7 @@ fn main() { .opt() .codegen_units(1) .emit("llvm-ir") + .codegen_source_order() .run(); llvm_filecheck() .patterns("filecheck-patterns.txt") diff --git a/tests/run-make/pgo-indirect-call-promotion/rmake.rs b/tests/run-make/pgo-indirect-call-promotion/rmake.rs index ce9754f13b931..ee09141912b11 100644 --- a/tests/run-make/pgo-indirect-call-promotion/rmake.rs +++ b/tests/run-make/pgo-indirect-call-promotion/rmake.rs @@ -14,11 +14,17 @@ use run_make_support::{llvm_filecheck, llvm_profdata, rfs, run, rustc}; fn main() { // We don't compile `opaque` with either optimizations or instrumentation. - rustc().input("opaque.rs").run(); + rustc().input("opaque.rs").codegen_source_order().run(); // Compile the test program with instrumentation rfs::create_dir("prof_data_dir"); - rustc().input("interesting.rs").profile_generate("prof_data_dir").opt().codegen_units(1).run(); - rustc().input("main.rs").profile_generate("prof_data_dir").opt().run(); + rustc() + .input("interesting.rs") + .profile_generate("prof_data_dir") + .opt() + .codegen_units(1) + .codegen_source_order() + .run(); + rustc().input("main.rs").profile_generate("prof_data_dir").opt().codegen_source_order().run(); // The argument below generates to the expected branch weights run("main"); llvm_profdata().merge().output("prof_data_dir/merged.profdata").input("prof_data_dir").run(); @@ -28,6 +34,7 @@ fn main() { .opt() .codegen_units(1) .emit("llvm-ir") + .codegen_source_order() .run(); llvm_filecheck() .patterns("filecheck-patterns.txt") diff --git a/tests/run-make/pgo-use/rmake.rs b/tests/run-make/pgo-use/rmake.rs index c09a82353b9be..137b0b859a042 100644 --- a/tests/run-make/pgo-use/rmake.rs +++ b/tests/run-make/pgo-use/rmake.rs @@ -22,6 +22,7 @@ fn main() { .opt_level("2") .codegen_units(1) .arg("-Cllvm-args=-disable-preinline") + .codegen_source_order() .profile_generate(cwd()) .input("main.rs") .run(); @@ -40,6 +41,7 @@ fn main() { .arg("-Cllvm-args=-disable-preinline") .profile_use("merged.profdata") .emit("llvm-ir") + .codegen_source_order() .input("main.rs") .run(); // Check that the generate IR contains some things that we expect. From 605621224f985454d7a3e1185314098863377df0 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Wed, 13 Aug 2025 11:16:00 +0700 Subject: [PATCH 129/252] Make std use the edition 2024 prelude This seem to have been overlooked in --- library/std/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index fd06a3b540cda..21892ee68027f 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -426,7 +426,7 @@ // to import the prelude implicitly when building crates that depend on std. #[prelude_import] #[allow(unused)] -use prelude::rust_2021::*; +use prelude::rust_2024::*; // Access to Bencher, etc. #[cfg(test)] From 6e7e243ef2790169cfd0e228d22fb6fdd9093317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 16:30:43 +0200 Subject: [PATCH 130/252] Prepare standard library for checking rustc in `prepare_compiler_for_check` --- src/bootstrap/src/core/build_steps/check.rs | 48 +++++++++----------- src/bootstrap/src/core/build_steps/clippy.rs | 2 +- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 0cbf8f55e9933..2d27ad4cdf325 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -168,12 +168,8 @@ pub struct Rustc { } impl Rustc { - pub fn new(builder: &Builder<'_>, build_compiler: Compiler, target: TargetSelection) -> Self { - let crates = builder - .in_tree_crates("rustc-main", Some(target)) - .into_iter() - .map(|krate| krate.name.to_string()) - .collect(); + pub fn new(builder: &Builder<'_>, target: TargetSelection, crates: Vec) -> Self { + let build_compiler = prepare_compiler_for_check(builder, target, Mode::Rustc); Self { build_compiler, target, crates } } } @@ -189,11 +185,7 @@ impl Step for Rustc { fn make_run(run: RunConfig<'_>) { let crates = run.make_run_crates(Alias::Compiler); - run.builder.ensure(Rustc { - target: run.target, - build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Rustc), - crates, - }); + run.builder.ensure(Rustc::new(run.builder, run.target, crates)); } /// Check the compiler. @@ -207,15 +199,6 @@ impl Step for Rustc { let build_compiler = self.build_compiler; let target = self.target; - // Build host std for compiling build scripts - builder.std(build_compiler, build_compiler.host); - - // Build target std so that the checked rustc can link to it during the check - // FIXME: maybe we can a way to only do a check of std here? - // But for that we would have to copy the stdlib rmetas to the sysroot of the build - // compiler, which conflicts with std rlibs, if we also build std. - builder.std(build_compiler, target); - let mut cargo = builder::Cargo::new( builder, build_compiler, @@ -289,11 +272,13 @@ fn prepare_compiler_for_check( build_compiler } Mode::ToolRustc | Mode::Codegen => { - // FIXME: this is a hack, see description of Mode::Rustc below - let stage = if host == target { builder.top_stage - 1 } else { builder.top_stage }; - // When checking tool stage N, we check it with compiler stage N-1 - let build_compiler = builder.compiler(stage, host); - builder.ensure(Rustc::new(builder, build_compiler, target)); + // Check Rustc to produce the required rmeta artifacts for rustc_private, and then + // return the build compiler that was used to check rustc. + // We do not need to check examples/tests/etc. of Rustc for rustc_private, so we pass + // an empty set of crates, which will avoid using `cargo -p`. + let check = Rustc::new(builder, target, vec![]); + let build_compiler = check.build_compiler; + builder.ensure(check); build_compiler } Mode::Rustc => { @@ -305,7 +290,18 @@ fn prepare_compiler_for_check( // FIXME: remove this and either fix cross-compilation check on stage 2 (which has a // myriad of other problems) or disable cross-checking on stage 1. let stage = if host == target { builder.top_stage - 1 } else { builder.top_stage }; - builder.compiler(stage, host) + let build_compiler = builder.compiler(stage, host); + + // Build host std for compiling build scripts + builder.std(build_compiler, build_compiler.host); + + // Build target std so that the checked rustc can link to it during the check + // FIXME: maybe we can a way to only do a check of std here? + // But for that we would have to copy the stdlib rmetas to the sysroot of the build + // compiler, which conflicts with std rlibs, if we also build std. + builder.std(build_compiler, target); + + build_compiler } Mode::Std => { // When checking std stage N, we want to do it with the stage N compiler diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 4d734fe5c667d..2cba9aa8e8b59 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -298,7 +298,7 @@ macro_rules! lint_any { let target = self.target; if !builder.download_rustc() { - builder.ensure(check::Rustc::new(builder, build_compiler, target)); + builder.ensure(check::Rustc::new(builder, target, vec![])); }; let cargo = prepare_tool_cargo( From 5d1535ca294db11c1cfff39aa31e18164eae28b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 16:59:03 +0200 Subject: [PATCH 131/252] Implement `clippy::CodegenGcc` as a separate step To correctly pass `RustcPrivateCompilers` to it and to avoid running it on `x clippy compiler`. --- src/bootstrap/src/core/build_steps/clippy.rs | 84 ++++++++++++++++++-- src/bootstrap/src/core/builder/mod.rs | 4 + 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 2cba9aa8e8b59..7ec6649aefbad 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -2,11 +2,11 @@ use super::check; use super::compile::{run_cargo, rustc_cargo, std_cargo}; -use super::tool::{SourceType, prepare_tool_cargo}; +use super::tool::{RustcPrivateCompilers, SourceType, prepare_tool_cargo}; use crate::builder::{Builder, ShouldRun}; use crate::core::build_steps::compile::std_crates_for_run_make; use crate::core::builder; -use crate::core::builder::{Alias, Kind, RunConfig, Step, crate_description}; +use crate::core::builder::{Alias, Kind, RunConfig, Step, StepMetadata, crate_description}; use crate::utils::build_stamp::{self, BuildStamp}; use crate::{Mode, Subcommand, TargetSelection}; @@ -263,6 +263,76 @@ impl Step for Rustc { } } +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct CodegenGcc { + compilers: RustcPrivateCompilers, + target: TargetSelection, + config: LintConfig, +} + +impl CodegenGcc { + fn new(builder: &Builder<'_>, target: TargetSelection, config: LintConfig) -> Self { + Self { + compilers: RustcPrivateCompilers::new(builder, builder.top_stage, target), + target, + config, + } + } +} + +impl Step for CodegenGcc { + type Output = (); + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("rustc_codegen_gcc") + } + + fn make_run(run: RunConfig<'_>) { + let builder = run.builder; + let config = LintConfig::new(builder); + builder.ensure(CodegenGcc::new(builder, run.target, config)); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let build_compiler = self.compilers.build_compiler(); + let target = self.target; + + let cargo = prepare_tool_cargo( + builder, + build_compiler, + Mode::Codegen, + target, + Kind::Clippy, + "compiler/rustc_codegen_gcc", + SourceType::InTree, + &[], + ); + + let _guard = + builder.msg(Kind::Clippy, "rustc_codegen_gcc", Mode::ToolRustc, build_compiler, target); + + let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, Mode::Codegen, target)) + .with_prefix("rustc_codegen_gcc-check"); + + run_cargo( + builder, + cargo, + lint_args(builder, &self.config, &[]), + &stamp, + vec![], + true, + false, + ); + } + + fn metadata(&self) -> Option { + Some( + StepMetadata::clippy("rustc_codegen_gcc", self.target) + .built_by(self.compilers.build_compiler()), + ) + } +} + macro_rules! lint_any { ($( $name:ident, $path:expr, $readable_name:expr @@ -346,7 +416,6 @@ lint_any!( CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri"; Clippy, "src/tools/clippy", "clippy"; CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata"; - CodegenGcc, "compiler/rustc_codegen_gcc", "rustc-codegen-gcc"; Compiletest, "src/tools/compiletest", "compiletest"; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; Jsondocck, "src/tools/jsondocck", "jsondocck"; @@ -449,9 +518,10 @@ impl Step for CI { deny: vec!["warnings".into()], forbid: vec![], }; - builder.ensure(CodegenGcc { - target: self.target, - config: self.config.merge(&rustc_codegen_gcc), - }); + builder.ensure(CodegenGcc::new( + builder, + self.target, + self.config.merge(&rustc_codegen_gcc), + )); } } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index de4b941ac9082..8e9f3c1eab469 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -160,6 +160,10 @@ impl StepMetadata { Self::new(name, target, Kind::Check) } + pub fn clippy(name: &str, target: TargetSelection) -> Self { + Self::new(name, target, Kind::Clippy) + } + pub fn doc(name: &str, target: TargetSelection) -> Self { Self::new(name, target, Kind::Doc) } From d2165674e78aff1d0712b02bf33979230c321c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 17:00:24 +0200 Subject: [PATCH 132/252] Forbid running Clippy on stage 0 --- src/bootstrap/src/core/config/config.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index a656927b1f64d..9ced81e1e283d 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1375,6 +1375,10 @@ impl Config { eprintln!("ERROR: cannot document anything on stage 0. Use at least stage 1."); exit!(1); } + (0, Subcommand::Clippy { .. }) => { + eprintln!("ERROR: cannot run clippy on stage 0. Use at least stage 1."); + exit!(1); + } _ => {} } From ba27938c8ca9a6b7e97a1011d611dcfcab78b550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 17:06:40 +0200 Subject: [PATCH 133/252] Add snapshot test for `x clippy ci` --- src/bootstrap/src/core/build_steps/clippy.rs | 12 ++++++ src/bootstrap/src/core/builder/tests.rs | 45 ++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 7ec6649aefbad..f029f9fa9390a 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -178,6 +178,10 @@ impl Step for Std { false, ); } + + fn metadata(&self) -> Option { + Some(StepMetadata::clippy("std", self.target)) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -261,6 +265,10 @@ impl Step for Rustc { false, ); } + + fn metadata(&self) -> Option { + Some(StepMetadata::clippy("rustc", self.target)) + } } #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -404,6 +412,10 @@ macro_rules! lint_any { false, ); } + + fn metadata(&self) -> Option { + Some(StepMetadata::clippy($readable_name, self.target)) + } } )+ } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 32d191c4265de..b9fc3ed57ec27 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2065,6 +2065,51 @@ mod snapshot { [doc] rustc 1 -> reference (book) 2 "); } + + #[test] + fn clippy_ci() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("ci") + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [check] rustc 1 -> rustc 2 + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 + [clippy] bootstrap + [clippy] std + [build] rustc 1 -> std 1 + [clippy] rustc + [clippy] rustc 0 -> rustc_codegen_gcc 1 + "); + } + + #[test] + fn clippy_ci_stage_2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("ci") + .stage(2) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [check] rustc 2 -> rustc 3 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 + [clippy] bootstrap + [clippy] std + [build] rustc 2 -> std 2 + [clippy] rustc + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 + [clippy] rustc 1 -> rustc_codegen_gcc 2 + "); + } } struct ExecutedSteps { From 5ffd5c2ec23f823a6dcb7c67d9d19b0723777fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 17:09:58 +0200 Subject: [PATCH 134/252] Fix Clippy staging for compiler --- src/bootstrap/src/core/build_steps/check.rs | 6 +- src/bootstrap/src/core/build_steps/clippy.rs | 74 ++++++++++++-------- src/bootstrap/src/core/builder/mod.rs | 17 +++-- src/bootstrap/src/core/builder/tests.rs | 34 ++++++--- src/bootstrap/src/utils/build_stamp.rs | 6 +- 5 files changed, 84 insertions(+), 53 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 2d27ad4cdf325..ae258bf2939ca 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -30,10 +30,6 @@ pub struct Std { impl Std { const CRATE_OR_DEPS: &[&str] = &["sysroot", "coretests", "alloctests"]; - - pub fn new(build_compiler: Compiler, target: TargetSelection) -> Self { - Self { build_compiler, target, crates: vec![] } - } } impl Step for Std { @@ -241,7 +237,7 @@ impl Step for Rustc { } /// Prepares a compiler that will check something with the given `mode`. -fn prepare_compiler_for_check( +pub fn prepare_compiler_for_check( builder: &Builder<'_>, target: TargetSelection, mode: Mode, diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index f029f9fa9390a..364d9bed883bd 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -1,14 +1,27 @@ //! Implementation of running clippy on the compiler, standard library and various tools. +//! +//! This serves a double purpose: +//! - The first is to run Clippy itself on in-tree code, in order to test and dogfood it. +//! - The second is to actually lint the in-tree codebase on CI, with a hard-coded set of rules, +//! which is performed by the `x clippy ci` command. +//! +//! In order to prepare a build compiler for running clippy, use the +//! `check::prepare_compiler_for_check` function. That prepares a compiler and a standard library +//! for running Clippy. The second part (actually building Clippy) is performed inside +//! [Builder::cargo_clippy_cmd]. It would be nice if this was more explicit, and we actually had +//! to pass a prebuilt Clippy from the outside when running `cargo clippy`, but that would be +//! (as usual) a massive undertaking/refactoring. use super::check; use super::compile::{run_cargo, rustc_cargo, std_cargo}; use super::tool::{RustcPrivateCompilers, SourceType, prepare_tool_cargo}; use crate::builder::{Builder, ShouldRun}; +use crate::core::build_steps::check::prepare_compiler_for_check; use crate::core::build_steps::compile::std_crates_for_run_make; use crate::core::builder; use crate::core::builder::{Alias, Kind, RunConfig, Step, StepMetadata, crate_description}; use crate::utils::build_stamp::{self, BuildStamp}; -use crate::{Mode, Subcommand, TargetSelection}; +use crate::{Compiler, Mode, Subcommand, TargetSelection}; /// Disable the most spammy clippy lints const IGNORED_RULES_FOR_STD_AND_RUSTC: &[&str] = &[ @@ -184,14 +197,35 @@ impl Step for Std { } } +/// Lints the compiler. +/// +/// This will build Clippy with the `build_compiler` and use it to lint +/// in-tree rustc. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Rustc { - pub target: TargetSelection, + build_compiler: Compiler, + target: TargetSelection, config: LintConfig, /// Whether to lint only a subset of crates. crates: Vec, } +impl Rustc { + fn new( + builder: &Builder<'_>, + target: TargetSelection, + config: LintConfig, + crates: Vec, + ) -> Self { + Self { + build_compiler: prepare_compiler_for_check(builder, target, Mode::Rustc), + target, + config, + crates, + } + } +} + impl Step for Rustc { type Output = (); const ONLY_HOSTS: bool = true; @@ -202,33 +236,16 @@ impl Step for Rustc { } fn make_run(run: RunConfig<'_>) { + let builder = run.builder; let crates = run.make_run_crates(Alias::Compiler); let config = LintConfig::new(run.builder); - run.builder.ensure(Rustc { target: run.target, config, crates }); + run.builder.ensure(Rustc::new(builder, run.target, config, crates)); } - /// Lints the compiler. - /// - /// This will lint the compiler for a particular stage of the build using - /// the `compiler` targeting the `target` architecture. fn run(self, builder: &Builder<'_>) { - let build_compiler = builder.compiler(builder.top_stage, builder.config.host_target); + let build_compiler = self.build_compiler; let target = self.target; - if !builder.download_rustc() { - if build_compiler.stage != 0 { - // If we're not in stage 0, then we won't have a std from the beta - // compiler around. That means we need to make sure there's one in - // the sysroot for the compiler to find. Otherwise, we're going to - // fail when building crates that need to generate code (e.g., build - // scripts and their dependencies). - builder.std(build_compiler, build_compiler.host); - builder.std(build_compiler, target); - } else { - builder.ensure(check::Std::new(build_compiler, target)); - } - } - let mut cargo = builder::Cargo::new( builder, build_compiler, @@ -267,7 +284,7 @@ impl Step for Rustc { } fn metadata(&self) -> Option { - Some(StepMetadata::clippy("rustc", self.target)) + Some(StepMetadata::clippy("rustc", self.target).built_by(self.build_compiler)) } } @@ -518,11 +535,12 @@ impl Step for CI { ], forbid: vec![], }; - builder.ensure(Rustc { - target: self.target, - config: self.config.merge(&compiler_clippy_cfg), - crates: vec![], - }); + builder.ensure(Rustc::new( + builder, + self.target, + self.config.merge(&compiler_clippy_cfg), + vec![], + )); let rustc_codegen_gcc = LintConfig { allow: vec![], diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 8e9f3c1eab469..9719bcbc56328 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1556,8 +1556,10 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s self.ensure(tool::Rustdoc { target_compiler }) } - pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { - if run_compiler.stage == 0 { + /// Create a Cargo command for running Clippy. + /// The used Clippy is (or in the case of stage 0, already was) built using `build_compiler`. + pub fn cargo_clippy_cmd(&self, build_compiler: Compiler) -> BootstrapCommand { + if build_compiler.stage == 0 { let cargo_clippy = self .config .initial_cargo_clippy @@ -1569,15 +1571,16 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s return cmd; } - // FIXME: double check that `run_compiler`'s stage is what we want to use - let compilers = - RustcPrivateCompilers::new(self, run_compiler.stage, self.build.host_target); - assert_eq!(run_compiler, compilers.target_compiler()); + let compilers = RustcPrivateCompilers::from_build_compiler( + self, + build_compiler, + self.build.host_target, + ); let _ = self.ensure(tool::Clippy::from_compilers(compilers)); let cargo_clippy = self.ensure(tool::CargoClippy::from_compilers(compilers)); let mut dylib_path = helpers::dylib_path(); - dylib_path.insert(0, self.sysroot(run_compiler).join("lib")); + dylib_path.insert(0, self.sysroot(build_compiler).join("lib")); let mut cmd = command(cargo_clippy.tool_path); cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b9fc3ed57ec27..2c1623f5385be 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2076,12 +2076,13 @@ mod snapshot { [build] llvm [build] rustc 0 -> rustc 1 [check] rustc 1 -> rustc 2 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 [clippy] bootstrap [clippy] std - [build] rustc 1 -> std 1 - [clippy] rustc + [clippy] rustc 0 -> rustc 1 [clippy] rustc 0 -> rustc_codegen_gcc 1 "); } @@ -2099,17 +2100,30 @@ mod snapshot { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [check] rustc 2 -> rustc 3 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 + [build] rustc 2 -> std 2 + [build] rustc 2 -> rustc 3 + [build] rustc 2 -> clippy-driver 3 + [build] rustc 2 -> cargo-clippy 3 [clippy] bootstrap [clippy] std - [build] rustc 2 -> std 2 - [clippy] rustc - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 + [clippy] rustc 1 -> rustc 2 [clippy] rustc 1 -> rustc_codegen_gcc 2 "); } + + #[test] + fn clippy_compiler() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("compiler") + .render_steps(), @r" + [build] llvm + [clippy] rustc 0 -> rustc 1 + "); + } } struct ExecutedSteps { diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs index bd4eb790ae50e..6c79385190e8e 100644 --- a/src/bootstrap/src/utils/build_stamp.rs +++ b/src/bootstrap/src/utils/build_stamp.rs @@ -146,13 +146,13 @@ pub fn libstd_stamp( } /// Cargo's output path for librustc in a given stage, compiled by a particular -/// compiler for the specified target. +/// `build_compiler` for the specified target. pub fn librustc_stamp( builder: &Builder<'_>, - compiler: Compiler, + build_compiler: Compiler, target: TargetSelection, ) -> BuildStamp { - BuildStamp::new(&builder.cargo_out(compiler, Mode::Rustc, target)).with_prefix("librustc") + BuildStamp::new(&builder.cargo_out(build_compiler, Mode::Rustc, target)).with_prefix("librustc") } /// Computes a hash representing the state of a repository/submodule and additional input. From 2071a68bd6e81a8e6779ee247048d37cd865a8c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 17:19:36 +0200 Subject: [PATCH 135/252] Add snapshot test for `x clippy std` --- src/bootstrap/src/core/builder/tests.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 2c1623f5385be..c521b7f5d0747 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2124,6 +2124,23 @@ mod snapshot { [clippy] rustc 0 -> rustc 1 "); } + + #[test] + fn clippy_std() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("std") + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 + [clippy] std + "); + } } struct ExecutedSteps { From c5dac1aa2a48ac014c8a33a5c8c8334ed48afafa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 17:23:34 +0200 Subject: [PATCH 136/252] Fix staging for `x clippy std` --- src/bootstrap/src/core/build_steps/clippy.rs | 36 +++++++++--- src/bootstrap/src/core/builder/mod.rs | 61 ++++++++++---------- src/bootstrap/src/core/builder/tests.rs | 26 ++++----- 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 364d9bed883bd..f67cf0edf02f9 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -134,12 +134,29 @@ impl LintConfig { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Std { - pub target: TargetSelection, + build_compiler: Compiler, + target: TargetSelection, config: LintConfig, /// Whether to lint only a subset of crates. crates: Vec, } +impl Std { + fn new( + builder: &Builder<'_>, + target: TargetSelection, + config: LintConfig, + crates: Vec, + ) -> Self { + Self { + build_compiler: builder.compiler(builder.top_stage, builder.host_target), + target, + config, + crates, + } + } +} + impl Step for Std { type Output = (); const DEFAULT: bool = true; @@ -151,12 +168,12 @@ impl Step for Std { fn make_run(run: RunConfig<'_>) { let crates = std_crates_for_run_make(&run); let config = LintConfig::new(run.builder); - run.builder.ensure(Std { target: run.target, config, crates }); + run.builder.ensure(Std::new(run.builder, run.target, config, crates)); } fn run(self, builder: &Builder<'_>) { let target = self.target; - let build_compiler = builder.compiler(builder.top_stage, builder.config.host_target); + let build_compiler = self.build_compiler; let mut cargo = builder::Cargo::new( builder, @@ -193,7 +210,7 @@ impl Step for Std { } fn metadata(&self) -> Option { - Some(StepMetadata::clippy("std", self.target)) + Some(StepMetadata::clippy("std", self.target).built_by(self.build_compiler)) } } @@ -510,11 +527,12 @@ impl Step for CI { ], forbid: vec![], }; - builder.ensure(Std { - target: self.target, - config: self.config.merge(&library_clippy_cfg), - crates: vec![], - }); + builder.ensure(Std::new( + builder, + self.target, + self.config.merge(&library_clippy_cfg), + vec![], + )); let compiler_clippy_cfg = LintConfig { allow: vec!["clippy::all".into()], diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 9719bcbc56328..54bf1842ab31b 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1556,6 +1556,32 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s self.ensure(tool::Rustdoc { target_compiler }) } + pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { + assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0"); + + let compilers = + RustcPrivateCompilers::new(self, run_compiler.stage, self.build.host_target); + assert_eq!(run_compiler, compilers.target_compiler()); + + // Prepare the tools + let miri = self.ensure(tool::Miri::from_compilers(compilers)); + let cargo_miri = self.ensure(tool::CargoMiri::from_compilers(compilers)); + // Invoke cargo-miri, make sure it can find miri and cargo. + let mut cmd = command(cargo_miri.tool_path); + cmd.env("MIRI", &miri.tool_path); + cmd.env("CARGO", &self.initial_cargo); + // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler` + // in `tool::ToolBuild` step, so they match the Miri we just built. However this means they + // are actually living one stage up, i.e. we are running `stage1-tools-bin/miri` with the + // libraries in `stage1/lib`. This is an unfortunate off-by-1 caused (possibly) by the fact + // that Miri doesn't have an "assemble" step like rustc does that would cross the stage boundary. + // We can't use `add_rustc_lib_path` as that's a NOP on Windows but we do need these libraries + // added to the PATH due to the stage mismatch. + // Also see https://github.com/rust-lang/rust/pull/123192#issuecomment-2028901503. + add_dylib_path(self.rustc_lib_paths(run_compiler), &mut cmd); + cmd + } + /// Create a Cargo command for running Clippy. /// The used Clippy is (or in the case of stage 0, already was) built using `build_compiler`. pub fn cargo_clippy_cmd(&self, build_compiler: Compiler) -> BootstrapCommand { @@ -1571,11 +1597,10 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s return cmd; } - let compilers = RustcPrivateCompilers::from_build_compiler( - self, - build_compiler, - self.build.host_target, - ); + // If we're linting something with build_compiler stage N, we want to build Clippy stage N + // and use that to lint it. That is why we use the `build_compiler` as the target compiler + // for RustcPrivateCompilers. We will use build compiler stage N-1 to build Clippy stage N. + let compilers = RustcPrivateCompilers::from_target_compiler(self, build_compiler); let _ = self.ensure(tool::Clippy::from_compilers(compilers)); let cargo_clippy = self.ensure(tool::CargoClippy::from_compilers(compilers)); @@ -1588,32 +1613,6 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s cmd } - pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { - assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0"); - - let compilers = - RustcPrivateCompilers::new(self, run_compiler.stage, self.build.host_target); - assert_eq!(run_compiler, compilers.target_compiler()); - - // Prepare the tools - let miri = self.ensure(tool::Miri::from_compilers(compilers)); - let cargo_miri = self.ensure(tool::CargoMiri::from_compilers(compilers)); - // Invoke cargo-miri, make sure it can find miri and cargo. - let mut cmd = command(cargo_miri.tool_path); - cmd.env("MIRI", &miri.tool_path); - cmd.env("CARGO", &self.initial_cargo); - // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler` - // in `tool::ToolBuild` step, so they match the Miri we just built. However this means they - // are actually living one stage up, i.e. we are running `stage1-tools-bin/miri` with the - // libraries in `stage1/lib`. This is an unfortunate off-by-1 caused (possibly) by the fact - // that Miri doesn't have an "assemble" step like rustc does that would cross the stage boundary. - // We can't use `add_rustc_lib_path` as that's a NOP on Windows but we do need these libraries - // added to the PATH due to the stage mismatch. - // Also see https://github.com/rust-lang/rust/pull/123192#issuecomment-2028901503. - add_dylib_path(self.rustc_lib_paths(run_compiler), &mut cmd); - cmd - } - pub fn rustdoc_cmd(&self, compiler: Compiler) -> BootstrapCommand { let mut cmd = command(self.bootstrap_out.join("rustdoc")); cmd.env("RUSTC_STAGE", compiler.stage.to_string()) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index c521b7f5d0747..28bec10f06191 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2076,12 +2076,10 @@ mod snapshot { [build] llvm [build] rustc 0 -> rustc 1 [check] rustc 1 -> rustc 2 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 [clippy] bootstrap - [clippy] std + [clippy] rustc 1 -> std 1 [clippy] rustc 0 -> rustc 1 [clippy] rustc 0 -> rustc_codegen_gcc 1 "); @@ -2100,14 +2098,12 @@ mod snapshot { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [check] rustc 2 -> rustc 3 - [build] rustc 2 -> std 2 - [build] rustc 2 -> rustc 3 - [build] rustc 2 -> clippy-driver 3 - [build] rustc 2 -> cargo-clippy 3 - [clippy] bootstrap - [clippy] std [build] rustc 1 -> clippy-driver 2 [build] rustc 1 -> cargo-clippy 2 + [clippy] bootstrap + [clippy] rustc 2 -> std 2 + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 [clippy] rustc 1 -> rustc 2 [clippy] rustc 1 -> rustc_codegen_gcc 2 "); @@ -2134,11 +2130,9 @@ mod snapshot { .render_steps(), @r" [build] llvm [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 - [clippy] std + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 + [clippy] rustc 1 -> std 1 "); } } From 87d92eecf925e990c6db13a8c2a56e36d4905ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 21:29:30 +0200 Subject: [PATCH 137/252] Fix staging of linting tools --- src/bootstrap/src/core/build_steps/clippy.rs | 74 ++++++++++---------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index f67cf0edf02f9..d8cf3d0c48856 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -6,13 +6,12 @@ //! which is performed by the `x clippy ci` command. //! //! In order to prepare a build compiler for running clippy, use the -//! `check::prepare_compiler_for_check` function. That prepares a compiler and a standard library +//! [check::prepare_compiler_for_check] function. That prepares a compiler and a standard library //! for running Clippy. The second part (actually building Clippy) is performed inside //! [Builder::cargo_clippy_cmd]. It would be nice if this was more explicit, and we actually had //! to pass a prebuilt Clippy from the outside when running `cargo clippy`, but that would be //! (as usual) a massive undertaking/refactoring. -use super::check; use super::compile::{run_cargo, rustc_cargo, std_cargo}; use super::tool::{RustcPrivateCompilers, SourceType, prepare_tool_cargo}; use crate::builder::{Builder, ShouldRun}; @@ -377,7 +376,10 @@ impl Step for CodegenGcc { macro_rules! lint_any { ($( - $name:ident, $path:expr, $readable_name:expr + $name:ident, + $path:expr, + $readable_name:expr, + $mode:expr $(,lint_by_default = $lint_by_default:expr)* ; )+) => { @@ -385,7 +387,8 @@ macro_rules! lint_any { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $name { - pub target: TargetSelection, + build_compiler: Compiler, + target: TargetSelection, config: LintConfig, } @@ -400,23 +403,19 @@ macro_rules! lint_any { fn make_run(run: RunConfig<'_>) { let config = LintConfig::new(run.builder); run.builder.ensure($name { + build_compiler: prepare_compiler_for_check(run.builder, run.target, $mode), target: run.target, config, }); } fn run(self, builder: &Builder<'_>) -> Self::Output { - let build_compiler = builder.compiler(builder.top_stage, builder.config.host_target); + let build_compiler = self.build_compiler; let target = self.target; - - if !builder.download_rustc() { - builder.ensure(check::Rustc::new(builder, target, vec![])); - }; - let cargo = prepare_tool_cargo( builder, build_compiler, - Mode::ToolRustc, + $mode, target, Kind::Clippy, $path, @@ -427,13 +426,13 @@ macro_rules! lint_any { let _guard = builder.msg( Kind::Clippy, $readable_name, - Mode::ToolRustc, + $mode, build_compiler, target, ); let stringified_name = stringify!($name).to_lowercase(); - let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, Mode::ToolRustc, target)) + let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, $mode, target)) .with_prefix(&format!("{}-check", stringified_name)); run_cargo( @@ -455,30 +454,32 @@ macro_rules! lint_any { } } +// Note: we use ToolTarget instead of ToolBootstrap here, to allow linting in-tree host tools +// using the in-tree Clippy. Because Mode::ToolBootstrap would always use stage 0 rustc/Clippy. lint_any!( - Bootstrap, "src/bootstrap", "bootstrap"; - BuildHelper, "src/build_helper", "build_helper"; - BuildManifest, "src/tools/build-manifest", "build-manifest"; - CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri"; - Clippy, "src/tools/clippy", "clippy"; - CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata"; - Compiletest, "src/tools/compiletest", "compiletest"; - CoverageDump, "src/tools/coverage-dump", "coverage-dump"; - Jsondocck, "src/tools/jsondocck", "jsondocck"; - Jsondoclint, "src/tools/jsondoclint", "jsondoclint"; - LintDocs, "src/tools/lint-docs", "lint-docs"; - LlvmBitcodeLinker, "src/tools/llvm-bitcode-linker", "llvm-bitcode-linker"; - Miri, "src/tools/miri", "miri"; - MiroptTestTools, "src/tools/miropt-test-tools", "miropt-test-tools"; - OptDist, "src/tools/opt-dist", "opt-dist"; - RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; - RemoteTestServer, "src/tools/remote-test-server", "remote-test-server"; - RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer"; - Rustdoc, "src/librustdoc", "clippy"; - Rustfmt, "src/tools/rustfmt", "rustfmt"; - RustInstaller, "src/tools/rust-installer", "rust-installer"; - Tidy, "src/tools/tidy", "tidy"; - TestFloatParse, "src/tools/test-float-parse", "test-float-parse"; + Bootstrap, "src/bootstrap", "bootstrap", Mode::ToolTarget; + BuildHelper, "src/build_helper", "build_helper", Mode::ToolTarget; + BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolTarget; + CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", Mode::ToolRustc; + Clippy, "src/tools/clippy", "clippy", Mode::ToolRustc; + CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata", Mode::ToolTarget; + Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolTarget; + CoverageDump, "src/tools/coverage-dump", "coverage-dump", Mode::ToolTarget; + Jsondocck, "src/tools/jsondocck", "jsondocck", Mode::ToolTarget; + Jsondoclint, "src/tools/jsondoclint", "jsondoclint", Mode::ToolTarget; + LintDocs, "src/tools/lint-docs", "lint-docs", Mode::ToolTarget; + LlvmBitcodeLinker, "src/tools/llvm-bitcode-linker", "llvm-bitcode-linker", Mode::ToolTarget; + Miri, "src/tools/miri", "miri", Mode::ToolRustc; + MiroptTestTools, "src/tools/miropt-test-tools", "miropt-test-tools", Mode::ToolTarget; + OptDist, "src/tools/opt-dist", "opt-dist", Mode::ToolTarget; + RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolTarget; + RemoteTestServer, "src/tools/remote-test-server", "remote-test-server", Mode::ToolTarget; + RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer", Mode::ToolRustc; + Rustdoc, "src/librustdoc", "clippy", Mode::ToolRustc; + Rustfmt, "src/tools/rustfmt", "rustfmt", Mode::ToolRustc; + RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::ToolTarget; + Tidy, "src/tools/tidy", "tidy", Mode::ToolTarget; + TestFloatParse, "src/tools/test-float-parse", "test-float-parse", Mode::ToolStd; ); #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -502,6 +503,7 @@ impl Step for CI { fn run(self, builder: &Builder<'_>) -> Self::Output { builder.ensure(Bootstrap { + build_compiler: prepare_compiler_for_check(builder, self.target, Mode::ToolTarget), target: self.target, config: self.config.merge(&LintConfig { allow: vec![], From 23bb607184e51870b278de3bcd2e8786c54faedf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 21:43:05 +0200 Subject: [PATCH 138/252] Add more tests --- src/bootstrap/src/core/build_steps/clippy.rs | 2 +- src/bootstrap/src/core/builder/tests.rs | 90 ++++++++++++++++++-- 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index d8cf3d0c48856..b71e5fbb95ca4 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -447,7 +447,7 @@ macro_rules! lint_any { } fn metadata(&self) -> Option { - Some(StepMetadata::clippy($readable_name, self.target)) + Some(StepMetadata::clippy($readable_name, self.target).built_by(self.build_compiler)) } } )+ diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 28bec10f06191..7fdbdd05fb683 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2073,12 +2073,11 @@ mod snapshot { ctx.config("clippy") .path("ci") .render_steps(), @r" + [clippy] rustc 0 -> bootstrap 1 [build] llvm [build] rustc 0 -> rustc 1 - [check] rustc 1 -> rustc 2 [build] rustc 0 -> clippy-driver 1 [build] rustc 0 -> cargo-clippy 1 - [clippy] bootstrap [clippy] rustc 1 -> std 1 [clippy] rustc 0 -> rustc 1 [clippy] rustc 0 -> rustc_codegen_gcc 1 @@ -2096,21 +2095,20 @@ mod snapshot { [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 + [clippy] rustc 1 -> bootstrap 2 [build] rustc 1 -> rustc 2 - [check] rustc 2 -> rustc 3 [build] rustc 1 -> clippy-driver 2 [build] rustc 1 -> cargo-clippy 2 - [clippy] bootstrap [clippy] rustc 2 -> std 2 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 [clippy] rustc 1 -> rustc 2 [clippy] rustc 1 -> rustc_codegen_gcc 2 "); } #[test] - fn clippy_compiler() { + fn clippy_compiler_stage1() { let ctx = TestCtx::new(); insta::assert_snapshot!( ctx.config("clippy") @@ -2122,7 +2120,24 @@ mod snapshot { } #[test] - fn clippy_std() { + fn clippy_compiler_stage2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("compiler") + .stage(2) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 + [clippy] rustc 1 -> rustc 2 + "); + } + + #[test] + fn clippy_std_stage1() { let ctx = TestCtx::new(); insta::assert_snapshot!( ctx.config("clippy") @@ -2135,6 +2150,65 @@ mod snapshot { [clippy] rustc 1 -> std 1 "); } + + #[test] + fn clippy_std_stage2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("std") + .stage(2) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [build] rustc 1 -> clippy-driver 2 + [build] rustc 1 -> cargo-clippy 2 + [clippy] rustc 2 -> std 2 + "); + } + + #[test] + fn clippy_miri_stage1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("miri") + .stage(1) + .render_steps(), @r" + [build] llvm + [check] rustc 0 -> rustc 1 + [clippy] rustc 0 -> miri 1 + "); + } + + #[test] + fn clippy_miri_stage2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("miri") + .stage(2) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [check] rustc 1 -> rustc 2 + [build] rustc 0 -> clippy-driver 1 + [build] rustc 0 -> cargo-clippy 1 + [clippy] rustc 1 -> miri 2 + "); + } + + #[test] + fn clippy_bootstrap() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("clippy") + .path("bootstrap") + .render_steps(), @"[clippy] rustc 0 -> bootstrap 1 "); + } } struct ExecutedSteps { From 27347831bd9d90db879fa4bf550f440217dcf81f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 21:47:18 +0200 Subject: [PATCH 139/252] Lint code in CI using in-tree Clippy --- src/ci/docker/host-x86_64/pr-check-2/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile index 6fea2437276d0..8073b8efb46f3 100644 --- a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile +++ b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile @@ -28,7 +28,7 @@ RUN sh /scripts/sccache.sh ENV SCRIPT \ python3 ../x.py check && \ - python3 ../x.py clippy ci && \ + python3 ../x.py clippy ci --stage 2 && \ python3 ../x.py test --stage 1 core alloc std test proc_macro && \ python3 ../x.py test --stage 1 src/tools/compiletest && \ python3 ../x.py doc bootstrap && \ From 75c5c36c0fe9f583773b2a21910ad920bca6abbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 21:49:10 +0200 Subject: [PATCH 140/252] Add change tracker entry --- 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 cd7fba39a8458..b454a8ddefb35 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -501,4 +501,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "The names of stageN directories in the build directory have been consolidated with the new (post-stage-0-redesign) staging scheme. Some tools and binaries might be located in a different build directory than before.", }, + ChangeInfo { + change_id: 145131, + severity: ChangeSeverity::Warning, + summary: "It is no longer possible to `x clippy` with stage 0. All clippy commands have to be on stage 1+.", + }, ]; From 92e1541f76106601bf33d3fe2bc0564b97c85d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 11 Aug 2025 19:53:55 +0200 Subject: [PATCH 141/252] Only check rustc when linting rustc_codegen_gcc --- src/bootstrap/src/core/build_steps/clippy.rs | 13 +++++-------- src/bootstrap/src/core/builder/tests.rs | 2 ++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index b71e5fbb95ca4..2f1adde70162d 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -13,7 +13,7 @@ //! (as usual) a massive undertaking/refactoring. use super::compile::{run_cargo, rustc_cargo, std_cargo}; -use super::tool::{RustcPrivateCompilers, SourceType, prepare_tool_cargo}; +use super::tool::{SourceType, prepare_tool_cargo}; use crate::builder::{Builder, ShouldRun}; use crate::core::build_steps::check::prepare_compiler_for_check; use crate::core::build_steps::compile::std_crates_for_run_make; @@ -306,7 +306,7 @@ impl Step for Rustc { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct CodegenGcc { - compilers: RustcPrivateCompilers, + build_compiler: Compiler, target: TargetSelection, config: LintConfig, } @@ -314,7 +314,7 @@ pub struct CodegenGcc { impl CodegenGcc { fn new(builder: &Builder<'_>, target: TargetSelection, config: LintConfig) -> Self { Self { - compilers: RustcPrivateCompilers::new(builder, builder.top_stage, target), + build_compiler: prepare_compiler_for_check(builder, target, Mode::Codegen), target, config, } @@ -335,7 +335,7 @@ impl Step for CodegenGcc { } fn run(self, builder: &Builder<'_>) -> Self::Output { - let build_compiler = self.compilers.build_compiler(); + let build_compiler = self.build_compiler; let target = self.target; let cargo = prepare_tool_cargo( @@ -367,10 +367,7 @@ impl Step for CodegenGcc { } fn metadata(&self) -> Option { - Some( - StepMetadata::clippy("rustc_codegen_gcc", self.target) - .built_by(self.compilers.build_compiler()), - ) + Some(StepMetadata::clippy("rustc_codegen_gcc", self.target).built_by(self.build_compiler)) } } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 7fdbdd05fb683..226732cd2af98 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2080,6 +2080,7 @@ mod snapshot { [build] rustc 0 -> cargo-clippy 1 [clippy] rustc 1 -> std 1 [clippy] rustc 0 -> rustc 1 + [check] rustc 0 -> rustc 1 [clippy] rustc 0 -> rustc_codegen_gcc 1 "); } @@ -2103,6 +2104,7 @@ mod snapshot { [build] rustc 1 -> cargo-clippy 2 [clippy] rustc 2 -> std 2 [clippy] rustc 1 -> rustc 2 + [check] rustc 1 -> rustc 2 [clippy] rustc 1 -> rustc_codegen_gcc 2 "); } From 0acfe86faa35eb47ecfe8fb36d4119c8a280e01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 11 Aug 2025 20:00:29 +0200 Subject: [PATCH 142/252] Manually optimize steps performed by `x clippy ci` --- src/bootstrap/src/core/build_steps/clippy.rs | 33 ++++++++++++++++++-- src/bootstrap/src/core/builder/tests.rs | 24 +------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 2f1adde70162d..ae35513a5444e 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -12,6 +12,8 @@ //! to pass a prebuilt Clippy from the outside when running `cargo clippy`, but that would be //! (as usual) a massive undertaking/refactoring. +use build_helper::exit; + use super::compile::{run_cargo, rustc_cargo, std_cargo}; use super::tool::{SourceType, prepare_tool_cargo}; use crate::builder::{Builder, ShouldRun}; @@ -154,6 +156,15 @@ impl Std { crates, } } + + fn from_build_compiler( + build_compiler: Compiler, + target: TargetSelection, + config: LintConfig, + crates: Vec, + ) -> Self { + Self { build_compiler, target, config, crates } + } } impl Step for Std { @@ -479,6 +490,7 @@ lint_any!( TestFloatParse, "src/tools/test-float-parse", "test-float-parse", Mode::ToolStd; ); +/// Runs Clippy on in-tree sources of selected projects using in-tree CLippy. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CI { target: TargetSelection, @@ -499,7 +511,20 @@ impl Step for CI { } fn run(self, builder: &Builder<'_>) -> Self::Output { + if builder.top_stage != 2 { + eprintln!("ERROR: `x clippy ci` should always be executed with --stage 2"); + exit!(1); + } + + // We want to check in-tree source using in-tree clippy. However, if we naively did + // a stage 2 `x clippy ci`, it would *build* a stage 2 rustc, in order to lint stage 2 + // std, which is wasteful. + // So we want to lint stage 2 [bootstrap/rustc/...], but only stage 1 std rustc_codegen_gcc. + // We thus construct the compilers in this step manually, to optimize the number of + // steps that get built. + builder.ensure(Bootstrap { + // This will be the stage 1 compiler build_compiler: prepare_compiler_for_check(builder, self.target, Mode::ToolTarget), target: self.target, config: self.config.merge(&LintConfig { @@ -509,6 +534,7 @@ impl Step for CI { forbid: vec![], }), }); + let library_clippy_cfg = LintConfig { allow: vec!["clippy::all".into()], warn: vec![], @@ -526,8 +552,9 @@ impl Step for CI { ], forbid: vec![], }; - builder.ensure(Std::new( - builder, + builder.ensure(Std::from_build_compiler( + // This will be the stage 1 compiler, to avoid building rustc stage 2 just to lint std + builder.compiler(1, self.target), self.target, self.config.merge(&library_clippy_cfg), vec![], @@ -552,6 +579,7 @@ impl Step for CI { ], forbid: vec![], }; + // This will lint stage 2 rustc using stage 1 Clippy builder.ensure(Rustc::new( builder, self.target, @@ -565,6 +593,7 @@ impl Step for CI { deny: vec!["warnings".into()], forbid: vec![], }; + // This will check stage 2 rustc builder.ensure(CodegenGcc::new( builder, self.target, diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 226732cd2af98..210f05a83464f 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2068,25 +2068,6 @@ mod snapshot { #[test] fn clippy_ci() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("ci") - .render_steps(), @r" - [clippy] rustc 0 -> bootstrap 1 - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 - [clippy] rustc 1 -> std 1 - [clippy] rustc 0 -> rustc 1 - [check] rustc 0 -> rustc 1 - [clippy] rustc 0 -> rustc_codegen_gcc 1 - "); - } - - #[test] - fn clippy_ci_stage_2() { let ctx = TestCtx::new(); insta::assert_snapshot!( ctx.config("clippy") @@ -2099,10 +2080,7 @@ mod snapshot { [build] rustc 0 -> clippy-driver 1 [build] rustc 0 -> cargo-clippy 1 [clippy] rustc 1 -> bootstrap 2 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 - [clippy] rustc 2 -> std 2 + [clippy] rustc 1 -> std 1 [clippy] rustc 1 -> rustc 2 [check] rustc 1 -> rustc 2 [clippy] rustc 1 -> rustc_codegen_gcc 2 From 2e4e0fcdb9b412d683ab28632170cc3d22d842c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 11 Aug 2025 20:33:23 +0200 Subject: [PATCH 143/252] Bless tests --- src/bootstrap/src/core/build_steps/clippy.rs | 3 ++- src/bootstrap/src/core/builder/tests.rs | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index ae35513a5444e..23d9a032eb909 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -6,7 +6,8 @@ //! which is performed by the `x clippy ci` command. //! //! In order to prepare a build compiler for running clippy, use the -//! [check::prepare_compiler_for_check] function. That prepares a compiler and a standard library +//! [prepare_compiler_for_check] function. That prepares a +//! compiler and a standard library //! for running Clippy. The second part (actually building Clippy) is performed inside //! [Builder::cargo_clippy_cmd]. It would be nice if this was more explicit, and we actually had //! to pass a prebuilt Clippy from the outside when running `cargo clippy`, but that would be diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 210f05a83464f..8669a17c5e163 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1516,6 +1516,7 @@ mod snapshot { .path("compiler") .render_steps(), @r" [check] rustc 0 -> rustc 1 + [check] rustc 0 -> rustc 1 [check] rustc 0 -> rustc_codegen_cranelift 1 [check] rustc 0 -> rustc_codegen_gcc 1 "); @@ -1548,6 +1549,7 @@ mod snapshot { .stage(1) .render_steps(), @r" [check] rustc 0 -> rustc 1 + [check] rustc 0 -> rustc 1 [check] rustc 0 -> rustc_codegen_cranelift 1 [check] rustc 0 -> rustc_codegen_gcc 1 "); @@ -1565,6 +1567,7 @@ mod snapshot { [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 [check] rustc 1 -> rustc 2 + [check] rustc 1 -> rustc 2 [check] rustc 1 -> rustc_codegen_cranelift 2 [check] rustc 1 -> rustc_codegen_gcc 2 "); @@ -1583,6 +1586,7 @@ mod snapshot { [build] rustc 1 -> std 1 [build] rustc 1 -> std 1 [check] rustc 1 -> rustc 2 + [check] rustc 1 -> rustc 2 [check] rustc 1 -> Rustdoc 2 [check] rustc 1 -> rustc_codegen_cranelift 2 [check] rustc 1 -> rustc_codegen_gcc 2 @@ -1679,6 +1683,7 @@ mod snapshot { .args(&args) .render_steps(), @r" [check] rustc 0 -> rustc 1 + [check] rustc 0 -> rustc 1 [check] rustc 0 -> rustc_codegen_cranelift 1 [check] rustc 0 -> rustc_codegen_gcc 1 "); From 6e5a6e0211677fe946b6123dfef4f39bbf576ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 13 Aug 2025 10:30:57 +0200 Subject: [PATCH 144/252] Install libgccjit into the compiler's sysroot when the GCC codegen backend is enabled --- src/bootstrap/src/core/build_steps/compile.rs | 124 ++++++++++-------- src/bootstrap/src/core/build_steps/gcc.rs | 13 ++ 2 files changed, 82 insertions(+), 55 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index c8feba48d84b2..2a236de01921e 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -18,7 +18,7 @@ use serde_derive::Deserialize; #[cfg(feature = "tracing")] use tracing::{instrument, span}; -use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; +use crate::core::build_steps::gcc::{Gcc, GccOutput, 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; @@ -1543,13 +1543,22 @@ impl Step for RustcLink { } } +/// Output of the `compile::GccCodegenBackend` step. +/// It includes the path to the libgccjit library on which this backend depends. +#[derive(Clone)] +pub struct GccCodegenBackendOutput { + stamp: BuildStamp, + gcc: GccOutput, +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GccCodegenBackend { compilers: RustcPrivateCompilers, } impl Step for GccCodegenBackend { - type Output = BuildStamp; + type Output = GccCodegenBackendOutput; + const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1584,6 +1593,8 @@ impl Step for GccCodegenBackend { &CodegenBackendKind::Gcc, ); + let gcc = builder.ensure(Gcc { target }); + if builder.config.keep_stage.contains(&build_compiler.stage) { trace!("`keep-stage` requested"); builder.info( @@ -1592,7 +1603,7 @@ impl Step for GccCodegenBackend { ); // Codegen backends are linked separately from this step today, so we don't do // anything here. - return stamp; + return GccCodegenBackendOutput { stamp, gcc }; } let mut cargo = builder::Cargo::new( @@ -1606,13 +1617,16 @@ impl Step for GccCodegenBackend { cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml")); rustc_cargo_env(builder, &mut cargo, target); - let gcc = builder.ensure(Gcc { target }); add_cg_gcc_cargo_flags(&mut cargo, &gcc); let _guard = builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, target); let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false); - write_codegen_backend_stamp(stamp, files, builder.config.dry_run()) + + GccCodegenBackendOutput { + stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()), + gcc, + } } fn metadata(&self) -> Option { @@ -2191,53 +2205,6 @@ impl Step for Assemble { ); build_compiler.stage = actual_stage; - let mut codegen_backend_stamps = vec![]; - { - #[cfg(feature = "tracing")] - let _codegen_backend_span = - span!(tracing::Level::DEBUG, "building requested codegen backends").entered(); - - for backend in builder.config.enabled_codegen_backends(target_compiler.host) { - // FIXME: this is a horrible hack used to make `x check` work when other codegen - // backends are enabled. - // `x check` will check stage 1 rustc, which copies its rmetas to the stage0 sysroot. - // Then it checks codegen backends, which correctly use these rmetas. - // Then it needs to check std, but for that it needs to build stage 1 rustc. - // This copies the build rmetas into the stage0 sysroot, effectively poisoning it, - // because we then have both check and build rmetas in the same sysroot. - // That would be fine on its own. However, when another codegen backend is enabled, - // then building stage 1 rustc implies also building stage 1 codegen backend (even if - // it isn't used for anything). And since that tries to use the poisoned - // rmetas, it fails to build. - // We don't actually need to build rustc-private codegen backends for checking std, - // so instead we skip that. - // Note: this would be also an issue for other rustc-private tools, but that is "solved" - // by check::Std being last in the list of checked things (see - // `Builder::get_step_descriptions`). - if builder.kind == Kind::Check && builder.top_stage == 1 { - continue; - } - - let prepare_compilers = || { - RustcPrivateCompilers::from_build_and_target_compiler( - build_compiler, - target_compiler, - ) - }; - - let stamp = match backend { - CodegenBackendKind::Cranelift => { - builder.ensure(CraneliftCodegenBackend { compilers: prepare_compilers() }) - } - CodegenBackendKind::Gcc => { - builder.ensure(GccCodegenBackend { compilers: prepare_compilers() }) - } - CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue, - }; - codegen_backend_stamps.push(stamp); - } - } - let stage = target_compiler.stage; let host = target_compiler.host; let (host_info, dir_name) = if build_compiler.host == host { @@ -2296,9 +2263,56 @@ impl Step for Assemble { } } - debug!("copying codegen backends to sysroot"); - for stamp in codegen_backend_stamps { - copy_codegen_backends_to_sysroot(builder, stamp, target_compiler); + { + #[cfg(feature = "tracing")] + let _codegen_backend_span = + span!(tracing::Level::DEBUG, "building requested codegen backends").entered(); + + for backend in builder.config.enabled_codegen_backends(target_compiler.host) { + // FIXME: this is a horrible hack used to make `x check` work when other codegen + // backends are enabled. + // `x check` will check stage 1 rustc, which copies its rmetas to the stage0 sysroot. + // Then it checks codegen backends, which correctly use these rmetas. + // Then it needs to check std, but for that it needs to build stage 1 rustc. + // This copies the build rmetas into the stage0 sysroot, effectively poisoning it, + // because we then have both check and build rmetas in the same sysroot. + // That would be fine on its own. However, when another codegen backend is enabled, + // then building stage 1 rustc implies also building stage 1 codegen backend (even if + // it isn't used for anything). And since that tries to use the poisoned + // rmetas, it fails to build. + // We don't actually need to build rustc-private codegen backends for checking std, + // so instead we skip that. + // Note: this would be also an issue for other rustc-private tools, but that is "solved" + // by check::Std being last in the list of checked things (see + // `Builder::get_step_descriptions`). + if builder.kind == Kind::Check && builder.top_stage == 1 { + continue; + } + + let prepare_compilers = || { + RustcPrivateCompilers::from_build_and_target_compiler( + build_compiler, + target_compiler, + ) + }; + + match backend { + CodegenBackendKind::Cranelift => { + let stamp = builder + .ensure(CraneliftCodegenBackend { compilers: prepare_compilers() }); + copy_codegen_backends_to_sysroot(builder, stamp, target_compiler); + } + CodegenBackendKind::Gcc => { + let output = + builder.ensure(GccCodegenBackend { compilers: prepare_compilers() }); + 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); + } + CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue, + } + } } if builder.config.lld_enabled { diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index d4cbbe60921fb..b1a12ef1bcb38 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -12,6 +12,7 @@ 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}; @@ -28,6 +29,18 @@ pub struct GccOutput { pub libgccjit: PathBuf, } +impl GccOutput { + /// Install the required libgccjit library file(s) to the specified `path`. + pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) { + let dst = directory.join(self.libgccjit.file_name().unwrap()); + builder.install(&self.libgccjit, directory, FileType::NativeLibrary); + // FIXME: try to remove the alias, it shouldn't be needed + // We just have to teach rustc_codegen_gcc to link to libgccjit.so directly, instead of + // linking to libgccjit.so.0. + create_lib_alias(builder, &dst); + } +} + impl Step for Gcc { type Output = GccOutput; From 76bc558e7e043fe13630b5576665b4136209875d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 13 Aug 2025 10:50:54 +0200 Subject: [PATCH 145/252] Make sure that we won't accidentally ship libgccjit.so in the dist component --- src/bootstrap/src/core/build_steps/dist.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index f9cb300b68ea1..542344886499f 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -478,7 +478,19 @@ impl Step for Rustc { if libdir_relative.to_str() != Some("bin") { let libdir = builder.rustc_libdir(compiler); for entry in builder.read_dir(&libdir) { - if is_dylib(&entry.path()) { + // A safeguard that we will not ship libgccjit.so from the libdir, in case the + // GCC codegen backend is enabled by default. + // Long-term we should probably split the config options for: + // - Include cg_gcc in the rustc sysroot by default + // - Run dist of a specific codegen backend in `x dist` by default + if is_dylib(&entry.path()) + && !entry + .path() + .file_name() + .and_then(|n| n.to_str()) + .map(|n| n.contains("libgccjit")) + .unwrap_or(false) + { // Don't use custom libdir here because ^lib/ will be resolved again // with installer builder.install(&entry.path(), &image.join("lib"), FileType::NativeLibrary); From f40a784e12226f2eecd0e2ad605e43950a9a045f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 13 Aug 2025 11:20:53 +0200 Subject: [PATCH 146/252] Remove the `libgccjit.so.0` alias and only create the versioned library when installing `libgccjit.so` --- src/bootstrap/src/core/build_steps/gcc.rs | 26 ++++++++--------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index b1a12ef1bcb38..389afaecea336 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -32,12 +32,15 @@ pub struct GccOutput { impl GccOutput { /// Install the required libgccjit library file(s) to the specified `path`. pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) { - let dst = directory.join(self.libgccjit.file_name().unwrap()); - builder.install(&self.libgccjit, directory, FileType::NativeLibrary); - // FIXME: try to remove the alias, it shouldn't be needed - // We just have to teach rustc_codegen_gcc to link to libgccjit.so directly, instead of - // linking to libgccjit.so.0. - create_lib_alias(builder, &dst); + // At build time, cg_gcc has to link to libgccjit.so (the unversioned symbol). + // However, at runtime, it will by default look for libgccjit.so.0. + // So when we install the built libgccjit.so file to the target `directory`, we add it there + // with the `.0` suffix. + let mut target_filename = self.libgccjit.file_name().unwrap().to_str().unwrap().to_string(); + target_filename.push_str(".0"); + + let dst = directory.join(target_filename); + builder.copy_link(&self.libgccjit, &dst, FileType::NativeLibrary); } } @@ -74,7 +77,6 @@ impl Step for Gcc { } build_gcc(&metadata, builder, target); - create_lib_alias(builder, &libgccjit_path); t!(metadata.stamp.write()); @@ -82,15 +84,6 @@ impl Step for Gcc { } } -/// Creates a libgccjit.so.0 alias next to libgccjit.so if it does not -/// already exist -fn create_lib_alias(builder: &Builder<'_>, libgccjit: &PathBuf) { - let lib_alias = libgccjit.parent().unwrap().join("libgccjit.so.0"); - if !lib_alias.exists() { - t!(builder.symlink_file(libgccjit, lib_alias)); - } -} - pub struct Meta { stamp: BuildStamp, out_dir: PathBuf, @@ -137,7 +130,6 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option { From ebcbcc8b73cb6fa8aad42e258ca0382db68e7876 Mon Sep 17 00:00:00 2001 From: Cathal Mullan Date: Wed, 13 Aug 2025 13:18:06 +0100 Subject: [PATCH 147/252] bootstrap: Fix jemalloc 64K page support for aarch64 tools --- src/bootstrap/src/core/build_steps/compile.rs | 1 + src/bootstrap/src/core/build_steps/tool.rs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 4519731ada7f3..edd9492225a98 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1391,6 +1391,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS // Build jemalloc on AArch64 with support for page sizes up to 64K // See: https://github.com/rust-lang/rust/pull/135081 + // See also the "JEMALLOC_SYS_WITH_LG_PAGE" setting in the tool build step. if builder.config.jemalloc(target) && target.starts_with("aarch64") && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index aa00cd03c5bb7..0c263120eeec9 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -257,6 +257,14 @@ pub fn prepare_tool_cargo( // own copy cargo.env("LZMA_API_STATIC", "1"); + // Build jemalloc on AArch64 with support for page sizes up to 64K + // See: https://github.com/rust-lang/rust/pull/135081 + // Note that `miri` always uses jemalloc. As such, there is no checking of the jemalloc build flag. + // See also the "JEMALLOC_SYS_WITH_LG_PAGE" setting in the compile build step. + if target.starts_with("aarch64") && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() { + cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16"); + } + // CFG_RELEASE is needed by rustfmt (and possibly other tools) which // import rustc-ap-rustc_attr which requires this to be set for the // `#[cfg(version(...))]` attribute. From 1d44bbe3f49fcca50664cc8229b0f36e4c30a92e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 13 Aug 2025 14:25:53 +0200 Subject: [PATCH 148/252] Use ci-mirrors for binutils in freebsd-toolchain.sh --- src/ci/docker/scripts/freebsd-toolchain.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 0d02636db9196..56b3c5cd82e7d 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -28,7 +28,9 @@ exit 1 # First up, build binutils mkdir binutils cd binutils -curl https://ftp.gnu.org/gnu/binutils/binutils-${binutils_version}.tar.bz2 | tar xjf - +# Originally downloaded from: +# https://sourceware.org/pub/binutils/releases/binutils-${binutils_version}.tar.bz2 +curl https://ci-mirrors.rust-lang.org/rustc/binutils-${binutils_version}.tar.bz2 | tar xjf - mkdir binutils-build cd binutils-build hide_output ../binutils-${binutils_version}/configure \ From 2ea2100c36edc1c12981bedf5821771e5035978a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 13 Aug 2025 14:36:29 +0200 Subject: [PATCH 149/252] Print crate count for `check::Rustc` in snapshot tests --- src/bootstrap/src/core/build_steps/check.rs | 8 +++++++- src/bootstrap/src/core/builder/tests.rs | 14 ++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index ae258bf2939ca..6d393446d458e 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -232,7 +232,13 @@ impl Step for Rustc { } fn metadata(&self) -> Option { - Some(StepMetadata::check("rustc", self.target).built_by(self.build_compiler)) + let metadata = StepMetadata::check("rustc", self.target).built_by(self.build_compiler); + let metadata = if self.crates.is_empty() { + metadata + } else { + metadata.with_metadata(format!("({} crates)", self.crates.len())) + }; + Some(metadata) } } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 8669a17c5e163..9ba57542549b5 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1515,7 +1515,7 @@ mod snapshot { ctx.config("check") .path("compiler") .render_steps(), @r" - [check] rustc 0 -> rustc 1 + [check] rustc 0 -> rustc 1 (73 crates) [check] rustc 0 -> rustc 1 [check] rustc 0 -> rustc_codegen_cranelift 1 [check] rustc 0 -> rustc_codegen_gcc 1 @@ -1528,9 +1528,7 @@ mod snapshot { insta::assert_snapshot!( ctx.config("check") .path("rustc") - .render_steps(), @r" - [check] rustc 0 -> rustc 1 - "); + .render_steps(), @"[check] rustc 0 -> rustc 1 (1 crates)"); } #[test] @@ -1548,7 +1546,7 @@ mod snapshot { .path("compiler") .stage(1) .render_steps(), @r" - [check] rustc 0 -> rustc 1 + [check] rustc 0 -> rustc 1 (73 crates) [check] rustc 0 -> rustc 1 [check] rustc 0 -> rustc_codegen_cranelift 1 [check] rustc 0 -> rustc_codegen_gcc 1 @@ -1566,7 +1564,7 @@ mod snapshot { [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 - [check] rustc 1 -> rustc 2 + [check] rustc 1 -> rustc 2 (73 crates) [check] rustc 1 -> rustc 2 [check] rustc 1 -> rustc_codegen_cranelift 2 [check] rustc 1 -> rustc_codegen_gcc 2 @@ -1585,7 +1583,7 @@ mod snapshot { [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 [build] rustc 1 -> std 1 - [check] rustc 1 -> rustc 2 + [check] rustc 1 -> rustc 2 (73 crates) [check] rustc 1 -> rustc 2 [check] rustc 1 -> Rustdoc 2 [check] rustc 1 -> rustc_codegen_cranelift 2 @@ -1682,7 +1680,7 @@ mod snapshot { .paths(&["library", "compiler"]) .args(&args) .render_steps(), @r" - [check] rustc 0 -> rustc 1 + [check] rustc 0 -> rustc 1 (73 crates) [check] rustc 0 -> rustc 1 [check] rustc 0 -> rustc_codegen_cranelift 1 [check] rustc 0 -> rustc_codegen_gcc 1 From cd79c7189db7b611f9199fd12ba56563afa18642 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 13 Aug 2025 14:44:26 +0200 Subject: [PATCH 150/252] Correctly handle when there are no unstable items in the documented crate --- src/librustdoc/html/static/js/search.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 10e01b4e26274..0011544d16e2f 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2060,7 +2060,9 @@ class DocSearch { // Deprecated and unstable items and items with no description this.searchIndexDeprecated.set(crate, new RoaringBitmap(crateCorpus.c)); this.searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e)); - this.searchIndexUnstable.set(crate, new RoaringBitmap(crateCorpus.u)); + if (crateCorpus.u !== undefined && crateCorpus.u !== null) { + this.searchIndexUnstable.set(crate, new RoaringBitmap(crateCorpus.u)); + } let descIndex = 0; /** From a0eea23317e60ef1b648abd0fe76ca89362ac44d Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 12 Aug 2025 18:36:16 +0800 Subject: [PATCH 151/252] doc test: fix mpsc.rs try_send doc test Signed-off-by: Eval EXEC --- library/std/src/sync/mpsc.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs index 41d1dd3ce674b..03d7fddc2faef 100644 --- a/library/std/src/sync/mpsc.rs +++ b/library/std/src/sync/mpsc.rs @@ -697,14 +697,14 @@ impl SyncSender { /// let sync_sender2 = sync_sender.clone(); /// /// // First thread owns sync_sender - /// thread::spawn(move || { + /// let handle1 = thread::spawn(move || { /// sync_sender.send(1).unwrap(); /// sync_sender.send(2).unwrap(); /// // Thread blocked /// }); /// /// // Second thread owns sync_sender2 - /// thread::spawn(move || { + /// let handle2 = thread::spawn(move || { /// // This will return an error and send /// // no message if the buffer is full /// let _ = sync_sender2.try_send(3); @@ -722,6 +722,10 @@ impl SyncSender { /// Ok(msg) => println!("message {msg} received"), /// Err(_) => println!("the third message was never sent"), /// } + /// + /// // Wait for threads to complete + /// handle1.join().unwrap(); + /// handle2.join().unwrap(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn try_send(&self, t: T) -> Result<(), TrySendError> { From dc0707a4d85f44d2b714d02be0e78cb1f9cc8fbc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 13 Aug 2025 16:02:20 +0200 Subject: [PATCH 152/252] Add another example for escaped `#` character in doctest in rustdoc book --- .../src/write-documentation/documentation-tests.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md index e6b15e0dbd325..4084c1d962a22 100644 --- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md +++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md @@ -191,6 +191,20 @@ We can document it by escaping the initial `#`: /// ## bar # baz"; ``` +Here is an example with a macro rule which matches on tokens starting with `#`: + +`````rust,no_run +/// ``` +/// macro_rules! ignore { (##tag) => {}; } +/// ignore! { +/// ###tag +/// } +/// ``` +# fn f() {} +````` + +As you can see, the rule is expecting two `#`, so when calling it, we need to add an extra `#` +because the first one is used as escape. ## Using `?` in doc tests From d4eb0947f133d8f44594d7551d99a48daff21c02 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 12 Aug 2025 17:57:02 -0500 Subject: [PATCH 153/252] Cleanup assoc parent utils --- .../src/diagnostics/mutability_errors.rs | 3 +- compiler/rustc_borrowck/src/type_check/mod.rs | 5 +-- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 43 ++++++++----------- .../rustc_const_eval/src/interpret/call.rs | 2 +- .../src/check/compare_impl_item.rs | 6 +-- .../rustc_hir_analysis/src/check/wfcheck.rs | 3 +- compiler/rustc_lint/src/pass_by_value.rs | 6 +-- compiler/rustc_lint/src/types.rs | 5 +-- compiler/rustc_middle/src/middle/privacy.rs | 6 +-- compiler/rustc_middle/src/ty/mod.rs | 39 ++++++++++++++--- .../src/check_call_recursion.rs | 4 +- .../src/check_packed_ref.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 2 +- .../rustc_monomorphize/src/partitioning.rs | 13 +++--- compiler/rustc_passes/src/dead.rs | 2 +- .../src/traits/project.rs | 2 +- 16 files changed, 79 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 5d9416b59fcec..c0ca35f9ff83a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -677,12 +677,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { /// - is the trait from the local crate? If not, we can't suggest changing signatures /// - `Span` of the argument in the trait definition fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option) { + let tcx = self.infcx.tcx; if self.body.local_kind(local) != LocalKind::Arg { return (false, false, None); } let my_def = self.body.source.def_id(); let Some(td) = - self.infcx.tcx.impl_of_assoc(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x)) + tcx.trait_impl_of_assoc(my_def).and_then(|id| self.infcx.tcx.trait_id_of_impl(id)) else { return (false, false, None); }; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index c3aa205d5aab3..a960b96b91c20 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1773,10 +1773,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { locations, ); - assert!(!matches!( - tcx.impl_of_assoc(def_id).map(|imp| tcx.def_kind(imp)), - Some(DefKind::Impl { of_trait: true }) - )); + assert_eq!(tcx.trait_impl_of_assoc(def_id), None); self.prove_predicates( args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())), locations, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 6cbf2dbf7d3fd..2c3a84499ac55 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -533,31 +533,26 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { // First, let's see if this is a method within an inherent impl. Because // if yes, we want to make the result subroutine DIE a child of the // subroutine's self-type. - if let Some(impl_def_id) = cx.tcx.impl_of_assoc(instance.def_id()) { - // If the method does *not* belong to a trait, proceed - if cx.tcx.trait_id_of_impl(impl_def_id).is_none() { - let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions( - instance.args, - cx.typing_env(), - cx.tcx.type_of(impl_def_id), - ); - - // Only "class" methods are generally understood by LLVM, - // so avoid methods on other types (e.g., `<*mut T>::null`). - if let ty::Adt(def, ..) = impl_self_ty.kind() - && !def.is_box() - { - // Again, only create type information if full debuginfo is enabled - if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() - { - return (type_di_node(cx, impl_self_ty), true); - } else { - return (namespace::item_namespace(cx, def.did()), false); - } + // For trait method impls we still use the "parallel namespace" + // strategy + if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) { + let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions( + instance.args, + cx.typing_env(), + cx.tcx.type_of(imp_def_id), + ); + + // Only "class" methods are generally understood by LLVM, + // so avoid methods on other types (e.g., `<*mut T>::null`). + if let ty::Adt(def, ..) = impl_self_ty.kind() + && !def.is_box() + { + // Again, only create type information if full debuginfo is enabled + if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() { + return (type_di_node(cx, impl_self_ty), true); + } else { + return (namespace::item_namespace(cx, def.did()), false); } - } else { - // For trait method impls we still use the "parallel namespace" - // strategy } } diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index b1cc0cc2878aa..21237cfe49216 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -731,7 +731,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) { let tcx = *self.tcx; - let trait_def_id = tcx.trait_of_assoc(def_id).unwrap(); + let trait_def_id = tcx.parent(def_id); let virtual_trait_ref = ty::TraitRef::from_assoc(tcx, trait_def_id, virtual_instance.args); let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6767e5ed88d4d..e482725619398 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -445,10 +445,10 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( tcx: TyCtxt<'tcx>, impl_m_def_id: LocalDefId, ) -> Result<&'tcx DefIdMap>>, ErrorGuaranteed> { - let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap(); - let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap(); + let impl_m = tcx.associated_item(impl_m_def_id.to_def_id()); + let trait_m = tcx.associated_item(impl_m.trait_item_def_id.unwrap()); let impl_trait_ref = - tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().instantiate_identity(); + tcx.impl_trait_ref(tcx.parent(impl_m_def_id.to_def_id())).unwrap().instantiate_identity(); // First, check a few of the same things as `compare_impl_method`, // just so we don't ICE during instantiation later. check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index c642435b9893c..e6a1f6d8d8bb7 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2287,8 +2287,7 @@ fn lint_redundant_lifetimes<'tcx>( // Proceed } DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { - let parent_def_id = tcx.local_parent(owner_id); - if matches!(tcx.def_kind(parent_def_id), DefKind::Impl { of_trait: true }) { + if tcx.trait_impl_of_assoc(owner_id.to_def_id()).is_some() { // Don't check for redundant lifetimes for associated items of trait // implementations, since the signature is required to be compatible // with the trait, even if the implementation implies some lifetimes diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 4f65acd8001ed..29006732aade5 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -24,10 +24,8 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) { match &ty.kind { TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => { - if let Some(impl_did) = cx.tcx.impl_of_assoc(ty.hir_id.owner.to_def_id()) { - if cx.tcx.impl_trait_ref(impl_did).is_some() { - return; - } + if cx.tcx.trait_impl_of_assoc(ty.hir_id.owner.to_def_id()).is_some() { + return; } if let Some(t) = path_for_pass_by_value(cx, inner_ty) { cx.emit_span_lint( diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index b0afc333ebe2f..f8a692313f030 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1904,10 +1904,9 @@ impl InvalidAtomicOrdering { if let ExprKind::MethodCall(method_path, _, args, _) = &expr.kind && recognized_names.contains(&method_path.ident.name) && let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && let Some(impl_did) = cx.tcx.impl_of_assoc(m_def_id) - && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() // skip extension traits, only lint functions from the standard library - && cx.tcx.trait_id_of_impl(impl_did).is_none() + && let Some(impl_did) = cx.tcx.inherent_impl_of_assoc(m_def_id) + && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() && let parent = cx.tcx.parent(adt.did()) && cx.tcx.is_diagnostic_item(sym::atomic_mod, parent) && ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did())) diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 785ddd1ee2980..e3e04c9d1800b 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -181,11 +181,7 @@ impl EffectiveVisibilities { // nominal visibility. For some items nominal visibility doesn't make sense so we // don't check this condition for them. let is_impl = matches!(tcx.def_kind(def_id), DefKind::Impl { .. }); - let is_associated_item_in_trait_impl = tcx - .impl_of_assoc(def_id.to_def_id()) - .and_then(|impl_id| tcx.trait_id_of_impl(impl_id)) - .is_some(); - if !is_impl && !is_associated_item_in_trait_impl { + if !is_impl && tcx.trait_impl_of_assoc(def_id.to_def_id()).is_none() { let nominal_vis = tcx.visibility(def_id); if !nominal_vis.is_at_least(ev.reachable, tcx) { span_bug!( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 73e1661106eaf..e70c98ab70425 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1925,21 +1925,50 @@ impl<'tcx> TyCtxt<'tcx> { self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id) } - /// If the given `DefId` is an associated item, returns the `DefId` of the parent trait or impl. - pub fn assoc_parent(self, def_id: DefId) -> Option { - self.def_kind(def_id).is_assoc().then(|| self.parent(def_id)) + /// If the given `DefId` is an associated item, returns the `DefId` and `DefKind` of the parent trait or impl. + pub fn assoc_parent(self, def_id: DefId) -> Option<(DefId, DefKind)> { + if !self.def_kind(def_id).is_assoc() { + return None; + } + let parent = self.parent(def_id); + let def_kind = self.def_kind(parent); + Some((parent, def_kind)) } /// If the given `DefId` is an associated item of a trait, /// returns the `DefId` of the trait; otherwise, returns `None`. pub fn trait_of_assoc(self, def_id: DefId) -> Option { - self.assoc_parent(def_id).filter(|id| self.def_kind(id) == DefKind::Trait) + match self.assoc_parent(def_id) { + Some((id, DefKind::Trait)) => Some(id), + _ => None, + } } /// If the given `DefId` is an associated item of an impl, /// returns the `DefId` of the impl; otherwise returns `None`. pub fn impl_of_assoc(self, def_id: DefId) -> Option { - self.assoc_parent(def_id).filter(|id| matches!(self.def_kind(id), DefKind::Impl { .. })) + match self.assoc_parent(def_id) { + Some((id, DefKind::Impl { .. })) => Some(id), + _ => None, + } + } + + /// If the given `DefId` is an associated item of an inherent impl, + /// returns the `DefId` of the impl; otherwise, returns `None`. + pub fn inherent_impl_of_assoc(self, def_id: DefId) -> Option { + match self.assoc_parent(def_id) { + Some((id, DefKind::Impl { of_trait: false })) => Some(id), + _ => None, + } + } + + /// If the given `DefId` is an associated item of a trait impl, + /// returns the `DefId` of the impl; otherwise, returns `None`. + pub fn trait_impl_of_assoc(self, def_id: DefId) -> Option { + match self.assoc_parent(def_id) { + Some((id, DefKind::Impl { of_trait: true })) => Some(id), + _ => None, + } } pub fn is_exportable(self, def_id: DefId) -> bool { diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs index 6d61ac2dd8037..a9acb1da5a3e0 100644 --- a/compiler/rustc_mir_transform/src/check_call_recursion.rs +++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs @@ -43,8 +43,8 @@ impl<'tcx> MirLint<'tcx> for CheckDropRecursion { // First check if `body` is an `fn drop()` of `Drop` if let DefKind::AssocFn = tcx.def_kind(def_id) - && let Some(trait_ref) = - tcx.impl_of_assoc(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) + && let Some(impl_id) = tcx.trait_impl_of_assoc(def_id.to_def_id()) + && let trait_ref = tcx.impl_trait_ref(impl_id).unwrap() && tcx.is_lang_item(trait_ref.instantiate_identity().def_id, LangItem::Drop) // avoid erroneous `Drop` impls from causing ICEs below && let sig = tcx.fn_sig(def_id).instantiate_identity() diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index dcb812c78993e..100104e9de03e 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -40,7 +40,7 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.typing_env, *place) { let def_id = self.body.source.instance.def_id(); - if let Some(impl_def_id) = self.tcx.impl_of_assoc(def_id) + if let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(def_id) && self.tcx.is_builtin_derived(impl_def_id) { // If we ever reach here it means that the generated derive diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index c687036f544dc..c6760b3583f20 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -75,7 +75,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id)) } ty::InstanceKind::FnPtrShim(def_id, ty) => { - let trait_ = tcx.trait_of_assoc(def_id).unwrap(); + let trait_ = tcx.parent(def_id); // Supports `Fn` or `async Fn` traits. let adjustment = match tcx .fn_trait_kind_from_def_id(trait_) diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index d76b27d9970b6..54d77b182f8d8 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -650,17 +650,18 @@ fn characteristic_def_id_of_mono_item<'tcx>( // its self-type. If the self-type does not provide a characteristic // DefId, we use the location of the impl after all. - if tcx.trait_of_assoc(def_id).is_some() { + let assoc_parent = tcx.assoc_parent(def_id); + + if let Some((_, DefKind::Trait)) = assoc_parent { let self_ty = instance.args.type_at(0); // This is a default implementation of a trait method. return characteristic_def_id_of_type(self_ty).or(Some(def_id)); } - if let Some(impl_def_id) = tcx.impl_of_assoc(def_id) { - if tcx.sess.opts.incremental.is_some() - && tcx - .trait_id_of_impl(impl_def_id) - .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Drop)) + if let Some((impl_def_id, DefKind::Impl { of_trait })) = assoc_parent { + if of_trait + && tcx.sess.opts.incremental.is_some() + && tcx.is_lang_item(tcx.trait_id_of_impl(impl_def_id).unwrap(), LangItem::Drop) { // Put `Drop::drop` into the same cgu as `drop_in_place` // since `drop_in_place` is the only thing that can diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index de52973acbb4a..08d06402000ae 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -371,7 +371,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { /// will be ignored for the purposes of dead code analysis (see PR #85200 /// for discussion). fn should_ignore_item(&mut self, def_id: DefId) -> bool { - if let Some(impl_of) = self.tcx.impl_of_assoc(def_id) { + if let Some(impl_of) = self.tcx.trait_impl_of_assoc(def_id) { if !self.tcx.is_automatically_derived(impl_of) { return false; } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 581191b2036d2..884d53732fe2a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1507,7 +1507,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( let tcx = selcx.tcx(); let self_ty = obligation.predicate.self_ty(); let item_def_id = obligation.predicate.def_id; - let trait_def_id = tcx.trait_of_assoc(item_def_id).unwrap(); + let trait_def_id = tcx.parent(item_def_id); let args = tcx.mk_args(&[self_ty.into()]); let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) { let discriminant_def_id = From 772493d51d24dabbffdc54aaf48859eec85d544e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 1 Aug 2025 18:07:59 +0300 Subject: [PATCH 154/252] resolve: Split extern prelude into two scopes One for `--extern` options and another for `extern crate` items. --- .../src/error_codes/E0578.md | 4 +- .../rustc_resolve/src/build_reduced_graph.rs | 21 ++--- compiler/rustc_resolve/src/diagnostics.rs | 4 +- compiler/rustc_resolve/src/ident.rs | 61 +++++++++----- compiler/rustc_resolve/src/lib.rs | 80 +++++++++++-------- tests/ui/imports/issue-109148.rs | 3 +- tests/ui/imports/issue-109148.stderr | 44 +++++++++- .../issue-78325-inconsistent-resolution.rs | 5 +- ...issue-78325-inconsistent-resolution.stderr | 46 ++++++++++- .../ui/resolve/extern-prelude-speculative.rs | 10 +++ tests/ui/resolve/visibility-indeterminate.rs | 2 +- .../resolve/visibility-indeterminate.stderr | 8 +- tests/ui/rust-2018/uniform-paths/deadlock.rs | 2 +- .../rust-2018/uniform-paths/deadlock.stderr | 8 +- 14 files changed, 212 insertions(+), 86 deletions(-) create mode 100644 tests/ui/resolve/extern-prelude-speculative.rs diff --git a/compiler/rustc_error_codes/src/error_codes/E0578.md b/compiler/rustc_error_codes/src/error_codes/E0578.md index fca89757287f5..78fabe855bb6d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0578.md +++ b/compiler/rustc_error_codes/src/error_codes/E0578.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + A module cannot be found and therefore, the visibility cannot be determined. Erroneous code example: -```compile_fail,E0578,edition2018 +```ignore (no longer emitted) foo!(); pub (in ::Sea) struct Shark; // error! diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3fee2ab6afe1e..819a5950f1799 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -971,40 +971,35 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let imported_binding = self.r.import(binding, import); if ident.name != kw::Underscore && parent == self.r.graph_root { let norm_ident = Macros20NormalizedIdent::new(ident); + // FIXME: this error is technically unnecessary now when extern prelude is split into + // two scopes, remove it with lang team approval. if let Some(entry) = self.r.extern_prelude.get(&norm_ident) && expansion != LocalExpnId::ROOT && orig_name.is_some() - && !entry.is_import() + && entry.item_binding.is_none() { self.r.dcx().emit_err( errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span }, ); - // `return` is intended to discard this binding because it's an - // unregistered ambiguity error which would result in a panic - // caused by inconsistency `path_res` - // more details: https://github.com/rust-lang/rust/pull/111761 - return; } use indexmap::map::Entry; match self.r.extern_prelude.entry(norm_ident) { Entry::Occupied(mut occupied) => { let entry = occupied.get_mut(); - if let Some(old_binding) = entry.binding.get() - && old_binding.is_import() - { + if entry.item_binding.is_some() { let msg = format!("extern crate `{ident}` already in extern prelude"); self.r.tcx.dcx().span_delayed_bug(item.span, msg); } else { - // Binding from `extern crate` item in source code can replace - // a binding from `--extern` on command line here. - entry.binding.set(Some(imported_binding)); + entry.item_binding = Some(imported_binding); entry.introduced_by_item = orig_name.is_some(); } entry } Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { - binding: Cell::new(Some(imported_binding)), + item_binding: Some(imported_binding), + flag_binding: Cell::new(None), + only_item: true, introduced_by_item: true, }), }; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 210ab72678c56..e5321c7f3be61 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1096,12 +1096,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } } - Scope::ExternPrelude => { + Scope::ExternPreludeItems => { + // Add idents from both item and flag scopes. suggestions.extend(this.extern_prelude.keys().filter_map(|ident| { let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); filter_fn(res).then_some(TypoSuggestion::typo_from_ident(ident.0, res)) })); } + Scope::ExternPreludeFlags => {} Scope::ToolPrelude => { let res = Res::NonMacroAttr(NonMacroAttrKind::Tool); suggestions.extend( diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 9efcef695b7b4..1864540655cbe 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -102,6 +102,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ScopeSet::All(ns) | ScopeSet::ModuleAndExternPrelude(ns, _) | ScopeSet::Late(ns, ..) => (ns, None), + ScopeSet::ExternPrelude => (TypeNS, None), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), }; let module = match scope_set { @@ -111,8 +112,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => parent_scope.module.nearest_item_scope(), }; let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)); + let extern_prelude = matches!(scope_set, ScopeSet::ExternPrelude); let mut scope = match ns { _ if module_and_extern_prelude => Scope::Module(module, None), + _ if extern_prelude => Scope::ExternPreludeItems, TypeNS | ValueNS => Scope::Module(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; @@ -143,7 +146,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::Module(..) => true, Scope::MacroUsePrelude => use_prelude || rust_2015, Scope::BuiltinAttrs => true, - Scope::ExternPrelude => use_prelude || module_and_extern_prelude, + Scope::ExternPreludeItems | Scope::ExternPreludeFlags => { + use_prelude || module_and_extern_prelude || extern_prelude + } Scope::ToolPrelude => use_prelude, Scope::StdLibPrelude => use_prelude || ns == MacroNS, Scope::BuiltinTypes => true, @@ -182,7 +187,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::Module(..) if module_and_extern_prelude => match ns { TypeNS => { ctxt.adjust(ExpnId::root()); - Scope::ExternPrelude + Scope::ExternPreludeItems } ValueNS | MacroNS => break, }, @@ -199,7 +204,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => { ctxt.adjust(ExpnId::root()); match ns { - TypeNS => Scope::ExternPrelude, + TypeNS => Scope::ExternPreludeItems, ValueNS => Scope::StdLibPrelude, MacroNS => Scope::MacroUsePrelude, } @@ -208,8 +213,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::MacroUsePrelude => Scope::StdLibPrelude, Scope::BuiltinAttrs => break, // nowhere else to search - Scope::ExternPrelude if module_and_extern_prelude => break, - Scope::ExternPrelude => Scope::ToolPrelude, + Scope::ExternPreludeItems => Scope::ExternPreludeFlags, + Scope::ExternPreludeFlags if module_and_extern_prelude || extern_prelude => break, + Scope::ExternPreludeFlags => Scope::ToolPrelude, Scope::ToolPrelude => Scope::StdLibPrelude, Scope::StdLibPrelude => match ns { TypeNS => Scope::BuiltinTypes, @@ -413,6 +419,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ScopeSet::All(ns) | ScopeSet::ModuleAndExternPrelude(ns, _) | ScopeSet::Late(ns, ..) => (ns, None), + ScopeSet::ExternPrelude => (TypeNS, None), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), }; @@ -429,6 +436,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // to detect potential ambiguities. let mut innermost_result: Option<(NameBinding<'_>, Flags)> = None; let mut determinacy = Determinacy::Determined; + // Shadowed bindings don't need to be marked as used or non-speculatively loaded. + macro finalize_scope() { + if innermost_result.is_none() { finalize } else { None } + } // Go through all the scopes and try to resolve the name. let break_result = self.visit_scopes( @@ -494,7 +505,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => Err(Determinacy::Determined), }, Scope::Module(module, derive_fallback_lint_id) => { - let (adjusted_parent_scope, finalize) = + // FIXME: use `finalize_scope` here. + let (adjusted_parent_scope, adjusted_finalize) = if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) { (parent_scope, finalize) } else { @@ -513,7 +525,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { Shadowing::Restricted }, - finalize, + adjusted_finalize, ignore_binding, ignore_import, ); @@ -561,14 +573,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(binding) => Ok((*binding, Flags::empty())), None => Err(Determinacy::Determined), }, - Scope::ExternPrelude => { - match this.reborrow().extern_prelude_get(ident, finalize.is_some()) { + Scope::ExternPreludeItems => { + // FIXME: use `finalize_scope` here. + match this.reborrow().extern_prelude_get_item(ident, finalize.is_some()) { Some(binding) => Ok((binding, Flags::empty())), None => Err(Determinacy::determined( this.graph_root.unexpanded_invocations.borrow().is_empty(), )), } } + Scope::ExternPreludeFlags => { + match this.extern_prelude_get_flag(ident, finalize_scope!().is_some()) { + Some(binding) => Ok((binding, Flags::empty())), + None => Err(Determinacy::Determined), + } + } Scope::ToolPrelude => match this.registered_tool_bindings.get(&ident) { Some(binding) => Ok((*binding, Flags::empty())), None => Err(Determinacy::Determined), @@ -599,8 +618,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if matches!(ident.name, sym::f16) && !this.tcx.features().f16() && !ident.span.allows_unstable(sym::f16) - && finalize.is_some() - && innermost_result.is_none() + && finalize_scope!().is_some() { feature_err( this.tcx.sess, @@ -613,8 +631,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if matches!(ident.name, sym::f128) && !this.tcx.features().f128() && !ident.span.allows_unstable(sym::f128) - && finalize.is_some() - && innermost_result.is_none() + && finalize_scope!().is_some() { feature_err( this.tcx.sess, @@ -829,15 +846,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { assert_eq!(shadowing, Shadowing::Unrestricted); return if ns != TypeNS { Err((Determined, Weak::No)) - } else if let Some(binding) = - self.reborrow().extern_prelude_get(ident, finalize.is_some()) - { - Ok(binding) - } else if !self.graph_root.unexpanded_invocations.borrow().is_empty() { - // Macro-expanded `extern crate` items can add names to extern prelude. - Err((Undetermined, Weak::No)) } else { - Err((Determined, Weak::No)) + let binding = self.early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::ExternPrelude, + parent_scope, + finalize, + finalize.is_some(), + ignore_binding, + ignore_import, + ); + return binding.map_err(|determinacy| (determinacy, Weak::No)); }; } ModuleOrUniformRoot::CurrentScope => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b43f71913d9ba..15dd7069602b2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -15,6 +15,7 @@ #![feature(arbitrary_self_types)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(decl_macro)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(rustc_attrs)] @@ -113,34 +114,46 @@ impl Determinacy { } /// A specific scope in which a name can be looked up. -/// This enum is currently used only for early resolution (imports and macros), -/// but not for late resolution yet. #[derive(Clone, Copy, Debug)] enum Scope<'ra> { + /// Inert attributes registered by derive macros. DeriveHelpers(LocalExpnId), + /// Inert attributes registered by derive macros, but used before they are actually declared. + /// This scope will exist until the compatibility lint `LEGACY_DERIVE_HELPERS` + /// is turned into a hard error. DeriveHelpersCompat, + /// Textual `let`-like scopes introduced by `macro_rules!` items. MacroRules(MacroRulesScopeRef<'ra>), - // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` - // lint if it should be reported. + /// Names declared in the given module. + /// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` + /// lint if it should be reported. Module(Module<'ra>, Option), + /// Names introduced by `#[macro_use]` attributes on `extern crate` items. MacroUsePrelude, + /// Built-in attributes. BuiltinAttrs, - ExternPrelude, + /// Extern prelude names introduced by `extern crate` items. + ExternPreludeItems, + /// Extern prelude names introduced by `--extern` flags. + ExternPreludeFlags, + /// Tool modules introduced with `#![register_tool]`. ToolPrelude, + /// Standard library prelude introduced with an internal `#[prelude_import]` import. StdLibPrelude, + /// Built-in types. BuiltinTypes, } /// Names from different contexts may want to visit different subsets of all specific scopes /// with different restrictions when looking up the resolution. -/// This enum is currently used only for early resolution (imports and macros), -/// but not for late resolution yet. #[derive(Clone, Copy, Debug)] enum ScopeSet<'ra> { /// All scopes with the given namespace. All(Namespace), /// A module, then extern prelude (used for mixed 2015-2018 mode in macros). ModuleAndExternPrelude(Namespace, Module<'ra>), + /// Just two extern prelude scopes. + ExternPrelude, /// All scopes with macro namespace and the given macro kind restriction. Macro(MacroKind), /// All scopes with the given namespace, used for partially performing late resolution. @@ -1012,16 +1025,18 @@ impl<'ra> NameBindingData<'ra> { #[derive(Default, Clone)] struct ExternPreludeEntry<'ra> { - binding: Cell>>, + /// Binding from an `extern crate` item. + item_binding: Option>, + /// Binding from an `--extern` flag, lazily populated on first use. + flag_binding: Cell>>, + /// There was no `--extern` flag introducing this name, + /// `flag_binding` doesn't need to be populated. + only_item: bool, + /// `item_binding` is non-redundant, happens either when `only_item` is true, + /// or when `extern crate` introducing `item_binding` used renaming. introduced_by_item: bool, } -impl ExternPreludeEntry<'_> { - fn is_import(&self) -> bool { - self.binding.get().is_some_and(|binding| binding.is_import()) - } -} - struct DeriveData { resolutions: Vec, helper_attrs: Vec<(usize, Ident)>, @@ -1889,7 +1904,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); } } - Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {} + Scope::ExternPreludeItems + | Scope::ExternPreludeFlags + | Scope::ToolPrelude + | Scope::BuiltinTypes => {} _ => unreachable!(), } None::<()> @@ -2054,7 +2072,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // but not introduce it, as used if they are accessed from lexical scope. if used == Used::Scope { if let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) { - if !entry.introduced_by_item && entry.binding.get() == Some(used_binding) { + if !entry.introduced_by_item && entry.item_binding == Some(used_binding) { return; } } @@ -2210,26 +2228,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn extern_prelude_get<'r>( + fn extern_prelude_get_item<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, ident: Ident, finalize: bool, ) -> Option> { - let mut record_use = None; let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - let binding = entry.and_then(|entry| match entry.binding.get() { - Some(binding) if binding.is_import() => { - if finalize { - record_use = Some(binding); - } - Some(binding) + entry.and_then(|entry| entry.item_binding).map(|binding| { + if finalize { + self.get_mut().record_use(ident, binding, Used::Scope); } + binding + }) + } + + fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option> { + let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); + entry.and_then(|entry| match entry.flag_binding.get() { Some(binding) => { if finalize { self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); } Some(binding) } + None if entry.only_item => None, None => { let crate_id = if finalize { self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) @@ -2241,19 +2263,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); let binding = self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); - entry.binding.set(Some(binding)); + entry.flag_binding.set(Some(binding)); Some(binding) } None => finalize.then_some(self.dummy_binding), } } - }); - - if let Some(binding) = record_use { - self.get_mut().record_use(ident, binding, Used::Scope); - } - - binding + }) } /// Rustdoc uses this to resolve doc link paths in a recoverable way. `PathResult<'a>` diff --git a/tests/ui/imports/issue-109148.rs b/tests/ui/imports/issue-109148.rs index 9d657a8738102..49fc2fe0f5bc6 100644 --- a/tests/ui/imports/issue-109148.rs +++ b/tests/ui/imports/issue-109148.rs @@ -10,6 +10,7 @@ macro_rules! m { m!(); -use std::mem; +use std::mem; //~ ERROR `std` is ambiguous +use ::std::mem as _; //~ ERROR `std` is ambiguous fn main() {} diff --git a/tests/ui/imports/issue-109148.stderr b/tests/ui/imports/issue-109148.stderr index b7f1f69dc8f0c..eead173ba7a9a 100644 --- a/tests/ui/imports/issue-109148.stderr +++ b/tests/ui/imports/issue-109148.stderr @@ -9,5 +9,47 @@ LL | m!(); | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error[E0659]: `std` is ambiguous + --> $DIR/issue-109148.rs:13:5 + | +LL | use std::mem; + | ^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `std` could refer to a built-in crate + = help: use `::std` to refer to this crate unambiguously +note: `std` could also refer to the crate imported here + --> $DIR/issue-109148.rs:6:9 + | +LL | extern crate core as std; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + = help: use `::std` to refer to this crate unambiguously + = help: or use `crate::std` to refer to this crate unambiguously + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `std` is ambiguous + --> $DIR/issue-109148.rs:14:7 + | +LL | use ::std::mem as _; + | ^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `std` could refer to a built-in crate + = help: use `::std` to refer to this crate unambiguously +note: `std` could also refer to the crate imported here + --> $DIR/issue-109148.rs:6:9 + | +LL | extern crate core as std; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + = help: use `::std` to refer to this crate unambiguously + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/macros/issue-78325-inconsistent-resolution.rs b/tests/ui/macros/issue-78325-inconsistent-resolution.rs index 919eca4f9bf6d..021ba599d126a 100644 --- a/tests/ui/macros/issue-78325-inconsistent-resolution.rs +++ b/tests/ui/macros/issue-78325-inconsistent-resolution.rs @@ -1,3 +1,5 @@ +//@ edition: 2018 + macro_rules! define_other_core { ( ) => { extern crate std as core; @@ -6,7 +8,8 @@ macro_rules! define_other_core { } fn main() { - core::panic!(); + core::panic!(); //~ ERROR `core` is ambiguous + ::core::panic!(); //~ ERROR `core` is ambiguous } define_other_core!(); diff --git a/tests/ui/macros/issue-78325-inconsistent-resolution.stderr b/tests/ui/macros/issue-78325-inconsistent-resolution.stderr index b75e4a9c9e064..5574a1f049110 100644 --- a/tests/ui/macros/issue-78325-inconsistent-resolution.stderr +++ b/tests/ui/macros/issue-78325-inconsistent-resolution.stderr @@ -1,5 +1,5 @@ error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` - --> $DIR/issue-78325-inconsistent-resolution.rs:3:9 + --> $DIR/issue-78325-inconsistent-resolution.rs:5:9 | LL | extern crate std as core; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,5 +9,47 @@ LL | define_other_core!(); | = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error[E0659]: `core` is ambiguous + --> $DIR/issue-78325-inconsistent-resolution.rs:11:5 + | +LL | core::panic!(); + | ^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `core` could refer to a built-in crate + = help: use `::core` to refer to this crate unambiguously +note: `core` could also refer to the crate imported here + --> $DIR/issue-78325-inconsistent-resolution.rs:5:9 + | +LL | extern crate std as core; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | define_other_core!(); + | -------------------- in this macro invocation + = help: use `::core` to refer to this crate unambiguously + = help: or use `crate::core` to refer to this crate unambiguously + = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0659]: `core` is ambiguous + --> $DIR/issue-78325-inconsistent-resolution.rs:12:7 + | +LL | ::core::panic!(); + | ^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `core` could refer to a built-in crate + = help: use `::core` to refer to this crate unambiguously +note: `core` could also refer to the crate imported here + --> $DIR/issue-78325-inconsistent-resolution.rs:5:9 + | +LL | extern crate std as core; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | define_other_core!(); + | -------------------- in this macro invocation + = help: use `::core` to refer to this crate unambiguously + = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0659`. diff --git a/tests/ui/resolve/extern-prelude-speculative.rs b/tests/ui/resolve/extern-prelude-speculative.rs new file mode 100644 index 0000000000000..afbc32d22ac40 --- /dev/null +++ b/tests/ui/resolve/extern-prelude-speculative.rs @@ -0,0 +1,10 @@ +// Non-existent path in `--extern` doesn't result in an error if it's shadowed by `extern crate`. + +//@ check-pass +//@ compile-flags: --extern something=/path/to/nowhere + +extern crate std as something; + +fn main() { + something::println!(); +} diff --git a/tests/ui/resolve/visibility-indeterminate.rs b/tests/ui/resolve/visibility-indeterminate.rs index 17e5fec4701b9..181bb29077430 100644 --- a/tests/ui/resolve/visibility-indeterminate.rs +++ b/tests/ui/resolve/visibility-indeterminate.rs @@ -2,6 +2,6 @@ foo!(); //~ ERROR cannot find macro `foo` in this scope -pub(in ::bar) struct Baz {} //~ ERROR cannot determine resolution for the visibility +pub(in ::bar) struct Baz {} //~ ERROR failed to resolve: could not find `bar` in the list of imported crates fn main() {} diff --git a/tests/ui/resolve/visibility-indeterminate.stderr b/tests/ui/resolve/visibility-indeterminate.stderr index 84d82ce852240..bbe28747f7c06 100644 --- a/tests/ui/resolve/visibility-indeterminate.stderr +++ b/tests/ui/resolve/visibility-indeterminate.stderr @@ -1,8 +1,8 @@ -error[E0578]: cannot determine resolution for the visibility - --> $DIR/visibility-indeterminate.rs:5:8 +error[E0433]: failed to resolve: could not find `bar` in the list of imported crates + --> $DIR/visibility-indeterminate.rs:5:10 | LL | pub(in ::bar) struct Baz {} - | ^^^^^ + | ^^^ could not find `bar` in the list of imported crates error: cannot find macro `foo` in this scope --> $DIR/visibility-indeterminate.rs:3:1 @@ -12,4 +12,4 @@ LL | foo!(); error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0578`. +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/rust-2018/uniform-paths/deadlock.rs b/tests/ui/rust-2018/uniform-paths/deadlock.rs index 4011ba3ee2822..d2296c51bdd39 100644 --- a/tests/ui/rust-2018/uniform-paths/deadlock.rs +++ b/tests/ui/rust-2018/uniform-paths/deadlock.rs @@ -2,7 +2,7 @@ //@ compile-flags:--extern foo --extern bar use bar::foo; //~ ERROR can't find crate for `bar` -use foo::bar; //~ ERROR can't find crate for `foo` +use foo::bar; //~^^ ERROR unresolved imports `bar::foo`, `foo::bar` fn main() {} diff --git a/tests/ui/rust-2018/uniform-paths/deadlock.stderr b/tests/ui/rust-2018/uniform-paths/deadlock.stderr index 8b9863948bd6c..c50bc16ac55f3 100644 --- a/tests/ui/rust-2018/uniform-paths/deadlock.stderr +++ b/tests/ui/rust-2018/uniform-paths/deadlock.stderr @@ -4,12 +4,6 @@ error[E0463]: can't find crate for `bar` LL | use bar::foo; | ^^^ can't find crate -error[E0463]: can't find crate for `foo` - --> $DIR/deadlock.rs:5:5 - | -LL | use foo::bar; - | ^^^ can't find crate - error[E0432]: unresolved imports `bar::foo`, `foo::bar` --> $DIR/deadlock.rs:4:5 | @@ -18,7 +12,7 @@ LL | use bar::foo; LL | use foo::bar; | ^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0432, E0463. For more information about an error, try `rustc --explain E0432`. From d98eaad5096a516f9a1601c61e7e9b6e9f25e695 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 13 Aug 2025 15:46:11 +0300 Subject: [PATCH 155/252] resolve: Improve diagnostics for ambiguities in extern prelude --- compiler/rustc_resolve/src/diagnostics.rs | 11 +++++++++-- tests/ui/imports/issue-109148.stderr | 6 +----- .../macros/issue-78325-inconsistent-resolution.stderr | 6 +----- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e5321c7f3be61..e420e68264bf2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1864,14 +1864,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag { + fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'ra>) -> AmbiguityErrorDiag { let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error; + let extern_prelude_ambiguity = || { + self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| { + entry.item_binding == Some(b1) && entry.flag_binding.get() == Some(b2) + }) + }; let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { // We have to print the span-less alternative first, otherwise formatting looks bad. (b2, b1, misc2, misc1, true) } else { (b1, b2, misc1, misc2, false) }; + let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| { let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude); let note_msg = format!("`{ident}` could{also} refer to {what}"); @@ -1887,7 +1893,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { "consider adding an explicit import of `{ident}` to disambiguate" )) } - if b.is_extern_crate() && ident.span.at_least_rust_2018() { + if b.is_extern_crate() && ident.span.at_least_rust_2018() && !extern_prelude_ambiguity() + { help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously")) } match misc { diff --git a/tests/ui/imports/issue-109148.stderr b/tests/ui/imports/issue-109148.stderr index eead173ba7a9a..ee047385ae328 100644 --- a/tests/ui/imports/issue-109148.stderr +++ b/tests/ui/imports/issue-109148.stderr @@ -17,7 +17,6 @@ LL | use std::mem; | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution = note: `std` could refer to a built-in crate - = help: use `::std` to refer to this crate unambiguously note: `std` could also refer to the crate imported here --> $DIR/issue-109148.rs:6:9 | @@ -26,8 +25,7 @@ LL | extern crate core as std; ... LL | m!(); | ---- in this macro invocation - = help: use `::std` to refer to this crate unambiguously - = help: or use `crate::std` to refer to this crate unambiguously + = help: use `crate::std` to refer to this crate unambiguously = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `std` is ambiguous @@ -38,7 +36,6 @@ LL | use ::std::mem as _; | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution = note: `std` could refer to a built-in crate - = help: use `::std` to refer to this crate unambiguously note: `std` could also refer to the crate imported here --> $DIR/issue-109148.rs:6:9 | @@ -47,7 +44,6 @@ LL | extern crate core as std; ... LL | m!(); | ---- in this macro invocation - = help: use `::std` to refer to this crate unambiguously = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/macros/issue-78325-inconsistent-resolution.stderr b/tests/ui/macros/issue-78325-inconsistent-resolution.stderr index 5574a1f049110..7c745040640ce 100644 --- a/tests/ui/macros/issue-78325-inconsistent-resolution.stderr +++ b/tests/ui/macros/issue-78325-inconsistent-resolution.stderr @@ -17,7 +17,6 @@ LL | core::panic!(); | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution = note: `core` could refer to a built-in crate - = help: use `::core` to refer to this crate unambiguously note: `core` could also refer to the crate imported here --> $DIR/issue-78325-inconsistent-resolution.rs:5:9 | @@ -26,8 +25,7 @@ LL | extern crate std as core; ... LL | define_other_core!(); | -------------------- in this macro invocation - = help: use `::core` to refer to this crate unambiguously - = help: or use `crate::core` to refer to this crate unambiguously + = help: use `crate::core` to refer to this crate unambiguously = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `core` is ambiguous @@ -38,7 +36,6 @@ LL | ::core::panic!(); | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution = note: `core` could refer to a built-in crate - = help: use `::core` to refer to this crate unambiguously note: `core` could also refer to the crate imported here --> $DIR/issue-78325-inconsistent-resolution.rs:5:9 | @@ -47,7 +44,6 @@ LL | extern crate std as core; ... LL | define_other_core!(); | -------------------- in this macro invocation - = help: use `::core` to refer to this crate unambiguously = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors From 12d1665d1163d62de0dd2c2fcb2f508fea8123f1 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Wed, 13 Aug 2025 23:17:29 +0800 Subject: [PATCH 156/252] Add test suggest-add-wrapper-issue-145294 Signed-off-by: xizheyin --- .../suggest-add-wrapper-issue-145294.rs | 26 +++++++++++++++++ .../suggest-add-wrapper-issue-145294.stderr | 29 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs create mode 100644 tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr diff --git a/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs new file mode 100644 index 0000000000000..cfe167cf88d76 --- /dev/null +++ b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs @@ -0,0 +1,26 @@ +// Suppress the suggestion that adding a wrapper. +// When expected_ty and expr_ty are the same ADT, +// we prefer to compare their internal generic params, +// so when the current variant corresponds to an unresolved infer, +// the suggestion is rejected. +// e.g. `Ok(Some("hi"))` is type of `Result, _>`, +// where `E` is still an unresolved inference variable. + +fn foo() -> Result, ()> { + todo!() +} + +#[derive(PartialEq, Debug)] +enum Bar { + A(T), + B(E), +} + +fn bar() -> Bar { + todo!() +} + +fn main() { + assert_eq!(Ok(Some("hi")), foo()); //~ ERROR mismatched types [E0308] + assert_eq!(Bar::A("hi"), bar()); //~ ERROR mismatched types [E0308] +} diff --git a/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr new file mode 100644 index 0000000000000..ef5eeb29cf504 --- /dev/null +++ b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> $DIR/suggest-add-wrapper-issue-145294.rs:24:32 + | +LL | assert_eq!(Ok(Some("hi")), foo()); + | ^^^^^ expected `Result, _>`, found `Result, ()>` + | + = note: expected enum `Result, _>` + found enum `Result, ()>` +help: try wrapping the expression in `Err` + | +LL | assert_eq!(Ok(Some("hi")), Err(foo())); + | ++++ + + +error[E0308]: mismatched types + --> $DIR/suggest-add-wrapper-issue-145294.rs:25:30 + | +LL | assert_eq!(Bar::A("hi"), bar()); + | ^^^^^ expected `Bar<&str, _>`, found `Bar` + | + = note: expected enum `Bar<&str, _>` + found enum `Bar` +help: try wrapping the expression in `Bar::B` + | +LL | assert_eq!(Bar::A("hi"), Bar::B(bar())); + | +++++++ + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From e0cc2beea3d52ce34b16df9730b65a670c68c623 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Wed, 13 Aug 2025 23:23:18 +0800 Subject: [PATCH 157/252] Suppress wrapper suggestion when expected and actual ty are the same adt and the variant is unresolved Signed-off-by: xizheyin --- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 9 +++++++++ .../suggestions/suggest-add-wrapper-issue-145294.stderr | 8 -------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 2345cdab208e3..c44e007dbdb82 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2378,6 +2378,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter_map(|variant| { let sole_field = &variant.single_field(); + // When expected_ty and expr_ty are the same ADT, we prefer to compare their internal generic params, + // When the current variant has a sole field whose type is still an unresolved inference variable, + // suggestions would be often wrong. So suppress the suggestion. See #145294. + if let (ty::Adt(exp_adt, _), ty::Adt(act_adt, _)) = (expected.kind(), expr_ty.kind()) + && exp_adt.did() == act_adt.did() + && sole_field.ty(self.tcx, args).is_ty_var() { + return None; + } + let field_is_local = sole_field.did.is_local(); let field_is_accessible = sole_field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx) diff --git a/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr index ef5eeb29cf504..5e4ad13221046 100644 --- a/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr +++ b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr @@ -6,10 +6,6 @@ LL | assert_eq!(Ok(Some("hi")), foo()); | = note: expected enum `Result, _>` found enum `Result, ()>` -help: try wrapping the expression in `Err` - | -LL | assert_eq!(Ok(Some("hi")), Err(foo())); - | ++++ + error[E0308]: mismatched types --> $DIR/suggest-add-wrapper-issue-145294.rs:25:30 @@ -19,10 +15,6 @@ LL | assert_eq!(Bar::A("hi"), bar()); | = note: expected enum `Bar<&str, _>` found enum `Bar` -help: try wrapping the expression in `Bar::B` - | -LL | assert_eq!(Bar::A("hi"), Bar::B(bar())); - | +++++++ + error: aborting due to 2 previous errors From 6c96c949816bfb76b4487d49202482c440bc49f8 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Wed, 13 Aug 2025 17:29:54 +0200 Subject: [PATCH 158/252] Add missing entry in STAGE0_MISSING_TARGETS Signed-off-by: Jens Reidel --- 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 15e04f591296c..c839c4988df95 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -34,6 +34,7 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined + "aarch64_be-unknown-none-softfloat", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM From 9aa6cb5e56bc1987974bfa176e68281edd56ca8d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 13 Aug 2025 19:29:53 +0300 Subject: [PATCH 159/252] Update clippy tests --- src/tools/clippy/tests/ui/crashes/ice-6255.rs | 2 +- .../clippy/tests/ui/crashes/ice-6255.stderr | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/tools/clippy/tests/ui/crashes/ice-6255.rs b/src/tools/clippy/tests/ui/crashes/ice-6255.rs index ef1e01f80ef0b..5f31696c7917c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6255.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6255.rs @@ -9,7 +9,7 @@ macro_rules! define_other_core { } fn main() { - core::panic!(); + core::panic!(); //~ ERROR: `core` is ambiguous } define_other_core!(); diff --git a/src/tools/clippy/tests/ui/crashes/ice-6255.stderr b/src/tools/clippy/tests/ui/crashes/ice-6255.stderr index 738e9d1bd5cad..420e4af936f81 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6255.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6255.stderr @@ -9,5 +9,25 @@ LL | define_other_core!(); | = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error[E0659]: `core` is ambiguous + --> tests/ui/crashes/ice-6255.rs:12:5 + | +LL | core::panic!(); + | ^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `core` could refer to a built-in crate +note: `core` could also refer to the crate imported here + --> tests/ui/crashes/ice-6255.rs:6:9 + | +LL | extern crate std as core; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | define_other_core!(); + | -------------------- in this macro invocation + = help: use `crate::core` to refer to this crate unambiguously + = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0659`. From f978932903cac8cf508ef78b8133fafd9fe5a5b8 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Tue, 12 Aug 2025 00:39:24 +0300 Subject: [PATCH 160/252] fix(compiler/rustc_codegen_llvm): apply `target-cpu` attribute --- Cargo.lock | 2 +- compiler/rustc_codegen_llvm/src/allocator.rs | 17 ++++++++- src/tools/run-make-support/Cargo.toml | 2 +- .../wasm-unexpected-features/rmake.rs | 38 +++++++++++++++++++ .../wasm32_test/Cargo.toml | 13 +++++++ .../wasm32_test/src/lib.rs | 34 +++++++++++++++++ 6 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 tests/run-make/wasm-unexpected-features/rmake.rs create mode 100644 tests/run-make/wasm-unexpected-features/wasm32_test/Cargo.toml create mode 100644 tests/run-make/wasm-unexpected-features/wasm32_test/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 4eb246995b1ca..1a196172cdc80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3283,7 +3283,7 @@ dependencies = [ "regex", "serde_json", "similar", - "wasmparser 0.219.2", + "wasmparser 0.236.0", ] [[package]] diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 2b5090ed6dbab..23610aa856cb1 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -8,11 +8,12 @@ use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; use rustc_symbol_mangling::mangle_internal_symbol; +use smallvec::SmallVec; use crate::builder::SBuilder; use crate::declare::declare_simple_fn; use crate::llvm::{self, False, True, Type, Value}; -use crate::{SimpleCx, attributes, debuginfo}; +use crate::{SimpleCx, attributes, debuginfo, llvm_util}; pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, @@ -147,6 +148,20 @@ fn create_wrapper_function( llvm::Visibility::from_generic(tcx.sess.default_visibility()), ty, ); + + let mut attrs = SmallVec::<[_; 2]>::new(); + + let target_cpu = llvm_util::target_cpu(tcx.sess); + let target_cpu_attr = llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu); + + let tune_cpu_attr = llvm_util::tune_cpu(tcx.sess) + .map(|tune_cpu| llvm::CreateAttrStringValue(cx.llcx, "tune-cpu", tune_cpu)); + + attrs.push(target_cpu_attr); + attrs.extend(tune_cpu_attr); + + attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs); + let no_return = if no_return { // -> ! DIFlagNoReturn let no_return = llvm::AttributeKind::NoReturn.create_attr(cx.llcx); diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index a4e7534137d5e..250e0f65a9f44 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -17,7 +17,7 @@ object = "0.37" regex = "1.11" serde_json = "1.0" similar = "2.7" -wasmparser = { version = "0.219", default-features = false, features = ["std"] } +wasmparser = { version = "0.236", default-features = false, features = ["std", "features", "validate"] } # tidy-alphabetical-end # Shared with bootstrap and compiletest diff --git a/tests/run-make/wasm-unexpected-features/rmake.rs b/tests/run-make/wasm-unexpected-features/rmake.rs new file mode 100644 index 0000000000000..142860c47ec0d --- /dev/null +++ b/tests/run-make/wasm-unexpected-features/rmake.rs @@ -0,0 +1,38 @@ +//@ only-wasm32-wasip1 + +use std::path::Path; + +use run_make_support::{cargo, path, rfs, target, wasmparser}; + +fn main() { + let target_dir = path("target"); + + cargo() + .args([ + "rustc", + "--manifest-path", + "wasm32_test/Cargo.toml", + "--profile", + "release", + "--target", + "wasm32-wasip1", + "-Zbuild-std=core,alloc,panic_abort", + "--", + "-Clink-arg=--import-memory", + "-Clinker-plugin-lto=on", + ]) + .env("RUSTFLAGS", "-Ctarget-cpu=mvp") + .env("CARGO_TARGET_DIR", &target_dir) + .run(); + + let wasm32_program_path = target_dir.join(target()).join("release").join("wasm32_program.wasm"); + verify_features(&wasm32_program_path); +} + +fn verify_features(path: &Path) { + eprintln!("verify {path:?}"); + let file = rfs::read(&path); + + let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures::WASM1); + validator.validate_all(&file).unwrap(); +} diff --git a/tests/run-make/wasm-unexpected-features/wasm32_test/Cargo.toml b/tests/run-make/wasm-unexpected-features/wasm32_test/Cargo.toml new file mode 100644 index 0000000000000..9f1070e1c54c3 --- /dev/null +++ b/tests/run-make/wasm-unexpected-features/wasm32_test/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "wasm32_test" +version = "0.1.0" +edition = "2024" + +[lib] +crate-type = ["cdylib"] +name = "wasm32_program" + +[profile.release] +codegen-units = 1 +lto = "fat" +opt-level = "z" diff --git a/tests/run-make/wasm-unexpected-features/wasm32_test/src/lib.rs b/tests/run-make/wasm-unexpected-features/wasm32_test/src/lib.rs new file mode 100644 index 0000000000000..123c2c1b6ca0c --- /dev/null +++ b/tests/run-make/wasm-unexpected-features/wasm32_test/src/lib.rs @@ -0,0 +1,34 @@ +#![no_std] + +extern crate alloc; + +use core::alloc::{GlobalAlloc, Layout}; +use core::mem::MaybeUninit; + +#[global_allocator] +static ALLOC: GlobalDlmalloc = GlobalDlmalloc; + +struct GlobalDlmalloc; + +unsafe impl GlobalAlloc for GlobalDlmalloc { + #[inline] + unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { + core::ptr::null_mut() + } + + #[inline] + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +} + +#[used] +static mut BUF: MaybeUninit<[u8; 1024]> = MaybeUninit::uninit(); + +#[unsafe(no_mangle)] +extern "C" fn init() { + alloc::alloc::handle_alloc_error(Layout::new::<[u8; 64 * 1024]>()); +} + +#[panic_handler] +fn my_panic(_: &core::panic::PanicInfo) -> ! { + loop {} +} From 7b5d9efb7d0833e7d9b3ca8690ec2b8173ee499c Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 11 Jun 2025 18:23:06 +0200 Subject: [PATCH 161/252] Improve `--remap-path-prefix` documentation Co-Authored-By: Weihang Lo Co-Authored-By: Wesley Wiser --- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/command-line-arguments.md | 21 +++----- src/doc/rustc/src/remap-source-paths.md | 53 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 src/doc/rustc/src/remap-source-paths.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 25f154f11807c..9efcbe82f6325 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -23,6 +23,7 @@ - [Linker-plugin-based LTO](linker-plugin-lto.md) - [Checking Conditional Configurations](check-cfg.md) - [Cargo Specifics](check-cfg/cargo-specifics.md) +- [Remap source paths](remap-source-paths.md) - [Exploit Mitigations](exploit-mitigations.md) - [Symbol Mangling](symbol-mangling/index.md) - [v0 Symbol Format](symbol-mangling/v0.md) diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index d45ad1be27b8c..0b15fbc24dfc2 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -418,22 +418,15 @@ This flag takes a number that specifies the width of the terminal in characters. Formatting of diagnostics will take the width into consideration to make them better fit on the screen. -## `--remap-path-prefix`: remap source names in output +## `--remap-path-prefix`: remap source paths in output Remap source path prefixes in all output, including compiler diagnostics, -debug information, macro expansions, etc. It takes a value of the form -`FROM=TO` where a path prefix equal to `FROM` is rewritten to the value `TO`. -The `FROM` may itself contain an `=` symbol, but the `TO` value may not. This -flag may be specified multiple times. - -This is useful for normalizing build products, for example by removing the -current directory out of pathnames emitted into the object files. The -replacement is purely textual, with no consideration of the current system's -pathname syntax. For example `--remap-path-prefix foo=bar` will match -`foo/lib.rs` but not `./foo/lib.rs`. - -When multiple remappings are given and several of them match, the **last** -matching one is applied. +debug information, macro expansions, etc. It takes a value of the form `FROM=TO` +where a path prefix equal to `FROM` is rewritten to the value `TO`. This flag may be +specified multiple times. + +Refer to the [Remap source paths](remap-source-paths.md) section of this book for +further details and explanation. ## `--json`: configure json messages printed by the compiler diff --git a/src/doc/rustc/src/remap-source-paths.md b/src/doc/rustc/src/remap-source-paths.md new file mode 100644 index 0000000000000..03f5d98091cc6 --- /dev/null +++ b/src/doc/rustc/src/remap-source-paths.md @@ -0,0 +1,53 @@ +# Remap source paths + +`rustc` supports remapping source paths prefixes **as a best effort** in all compiler generated +output, including compiler diagnostics, debugging information, macro expansions, etc. + +This is useful for normalizing build products, for example by removing the current directory +out of the paths emitted into object files. + +The remapping is done via the `--remap-path-prefix` option. + +## `--remap-path-prefix` + +It takes a value of the form `FROM=TO` where a path prefix equal to `FROM` is rewritten +to the value `TO`. `FROM` may itself contain an `=` symbol, but `TO` value may not. + +The replacement is purely textual, with no consideration of the current system's path separator. + +When multiple remappings are given and several of them match, the **last** matching one is applied. + +### Example + +```bash +rustc --remap-path-prefix "/home/user/project=/redacted" +``` + +This example replaces all occurrences of `/home/user/project` in emitted paths with `/redacted`. + +## Caveats and Limitations + +### Linkers generated paths + +On some platforms like `x86_64-pc-windows-msvc`, the linker may embed absolute host paths and compiler +arguments into debug info files (like `.pdb`) independently of `rustc`. + +Additionally, on Apple platforms, linkers generate [OSO entries] which are not remapped by the compiler +and need to be manually remapped with `-oso_prefix`. + +The `--remap-path-prefix` option does not affect these linker-generated paths. + +### Textual replacement only + +The remapping is strictly textual and does not account for different path separator conventions across +platforms. Care must be taken when specifying prefixes, especially on Windows where both `/` and `\` may +appear in paths. + +### External tools + +Paths introduced by external tools or environment variables may not be covered by `--remap-path-prefix` +unless explicitly accounted for. + +For example, generated code introduced by Cargo's build script may still contain un-remapped paths. + +[OSO entries]: https://wiki.dwarfstd.org/Apple%27s_%22Lazy%22_DWARF_Scheme.md From d435197afcb019a692aa1faf8b7169e167ac1de8 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Tue, 12 Aug 2025 20:22:45 +0200 Subject: [PATCH 162/252] Port the `#[linkage]` attribute to the new attribute system --- .../src/attributes/link_attrs.rs | 76 +++++++++++++++++- compiler/rustc_attr_parsing/src/context.rs | 3 +- .../rustc_codegen_cranelift/src/constant.rs | 8 +- .../rustc_codegen_cranelift/src/driver/aot.rs | 5 +- .../rustc_codegen_cranelift/src/linkage.rs | 3 +- compiler/rustc_codegen_gcc/src/base.rs | 2 +- compiler/rustc_codegen_gcc/src/consts.rs | 2 +- compiler/rustc_codegen_gcc/src/mono_item.rs | 3 +- compiler/rustc_codegen_llvm/src/base.rs | 3 +- compiler/rustc_codegen_llvm/src/consts.rs | 3 +- compiler/rustc_codegen_llvm/src/mono_item.rs | 3 +- .../src/back/symbol_export.rs | 3 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 77 ++++++------------- .../rustc_codegen_ssa/src/mir/naked_asm.rs | 4 +- compiler/rustc_codegen_ssa/src/mono_item.rs | 3 +- .../rustc_codegen_ssa/src/traits/declare.rs | 3 +- .../rustc_hir/src/attrs/data_structures.rs | 21 +++++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_hir/src/hir.rs | 1 + .../src/middle/codegen_fn_attrs.rs | 3 +- compiler/rustc_middle/src/mir/mono.rs | 18 +---- .../rustc_monomorphize/src/partitioning.rs | 4 +- compiler/rustc_passes/src/check_attr.rs | 8 +- compiler/rustc_span/src/symbol.rs | 8 ++ tests/ui/attributes/malformed-attrs.stderr | 37 +++++---- tests/ui/linkage-attr/linkage3.rs | 2 +- tests/ui/linkage-attr/linkage3.stderr | 27 ++++++- 27 files changed, 207 insertions(+), 124 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index d406c30b83ef3..e4ced2e37c55d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -1,6 +1,6 @@ use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::attrs::AttributeKind; use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; +use rustc_hir::attrs::{AttributeKind, Linkage}; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{ @@ -129,3 +129,77 @@ impl SingleAttributeParser for LinkOrdinalParser { Some(LinkOrdinal { ordinal, span: cx.attr_span }) } } + +pub(crate) struct LinkageParser; + +impl SingleAttributeParser for LinkageParser { + const PATH: &[Symbol] = &[sym::linkage]; + + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + + const TEMPLATE: AttributeTemplate = template!(NameValueStr: [ + "available_externally", + "common", + "extern_weak", + "external", + "internal", + "linkonce", + "linkonce_odr", + "weak", + "weak_odr", + ]); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let Some(name_value) = args.name_value() else { + cx.expected_name_value(cx.attr_span, Some(sym::linkage)); + return None; + }; + + let Some(value) = name_value.value_as_str() else { + cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit())); + return None; + }; + + // Use the names from src/llvm/docs/LangRef.rst here. Most types are only + // applicable to variable declarations and may not really make sense for + // Rust code in the first place but allow them anyway and trust that the + // user knows what they're doing. Who knows, unanticipated use cases may pop + // up in the future. + // + // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported + // and don't have to be, LLVM treats them as no-ops. + let linkage = match value { + sym::available_externally => Linkage::AvailableExternally, + sym::common => Linkage::Common, + sym::extern_weak => Linkage::ExternalWeak, + sym::external => Linkage::External, + sym::internal => Linkage::Internal, + sym::linkonce => Linkage::LinkOnceAny, + sym::linkonce_odr => Linkage::LinkOnceODR, + sym::weak => Linkage::WeakAny, + sym::weak_odr => Linkage::WeakODR, + + _ => { + cx.expected_specific_argument( + name_value.value_span, + vec![ + "available_externally", + "common", + "extern_weak", + "external", + "internal", + "linkonce", + "linkonce_odr", + "weak", + "weak_odr", + ], + ); + return None; + } + }; + + Some(AttributeKind::Linkage(linkage, cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1420753a44ea2..6045a8b28a225 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -27,7 +27,7 @@ use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::link_attrs::{ ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser, - LinkSectionParser, StdInternalSymbolParser, + LinkSectionParser, LinkageParser, StdInternalSymbolParser, }; use crate::attributes::lint_helpers::{ AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser, @@ -167,6 +167,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index bec546badc9cf..a56466750e75c 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -281,8 +281,8 @@ fn data_id_for_static( .abi .bytes(); - let linkage = if import_linkage == rustc_middle::mir::mono::Linkage::ExternalWeak - || import_linkage == rustc_middle::mir::mono::Linkage::WeakAny + let linkage = if import_linkage == rustc_hir::attrs::Linkage::ExternalWeak + || import_linkage == rustc_hir::attrs::Linkage::WeakAny { Linkage::Preemptible } else { @@ -332,8 +332,8 @@ fn data_id_for_static( let linkage = if definition { crate::linkage::get_static_linkage(tcx, def_id) - } else if attrs.linkage == Some(rustc_middle::mir::mono::Linkage::ExternalWeak) - || attrs.linkage == Some(rustc_middle::mir::mono::Linkage::WeakAny) + } else if attrs.linkage == Some(rustc_hir::attrs::Linkage::ExternalWeak) + || attrs.linkage == Some(rustc_hir::attrs::Linkage::WeakAny) { Linkage::Preemptible } else { diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 8ec3599b63d89..7e77781dc2fc1 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -18,12 +18,11 @@ use rustc_codegen_ssa::{ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{IntoDynSyncSend, par_map}; +use rustc_hir::attrs::Linkage as RLinkage; use rustc_metadata::fs::copy_to_stdout; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::mono::{ - CodegenUnit, Linkage as RLinkage, MonoItem, MonoItemData, Visibility, -}; +use rustc_middle::mir::mono::{CodegenUnit, MonoItem, MonoItemData, Visibility}; use rustc_session::Session; use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType}; diff --git a/compiler/rustc_codegen_cranelift/src/linkage.rs b/compiler/rustc_codegen_cranelift/src/linkage.rs index ca853aac15892..d76ab9d0109f0 100644 --- a/compiler/rustc_codegen_cranelift/src/linkage.rs +++ b/compiler/rustc_codegen_cranelift/src/linkage.rs @@ -1,4 +1,5 @@ -use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility}; +use rustc_hir::attrs::Linkage as RLinkage; +use rustc_middle::mir::mono::{MonoItem, Visibility}; use crate::prelude::*; diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index c105916bbb2b5..e9d72e457a086 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -8,8 +8,8 @@ use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::traits::DebugInfoCodegenMethods; +use rustc_hir::attrs::Linkage; use rustc_middle::dep_graph; -use rustc_middle::mir::mono::Linkage; #[cfg(feature = "master")] use rustc_middle::mir::mono::Visibility; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 873f1f1951c10..619277eba8b83 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -5,13 +5,13 @@ use rustc_abi::{self as abi, Align, HasDataLayout, Primitive, Size, WrappingRang use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, }; +use rustc_hir::attrs::Linkage; use rustc_hir::def::DefKind; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint, }; -use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index ff188c437daea..35d44d21bcbf6 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -1,11 +1,12 @@ #[cfg(feature = "master")] use gccjit::{FnAttribute, VarAttribute}; use rustc_codegen_ssa::traits::PreDefineCodegenMethods; +use rustc_hir::attrs::Linkage; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::mir::mono::Visibility; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 5dda836988c81..9cc5d8dbc21cf 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -18,9 +18,10 @@ use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::traits::*; use rustc_data_structures::small_c_str::SmallCStr; +use rustc_hir::attrs::Linkage; use rustc_middle::dep_graph; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::mir::mono::Visibility; use rustc_middle::ty::TyCtxt; use rustc_session::config::DebugInfo; use rustc_span::Symbol; diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 6b06daf3477f8..9ec7b0f80aee7 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -4,6 +4,7 @@ use rustc_abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange}; use rustc_codegen_ssa::common; use rustc_codegen_ssa::traits::*; use rustc_hir::LangItem; +use rustc_hir::attrs::Linkage; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -11,7 +12,7 @@ use rustc_middle::mir::interpret::{ Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, Scalar as InterpScalar, read_target_uint, }; -use rustc_middle::mir::mono::{Linkage, MonoItem}; +use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index f9edaded60de6..5075befae8a54 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -1,8 +1,9 @@ use rustc_codegen_ssa::traits::*; +use rustc_hir::attrs::Linkage; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::bug; -use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::mir::mono::Visibility; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_session::config::CrateType; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 0494666bda923..77096822fdc4d 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -306,7 +306,8 @@ fn exported_generic_symbols_provider_local<'tcx>( let mut symbols: Vec<_> = vec![]; if tcx.local_crate_exports_generics() { - use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; + use rustc_hir::attrs::Linkage; + use rustc_middle::mir::mono::{MonoItem, Visibility}; use rustc_middle::ty::InstanceKind; // Normally, we require that shared monomorphizations are not hidden, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 287787eb3d1ff..a36a772bc9719 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -11,7 +11,6 @@ use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, }; -use rustc_middle::mir::mono::Linkage; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{self as ty, TyCtxt}; @@ -26,31 +25,6 @@ use crate::target_features::{ check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr, }; -fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage { - use rustc_middle::mir::mono::Linkage::*; - - // Use the names from src/llvm/docs/LangRef.rst here. Most types are only - // applicable to variable declarations and may not really make sense for - // Rust code in the first place but allow them anyway and trust that the - // user knows what they're doing. Who knows, unanticipated use cases may pop - // up in the future. - // - // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported - // and don't have to be, LLVM treats them as no-ops. - match name { - "available_externally" => AvailableExternally, - "common" => Common, - "extern_weak" => ExternalWeak, - "external" => External, - "internal" => Internal, - "linkonce" => LinkOnceAny, - "linkonce_odr" => LinkOnceODR, - "weak" => WeakAny, - "weak_odr" => WeakODR, - _ => tcx.dcx().span_fatal(tcx.def_span(def_id), "invalid linkage specified"), - } -} - /// In some cases, attributes are only valid on functions, but it's the `check_attr` /// pass that checks that they aren't used anywhere else, rather than this module. /// In these cases, we bail from performing further checks that are only meaningful for @@ -103,13 +77,6 @@ fn parse_instruction_set_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option, did: LocalDefId, attr: &Attribute) -> Option { - let val = attr.value_str()?; - let linkage = linkage_by_name(tcx, did, val.as_str()); - Some(linkage) -} - // FIXME(jdonszelmann): remove when no_sanitize becomes a parsed attr fn parse_no_sanitize_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option { let list = attr.meta_item_list()?; @@ -332,6 +299,28 @@ fn process_builtin_attrs( AttributeKind::StdInternalSymbol(_) => { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL } + AttributeKind::Linkage(linkage, _) => { + let linkage = Some(*linkage); + + if tcx.is_foreign_item(did) { + codegen_fn_attrs.import_linkage = linkage; + + if tcx.is_mutable_static(did.into()) { + let mut diag = tcx.dcx().struct_span_err( + attr.span(), + "extern mutable statics are not allowed with `#[linkage]`", + ); + diag.note( + "marking the extern static mutable would allow changing which \ + symbol the static references rather than make the target of the \ + symbol mutable", + ); + diag.emit(); + } + } else { + codegen_fn_attrs.linkage = linkage; + } + } _ => {} } } @@ -349,28 +338,6 @@ fn process_builtin_attrs( codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, - sym::linkage => { - let linkage = parse_linkage_attr(tcx, did, attr); - - if tcx.is_foreign_item(did) { - codegen_fn_attrs.import_linkage = linkage; - - if tcx.is_mutable_static(did.into()) { - let mut diag = tcx.dcx().struct_span_err( - attr.span(), - "extern mutable statics are not allowed with `#[linkage]`", - ); - diag.note( - "marking the extern static mutable would allow changing which \ - symbol the static references rather than make the target of the \ - symbol mutable", - ); - diag.emit(); - } - } else { - codegen_fn_attrs.linkage = linkage; - } - } sym::no_sanitize => { interesting_spans.no_sanitize = Some(attr.span()); codegen_fn_attrs.no_sanitize |= diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 2a9b5c9019b9f..31784cabf4af3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -1,6 +1,6 @@ use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind}; -use rustc_hir::attrs::InstructionSetAttr; -use rustc_middle::mir::mono::{Linkage, MonoItemData, Visibility}; +use rustc_hir::attrs::{InstructionSetAttr, Linkage}; +use rustc_middle::mir::mono::{MonoItemData, Visibility}; use rustc_middle::mir::{InlineAsmOperand, START_BLOCK}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::{Instance, Ty, TyCtxt, TypeVisitableExt}; diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index b9040c330fb10..8f03dc1e6b5e0 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,5 +1,6 @@ +use rustc_hir::attrs::Linkage; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; +use rustc_middle::mir::mono::{MonoItem, MonoItemData, Visibility}; use rustc_middle::ty::layout::HasTyCtxt; use tracing::debug; diff --git a/compiler/rustc_codegen_ssa/src/traits/declare.rs b/compiler/rustc_codegen_ssa/src/traits/declare.rs index 9f735546558b0..8d5f0a5b939a2 100644 --- a/compiler/rustc_codegen_ssa/src/traits/declare.rs +++ b/compiler/rustc_codegen_ssa/src/traits/declare.rs @@ -1,5 +1,6 @@ +use rustc_hir::attrs::Linkage; use rustc_hir::def_id::DefId; -use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::mir::mono::Visibility; use rustc_middle::ty::Instance; pub trait PreDefineCodegenMethods<'tcx> { diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e02edf5fe24db..510fc83297829 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -187,6 +187,24 @@ pub enum CfgEntry { Version(Option, Span), } +/// Possible values for the `#[linkage]` attribute, allowing to specify the +/// linkage type for a `MonoItem`. +/// +/// See for more details about these variants. +#[derive(Encodable, Decodable, Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic, PrintAttribute)] +pub enum Linkage { + AvailableExternally, + Common, + ExternalWeak, + External, + Internal, + LinkOnceAny, + LinkOnceODR, + WeakAny, + WeakODR, +} + /// Represents parsed *built-in* inert attributes. /// /// ## Overview @@ -360,6 +378,9 @@ pub enum AttributeKind { /// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute) LinkSection { name: Symbol, span: Span }, + /// Represents `#[linkage]`. + Linkage(Linkage, Span), + /// Represents `#[loop_match]`. LoopMatch(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 7ce624dcc550a..84a975523f2c8 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -46,6 +46,7 @@ impl AttributeKind { LinkName { .. } => Yes, // Needed for rustdoc LinkOrdinal { .. } => No, LinkSection { .. } => Yes, // Needed for rustdoc + Linkage(..) => No, LoopMatch(..) => No, MacroEscape(..) => No, MacroTransparency(..) => Yes, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b27c223527ec2..260cfc1052b12 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1311,6 +1311,7 @@ impl AttributeExt for Attribute { Attribute::Parsed(AttributeKind::ShouldPanic { span, .. }) => *span, Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span, Attribute::Parsed(AttributeKind::AllowInternalUnsafe(span)) => *span, + Attribute::Parsed(AttributeKind::Linkage(_, span)) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 52341df074085..2852c4cbd34c7 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -2,13 +2,12 @@ use std::borrow::Cow; use rustc_abi::Align; use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; -use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, Linkage, OptimizeAttr}; use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; -use crate::mir::mono::Linkage; use crate::ty::{InstanceKind, TyCtxt}; impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 0d98e055d9563..440771b3d68a0 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -10,7 +10,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHas use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash128; use rustc_hir::ItemId; -use rustc_hir::attrs::InlineAttr; +use rustc_hir::attrs::{InlineAttr, Linkage}; use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; @@ -368,22 +368,6 @@ pub struct MonoItemData { pub size_estimate: usize, } -/// Specifies the linkage type for a `MonoItem`. -/// -/// See for more details about these variants. -#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] -pub enum Linkage { - External, - AvailableExternally, - LinkOnceAny, - LinkOnceODR, - WeakAny, - WeakODR, - Internal, - ExternalWeak, - Common, -} - /// Specifies the symbol visibility with regards to dynamic linking. /// /// Visibility doesn't have any effect when linkage is internal. diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index d76b27d9970b6..c80d058c5035f 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -104,7 +104,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sync; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::LangItem; -use rustc_hir::attrs::InlineAttr; +use rustc_hir::attrs::{InlineAttr, Linkage}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::definitions::DefPathDataName; @@ -112,7 +112,7 @@ use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_middle::mir::mono::{ - CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, MonoItemData, + CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, MonoItem, MonoItemData, MonoItemPartitions, Visibility, }; use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths}; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 165f8fe199519..df1db65c06e01 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -332,6 +332,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::Coroutine(attr_span)) => { self.check_coroutine(attr_span, target) } + &Attribute::Parsed(AttributeKind::Linkage(_, attr_span)) => { + self.check_linkage(attr_span, span, target); + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -395,7 +398,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } - [sym::linkage, ..] => self.check_linkage(attr, span, target), [ // ok sym::allow @@ -2707,7 +2709,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_linkage(&self, attr: &Attribute, span: Span, target: Target) { + fn check_linkage(&self, attr_span: Span, span: Span, target: Target) { match target { Target::Fn | Target::Method(..) @@ -2715,7 +2717,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::ForeignStatic | Target::ForeignFn => {} _ => { - self.dcx().emit_err(errors::Linkage { attr_span: attr.span(), span }); + self.dcx().emit_err(errors::Linkage { attr_span, span }); } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index acbed7a9eed81..416ce27367e5e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -545,6 +545,7 @@ symbols! { autodiff_forward, autodiff_reverse, automatically_derived, + available_externally, avx, avx10_target_feature, avx512_target_feature, @@ -676,6 +677,7 @@ symbols! { cold_path, collapse_debuginfo, column, + common, compare_bytes, compare_exchange, compare_exchange_weak, @@ -956,6 +958,7 @@ symbols! { extern_prelude, extern_system_varargs, extern_types, + extern_weak, external, external_doc, f, @@ -1213,6 +1216,7 @@ symbols! { instruction_set, integer_: "integer", // underscore to avoid clashing with the function `sym::integer` below integral, + internal, internal_features, into_async_iter_into_iter, into_future, @@ -1287,6 +1291,8 @@ symbols! { linkage, linker, linker_messages, + linkonce, + linkonce_odr, lint_reasons, literal, load, @@ -2360,6 +2366,8 @@ symbols! { wasm_abi, wasm_import_module, wasm_target_feature, + weak, + weak_odr, where_clause_attrs, while_let, width, diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 705050e9a7deb..aa4891459aaf2 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -90,25 +90,6 @@ error: malformed `cfi_encoding` attribute input LL | #[cfi_encoding] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]` -error: malformed `linkage` attribute input - --> $DIR/malformed-attrs.rs:170:5 - | -LL | #[linkage] - | ^^^^^^^^^^ - | - = note: for more information, visit -help: the following are the possible correct uses - | -LL | #[linkage = "available_externally"] - | ++++++++++++++++++++++++ -LL | #[linkage = "common"] - | ++++++++++ -LL | #[linkage = "extern_weak"] - | +++++++++++++++ -LL | #[linkage = "external"] - | ++++++++++++ - = and 5 other candidates - error: malformed `allow` attribute input --> $DIR/malformed-attrs.rs:175:1 | @@ -659,6 +640,24 @@ LL | #[unsafe(ffi_const = 1)] | | didn't expect any arguments here | help: must be of the form: `#[ffi_const]` +error[E0539]: malformed `linkage` attribute input + --> $DIR/malformed-attrs.rs:170:5 + | +LL | #[linkage] + | ^^^^^^^^^^ expected this to be of the form `linkage = "..."` + | +help: try changing it to one of the following valid forms of the attribute + | +LL | #[linkage = "available_externally"] + | ++++++++++++++++++++++++ +LL | #[linkage = "common"] + | ++++++++++ +LL | #[linkage = "extern_weak"] + | +++++++++++++++ +LL | #[linkage = "external"] + | ++++++++++++ + = and 5 other candidates + error[E0565]: malformed `automatically_derived` attribute input --> $DIR/malformed-attrs.rs:188:1 | diff --git a/tests/ui/linkage-attr/linkage3.rs b/tests/ui/linkage-attr/linkage3.rs index f95e5eecc48f7..74a6fd6600b8e 100644 --- a/tests/ui/linkage-attr/linkage3.rs +++ b/tests/ui/linkage-attr/linkage3.rs @@ -5,7 +5,7 @@ extern "C" { #[linkage = "foo"] static foo: *const i32; -//~^ ERROR: invalid linkage specified +//~^^ ERROR: malformed `linkage` attribute input [E0539] } fn main() { diff --git a/tests/ui/linkage-attr/linkage3.stderr b/tests/ui/linkage-attr/linkage3.stderr index 5f7b7ef227c84..f1215f09aeafc 100644 --- a/tests/ui/linkage-attr/linkage3.stderr +++ b/tests/ui/linkage-attr/linkage3.stderr @@ -1,8 +1,27 @@ -error: invalid linkage specified - --> $DIR/linkage3.rs:7:5 +error[E0539]: malformed `linkage` attribute input + --> $DIR/linkage3.rs:6:5 | -LL | static foo: *const i32; - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[linkage = "foo"] + | ^^^^^^^^^^^^-----^ + | | + | valid arguments are `available_externally`, `common`, `extern_weak`, `external`, `internal`, `linkonce`, `linkonce_odr`, `weak` or `weak_odr` + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[linkage = "foo"] +LL + #[linkage = "available_externally"] + | +LL - #[linkage = "foo"] +LL + #[linkage = "common"] + | +LL - #[linkage = "foo"] +LL + #[linkage = "extern_weak"] + | +LL - #[linkage = "foo"] +LL + #[linkage = "external"] + | + = and 5 other candidates error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. From 100d19ce5ba823faeb8b1ed6944b1047fe342de9 Mon Sep 17 00:00:00 2001 From: sayantn Date: Mon, 28 Jul 2025 00:05:24 +0530 Subject: [PATCH 163/252] Stabilize `sse4a` and `tbm` target features - remove some stabilized target features from `gate.rs` --- compiler/rustc_feature/src/accepted.rs | 4 ++++ compiler/rustc_feature/src/unstable.rs | 2 -- compiler/rustc_target/src/target_features.rs | 4 ++-- library/core/src/lib.rs | 2 -- library/stdarch/crates/core_arch/src/lib.rs | 2 -- tests/ui/target-feature/gate.rs | 6 ------ tests/ui/target-feature/gate.stderr | 2 +- 7 files changed, 7 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 83be3241b127c..9fe55216f9395 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -396,6 +396,8 @@ declare_features! ( (accepted, slice_patterns, "1.42.0", Some(62254)), /// Allows use of `&foo[a..b]` as a slicing syntax. (accepted, slicing_syntax, "1.0.0", None), + /// Allows use of `sse4a` target feature. + (accepted, sse4a_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), /// Allows elision of `'static` lifetimes in `static`s and `const`s. (accepted, static_in_const, "1.17.0", Some(35897)), /// Allows the definition recursive static items. @@ -408,6 +410,8 @@ declare_features! ( (accepted, target_feature, "1.27.0", None), /// Allows the use of `#[target_feature]` on safe functions. (accepted, target_feature_11, "1.86.0", Some(69098)), + /// Allows use of `tbm` target feature. + (accepted, tbm_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). (accepted, termination_trait, "1.26.0", Some(43301)), /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index acc21f6c6d253..87ecc7b41e213 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -334,8 +334,6 @@ declare_features! ( (unstable, rtm_target_feature, "1.35.0", Some(44839)), (unstable, s390x_target_feature, "1.82.0", Some(44839)), (unstable, sparc_target_feature, "1.84.0", Some(132783)), - (unstable, sse4a_target_feature, "1.27.0", Some(44839)), - (unstable, tbm_target_feature, "1.27.0", Some(44839)), (unstable, wasm_target_feature, "1.30.0", Some(44839)), (unstable, x87_target_feature, "1.85.0", Some(44839)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 297d9ed84c504..77726e9c55553 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -471,9 +471,9 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("sse3", Stable, &["sse2"]), ("sse4.1", Stable, &["ssse3"]), ("sse4.2", Stable, &["sse4.1"]), - ("sse4a", Unstable(sym::sse4a_target_feature), &["sse3"]), + ("sse4a", Stable, &["sse3"]), ("ssse3", Stable, &["sse3"]), - ("tbm", Unstable(sym::tbm_target_feature), &[]), + ("tbm", Stable, &[]), ("vaes", Stable, &["avx2", "aes"]), ("vpclmulqdq", Stable, &["avx", "pclmulqdq"]), ("widekl", Stable, &["kl"]), diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d5bce6ad233e9..a6825b4be683a 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -200,8 +200,6 @@ #![feature(riscv_target_feature)] #![feature(rtm_target_feature)] #![feature(s390x_target_feature)] -#![feature(sse4a_target_feature)] -#![feature(tbm_target_feature)] #![feature(wasm_target_feature)] #![feature(x86_amx_intrinsics)] // tidy-alphabetical-end diff --git a/library/stdarch/crates/core_arch/src/lib.rs b/library/stdarch/crates/core_arch/src/lib.rs index c58580f641780..7d3cbd55ad85c 100644 --- a/library/stdarch/crates/core_arch/src/lib.rs +++ b/library/stdarch/crates/core_arch/src/lib.rs @@ -18,8 +18,6 @@ rustc_attrs, staged_api, doc_cfg, - tbm_target_feature, - sse4a_target_feature, riscv_target_feature, arm_target_feature, mips_target_feature, diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs index 81ed8b3de760f..fc3763820cbec 100644 --- a/tests/ui/target-feature/gate.rs +++ b/tests/ui/target-feature/gate.rs @@ -1,18 +1,12 @@ //@ only-x86_64 // -// gate-test-sse4a_target_feature // gate-test-powerpc_target_feature -// gate-test-tbm_target_feature // gate-test-arm_target_feature // gate-test-hexagon_target_feature // gate-test-mips_target_feature // gate-test-nvptx_target_feature // gate-test-wasm_target_feature -// gate-test-adx_target_feature -// gate-test-cmpxchg16b_target_feature -// gate-test-movbe_target_feature // gate-test-rtm_target_feature -// gate-test-f16c_target_feature // gate-test-riscv_target_feature // gate-test-ermsb_target_feature // gate-test-bpf_target_feature diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr index 3e9374be73db8..345dc2006d0bf 100644 --- a/tests/ui/target-feature/gate.stderr +++ b/tests/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `x87` is currently unstable - --> $DIR/gate.rs:30:18 + --> $DIR/gate.rs:24:18 | LL | #[target_feature(enable = "x87")] | ^^^^^^^^^^^^^^ From 8f472e8b5c0923a36a3cd90c3d5fc990943dd034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Thu, 14 Aug 2025 03:29:51 +0200 Subject: [PATCH 164/252] Add regression test for a former ICE involving helper attributes containing interpolated tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jana Dönszelmann --- .../auxiliary/derive_macro_with_helper.rs | 8 ++++++++ .../helper-attr-interpolated-non-lit-arg.rs | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 tests/ui/attributes/auxiliary/derive_macro_with_helper.rs create mode 100644 tests/ui/attributes/helper-attr-interpolated-non-lit-arg.rs diff --git a/tests/ui/attributes/auxiliary/derive_macro_with_helper.rs b/tests/ui/attributes/auxiliary/derive_macro_with_helper.rs new file mode 100644 index 0000000000000..128af50ce3691 --- /dev/null +++ b/tests/ui/attributes/auxiliary/derive_macro_with_helper.rs @@ -0,0 +1,8 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(Derive, attributes(arg))] +pub fn derive(_: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/tests/ui/attributes/helper-attr-interpolated-non-lit-arg.rs b/tests/ui/attributes/helper-attr-interpolated-non-lit-arg.rs new file mode 100644 index 0000000000000..17c9ad1bd48e6 --- /dev/null +++ b/tests/ui/attributes/helper-attr-interpolated-non-lit-arg.rs @@ -0,0 +1,20 @@ +// Regression test for . +//@ proc-macro: derive_macro_with_helper.rs +//@ edition: 2018 +//@ check-pass + +macro_rules! expand { + ($text:expr) => { + #[derive(derive_macro_with_helper::Derive)] + // This inert attr is completely valid because it follows the grammar + // `#` `[` SimplePath DelimitedTokenStream `]`. + // However, we used to incorrectly delay a bug here and ICE when trying to parse `$text` as + // the inside of a "meta item list" which may only begin with literals or paths. + #[arg($text)] + pub struct Foo; + }; +} + +expand!(1 + 1); + +fn main() {} From 74aca53f5591f9ad4a5e74c42eb101534c3e7b12 Mon Sep 17 00:00:00 2001 From: Tsukasa OI Date: Thu, 14 Aug 2025 04:39:31 +0000 Subject: [PATCH 165/252] rustdoc: Allow multiple references to a single footnote MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Multiple references to a single footnote is a part of GitHub Flavored Markdown syntax (although not explicitly documented as well as regular footnotes, it is implemented in GitHub's fork of CommonMark) and not prohibited by rustdoc. cf. However, using it makes multiple "sup" elements with the same "id" attribute, which is invalid per the HTML specification. Still, not only this is a valid GitHub Flavored Markdown syntax, this is helpful on certain cases and actually tested (accidentally) in tests/rustdoc/footnote-reference-in-footnote-def.rs. This commit keeps track of the number of references per footnote and gives unique ID to each reference. It also emits *all* back links from a footnote to its references as "↩" (return symbol) plus a numeric list in superscript. As a known limitation, it assumes that all references to a footnote are rendered (this is not always true if a dangling footnote has one or more references but considered a reasonable compromise). Also note that, this commit is designed so that no HTML changes will occur unless multiple references to a single footnote is actually used. --- src/librustdoc/html/markdown/footnotes.rs | 33 ++++++++++++++----- tests/rustdoc/footnote-reference-ids.rs | 23 +++++++++++++ .../footnote-reference-in-footnote-def.rs | 2 +- 3 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 tests/rustdoc/footnote-reference-ids.rs diff --git a/src/librustdoc/html/markdown/footnotes.rs b/src/librustdoc/html/markdown/footnotes.rs index 7ee012c4da239..a81d8dd6035e0 100644 --- a/src/librustdoc/html/markdown/footnotes.rs +++ b/src/librustdoc/html/markdown/footnotes.rs @@ -23,6 +23,8 @@ struct FootnoteDef<'a> { content: Vec>, /// The number that appears in the footnote reference and list. id: usize, + /// The number of footnote references. + num_refs: usize, } impl<'a, I: Iterator>> Footnotes<'a, I> { @@ -33,21 +35,25 @@ impl<'a, I: Iterator>> Footnotes<'a, I> { Footnotes { inner: iter, footnotes: FxIndexMap::default(), existing_footnotes, start_id } } - fn get_entry(&mut self, key: &str) -> (&mut Vec>, usize) { + fn get_entry(&mut self, key: &str) -> (&mut Vec>, usize, &mut usize) { let new_id = self.footnotes.len() + 1 + self.start_id; let key = key.to_owned(); - let FootnoteDef { content, id } = - self.footnotes.entry(key).or_insert(FootnoteDef { content: Vec::new(), id: new_id }); + let FootnoteDef { content, id, num_refs } = self + .footnotes + .entry(key) + .or_insert(FootnoteDef { content: Vec::new(), id: new_id, num_refs: 0 }); // Don't allow changing the ID of existing entries, but allow changing the contents. - (content, *id) + (content, *id, num_refs) } fn handle_footnote_reference(&mut self, reference: &CowStr<'a>) -> Event<'a> { // When we see a reference (to a footnote we may not know) the definition of, // reserve a number for it, and emit a link to that number. - let (_, id) = self.get_entry(reference); + let (_, id, num_refs) = self.get_entry(reference); + *num_refs += 1; + let fnref_suffix = if *num_refs <= 1 { "".to_owned() } else { format!("-{num_refs}") }; let reference = format!( - "{1}", + "{1}", id, // Although the ID count is for the whole page, the footnote reference // are local to the item so we make this ID "local" when displayed. @@ -85,7 +91,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { // When we see a footnote definition, collect the associated content, and store // that for rendering later. let content = self.collect_footnote_def(); - let (entry_content, _) = self.get_entry(&def); + let (entry_content, _, _) = self.get_entry(&def); *entry_content = content; } Some(e) => return Some(e), @@ -113,7 +119,7 @@ fn render_footnotes_defs(mut footnotes: Vec>) -> String { // browser generated for
  • are right. footnotes.sort_by_key(|x| x.id); - for FootnoteDef { mut content, id } in footnotes { + for FootnoteDef { mut content, id, num_refs } in footnotes { write!(ret, "
  • ").unwrap(); let mut is_paragraph = false; if let Some(&Event::End(TagEnd::Paragraph)) = content.last() { @@ -121,7 +127,16 @@ fn render_footnotes_defs(mut footnotes: Vec>) -> String { is_paragraph = true; } html::push_html(&mut ret, content.into_iter()); - write!(ret, " ").unwrap(); + if num_refs <= 1 { + write!(ret, " ").unwrap(); + } else { + // There are multiple references to single footnote. Make the first + // back link a single "a" element to make touch region larger. + write!(ret, " ↩ 1").unwrap(); + for refid in 2..=num_refs { + write!(ret, " {refid}").unwrap(); + } + } if is_paragraph { ret.push_str("

    "); } diff --git a/tests/rustdoc/footnote-reference-ids.rs b/tests/rustdoc/footnote-reference-ids.rs new file mode 100644 index 0000000000000..ffa04e1d7675d --- /dev/null +++ b/tests/rustdoc/footnote-reference-ids.rs @@ -0,0 +1,23 @@ +// This test ensures that multiple references to a single footnote and +// corresponding back links work as expected. + +#![crate_name = "foo"] + +//@ has 'foo/index.html' +//@ has - '//*[@class="docblock"]/p/sup[@id="fnref1"]/a[@href="#fn1"]' '1' +//@ has - '//*[@class="docblock"]/p/sup[@id="fnref2"]/a[@href="#fn2"]' '2' +//@ has - '//*[@class="docblock"]/p/sup[@id="fnref2-2"]/a[@href="#fn2"]' '2' +//@ has - '//li[@id="fn1"]/p' 'meow' +//@ has - '//li[@id="fn1"]/p/a[@href="#fnref1"]' '↩' +//@ has - '//li[@id="fn2"]/p' 'uwu' +//@ has - '//li[@id="fn2"]/p/a[@href="#fnref2"]/sup' '1' +//@ has - '//li[@id="fn2"]/p/sup/a[@href="#fnref2-2"]' '2' + +//! # Footnote, references and back links +//! +//! Single: [^a]. +//! +//! Double: [^b] [^b]. +//! +//! [^a]: meow +//! [^b]: uwu diff --git a/tests/rustdoc/footnote-reference-in-footnote-def.rs b/tests/rustdoc/footnote-reference-in-footnote-def.rs index db3f9a59ef830..504d0bdb8f79f 100644 --- a/tests/rustdoc/footnote-reference-in-footnote-def.rs +++ b/tests/rustdoc/footnote-reference-in-footnote-def.rs @@ -9,7 +9,7 @@ //@ has - '//li[@id="fn1"]/p/sup[@id="fnref2"]/a[@href="#fn2"]' '2' //@ has - '//li[@id="fn1"]//a[@href="#fn2"]' '2' //@ has - '//li[@id="fn2"]/p' 'uwu' -//@ has - '//li[@id="fn2"]/p/sup[@id="fnref1"]/a[@href="#fn1"]' '1' +//@ has - '//li[@id="fn2"]/p/sup[@id="fnref1-2"]/a[@href="#fn1"]' '1' //@ has - '//li[@id="fn2"]//a[@href="#fn1"]' '1' //! # footnote-hell From d10a8a33210b1f36013f8cd68c194f646180a32b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 13 Aug 2025 22:01:58 -0700 Subject: [PATCH 166/252] bootstrap: Support passing `--timings` to cargo Useful for optimizing the sequencing of the compiler's own build. --- src/bootstrap/src/core/builder/cargo.rs | 4 ++++ src/bootstrap/src/core/builder/mod.rs | 2 +- src/bootstrap/src/core/config/config.rs | 6 +++--- src/bootstrap/src/core/config/flags.rs | 27 +++++++++++++++++++++---- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 757b9277ec65d..3ce21eb151c3c 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -499,6 +499,10 @@ impl Builder<'_> { build_stamp::clear_if_dirty(self, &out_dir, &backend); } + if self.config.cmd.timings() { + cargo.arg("--timings"); + } + if cmd_kind == Kind::Doc { let my_out = match mode { // This is the intended out directory for compiler documentation. diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index de4b941ac9082..0f18441067b91 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1267,7 +1267,7 @@ impl<'a> Builder<'a> { pub fn new(build: &Build) -> Builder<'_> { let paths = &build.config.paths; let (kind, paths) = match build.config.cmd { - Subcommand::Build => (Kind::Build, &paths[..]), + Subcommand::Build { .. } => (Kind::Build, &paths[..]), Subcommand::Check { .. } => (Kind::Check, &paths[..]), Subcommand::Clippy { .. } => (Kind::Clippy, &paths[..]), Subcommand::Fix => (Kind::Fix, &paths[..]), diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index a656927b1f64d..32011c14c0c00 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1342,7 +1342,7 @@ impl Config { Subcommand::Doc { .. } => { flags_stage.or(build_doc_stage).unwrap_or(if download_rustc { 2 } else { 1 }) } - Subcommand::Build => { + Subcommand::Build { .. } => { flags_stage.or(build_build_stage).unwrap_or(if download_rustc { 2 } else { 1 }) } Subcommand::Test { .. } | Subcommand::Miri { .. } => { @@ -1363,7 +1363,7 @@ impl Config { // Now check that the selected stage makes sense, and if not, print a warning and end match (config.stage, &config.cmd) { - (0, Subcommand::Build) => { + (0, Subcommand::Build { .. }) => { eprintln!("ERROR: cannot build anything on stage 0. Use at least stage 1."); exit!(1); } @@ -1392,7 +1392,7 @@ impl Config { Subcommand::Test { .. } | Subcommand::Miri { .. } | Subcommand::Doc { .. } - | Subcommand::Build + | Subcommand::Build { .. } | Subcommand::Bench { .. } | Subcommand::Dist | Subcommand::Install => { diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 31a427f9ffaac..17bfb388280a9 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -241,7 +241,7 @@ fn normalize_args(args: &[String]) -> Vec { it.collect() } -#[derive(Debug, Clone, Default, clap::Subcommand)] +#[derive(Debug, Clone, clap::Subcommand)] pub enum Subcommand { #[command(aliases = ["b"], long_about = "\n Arguments: @@ -256,8 +256,11 @@ pub enum Subcommand { ./x.py build --stage 0 ./x.py build ")] /// Compile either the compiler or libraries - #[default] - Build, + Build { + #[arg(long)] + /// Pass `--timings` to Cargo to get crate build timings + timings: bool, + }, #[command(aliases = ["c"], long_about = "\n Arguments: This subcommand accepts a number of paths to directories to the crates @@ -269,6 +272,9 @@ pub enum Subcommand { #[arg(long)] /// Check all targets all_targets: bool, + #[arg(long)] + /// Pass `--timings` to Cargo to get crate build timings + timings: bool, }, /// Run Clippy (uses rustup/cargo-installed clippy binary) #[command(long_about = "\n @@ -494,11 +500,17 @@ Arguments: Perf(PerfArgs), } +impl Default for Subcommand { + fn default() -> Self { + Subcommand::Build { timings: false } + } +} + impl Subcommand { pub fn kind(&self) -> Kind { match self { Subcommand::Bench { .. } => Kind::Bench, - Subcommand::Build => Kind::Build, + Subcommand::Build { .. } => Kind::Build, Subcommand::Check { .. } => Kind::Check, Subcommand::Clippy { .. } => Kind::Clippy, Subcommand::Doc { .. } => Kind::Doc, @@ -626,6 +638,13 @@ impl Subcommand { } } + pub fn timings(&self) -> bool { + match *self { + Subcommand::Build { timings, .. } | Subcommand::Check { timings, .. } => timings, + _ => false, + } + } + pub fn vendor_versioned_dirs(&self) -> bool { match *self { Subcommand::Vendor { versioned_dirs, .. } => versioned_dirs, From 3ecea538cd623ae4e67f05edf180674c5418b583 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 13 Aug 2025 22:53:50 -0700 Subject: [PATCH 167/252] bootstrap: Update completions for new --timings argument --- src/etc/completions/x.fish | 2 ++ src/etc/completions/x.ps1 | 2 ++ src/etc/completions/x.py.fish | 2 ++ src/etc/completions/x.py.ps1 | 2 ++ src/etc/completions/x.py.sh | 4 ++-- src/etc/completions/x.py.zsh | 2 ++ src/etc/completions/x.sh | 4 ++-- src/etc/completions/x.zsh | 2 ++ 8 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index a5e5bb8f09e81..0b9af33421461 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -97,6 +97,7 @@ complete -c x -n "__fish_x_using_subcommand build" -l llvm-profile-use -d 'use P complete -c x -n "__fish_x_using_subcommand build" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r complete -c x -n "__fish_x_using_subcommand build" -l set -d 'override options in bootstrap.toml' -r -f complete -c x -n "__fish_x_using_subcommand build" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" +complete -c x -n "__fish_x_using_subcommand build" -l timings -d 'Pass `--timings` to Cargo to get crate build timings' complete -c x -n "__fish_x_using_subcommand build" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x -n "__fish_x_using_subcommand build" -s i -l incremental -d 'use incremental compilation' complete -c x -n "__fish_x_using_subcommand build" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -133,6 +134,7 @@ complete -c x -n "__fish_x_using_subcommand check" -l reproducible-artifact -d ' complete -c x -n "__fish_x_using_subcommand check" -l set -d 'override options in bootstrap.toml' -r -f complete -c x -n "__fish_x_using_subcommand check" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" complete -c x -n "__fish_x_using_subcommand check" -l all-targets -d 'Check all targets' +complete -c x -n "__fish_x_using_subcommand check" -l timings -d 'Pass `--timings` to Cargo to get crate build timings' complete -c x -n "__fish_x_using_subcommand check" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x -n "__fish_x_using_subcommand check" -s i -l incremental -d 'use incremental compilation' complete -c x -n "__fish_x_using_subcommand check" -l include-default-paths -d 'include default paths in addition to the provided ones' diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index 4fee3bc0a8692..95cee4b633625 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -102,6 +102,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') + [CompletionResult]::new('--timings', '--timings', [CompletionResultType]::ParameterName, 'Pass `--timings` to Cargo to get crate build timings') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -145,6 +146,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') [CompletionResult]::new('--all-targets', '--all-targets', [CompletionResultType]::ParameterName, 'Check all targets') + [CompletionResult]::new('--timings', '--timings', [CompletionResultType]::ParameterName, 'Pass `--timings` to Cargo to get crate build timings') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index e2e6ae05ee03d..6fba6a4562368 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -97,6 +97,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand build" -l llvm-profile-use -d complete -c x.py -n "__fish_x.py_using_subcommand build" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r complete -c x.py -n "__fish_x.py_using_subcommand build" -l set -d 'override options in bootstrap.toml' -r -f complete -c x.py -n "__fish_x.py_using_subcommand build" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" +complete -c x.py -n "__fish_x.py_using_subcommand build" -l timings -d 'Pass `--timings` to Cargo to get crate build timings' complete -c x.py -n "__fish_x.py_using_subcommand build" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_x.py_using_subcommand build" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_x.py_using_subcommand build" -l include-default-paths -d 'include default paths in addition to the provided ones' @@ -133,6 +134,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand check" -l reproducible-artifac complete -c x.py -n "__fish_x.py_using_subcommand check" -l set -d 'override options in bootstrap.toml' -r -f complete -c x.py -n "__fish_x.py_using_subcommand check" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}" complete -c x.py -n "__fish_x.py_using_subcommand check" -l all-targets -d 'Check all targets' +complete -c x.py -n "__fish_x.py_using_subcommand check" -l timings -d 'Pass `--timings` to Cargo to get crate build timings' complete -c x.py -n "__fish_x.py_using_subcommand check" -s v -l verbose -d 'use verbose output (-vv for very verbose)' complete -c x.py -n "__fish_x.py_using_subcommand check" -s i -l incremental -d 'use incremental compilation' complete -c x.py -n "__fish_x.py_using_subcommand check" -l include-default-paths -d 'include default paths in addition to the provided ones' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index ea3aacc21c7ac..458879a17a7b9 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -102,6 +102,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive') [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') + [CompletionResult]::new('--timings', '--timings', [CompletionResultType]::ParameterName, 'Pass `--timings` to Cargo to get crate build timings') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') @@ -145,6 +146,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml') [CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not') [CompletionResult]::new('--all-targets', '--all-targets', [CompletionResultType]::ParameterName, 'Check all targets') + [CompletionResult]::new('--timings', '--timings', [CompletionResultType]::ParameterName, 'Pass `--timings` to Cargo to get crate build timings') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation') diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index f31bdb58dc448..e003bf7fd0b43 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -458,7 +458,7 @@ _x.py() { return 0 ;; x.py__build) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --timings --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -644,7 +644,7 @@ _x.py() { return 0 ;; x.py__check) - opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --all-targets --timings --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index 32e986ad141fa..b82c2d65e8694 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -90,6 +90,7 @@ _arguments "${_arguments_options[@]}" : \ '*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \ '*--set=[override options in bootstrap.toml]:section.option=value:' \ '--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ +'--timings[Pass \`--timings\` to Cargo to get crate build timings]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ @@ -135,6 +136,7 @@ _arguments "${_arguments_options[@]}" : \ '*--set=[override options in bootstrap.toml]:section.option=value:' \ '--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ '--all-targets[Check all targets]' \ +'--timings[Pass \`--timings\` to Cargo to get crate build timings]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh index 927d8f7661cd3..c2cb771002017 100644 --- a/src/etc/completions/x.sh +++ b/src/etc/completions/x.sh @@ -458,7 +458,7 @@ _x() { return 0 ;; x__build) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --timings --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -644,7 +644,7 @@ _x() { return 0 ;; x__check) - opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --all-targets --timings --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 65995553276d9..49139e70f7fb2 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -90,6 +90,7 @@ _arguments "${_arguments_options[@]}" : \ '*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \ '*--set=[override options in bootstrap.toml]:section.option=value:' \ '--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ +'--timings[Pass \`--timings\` to Cargo to get crate build timings]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ @@ -135,6 +136,7 @@ _arguments "${_arguments_options[@]}" : \ '*--set=[override options in bootstrap.toml]:section.option=value:' \ '--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \ '--all-targets[Check all targets]' \ +'--timings[Pass \`--timings\` to Cargo to get crate build timings]' \ '*-v[use verbose output (-vv for very verbose)]' \ '*--verbose[use verbose output (-vv for very verbose)]' \ '-i[use incremental compilation]' \ From 51eb5ed8f099cb8169ca48eb684ea98030988849 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 8 Aug 2025 19:54:27 +0300 Subject: [PATCH 168/252] resolve: Do not call `resolve_macro_path` from late resolution `maybe_resolve_path` is less precise in corner cases, but it's only used for diagnostics and error recovery, so it's good enough. --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/ident.rs | 2 +- compiler/rustc_resolve/src/late.rs | 22 +++++----------------- compiler/rustc_resolve/src/macros.rs | 15 ++++++--------- 4 files changed, 13 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8526b233ba222..f294ec748e7df 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1047,7 +1047,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; let Ok((Some(ext), _)) = this.reborrow().resolve_macro_path( derive, - Some(MacroKind::Derive), + MacroKind::Derive, parent_scope, false, false, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7ab932d9f2a03..5b430a18c04ec 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -469,7 +469,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; match this.reborrow().resolve_macro_path( derive, - Some(MacroKind::Derive), + MacroKind::Derive, parent_scope, true, force, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index e52cbeb733ac0..1e4ab57a3160a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4315,7 +4315,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { qself, path, ns, - path_span, source.defer_to_typeck(), finalize, source, @@ -4438,7 +4437,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { qself: &Option>, path: &[Segment], primary_ns: Namespace, - span: Span, defer_to_typeck: bool, finalize: Finalize, source: PathSource<'_, 'ast, 'ra>, @@ -4463,21 +4461,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } assert!(primary_ns != MacroNS); - - if qself.is_none() { - let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); - let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; - if let Ok((_, res)) = self.r.cm().resolve_macro_path( - &path, - None, - &self.parent_scope, - false, - false, - None, - None, - ) { - return Ok(Some(PartialRes::new(res))); - } + if qself.is_none() + && let PathResult::NonModule(res) = + self.r.cm().maybe_resolve_path(path, Some(MacroNS), &self.parent_scope, None) + { + return Ok(Some(res)); } Ok(fin_res) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 9f25635f1fd1a..72ed899024168 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -398,7 +398,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { resolution.exts = Some( match self.cm().resolve_macro_path( &resolution.path, - Some(MacroKind::Derive), + MacroKind::Derive, &parent_scope, true, force, @@ -563,7 +563,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Result<(Arc, Res), Indeterminate> { let (ext, res) = match self.cm().resolve_macro_or_delegation_path( path, - Some(kind), + kind, parent_scope, true, force, @@ -710,7 +710,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn resolve_macro_path<'r>( self: CmResolver<'r, 'ra, 'tcx>, path: &ast::Path, - kind: Option, + kind: MacroKind, parent_scope: &ParentScope<'ra>, trace: bool, force: bool, @@ -733,7 +733,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_macro_or_delegation_path<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, ast_path: &ast::Path, - kind: Option, + kind: MacroKind, parent_scope: &ParentScope<'ra>, trace: bool, force: bool, @@ -747,7 +747,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Possibly apply the macro helper hack if deleg_impl.is_none() - && kind == Some(MacroKind::Bang) + && kind == MacroKind::Bang && let [segment] = path.as_slice() && segment.ident.span.ctxt().outer_expn_data().local_inner_macros { @@ -775,7 +775,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; if trace { - let kind = kind.expect("macro kind must be specified if tracing is enabled"); // FIXME: Should be an output of Speculative Resolution. self.multi_segment_macro_resolutions.borrow_mut().push(( path, @@ -790,10 +789,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); res } else { - let scope_set = kind.map_or(ScopeSet::All(MacroNS), ScopeSet::Macro); let binding = self.reborrow().early_resolve_ident_in_lexical_scope( path[0].ident, - scope_set, + ScopeSet::Macro(kind), parent_scope, None, force, @@ -805,7 +803,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } if trace { - let kind = kind.expect("macro kind must be specified if tracing is enabled"); // FIXME: Should be an output of Speculative Resolution. self.single_segment_macro_resolutions.borrow_mut().push(( path[0].ident, From d682943396fdc0a8fcf907c570435d01a3035fe2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 8 Aug 2025 21:26:50 +0300 Subject: [PATCH 169/252] resolve: Do not show deprecated helper attributes in typo recommendations Remove one FIXME, addressing it does not reduce the hacky-ness much, and the logic is going to be removed anyway together with the `legacy_derive_helpers` deprecation lint. --- compiler/rustc_resolve/src/diagnostics.rs | 23 +------------------ compiler/rustc_resolve/src/ident.rs | 5 ---- .../proc-macro/proc-macro-attributes.stderr | 8 ++++++- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index f294ec748e7df..5f54411b463a5 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1041,28 +1041,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::DeriveHelpersCompat => { - let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat); - if filter_fn(res) { - for derive in parent_scope.derives { - let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - let Ok((Some(ext), _)) = this.reborrow().resolve_macro_path( - derive, - MacroKind::Derive, - parent_scope, - false, - false, - None, - None, - ) else { - continue; - }; - suggestions.extend( - ext.helper_attrs - .iter() - .map(|name| TypoSuggestion::typo_from_name(*name, res)), - ); - } - } + // Never recommend deprecated helper attributes. } Scope::MacroRules(macro_rules_scope) => { if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 5b430a18c04ec..dc01c94af5729 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -459,11 +459,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::DeriveHelpersCompat => { - // FIXME: Try running this logic earlier, to allocate name bindings for - // legacy derive helpers when creating an attribute invocation with - // following derives. Legacy derive helpers are not common, so it shouldn't - // affect performance. It should also allow to remove the `derives` - // component from `ParentScope`. let mut result = Err(Determinacy::Determined); for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; diff --git a/tests/ui/proc-macro/proc-macro-attributes.stderr b/tests/ui/proc-macro/proc-macro-attributes.stderr index 2cc57383eb39c..892728901fb99 100644 --- a/tests/ui/proc-macro/proc-macro-attributes.stderr +++ b/tests/ui/proc-macro/proc-macro-attributes.stderr @@ -2,7 +2,13 @@ error: cannot find attribute `C` in this scope --> $DIR/proc-macro-attributes.rs:9:3 | LL | #[C] - | ^ help: a derive helper attribute with a similar name exists: `B` + | ^ + | +help: the derive macro `B` accepts the similarly named `B` attribute + | +LL - #[C] +LL + #[B] + | error[E0659]: `B` is ambiguous --> $DIR/proc-macro-attributes.rs:6:3 From 9b797b9f7ac12a8ad6a2a5097b69e0216958709e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 13 Aug 2025 22:01:02 +0300 Subject: [PATCH 170/252] resolve: Improve code reuse in typo candidate collection --- compiler/rustc_resolve/src/diagnostics.rs | 25 ++++++--- .../rustc_resolve/src/late/diagnostics.rs | 51 +++++++------------ tests/ui/hygiene/arguments.stderr | 3 ++ .../hygiene/cross-crate-name-hiding-2.stderr | 5 ++ tests/ui/hygiene/globs.stderr | 14 ++--- 5 files changed, 52 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5f54411b463a5..c5fcbdfb42fe7 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1016,16 +1016,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .emit() } - /// Lookup typo candidate in scope for a macro or import. - fn early_lookup_typo_candidate( + pub(crate) fn add_scope_set_candidates( &mut self, + suggestions: &mut Vec, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, - ident: Ident, + ctxt: SyntaxContext, filter_fn: &impl Fn(Res) -> bool, - ) -> Option { - let mut suggestions = Vec::new(); - let ctxt = ident.span.ctxt(); + ) { self.cm().visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| { match scope { Scope::DeriveHelpers(expn_id) => { @@ -1055,7 +1053,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } Scope::Module(module, _) => { - this.add_module_candidates(module, &mut suggestions, filter_fn, None); + this.add_module_candidates(module, suggestions, filter_fn, None); } Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map( @@ -1113,6 +1111,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None::<()> }); + } + + /// Lookup typo candidate in scope for a macro or import. + fn early_lookup_typo_candidate( + &mut self, + scope_set: ScopeSet<'ra>, + parent_scope: &ParentScope<'ra>, + ident: Ident, + filter_fn: &impl Fn(Res) -> bool, + ) -> Option { + let mut suggestions = Vec::new(); + let ctxt = ident.span.ctxt(); + self.add_scope_set_candidates(&mut suggestions, scope_set, parent_scope, ctxt, filter_fn); // Make sure error reporting is deterministic. suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str())); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c8cab5a0fe9a1..6a753b380359f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -38,8 +38,8 @@ use crate::late::{ }; use crate::ty::fast_reject::SimplifiedType; use crate::{ - Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, Segment, errors, - path_names_to_string, + Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, ScopeSet, Segment, + errors, path_names_to_string, }; type Res = def::Res; @@ -2458,45 +2458,30 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } + if let RibKind::Module(module) = rib.kind + && let ModuleKind::Block = module.kind + { + self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt)); + } else if let RibKind::Module(module) = rib.kind { + // Encountered a module item, abandon ribs and look into that module and preludes. + self.r.add_scope_set_candidates( + &mut names, + ScopeSet::Late(ns, module, None), + &self.parent_scope, + ctxt, + filter_fn, + ); + break; + } + if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. ctxt.remove_mark(); - continue; - } - - // Items in scope - if let RibKind::Module(module) = rib.kind { - // Items from this module - self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt)); - - if let ModuleKind::Block = module.kind { - // We can see through blocks - } else { - // Items from the prelude - if !module.no_implicit_prelude { - names.extend(self.r.extern_prelude.keys().flat_map(|ident| { - let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()); - filter_fn(res) - .then_some(TypoSuggestion::typo_from_ident(ident.0, res)) - })); - - if let Some(prelude) = self.r.prelude { - self.r.add_module_candidates(prelude, &mut names, &filter_fn, None); - } - } - break; - } } } - // Add primitive types to the mix - if filter_fn(Res::PrimTy(PrimTy::Bool)) { - names.extend(PrimTy::ALL.iter().map(|prim_ty| { - TypoSuggestion::typo_from_name(prim_ty.name(), Res::PrimTy(*prim_ty)) - })) - } } else { // Search in module. let mod_path = &path[..path.len() - 1]; diff --git a/tests/ui/hygiene/arguments.stderr b/tests/ui/hygiene/arguments.stderr index 0d8d652b6f33d..fe92daf643796 100644 --- a/tests/ui/hygiene/arguments.stderr +++ b/tests/ui/hygiene/arguments.stderr @@ -1,6 +1,9 @@ error[E0412]: cannot find type `S` in this scope --> $DIR/arguments.rs:14:8 | +LL | struct S; + | - you might have meant to refer to this struct +... LL | m!(S, S); | ^ not found in this scope diff --git a/tests/ui/hygiene/cross-crate-name-hiding-2.stderr b/tests/ui/hygiene/cross-crate-name-hiding-2.stderr index a5d509fab996f..fe3a12e93a7e7 100644 --- a/tests/ui/hygiene/cross-crate-name-hiding-2.stderr +++ b/tests/ui/hygiene/cross-crate-name-hiding-2.stderr @@ -3,6 +3,11 @@ error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope | LL | let x = MyStruct {}; | ^^^^^^^^ not found in this scope + | + ::: $DIR/auxiliary/use_by_macro.rs:15:1 + | +LL | x!(my_struct); + | ------------- you might have meant to refer to this struct error: aborting due to 1 previous error diff --git a/tests/ui/hygiene/globs.stderr b/tests/ui/hygiene/globs.stderr index 31f25b182f1f5..85946bf34bc53 100644 --- a/tests/ui/hygiene/globs.stderr +++ b/tests/ui/hygiene/globs.stderr @@ -48,7 +48,10 @@ error[E0425]: cannot find function `f` in this scope --> $DIR/globs.rs:61:12 | LL | n!(f); - | ----- in this macro invocation + | ----- + | | | + | | you might have meant to refer to this function + | in this macro invocation ... LL | $j(); | -- due to this macro variable @@ -56,15 +59,16 @@ LL | $j(); LL | n!(f); | ^ not found in this scope | - = help: consider importing this function: - foo::f = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find function `f` in this scope --> $DIR/globs.rs:65:17 | LL | n!(f); - | ----- in this macro invocation + | ----- + | | | + | | you might have meant to refer to this function + | in this macro invocation ... LL | $j(); | -- due to this macro variable @@ -72,8 +76,6 @@ LL | $j(); LL | f | ^ not found in this scope | - = help: consider importing this function: - foo::f = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors From 3f1e99dca47b2cfc33906f1f1334fbed3a9fc4ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Jul 2025 16:59:06 +0200 Subject: [PATCH 171/252] PatKind: store constants as valtrees --- compiler/rustc_middle/src/thir.rs | 9 +- compiler/rustc_middle/src/thir/visit.rs | 2 +- .../src/builder/custom/parse/instruction.rs | 6 +- .../src/builder/matches/match_pair.rs | 6 +- .../src/builder/matches/mod.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 16 ++-- .../rustc_mir_build/src/thir/pattern/mod.rs | 13 ++- compiler/rustc_mir_build/src/thir/print.rs | 2 +- compiler/rustc_pattern_analysis/src/rustc.rs | 84 ++++++++----------- compiler/rustc_ty_utils/src/consts.rs | 2 +- .../ui/thir-print/thir-tree-loop-match.stdout | 4 +- 11 files changed, 68 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3dd6d2c892869..8569f57b79da0 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -832,17 +832,20 @@ pub enum PatKind<'tcx> { }, /// One of the following: - /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus + /// * `&str`, which will be handled as a string pattern and thus /// exhaustiveness checking will detect if you use the same string twice in different /// patterns. - /// * integer, bool, char or float (represented as a valtree), which will be handled by + /// * integer, bool, char or float, which will be handled by /// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are /// much simpler. /// * raw pointers derived from integers, other raw pointers will have already resulted in an // error. /// * `String`, if `string_deref_patterns` is enabled. Constant { - value: mir::Const<'tcx>, + // Not using `ty::Value` since this is conceptually not a type-level constant. In + // particular, it can have raw pointers. + ty: Ty<'tcx>, + value: ty::ValTree<'tcx>, }, /// Pattern obtained by converting a constant (inline or named) to its pattern diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index dcfa6c4db3274..9d3ba74ad0fd8 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -265,7 +265,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( PatKind::Missing | PatKind::Wild | PatKind::Binding { subpattern: None, .. } - | PatKind::Constant { value: _ } + | PatKind::Constant { .. } | PatKind::Range(_) | PatKind::Never | PatKind::Error(_) => {} diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 9825b947fe09a..dbe4ab9937fb1 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -146,9 +146,9 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { for arm in rest { let arm = &self.thir[*arm]; let value = match arm.pattern.kind { - PatKind::Constant { value } => value, + PatKind::Constant { value, .. } => value, PatKind::ExpandedConstant { ref subpattern, def_id: _ } - if let PatKind::Constant { value } = subpattern.kind => + if let PatKind::Constant { value, .. } = subpattern.kind => { value } @@ -160,7 +160,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { }); } }; - values.push(value.eval_bits(self.tcx, self.typing_env)); + values.push(value.unwrap_leaf().to_bits_unchecked()); targets.push(self.parse_block(arm.body)?); } diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 7a848536d0e33..19ea9cd52b280 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -146,7 +146,11 @@ impl<'tcx> MatchPairTree<'tcx> { } } - PatKind::Constant { value } => Some(TestCase::Constant { value }), + PatKind::Constant { ty: value_ty, value } => { + // FIXME: `TestCase::Constant` should probably represent that it is always a `ValTree`. + let value = Const::Ty(value_ty, ty::Const::new_value(cx.tcx, value, value_ty)); + Some(TestCase::Constant { value }) + } PatKind::AscribeUserType { ascription: Ascription { ref annotation, variance }, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 94ae5dadd8ace..b347d2dbd2afe 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1321,7 +1321,7 @@ enum TestKind<'tcx> { value: Const<'tcx>, // Integer types are handled by `SwitchInt`, and constants with ADT // types and `&[T]` types are converted back into patterns, so this can - // only be `&str`, `f32` or `f64`. + // only be `&str` or `f*`. ty: Ty<'tcx>, }, diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index a501cdf88c20b..c1e9da3925edc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -11,11 +11,11 @@ use rustc_index::Idx; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::span_bug; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, ValTree, }; -use rustc_middle::{mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::traits::ObligationCause; @@ -288,16 +288,12 @@ impl<'tcx> ConstToPat<'tcx> { // when lowering to MIR in `Builder::perform_test`, treat the constant as a `&str`. // This works because `str` and `&str` have the same valtree representation. let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty); - PatKind::Constant { - value: mir::Const::Ty(ref_str_ty, ty::Const::new_value(tcx, cv, ref_str_ty)), - } + PatKind::Constant { ty: ref_str_ty, value: cv } } ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // `&str` is represented as a valtree, let's keep using this // optimization for now. - ty::Str => PatKind::Constant { - value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), - }, + ty::Str => PatKind::Constant { ty, value: cv }, // All other references are converted into deref patterns and then recursively // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. @@ -326,15 +322,13 @@ impl<'tcx> ConstToPat<'tcx> { // Also see . return self.mk_err(tcx.dcx().create_err(NaNPattern { span }), ty); } else { - PatKind::Constant { - value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), - } + PatKind::Constant { ty, value: cv } } } ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { // The raw pointers we see here have been "vetted" by valtree construction to be // just integers, so we simply allow them. - PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)) } + PatKind::Constant { ty, value: cv } } ty::FnPtr(..) => { unreachable!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a44afed5492d3..25fff0a3c237f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::thir::{ use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode}; -use rustc_middle::{bug, span_bug}; +use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::{ErrorGuaranteed, Span}; use tracing::{debug, instrument}; @@ -156,12 +156,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } // The unpeeled kind should now be a constant, giving us the endpoint value. - let PatKind::Constant { value } = kind else { + let PatKind::Constant { ty, value } = kind else { let msg = format!("found bad range pattern endpoint `{expr:?}` outside of error recovery"); return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg)); }; - + // FIXME: `Finite` should probably take a `ValTree` or even a `ScalarInt` + // (but it should also be the same type as what `TestCase::Constant` uses, or at least + // easy to convert). + let value = mir::Const::Ty(ty, ty::Const::new_value(self.tcx, value, ty)); Ok(Some(PatRangeBoundary::Finite(value))) } @@ -244,7 +247,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { (RangeEnd::Included, Some(Ordering::Less)) => {} // `x..=y` where `x == y` and `x` and `y` are finite. (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => { - kind = PatKind::Constant { value: lo.as_finite().unwrap() }; + // FIXME: silly conversion because not all pattern stuff uses valtrees yet. + let mir::Const::Ty(ty, val) = lo.as_finite().unwrap() else { unreachable!() }; + kind = PatKind::Constant { ty, value: val.to_value().valtree }; } // `..=x` where `x == ty::MIN`. (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {} diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 5efc4be2de2df..899f3e04ba2a1 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -761,7 +761,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Constant { value } => { + PatKind::Constant { value, ty: _ } => { print_indented!(self, "Constant {", depth_lvl + 1); print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 0c1b0d622f229..0396cdc1aa292 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -517,78 +517,57 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ), } } - PatKind::Constant { value } => { + PatKind::Constant { ty: value_ty, value } => { match ty.kind() { ty::Bool => { - ctor = match value.try_eval_bool(cx.tcx, cx.typing_env) { - Some(b) => Bool(b), - None => Opaque(OpaqueId::new()), - }; + ctor = Bool(value.unwrap_leaf().try_to_bool().unwrap()); fields = vec![]; arity = 0; } ty::Char | ty::Int(_) | ty::Uint(_) => { - ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) { - Some(bits) => { - let x = match *ty.kind() { - ty::Int(ity) => { - let size = Integer::from_int_ty(&cx.tcx, ity).size().bits(); - MaybeInfiniteInt::new_finite_int(bits, size) - } - _ => MaybeInfiniteInt::new_finite_uint(bits), - }; - IntRange(IntRange::from_singleton(x)) - } - None => Opaque(OpaqueId::new()), + ctor = { + let bits = value.unwrap_leaf().to_bits_unchecked(); + let x = match *ty.kind() { + ty::Int(ity) => { + let size = Integer::from_int_ty(&cx.tcx, ity).size().bits(); + MaybeInfiniteInt::new_finite_int(bits, size) + } + _ => MaybeInfiniteInt::new_finite_uint(bits), + }; + IntRange(IntRange::from_singleton(x)) }; fields = vec![]; arity = 0; } ty::Float(ty::FloatTy::F16) => { - ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) { - Some(bits) => { - use rustc_apfloat::Float; - let value = rustc_apfloat::ieee::Half::from_bits(bits); - F16Range(value, value, RangeEnd::Included) - } - None => Opaque(OpaqueId::new()), - }; + use rustc_apfloat::Float; + let bits = value.unwrap_leaf().to_u16(); + let value = rustc_apfloat::ieee::Half::from_bits(bits.into()); + ctor = F16Range(value, value, RangeEnd::Included); fields = vec![]; arity = 0; } ty::Float(ty::FloatTy::F32) => { - ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) { - Some(bits) => { - use rustc_apfloat::Float; - let value = rustc_apfloat::ieee::Single::from_bits(bits); - F32Range(value, value, RangeEnd::Included) - } - None => Opaque(OpaqueId::new()), - }; + use rustc_apfloat::Float; + let bits = value.unwrap_leaf().to_u32(); + let value = rustc_apfloat::ieee::Single::from_bits(bits.into()); + ctor = F32Range(value, value, RangeEnd::Included); fields = vec![]; arity = 0; } ty::Float(ty::FloatTy::F64) => { - ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) { - Some(bits) => { - use rustc_apfloat::Float; - let value = rustc_apfloat::ieee::Double::from_bits(bits); - F64Range(value, value, RangeEnd::Included) - } - None => Opaque(OpaqueId::new()), - }; + use rustc_apfloat::Float; + let bits = value.unwrap_leaf().to_u64(); + let value = rustc_apfloat::ieee::Double::from_bits(bits.into()); + ctor = F64Range(value, value, RangeEnd::Included); fields = vec![]; arity = 0; } ty::Float(ty::FloatTy::F128) => { - ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) { - Some(bits) => { - use rustc_apfloat::Float; - let value = rustc_apfloat::ieee::Quad::from_bits(bits); - F128Range(value, value, RangeEnd::Included) - } - None => Opaque(OpaqueId::new()), - }; + use rustc_apfloat::Float; + let bits = value.unwrap_leaf().to_u128(); + let value = rustc_apfloat::ieee::Quad::from_bits(bits); + ctor = F128Range(value, value, RangeEnd::Included); fields = vec![]; arity = 0; } @@ -601,7 +580,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // subfields. // Note: `t` is `str`, not `&str`. let ty = self.reveal_opaque_ty(*t); - let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), 0, ty, pat); + // FIXME: why does `Str` need a `mir::Value`? + let val = mir::Const::Ty( + *value_ty, + ty::Const::new_value(self.tcx, *value, *value_ty), + ); + let subpattern = DeconstructedPat::new(Str(val), Vec::new(), 0, ty, pat); ctor = Ref; fields = vec![subpattern.at_index(0)]; arity = 1; diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index eb751da7c7363..6d994a2b967f7 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -375,7 +375,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { } match pat.kind { - thir::PatKind::Constant { value } => value.has_non_region_param(), + thir::PatKind::Constant { value, .. } => value.has_non_region_param(), thir::PatKind::Range(ref range) => { let &thir::PatRange { lo, hi, .. } = range.as_ref(); lo.has_non_region_param() || hi.has_non_region_param() diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout index 5c4c50cb15623..b3d11050bdcd4 100644 --- a/tests/ui/thir-print/thir-tree-loop-match.stdout +++ b/tests/ui/thir-print/thir-tree-loop-match.stdout @@ -121,7 +121,7 @@ body: span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0) kind: PatKind { Constant { - value: Ty(bool, true) + value: Leaf(0x01) } } } @@ -219,7 +219,7 @@ body: span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0) kind: PatKind { Constant { - value: Ty(bool, false) + value: Leaf(0x00) } } } From d61fdbf266cf25ddf8c4798fd86e21577c8664e8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Jul 2025 18:16:47 +0200 Subject: [PATCH 172/252] pattern testing: store constants as valtrees --- compiler/rustc_middle/src/thir.rs | 73 +++++++------------ .../rustc_middle/src/ty/consts/valtree.rs | 13 ++++ .../rustc_middle/src/ty/structural_impls.rs | 13 +--- .../src/builder/matches/match_pair.rs | 6 +- .../src/builder/matches/mod.rs | 15 ++-- .../src/builder/matches/test.rs | 69 +++++++++--------- .../rustc_mir_build/src/thir/pattern/mod.rs | 14 +--- compiler/rustc_mir_build/src/thir/print.rs | 3 +- compiler/rustc_pattern_analysis/src/rustc.rs | 18 +++-- .../ui/thir-print/thir-tree-loop-match.stdout | 2 + 10 files changed, 106 insertions(+), 120 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 8569f57b79da0..62f76671b78ed 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -937,8 +937,8 @@ impl<'tcx> PatRange<'tcx> { // Also, for performance, it's important to only do the second `try_to_bits` if necessary. let lo_is_min = match self.lo { PatRangeBoundary::NegInfinity => true, - PatRangeBoundary::Finite(value) => { - let lo = value.try_to_bits(size).unwrap() ^ bias; + PatRangeBoundary::Finite(_ty, value) => { + let lo = value.unwrap_leaf().to_bits(size) ^ bias; lo <= min } PatRangeBoundary::PosInfinity => false, @@ -946,8 +946,8 @@ impl<'tcx> PatRange<'tcx> { if lo_is_min { let hi_is_max = match self.hi { PatRangeBoundary::NegInfinity => false, - PatRangeBoundary::Finite(value) => { - let hi = value.try_to_bits(size).unwrap() ^ bias; + PatRangeBoundary::Finite(_ty, value) => { + let hi = value.unwrap_leaf().to_bits(size) ^ bias; hi > max || hi == max && self.end == RangeEnd::Included } PatRangeBoundary::PosInfinity => true, @@ -960,22 +960,16 @@ impl<'tcx> PatRange<'tcx> { } #[inline] - pub fn contains( - &self, - value: mir::Const<'tcx>, - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - ) -> Option { + pub fn contains(&self, value: ty::ValTree<'tcx>, tcx: TyCtxt<'tcx>) -> Option { use Ordering::*; - debug_assert_eq!(self.ty, value.ty()); let ty = self.ty; - let value = PatRangeBoundary::Finite(value); + let value = PatRangeBoundary::Finite(ty, value); // For performance, it's important to only do the second comparison if necessary. Some( - match self.lo.compare_with(value, ty, tcx, typing_env)? { + match self.lo.compare_with(value, ty, tcx)? { Less | Equal => true, Greater => false, - } && match value.compare_with(self.hi, ty, tcx, typing_env)? { + } && match value.compare_with(self.hi, ty, tcx)? { Less => true, Equal => self.end == RangeEnd::Included, Greater => false, @@ -984,21 +978,16 @@ impl<'tcx> PatRange<'tcx> { } #[inline] - pub fn overlaps( - &self, - other: &Self, - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - ) -> Option { + pub fn overlaps(&self, other: &Self, tcx: TyCtxt<'tcx>) -> Option { use Ordering::*; debug_assert_eq!(self.ty, other.ty); // For performance, it's important to only do the second comparison if necessary. Some( - match other.lo.compare_with(self.hi, self.ty, tcx, typing_env)? { + match other.lo.compare_with(self.hi, self.ty, tcx)? { Less => true, Equal => self.end == RangeEnd::Included, Greater => false, - } && match self.lo.compare_with(other.hi, self.ty, tcx, typing_env)? { + } && match self.lo.compare_with(other.hi, self.ty, tcx)? { Less => true, Equal => other.end == RangeEnd::Included, Greater => false, @@ -1009,10 +998,13 @@ impl<'tcx> PatRange<'tcx> { impl<'tcx> fmt::Display for PatRange<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let PatRangeBoundary::Finite(value) = &self.lo { + if let &PatRangeBoundary::Finite(ty, value) = &self.lo { + // `ty::Value` has a reasonable pretty-printing implementation. + let value = ty::Value { ty, valtree: value }; write!(f, "{value}")?; } - if let PatRangeBoundary::Finite(value) = &self.hi { + if let &PatRangeBoundary::Finite(ty, value) = &self.hi { + let value = ty::Value { ty, valtree: value }; write!(f, "{}", self.end)?; write!(f, "{value}")?; } else { @@ -1027,7 +1019,7 @@ impl<'tcx> fmt::Display for PatRange<'tcx> { /// If present, the const must be of a numeric type. #[derive(Copy, Clone, Debug, PartialEq, HashStable, TypeVisitable)] pub enum PatRangeBoundary<'tcx> { - Finite(mir::Const<'tcx>), + Finite(Ty<'tcx>, ty::ValTree<'tcx>), NegInfinity, PosInfinity, } @@ -1038,20 +1030,15 @@ impl<'tcx> PatRangeBoundary<'tcx> { matches!(self, Self::Finite(..)) } #[inline] - pub fn as_finite(self) -> Option> { + pub fn as_finite(self) -> Option> { match self { - Self::Finite(value) => Some(value), + Self::Finite(_ty, value) => Some(value), Self::NegInfinity | Self::PosInfinity => None, } } - pub fn eval_bits( - self, - ty: Ty<'tcx>, - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - ) -> u128 { + pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> u128 { match self { - Self::Finite(value) => value.eval_bits(tcx, typing_env), + Self::Finite(_ty, value) => value.unwrap_leaf().to_bits_unchecked(), Self::NegInfinity => { // Unwrap is ok because the type is known to be numeric. ty.numeric_min_and_max_as_bits(tcx).unwrap().0 @@ -1063,14 +1050,8 @@ impl<'tcx> PatRangeBoundary<'tcx> { } } - #[instrument(skip(tcx, typing_env), level = "debug", ret)] - pub fn compare_with( - self, - other: Self, - ty: Ty<'tcx>, - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - ) -> Option { + #[instrument(skip(tcx), level = "debug", ret)] + pub fn compare_with(self, other: Self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option { use PatRangeBoundary::*; match (self, other) { // When comparing with infinities, we must remember that `0u8..` and `0u8..=255` @@ -1084,7 +1065,9 @@ impl<'tcx> PatRangeBoundary<'tcx> { // we can do scalar comparisons. E.g. `unicode-normalization` has // many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared // in this way. - (Finite(a), Finite(b)) if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) => { + (Finite(_, a), Finite(_, b)) + if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) => + { if let (Some(a), Some(b)) = (a.try_to_scalar_int(), b.try_to_scalar_int()) { let sz = ty.primitive_size(tcx); let cmp = match ty.kind() { @@ -1098,8 +1081,8 @@ impl<'tcx> PatRangeBoundary<'tcx> { _ => {} } - let a = self.eval_bits(ty, tcx, typing_env); - let b = other.eval_bits(ty, tcx, typing_env); + let a = self.eval_bits(ty, tcx); + let b = other.eval_bits(ty, tcx); match ty.kind() { ty::Float(ty::FloatTy::F16) => { diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index d95006dcf4a62..002a86a8897a0 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -2,10 +2,12 @@ use std::fmt; use std::ops::Deref; use rustc_data_structures::intern::Interned; +use rustc_hir::def::Namespace; use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use super::ScalarInt; use crate::mir::interpret::{ErrorHandled, Scalar}; +use crate::ty::print::{FmtPrinter, PrettyPrinter}; use crate::ty::{self, Ty, TyCtxt}; /// This datastructure is used to represent the value of constants used in the type system. @@ -203,3 +205,14 @@ impl<'tcx> rustc_type_ir::inherent::ValueConst> for Value<'tcx> { self.valtree } } + +impl<'tcx> fmt::Display for Value<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ty::tls::with(move |tcx| { + let cv = tcx.lift(*self).unwrap(); + let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); + p.pretty_print_const_valtree(cv, /*print_ty*/ true)?; + f.write_str(&p.into_buffer()) + }) + } +} diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 0e2aff6f9bdac..89ef46b1ae571 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -12,7 +12,6 @@ use rustc_hir::def_id::LocalDefId; use rustc_span::source_map::Spanned; use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit}; -use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Pattern, Region}; use crate::mir::PlaceElem; use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths}; @@ -168,15 +167,11 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // If this is a value, we spend some effort to make it look nice. if let ConstKind::Value(cv) = self.kind() { - return ty::tls::with(move |tcx| { - let cv = tcx.lift(cv).unwrap(); - let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); - p.pretty_print_const_valtree(cv, /*print_ty*/ true)?; - f.write_str(&p.into_buffer()) - }); + write!(f, "{}", cv) + } else { + // Fall back to something verbose. + write!(f, "{:?}", self.kind()) } - // Fall back to something verbose. - write!(f, "{:?}", self.kind()) } } diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 19ea9cd52b280..14a237af94e99 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -146,11 +146,7 @@ impl<'tcx> MatchPairTree<'tcx> { } } - PatKind::Constant { ty: value_ty, value } => { - // FIXME: `TestCase::Constant` should probably represent that it is always a `ValTree`. - let value = Const::Ty(value_ty, ty::Const::new_value(cx.tcx, value, value_ty)); - Some(TestCase::Constant { value }) - } + PatKind::Constant { ty, value } => Some(TestCase::Constant { ty, value }), PatKind::AscribeUserType { ascription: Ascription { ref annotation, variance }, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index b347d2dbd2afe..99c3611fb8a0b 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -16,7 +16,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::{BindingMode, ByRef, LetStmt, LocalSource, Node}; use rustc_middle::bug; use rustc_middle::middle::region; -use rustc_middle::mir::{self, *}; +use rustc_middle::mir::*; use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind}; use rustc_pattern_analysis::constructor::RangeEnd; @@ -1245,7 +1245,7 @@ struct Ascription<'tcx> { #[derive(Debug, Clone)] enum TestCase<'tcx> { Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx }, - Constant { value: mir::Const<'tcx> }, + Constant { ty: Ty<'tcx>, value: ty::ValTree<'tcx> }, Range(Arc>), Slice { len: usize, variable_length: bool }, Deref { temp: Place<'tcx>, mutability: Mutability }, @@ -1318,11 +1318,12 @@ enum TestKind<'tcx> { /// Test for equality with value, possibly after an unsizing coercion to /// `ty`, Eq { - value: Const<'tcx>, + value: ty::ValTree<'tcx>, + value_ty: Ty<'tcx>, // Integer types are handled by `SwitchInt`, and constants with ADT // types and `&[T]` types are converted back into patterns, so this can // only be `&str` or `f*`. - ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, }, /// Test whether the value falls within an inclusive or exclusive range. @@ -1358,7 +1359,7 @@ enum TestBranch<'tcx> { /// Success branch, used for tests with two possible outcomes. Success, /// Branch corresponding to this constant. - Constant(Const<'tcx>, u128), + Constant(ty::ValTree<'tcx>, u128), /// Branch corresponding to this variant. Variant(VariantIdx), /// Failure branch for tests with two possible outcomes, and "otherwise" branch for other tests. @@ -1366,8 +1367,8 @@ enum TestBranch<'tcx> { } impl<'tcx> TestBranch<'tcx> { - fn as_constant(&self) -> Option<&Const<'tcx>> { - if let Self::Constant(v, _) = self { Some(v) } else { None } + fn as_constant(&self) -> Option> { + if let Self::Constant(v, _) = self { Some(*v) } else { None } } } diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index a4609a6053ea5..6ccaafc1f35a5 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -35,7 +35,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestCase::Constant { .. } if match_pair.pattern_ty.is_bool() => TestKind::If, TestCase::Constant { .. } if is_switch_ty(match_pair.pattern_ty) => TestKind::SwitchInt, - TestCase::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern_ty }, + TestCase::Constant { value, ty: value_ty } => { + TestKind::Eq { value, value_ty, cast_ty: match_pair.pattern_ty } + } TestCase::Range(ref range) => { assert_eq!(range.ty, match_pair.pattern_ty); @@ -135,17 +137,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(block, self.source_info(match_start_span), terminator); } - TestKind::Eq { value, mut ty } => { + TestKind::Eq { value, value_ty, mut cast_ty } => { let tcx = self.tcx; let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); - let mut expect_ty = value.ty(); + let mut expect_ty = value_ty; + let value = Const::Ty(value_ty, ty::Const::new_value(tcx, value, value_ty)); let mut expect = self.literal_operand(test.span, value); let mut place = place; let mut block = block; - match ty.kind() { + match cast_ty.kind() { ty::Str => { // String literal patterns may have type `str` if `deref_patterns` is // enabled, in order to allow `deref!("..."): String`. In this case, `value` @@ -167,7 +170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Ref(re_erased, BorrowKind::Shared, place), ); place = ref_place; - ty = ref_str_ty; + cast_ty = ref_str_ty; } ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => { if !tcx.features().string_deref_patterns() { @@ -186,7 +189,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { eq_block, place, Mutability::Not, - ty, + cast_ty, ref_str, test.span, ); @@ -195,10 +198,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Similarly, the normal test code should be generated for the `&str`, instead of the `String`. block = eq_block; place = ref_str; - ty = ref_str_ty; + cast_ty = ref_str_ty; } &ty::Pat(base, _) => { - assert_eq!(ty, value.ty()); + assert_eq!(cast_ty, value_ty); assert!(base.is_trivially_pure_clone_copy()); let transmuted_place = self.temp(base, test.span); @@ -219,14 +222,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place = transmuted_place; expect = Operand::Copy(transmuted_expect); - ty = base; + cast_ty = base; expect_ty = base; } _ => {} } - assert_eq!(expect_ty, ty); - if !ty.is_scalar() { + assert_eq!(expect_ty, cast_ty); + if !cast_ty.is_scalar() { // Use `PartialEq::eq` instead of `BinOp::Eq` // (the binop can only handle primitives) // Make sure that we do *not* call any user-defined code here. @@ -234,10 +237,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // comparison defined in `core`. // (Interestingly this means that exhaustiveness analysis relies, for soundness, // on the `PartialEq` impl for `str` to b correct!) - match *ty.kind() { + match *cast_ty.kind() { ty::Ref(_, deref_ty, _) if deref_ty == self.tcx.types.str_ => {} _ => { - span_bug!(source_info.span, "invalid type for non-scalar compare: {ty}") + span_bug!( + source_info.span, + "invalid type for non-scalar compare: {cast_ty}" + ) } }; self.string_compare( @@ -276,6 +282,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; if let Some(lo) = range.lo.as_finite() { + let lo = Const::Ty(range.ty, ty::Const::new_value(self.tcx, lo, range.ty)); let lo = self.literal_operand(test.span, lo); self.compare( block, @@ -289,6 +296,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; if let Some(hi) = range.hi.as_finite() { + let hi = Const::Ty(range.ty, ty::Const::new_value(self.tcx, hi, range.ty)); let hi = self.literal_operand(test.span, hi); let op = match range.end { RangeEnd::Included => BinOp::Le, @@ -545,7 +553,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // FIXME(#29623) we could use PatKind::Range to rule // things out here, in some cases. - (TestKind::SwitchInt, &TestCase::Constant { value }) + (TestKind::SwitchInt, &TestCase::Constant { value, .. }) if is_switch_ty(match_pair.pattern_ty) => { // An important invariant of candidate sorting is that a candidate @@ -555,10 +563,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // not to add such values here. let is_covering_range = |test_case: &TestCase<'tcx>| { test_case.as_range().is_some_and(|range| { - matches!( - range.contains(value, self.tcx, self.typing_env()), - None | Some(true) - ) + matches!(range.contains(value, self.tcx), None | Some(true)) }) }; let is_conflicting_candidate = |candidate: &&mut Candidate<'tcx>| { @@ -575,7 +580,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None } else { fully_matched = true; - let bits = value.eval_bits(self.tcx, self.typing_env()); + let bits = value.unwrap_leaf().to_bits_unchecked(); Some(TestBranch::Constant(value, bits)) } } @@ -585,12 +590,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // the values being tested. (This restricts what values can be // added to the test by subsequent candidates.) fully_matched = false; - let not_contained = - sorted_candidates.keys().filter_map(|br| br.as_constant()).copied().all( - |val| { - matches!(range.contains(val, self.tcx, self.typing_env()), Some(false)) - }, - ); + let not_contained = sorted_candidates + .keys() + .filter_map(|br| br.as_constant()) + .all(|val| matches!(range.contains(val, self.tcx), Some(false))); not_contained.then(|| { // No switch values are contained in the pattern range, @@ -599,9 +602,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) } - (TestKind::If, TestCase::Constant { value }) => { + (TestKind::If, TestCase::Constant { value, .. }) => { fully_matched = true; - let value = value.try_eval_bool(self.tcx, self.typing_env()).unwrap_or_else(|| { + let value = value.unwrap_leaf().try_to_bool().unwrap_or_else(|_| { span_bug!(test.span, "expected boolean value but got {value:?}") }); Some(if value { TestBranch::Success } else { TestBranch::Failure }) @@ -681,16 +684,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fully_matched = false; // If the testing range does not overlap with pattern range, // the pattern can be matched only if this test fails. - if !test.overlaps(pat, self.tcx, self.typing_env())? { - Some(TestBranch::Failure) - } else { - None - } + if !test.overlaps(pat, self.tcx)? { Some(TestBranch::Failure) } else { None } } } - (TestKind::Range(range), &TestCase::Constant { value }) => { + (TestKind::Range(range), &TestCase::Constant { value, .. }) => { fully_matched = false; - if !range.contains(value, self.tcx, self.typing_env())? { + if !range.contains(value, self.tcx)? { // `value` is not contained in the testing range, // so `value` can be matched only if this test fails. Some(TestBranch::Failure) @@ -699,7 +698,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) => { + (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val, .. }) => { if test_val == case_val { fully_matched = true; Some(TestBranch::Success) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 25fff0a3c237f..3a4e33b59d792 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::thir::{ use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode}; -use rustc_middle::{bug, mir, span_bug}; +use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_span::{ErrorGuaranteed, Span}; use tracing::{debug, instrument}; @@ -161,11 +161,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { format!("found bad range pattern endpoint `{expr:?}` outside of error recovery"); return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg)); }; - // FIXME: `Finite` should probably take a `ValTree` or even a `ScalarInt` - // (but it should also be the same type as what `TestCase::Constant` uses, or at least - // easy to convert). - let value = mir::Const::Ty(ty, ty::Const::new_value(self.tcx, value, ty)); - Ok(Some(PatRangeBoundary::Finite(value))) + Ok(Some(PatRangeBoundary::Finite(ty, value))) } /// Overflowing literals are linted against in a late pass. This is mostly fine, except when we @@ -238,7 +234,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity); let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity); - let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env); + let cmp = lo.compare_with(hi, ty, self.tcx); let mut kind = PatKind::Range(Arc::new(PatRange { lo, hi, end, ty })); match (end, cmp) { // `x..y` where `x < y`. @@ -247,9 +243,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { (RangeEnd::Included, Some(Ordering::Less)) => {} // `x..=y` where `x == y` and `x` and `y` are finite. (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => { - // FIXME: silly conversion because not all pattern stuff uses valtrees yet. - let mir::Const::Ty(ty, val) = lo.as_finite().unwrap() else { unreachable!() }; - kind = PatKind::Constant { ty, value: val.to_value().valtree }; + kind = PatKind::Constant { ty, value: lo.as_finite().unwrap() }; } // `..=x` where `x == ty::MIN`. (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {} diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 899f3e04ba2a1..e5ee60150a7e2 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -761,8 +761,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Constant { value, ty: _ } => { + PatKind::Constant { value, ty } => { print_indented!(self, "Constant {", depth_lvl + 1); + print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 0396cdc1aa292..26574c5fcfc69 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -429,8 +429,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ) -> MaybeInfiniteInt { match bdy { PatRangeBoundary::NegInfinity => MaybeInfiniteInt::NegInfinity, - PatRangeBoundary::Finite(value) => { - let bits = value.eval_bits(self.tcx, self.typing_env); + PatRangeBoundary::Finite(_ty, value) => { + let bits = value.unwrap_leaf().to_bits_unchecked(); match *ty.kind() { ty::Int(ity) => { let size = Integer::from_int_ty(&self.tcx, ity).size().bits(); @@ -614,8 +614,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(fty) => { use rustc_apfloat::Float; - let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.typing_env)); - let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.typing_env)); + let lo = lo.as_finite().map(|c| c.unwrap_leaf().to_bits_unchecked()); + let hi = hi.as_finite().map(|c| c.unwrap_leaf().to_bits_unchecked()); match fty { ty::FloatTy::F16 => { use rustc_apfloat::ieee::Half; @@ -723,8 +723,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { }; match ScalarInt::try_from_uint(bits, size) { Some(scalar) => { - let value = mir::Const::from_scalar(tcx, scalar.into(), ty.inner()); - PatRangeBoundary::Finite(value) + let value = ty::ValTree::from_scalar_int(tcx, scalar); + PatRangeBoundary::Finite(ty.inner(), value) } // The value doesn't fit. Since `x >= 0` and 0 always encodes the minimum value // for a type, the problem isn't that the value is too small. So it must be too @@ -745,7 +745,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } else if range.is_singleton() { let lo = cx.hoist_pat_range_bdy(range.lo, ty); let value = lo.as_finite().unwrap(); - value.to_string() + ty::Value { ty: ty.inner(), valtree: value }.to_string() } else { // We convert to an inclusive range for diagnostics. let mut end = rustc_hir::RangeEnd::Included; @@ -756,7 +756,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // fictitious values after `{u,i}size::MAX` (see [`IntRange::split`] for why we do // this). We show this to the user as `usize::MAX..` which is slightly incorrect but // probably clear enough. - lo = PatRangeBoundary::Finite(ty.numeric_max_val(cx.tcx).unwrap()); + let max = ty.numeric_max_val(cx.tcx).unwrap(); + let max = ty::ValTree::from_scalar_int(cx.tcx, max.try_to_scalar_int().unwrap()); + lo = PatRangeBoundary::Finite(ty.inner(), max); } let hi = if let Some(hi) = range.hi.minus_one() { hi diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout index b3d11050bdcd4..13d412b5737c9 100644 --- a/tests/ui/thir-print/thir-tree-loop-match.stdout +++ b/tests/ui/thir-print/thir-tree-loop-match.stdout @@ -121,6 +121,7 @@ body: span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0) kind: PatKind { Constant { + ty: bool value: Leaf(0x01) } } @@ -219,6 +220,7 @@ body: span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0) kind: PatKind { Constant { + ty: bool value: Leaf(0x00) } } From a171eaab4249f70d24904da7ed392476b516a0e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Jul 2025 08:54:34 +0200 Subject: [PATCH 173/252] use ty::Value instead of manual pairs of types and valtrees --- compiler/rustc_middle/src/mir/consts.rs | 5 +++ compiler/rustc_middle/src/thir.rs | 37 +++++++---------- compiler/rustc_middle/src/thir/visit.rs | 2 +- .../rustc_middle/src/ty/consts/valtree.rs | 14 +++++-- .../src/builder/custom/parse/instruction.rs | 6 +-- .../src/builder/matches/match_pair.rs | 2 +- .../src/builder/matches/mod.rs | 9 ++-- .../src/builder/matches/test.rs | 29 ++++++------- .../src/thir/pattern/const_to_pat.rs | 8 ++-- .../rustc_mir_build/src/thir/pattern/mod.rs | 6 +-- compiler/rustc_mir_build/src/thir/print.rs | 5 +-- compiler/rustc_pattern_analysis/src/rustc.rs | 41 ++++++++++--------- compiler/rustc_ty_utils/src/consts.rs | 2 +- .../ui/thir-print/thir-tree-loop-match.stdout | 6 +-- 14 files changed, 84 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 96131d47a177f..164433aede263 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -448,6 +448,11 @@ impl<'tcx> Const<'tcx> { Self::Val(val, ty) } + #[inline] + pub fn from_ty_value(tcx: TyCtxt<'tcx>, val: ty::Value<'tcx>) -> Self { + Self::Ty(val.ty, ty::Const::new_value(tcx, val.valtree, val.ty)) + } + pub fn from_bits( tcx: TyCtxt<'tcx>, bits: u128, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 62f76671b78ed..4910aa93be8d6 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -842,10 +842,7 @@ pub enum PatKind<'tcx> { // error. /// * `String`, if `string_deref_patterns` is enabled. Constant { - // Not using `ty::Value` since this is conceptually not a type-level constant. In - // particular, it can have raw pointers. - ty: Ty<'tcx>, - value: ty::ValTree<'tcx>, + value: ty::Value<'tcx>, }, /// Pattern obtained by converting a constant (inline or named) to its pattern @@ -937,8 +934,8 @@ impl<'tcx> PatRange<'tcx> { // Also, for performance, it's important to only do the second `try_to_bits` if necessary. let lo_is_min = match self.lo { PatRangeBoundary::NegInfinity => true, - PatRangeBoundary::Finite(_ty, value) => { - let lo = value.unwrap_leaf().to_bits(size) ^ bias; + PatRangeBoundary::Finite(value) => { + let lo = value.try_to_scalar_int().unwrap().to_bits(size) ^ bias; lo <= min } PatRangeBoundary::PosInfinity => false, @@ -946,8 +943,8 @@ impl<'tcx> PatRange<'tcx> { if lo_is_min { let hi_is_max = match self.hi { PatRangeBoundary::NegInfinity => false, - PatRangeBoundary::Finite(_ty, value) => { - let hi = value.unwrap_leaf().to_bits(size) ^ bias; + PatRangeBoundary::Finite(value) => { + let hi = value.try_to_scalar_int().unwrap().to_bits(size) ^ bias; hi > max || hi == max && self.end == RangeEnd::Included } PatRangeBoundary::PosInfinity => true, @@ -960,10 +957,11 @@ impl<'tcx> PatRange<'tcx> { } #[inline] - pub fn contains(&self, value: ty::ValTree<'tcx>, tcx: TyCtxt<'tcx>) -> Option { + pub fn contains(&self, value: ty::Value<'tcx>, tcx: TyCtxt<'tcx>) -> Option { use Ordering::*; + debug_assert_eq!(self.ty, value.ty); let ty = self.ty; - let value = PatRangeBoundary::Finite(ty, value); + let value = PatRangeBoundary::Finite(value); // For performance, it's important to only do the second comparison if necessary. Some( match self.lo.compare_with(value, ty, tcx)? { @@ -998,13 +996,10 @@ impl<'tcx> PatRange<'tcx> { impl<'tcx> fmt::Display for PatRange<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let &PatRangeBoundary::Finite(ty, value) = &self.lo { - // `ty::Value` has a reasonable pretty-printing implementation. - let value = ty::Value { ty, valtree: value }; + if let PatRangeBoundary::Finite(value) = &self.lo { write!(f, "{value}")?; } - if let &PatRangeBoundary::Finite(ty, value) = &self.hi { - let value = ty::Value { ty, valtree: value }; + if let PatRangeBoundary::Finite(value) = &self.hi { write!(f, "{}", self.end)?; write!(f, "{value}")?; } else { @@ -1019,7 +1014,7 @@ impl<'tcx> fmt::Display for PatRange<'tcx> { /// If present, the const must be of a numeric type. #[derive(Copy, Clone, Debug, PartialEq, HashStable, TypeVisitable)] pub enum PatRangeBoundary<'tcx> { - Finite(Ty<'tcx>, ty::ValTree<'tcx>), + Finite(ty::Value<'tcx>), NegInfinity, PosInfinity, } @@ -1030,15 +1025,15 @@ impl<'tcx> PatRangeBoundary<'tcx> { matches!(self, Self::Finite(..)) } #[inline] - pub fn as_finite(self) -> Option> { + pub fn as_finite(self) -> Option> { match self { - Self::Finite(_ty, value) => Some(value), + Self::Finite(value) => Some(value), Self::NegInfinity | Self::PosInfinity => None, } } pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> u128 { match self { - Self::Finite(_ty, value) => value.unwrap_leaf().to_bits_unchecked(), + Self::Finite(value) => value.try_to_scalar_int().unwrap().to_bits_unchecked(), Self::NegInfinity => { // Unwrap is ok because the type is known to be numeric. ty.numeric_min_and_max_as_bits(tcx).unwrap().0 @@ -1065,9 +1060,7 @@ impl<'tcx> PatRangeBoundary<'tcx> { // we can do scalar comparisons. E.g. `unicode-normalization` has // many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared // in this way. - (Finite(_, a), Finite(_, b)) - if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) => - { + (Finite(a), Finite(b)) if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) => { if let (Some(a), Some(b)) = (a.try_to_scalar_int(), b.try_to_scalar_int()) { let sz = ty.primitive_size(tcx); let cmp = match ty.kind() { diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 9d3ba74ad0fd8..dcfa6c4db3274 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -265,7 +265,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( PatKind::Missing | PatKind::Wild | PatKind::Binding { subpattern: None, .. } - | PatKind::Constant { .. } + | PatKind::Constant { value: _ } | PatKind::Range(_) | PatKind::Never | PatKind::Error(_) => {} diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 002a86a8897a0..0f6f3f0c0e24d 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -135,6 +135,8 @@ pub type ConstToValTreeResult<'tcx> = Result, Ty<'tcx>>, Er /// A type-level constant value. /// /// Represents a typed, fully evaluated constant. +/// Note that this is used by pattern elaboration to represent values which cannot occur in types, +/// such as raw pointers and floats. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable, Lift)] pub struct Value<'tcx> { @@ -149,15 +151,19 @@ impl<'tcx> Value<'tcx> { /// or an aggregate). #[inline] pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option { - let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else { - return None; - }; - let scalar = self.valtree.try_to_scalar_int()?; + let scalar = self.try_to_scalar_int()?; let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty); let size = tcx.layout_of(input).ok()?.size; Some(scalar.to_bits(size)) } + pub fn try_to_scalar_int(self) -> Option { + let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else { + return None; + }; + self.valtree.try_to_scalar_int() + } + pub fn try_to_bool(self) -> Option { if !self.ty.is_bool() { return None; diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index dbe4ab9937fb1..50e8fb15cab13 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -146,9 +146,9 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { for arm in rest { let arm = &self.thir[*arm]; let value = match arm.pattern.kind { - PatKind::Constant { value, .. } => value, + PatKind::Constant { value } => value, PatKind::ExpandedConstant { ref subpattern, def_id: _ } - if let PatKind::Constant { value, .. } = subpattern.kind => + if let PatKind::Constant { value } = subpattern.kind => { value } @@ -160,7 +160,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { }); } }; - values.push(value.unwrap_leaf().to_bits_unchecked()); + values.push(value.try_to_scalar_int().unwrap().to_bits_unchecked()); targets.push(self.parse_block(arm.body)?); } diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 14a237af94e99..7a848536d0e33 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -146,7 +146,7 @@ impl<'tcx> MatchPairTree<'tcx> { } } - PatKind::Constant { ty, value } => Some(TestCase::Constant { ty, value }), + PatKind::Constant { value } => Some(TestCase::Constant { value }), PatKind::AscribeUserType { ascription: Ascription { ref annotation, variance }, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 99c3611fb8a0b..cdbac050734e6 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1245,7 +1245,7 @@ struct Ascription<'tcx> { #[derive(Debug, Clone)] enum TestCase<'tcx> { Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx }, - Constant { ty: Ty<'tcx>, value: ty::ValTree<'tcx> }, + Constant { value: ty::Value<'tcx> }, Range(Arc>), Slice { len: usize, variable_length: bool }, Deref { temp: Place<'tcx>, mutability: Mutability }, @@ -1318,8 +1318,7 @@ enum TestKind<'tcx> { /// Test for equality with value, possibly after an unsizing coercion to /// `ty`, Eq { - value: ty::ValTree<'tcx>, - value_ty: Ty<'tcx>, + value: ty::Value<'tcx>, // Integer types are handled by `SwitchInt`, and constants with ADT // types and `&[T]` types are converted back into patterns, so this can // only be `&str` or `f*`. @@ -1359,7 +1358,7 @@ enum TestBranch<'tcx> { /// Success branch, used for tests with two possible outcomes. Success, /// Branch corresponding to this constant. - Constant(ty::ValTree<'tcx>, u128), + Constant(ty::Value<'tcx>, u128), /// Branch corresponding to this variant. Variant(VariantIdx), /// Failure branch for tests with two possible outcomes, and "otherwise" branch for other tests. @@ -1367,7 +1366,7 @@ enum TestBranch<'tcx> { } impl<'tcx> TestBranch<'tcx> { - fn as_constant(&self) -> Option> { + fn as_constant(&self) -> Option> { if let Self::Constant(v, _) = self { Some(*v) } else { None } } } diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 6ccaafc1f35a5..6771470e45a3d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -35,9 +35,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestCase::Constant { .. } if match_pair.pattern_ty.is_bool() => TestKind::If, TestCase::Constant { .. } if is_switch_ty(match_pair.pattern_ty) => TestKind::SwitchInt, - TestCase::Constant { value, ty: value_ty } => { - TestKind::Eq { value, value_ty, cast_ty: match_pair.pattern_ty } - } + TestCase::Constant { value } => TestKind::Eq { value, cast_ty: match_pair.pattern_ty }, TestCase::Range(ref range) => { assert_eq!(range.ty, match_pair.pattern_ty); @@ -137,14 +135,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate(block, self.source_info(match_start_span), terminator); } - TestKind::Eq { value, value_ty, mut cast_ty } => { + TestKind::Eq { value, mut cast_ty } => { let tcx = self.tcx; let success_block = target_block(TestBranch::Success); let fail_block = target_block(TestBranch::Failure); - let mut expect_ty = value_ty; - let value = Const::Ty(value_ty, ty::Const::new_value(tcx, value, value_ty)); - let mut expect = self.literal_operand(test.span, value); + let mut expect_ty = value.ty; + let mut expect = self.literal_operand(test.span, Const::from_ty_value(tcx, value)); let mut place = place; let mut block = block; @@ -201,7 +198,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { cast_ty = ref_str_ty; } &ty::Pat(base, _) => { - assert_eq!(cast_ty, value_ty); + assert_eq!(cast_ty, value.ty); assert!(base.is_trivially_pure_clone_copy()); let transmuted_place = self.temp(base, test.span); @@ -282,8 +279,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; if let Some(lo) = range.lo.as_finite() { - let lo = Const::Ty(range.ty, ty::Const::new_value(self.tcx, lo, range.ty)); - let lo = self.literal_operand(test.span, lo); + let lo = self.literal_operand(test.span, Const::from_ty_value(self.tcx, lo)); self.compare( block, intermediate_block, @@ -296,8 +292,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; if let Some(hi) = range.hi.as_finite() { - let hi = Const::Ty(range.ty, ty::Const::new_value(self.tcx, hi, range.ty)); - let hi = self.literal_operand(test.span, hi); + let hi = self.literal_operand(test.span, Const::from_ty_value(self.tcx, hi)); let op = match range.end { RangeEnd::Included => BinOp::Le, RangeEnd::Excluded => BinOp::Lt, @@ -553,7 +548,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // FIXME(#29623) we could use PatKind::Range to rule // things out here, in some cases. - (TestKind::SwitchInt, &TestCase::Constant { value, .. }) + (TestKind::SwitchInt, &TestCase::Constant { value }) if is_switch_ty(match_pair.pattern_ty) => { // An important invariant of candidate sorting is that a candidate @@ -580,7 +575,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None } else { fully_matched = true; - let bits = value.unwrap_leaf().to_bits_unchecked(); + let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked(); Some(TestBranch::Constant(value, bits)) } } @@ -602,9 +597,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) } - (TestKind::If, TestCase::Constant { value, .. }) => { + (TestKind::If, TestCase::Constant { value }) => { fully_matched = true; - let value = value.unwrap_leaf().try_to_bool().unwrap_or_else(|_| { + let value = value.try_to_bool().unwrap_or_else(|| { span_bug!(test.span, "expected boolean value but got {value:?}") }); Some(if value { TestBranch::Success } else { TestBranch::Failure }) @@ -687,7 +682,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if !test.overlaps(pat, self.tcx)? { Some(TestBranch::Failure) } else { None } } } - (TestKind::Range(range), &TestCase::Constant { value, .. }) => { + (TestKind::Range(range), &TestCase::Constant { value }) => { fully_matched = false; if !range.contains(value, self.tcx)? { // `value` is not contained in the testing range, diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index c1e9da3925edc..d46c4678bcf7d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -288,12 +288,12 @@ impl<'tcx> ConstToPat<'tcx> { // when lowering to MIR in `Builder::perform_test`, treat the constant as a `&str`. // This works because `str` and `&str` have the same valtree representation. let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty); - PatKind::Constant { ty: ref_str_ty, value: cv } + PatKind::Constant { value: ty::Value { ty: ref_str_ty, valtree: cv } } } ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // `&str` is represented as a valtree, let's keep using this // optimization for now. - ty::Str => PatKind::Constant { ty, value: cv }, + ty::Str => PatKind::Constant { value: ty::Value { ty, valtree: cv } }, // All other references are converted into deref patterns and then recursively // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. @@ -322,13 +322,13 @@ impl<'tcx> ConstToPat<'tcx> { // Also see . return self.mk_err(tcx.dcx().create_err(NaNPattern { span }), ty); } else { - PatKind::Constant { ty, value: cv } + PatKind::Constant { value: ty::Value { ty, valtree: cv } } } } ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { // The raw pointers we see here have been "vetted" by valtree construction to be // just integers, so we simply allow them. - PatKind::Constant { ty, value: cv } + PatKind::Constant { value: ty::Value { ty, valtree: cv } } } ty::FnPtr(..) => { unreachable!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3a4e33b59d792..539ebc3a3d73c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -156,12 +156,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } // The unpeeled kind should now be a constant, giving us the endpoint value. - let PatKind::Constant { ty, value } = kind else { + let PatKind::Constant { value } = kind else { let msg = format!("found bad range pattern endpoint `{expr:?}` outside of error recovery"); return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg)); }; - Ok(Some(PatRangeBoundary::Finite(ty, value))) + Ok(Some(PatRangeBoundary::Finite(value))) } /// Overflowing literals are linted against in a late pass. This is mostly fine, except when we @@ -243,7 +243,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { (RangeEnd::Included, Some(Ordering::Less)) => {} // `x..=y` where `x == y` and `x` and `y` are finite. (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => { - kind = PatKind::Constant { ty, value: lo.as_finite().unwrap() }; + kind = PatKind::Constant { value: lo.as_finite().unwrap() }; } // `..=x` where `x == ty::MIN`. (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {} diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index e5ee60150a7e2..b7e8d6fea40bb 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -761,10 +761,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Constant { value, ty } => { + PatKind::Constant { value } => { print_indented!(self, "Constant {", depth_lvl + 1); - print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 2); - print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); + print_indented!(self, format!("value: {}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } PatKind::ExpandedConstant { def_id, subpattern } => { diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 26574c5fcfc69..1cc68f7f1da07 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -429,8 +429,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ) -> MaybeInfiniteInt { match bdy { PatRangeBoundary::NegInfinity => MaybeInfiniteInt::NegInfinity, - PatRangeBoundary::Finite(_ty, value) => { - let bits = value.unwrap_leaf().to_bits_unchecked(); + PatRangeBoundary::Finite(value) => { + let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked(); match *ty.kind() { ty::Int(ity) => { let size = Integer::from_int_ty(&self.tcx, ity).size().bits(); @@ -517,16 +517,16 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ), } } - PatKind::Constant { ty: value_ty, value } => { + PatKind::Constant { value } => { match ty.kind() { ty::Bool => { - ctor = Bool(value.unwrap_leaf().try_to_bool().unwrap()); + ctor = Bool(value.try_to_bool().unwrap()); fields = vec![]; arity = 0; } ty::Char | ty::Int(_) | ty::Uint(_) => { ctor = { - let bits = value.unwrap_leaf().to_bits_unchecked(); + let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked(); let x = match *ty.kind() { ty::Int(ity) => { let size = Integer::from_int_ty(&cx.tcx, ity).size().bits(); @@ -541,7 +541,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(ty::FloatTy::F16) => { use rustc_apfloat::Float; - let bits = value.unwrap_leaf().to_u16(); + let bits = value.try_to_scalar_int().unwrap().to_u16(); let value = rustc_apfloat::ieee::Half::from_bits(bits.into()); ctor = F16Range(value, value, RangeEnd::Included); fields = vec![]; @@ -549,7 +549,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(ty::FloatTy::F32) => { use rustc_apfloat::Float; - let bits = value.unwrap_leaf().to_u32(); + let bits = value.try_to_scalar_int().unwrap().to_u32(); let value = rustc_apfloat::ieee::Single::from_bits(bits.into()); ctor = F32Range(value, value, RangeEnd::Included); fields = vec![]; @@ -557,7 +557,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(ty::FloatTy::F64) => { use rustc_apfloat::Float; - let bits = value.unwrap_leaf().to_u64(); + let bits = value.try_to_scalar_int().unwrap().to_u64(); let value = rustc_apfloat::ieee::Double::from_bits(bits.into()); ctor = F64Range(value, value, RangeEnd::Included); fields = vec![]; @@ -565,7 +565,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(ty::FloatTy::F128) => { use rustc_apfloat::Float; - let bits = value.unwrap_leaf().to_u128(); + let bits = value.try_to_scalar_int().unwrap().to_u128(); let value = rustc_apfloat::ieee::Quad::from_bits(bits); ctor = F128Range(value, value, RangeEnd::Included); fields = vec![]; @@ -580,11 +580,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // subfields. // Note: `t` is `str`, not `&str`. let ty = self.reveal_opaque_ty(*t); - // FIXME: why does `Str` need a `mir::Value`? - let val = mir::Const::Ty( - *value_ty, - ty::Const::new_value(self.tcx, *value, *value_ty), - ); + // FIXME: why does `Str` need a `mir::Const`? + let val = mir::Const::from_ty_value(self.tcx, *value); let subpattern = DeconstructedPat::new(Str(val), Vec::new(), 0, ty, pat); ctor = Ref; fields = vec![subpattern.at_index(0)]; @@ -614,8 +611,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(fty) => { use rustc_apfloat::Float; - let lo = lo.as_finite().map(|c| c.unwrap_leaf().to_bits_unchecked()); - let hi = hi.as_finite().map(|c| c.unwrap_leaf().to_bits_unchecked()); + let lo = lo + .as_finite() + .map(|c| c.try_to_scalar_int().unwrap().to_bits_unchecked()); + let hi = hi + .as_finite() + .map(|c| c.try_to_scalar_int().unwrap().to_bits_unchecked()); match fty { ty::FloatTy::F16 => { use rustc_apfloat::ieee::Half; @@ -723,8 +724,8 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { }; match ScalarInt::try_from_uint(bits, size) { Some(scalar) => { - let value = ty::ValTree::from_scalar_int(tcx, scalar); - PatRangeBoundary::Finite(ty.inner(), value) + let valtree = ty::ValTree::from_scalar_int(tcx, scalar); + PatRangeBoundary::Finite(ty::Value { ty: ty.inner(), valtree }) } // The value doesn't fit. Since `x >= 0` and 0 always encodes the minimum value // for a type, the problem isn't that the value is too small. So it must be too @@ -745,7 +746,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } else if range.is_singleton() { let lo = cx.hoist_pat_range_bdy(range.lo, ty); let value = lo.as_finite().unwrap(); - ty::Value { ty: ty.inner(), valtree: value }.to_string() + value.to_string() } else { // We convert to an inclusive range for diagnostics. let mut end = rustc_hir::RangeEnd::Included; @@ -758,7 +759,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // probably clear enough. let max = ty.numeric_max_val(cx.tcx).unwrap(); let max = ty::ValTree::from_scalar_int(cx.tcx, max.try_to_scalar_int().unwrap()); - lo = PatRangeBoundary::Finite(ty.inner(), max); + lo = PatRangeBoundary::Finite(ty::Value { ty: ty.inner(), valtree: max }); } let hi = if let Some(hi) = range.hi.minus_one() { hi diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 6d994a2b967f7..eb751da7c7363 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -375,7 +375,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { } match pat.kind { - thir::PatKind::Constant { value, .. } => value.has_non_region_param(), + thir::PatKind::Constant { value } => value.has_non_region_param(), thir::PatKind::Range(ref range) => { let &thir::PatRange { lo, hi, .. } = range.as_ref(); lo.has_non_region_param() || hi.has_non_region_param() diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout index 13d412b5737c9..f2b63782c596c 100644 --- a/tests/ui/thir-print/thir-tree-loop-match.stdout +++ b/tests/ui/thir-print/thir-tree-loop-match.stdout @@ -121,8 +121,7 @@ body: span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0) kind: PatKind { Constant { - ty: bool - value: Leaf(0x01) + value: true } } } @@ -220,8 +219,7 @@ body: span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0) kind: PatKind { Constant { - ty: bool - value: Leaf(0x00) + value: false } } } From a1acbfb050675f197fd525c830203f07412148bd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Jul 2025 09:01:05 +0200 Subject: [PATCH 174/252] change StrLit type to ty::Value as well --- compiler/rustc_pattern_analysis/src/rustc.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 1cc68f7f1da07..e4703ddfc454b 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -8,7 +8,6 @@ use rustc_hir::HirId; use rustc_hir::def_id::DefId; use rustc_index::{Idx, IndexVec}; use rustc_middle::middle::stability::EvalResult; -use rustc_middle::mir::{self, Const}; use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ @@ -580,9 +579,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // subfields. // Note: `t` is `str`, not `&str`. let ty = self.reveal_opaque_ty(*t); - // FIXME: why does `Str` need a `mir::Const`? - let val = mir::Const::from_ty_value(self.tcx, *value); - let subpattern = DeconstructedPat::new(Str(val), Vec::new(), 0, ty, pat); + let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), 0, ty, pat); ctor = Ref; fields = vec![subpattern.at_index(0)]; arity = 1; @@ -894,7 +891,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { type Ty = RevealedTy<'tcx>; type Error = ErrorGuaranteed; type VariantIdx = VariantIdx; - type StrLit = Const<'tcx>; + type StrLit = ty::Value<'tcx>; type ArmData = HirId; type PatData = &'p Pat<'tcx>; From dbc030e0346f0958bea91601de7d115554bbf74e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Jul 2025 13:28:47 +0200 Subject: [PATCH 175/252] shrink TestBranch::Constant and PatRangeBoundary::Finite --- compiler/rustc_middle/src/thir.rs | 15 +++++++++------ .../rustc_mir_build/src/builder/matches/mod.rs | 6 +++--- .../rustc_mir_build/src/builder/matches/test.rs | 8 +++++--- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 5 +++-- compiler/rustc_pattern_analysis/src/rustc.rs | 6 +++--- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 4910aa93be8d6..2c7b41193ebe6 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -959,9 +959,9 @@ impl<'tcx> PatRange<'tcx> { #[inline] pub fn contains(&self, value: ty::Value<'tcx>, tcx: TyCtxt<'tcx>) -> Option { use Ordering::*; - debug_assert_eq!(self.ty, value.ty); + debug_assert_eq!(value.ty, self.ty); let ty = self.ty; - let value = PatRangeBoundary::Finite(value); + let value = PatRangeBoundary::Finite(value.valtree); // For performance, it's important to only do the second comparison if necessary. Some( match self.lo.compare_with(value, ty, tcx)? { @@ -996,11 +996,13 @@ impl<'tcx> PatRange<'tcx> { impl<'tcx> fmt::Display for PatRange<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let PatRangeBoundary::Finite(value) = &self.lo { + if let &PatRangeBoundary::Finite(valtree) = &self.lo { + let value = ty::Value { ty: self.ty, valtree }; write!(f, "{value}")?; } - if let PatRangeBoundary::Finite(value) = &self.hi { + if let &PatRangeBoundary::Finite(valtree) = &self.hi { write!(f, "{}", self.end)?; + let value = ty::Value { ty: self.ty, valtree }; write!(f, "{value}")?; } else { // `0..` is parsed as an inclusive range, we must display it correctly. @@ -1014,7 +1016,8 @@ impl<'tcx> fmt::Display for PatRange<'tcx> { /// If present, the const must be of a numeric type. #[derive(Copy, Clone, Debug, PartialEq, HashStable, TypeVisitable)] pub enum PatRangeBoundary<'tcx> { - Finite(ty::Value<'tcx>), + /// The type of this valtree is stored in the surrounding `PatRange`. + Finite(ty::ValTree<'tcx>), NegInfinity, PosInfinity, } @@ -1025,7 +1028,7 @@ impl<'tcx> PatRangeBoundary<'tcx> { matches!(self, Self::Finite(..)) } #[inline] - pub fn as_finite(self) -> Option> { + pub fn as_finite(self) -> Option> { match self { Self::Finite(value) => Some(value), Self::NegInfinity | Self::PosInfinity => None, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index cdbac050734e6..2833b649ed7b1 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1357,8 +1357,8 @@ pub(crate) struct Test<'tcx> { enum TestBranch<'tcx> { /// Success branch, used for tests with two possible outcomes. Success, - /// Branch corresponding to this constant. - Constant(ty::Value<'tcx>, u128), + /// Branch corresponding to this constant. Must be a scalar. + Constant(ty::Value<'tcx>), /// Branch corresponding to this variant. Variant(VariantIdx), /// Failure branch for tests with two possible outcomes, and "otherwise" branch for other tests. @@ -1367,7 +1367,7 @@ enum TestBranch<'tcx> { impl<'tcx> TestBranch<'tcx> { fn as_constant(&self) -> Option> { - if let Self::Constant(v, _) = self { Some(*v) } else { None } + if let Self::Constant(v) = self { Some(*v) } else { None } } } diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 6771470e45a3d..f2f708bddcee0 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -112,7 +112,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let otherwise_block = target_block(TestBranch::Failure); let switch_targets = SwitchTargets::new( target_blocks.iter().filter_map(|(&branch, &block)| { - if let TestBranch::Constant(_, bits) = branch { + if let TestBranch::Constant(value) = branch { + let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked(); Some((bits, block)) } else { None @@ -279,6 +280,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; if let Some(lo) = range.lo.as_finite() { + let lo = ty::Value { ty: range.ty, valtree: lo }; let lo = self.literal_operand(test.span, Const::from_ty_value(self.tcx, lo)); self.compare( block, @@ -292,6 +294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; if let Some(hi) = range.hi.as_finite() { + let hi = ty::Value { ty: range.ty, valtree: hi }; let hi = self.literal_operand(test.span, Const::from_ty_value(self.tcx, hi)); let op = match range.end { RangeEnd::Included => BinOp::Le, @@ -575,8 +578,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None } else { fully_matched = true; - let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked(); - Some(TestBranch::Constant(value, bits)) + Some(TestBranch::Constant(value)) } } (TestKind::SwitchInt, TestCase::Range(range)) => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 539ebc3a3d73c..166e64a5fcb85 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -161,7 +161,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { format!("found bad range pattern endpoint `{expr:?}` outside of error recovery"); return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg)); }; - Ok(Some(PatRangeBoundary::Finite(value))) + Ok(Some(PatRangeBoundary::Finite(value.valtree))) } /// Overflowing literals are linted against in a late pass. This is mostly fine, except when we @@ -243,7 +243,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { (RangeEnd::Included, Some(Ordering::Less)) => {} // `x..=y` where `x == y` and `x` and `y` are finite. (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => { - kind = PatKind::Constant { value: lo.as_finite().unwrap() }; + let value = ty::Value { ty, valtree: lo.as_finite().unwrap() }; + kind = PatKind::Constant { value }; } // `..=x` where `x == ty::MIN`. (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {} diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index e4703ddfc454b..97f1c84279774 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -722,7 +722,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { match ScalarInt::try_from_uint(bits, size) { Some(scalar) => { let valtree = ty::ValTree::from_scalar_int(tcx, scalar); - PatRangeBoundary::Finite(ty::Value { ty: ty.inner(), valtree }) + PatRangeBoundary::Finite(valtree) } // The value doesn't fit. Since `x >= 0` and 0 always encodes the minimum value // for a type, the problem isn't that the value is too small. So it must be too @@ -742,7 +742,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { "_".to_string() } else if range.is_singleton() { let lo = cx.hoist_pat_range_bdy(range.lo, ty); - let value = lo.as_finite().unwrap(); + let value = ty::Value { ty: ty.inner(), valtree: lo.as_finite().unwrap() }; value.to_string() } else { // We convert to an inclusive range for diagnostics. @@ -756,7 +756,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // probably clear enough. let max = ty.numeric_max_val(cx.tcx).unwrap(); let max = ty::ValTree::from_scalar_int(cx.tcx, max.try_to_scalar_int().unwrap()); - lo = PatRangeBoundary::Finite(ty::Value { ty: ty.inner(), valtree: max }); + lo = PatRangeBoundary::Finite(max); } let hi = if let Some(hi) = range.hi.minus_one() { hi From e2cc7757e1bdbe8c9dc0dcffc1017ceff4799899 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Jul 2025 17:22:22 +0200 Subject: [PATCH 176/252] avoid unnecessary type sanity checks --- compiler/rustc_middle/src/ty/consts/valtree.rs | 12 ++++-------- .../src/builder/custom/parse/instruction.rs | 2 +- compiler/rustc_mir_build/src/builder/matches/test.rs | 2 +- compiler/rustc_pattern_analysis/src/rustc.rs | 10 +++++----- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 0f6f3f0c0e24d..bf20520f4cdc0 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -151,17 +151,13 @@ impl<'tcx> Value<'tcx> { /// or an aggregate). #[inline] pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option { - let scalar = self.try_to_scalar_int()?; - let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty); - let size = tcx.layout_of(input).ok()?.size; - Some(scalar.to_bits(size)) - } - - pub fn try_to_scalar_int(self) -> Option { let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else { return None; }; - self.valtree.try_to_scalar_int() + let scalar = self.valtree.try_to_scalar_int()?; + let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty); + let size = tcx.layout_of(input).ok()?.size; + Some(scalar.to_bits(size)) } pub fn try_to_bool(self) -> Option { diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 50e8fb15cab13..41d3aefcbe6b5 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -160,7 +160,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { }); } }; - values.push(value.try_to_scalar_int().unwrap().to_bits_unchecked()); + values.push(value.valtree.unwrap_leaf().to_bits_unchecked()); targets.push(self.parse_block(arm.body)?); } diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index f2f708bddcee0..cefc3d0bf14b5 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let switch_targets = SwitchTargets::new( target_blocks.iter().filter_map(|(&branch, &block)| { if let TestBranch::Constant(value) = branch { - let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked(); + let bits = value.valtree.unwrap_leaf().to_bits_unchecked(); Some((bits, block)) } else { None diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 97f1c84279774..c9bf4fe4449b0 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -525,7 +525,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Char | ty::Int(_) | ty::Uint(_) => { ctor = { - let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked(); + let bits = value.valtree.unwrap_leaf().to_bits_unchecked(); let x = match *ty.kind() { ty::Int(ity) => { let size = Integer::from_int_ty(&cx.tcx, ity).size().bits(); @@ -540,7 +540,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(ty::FloatTy::F16) => { use rustc_apfloat::Float; - let bits = value.try_to_scalar_int().unwrap().to_u16(); + let bits = value.valtree.unwrap_leaf().to_u16(); let value = rustc_apfloat::ieee::Half::from_bits(bits.into()); ctor = F16Range(value, value, RangeEnd::Included); fields = vec![]; @@ -548,7 +548,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(ty::FloatTy::F32) => { use rustc_apfloat::Float; - let bits = value.try_to_scalar_int().unwrap().to_u32(); + let bits = value.valtree.unwrap_leaf().to_u32(); let value = rustc_apfloat::ieee::Single::from_bits(bits.into()); ctor = F32Range(value, value, RangeEnd::Included); fields = vec![]; @@ -556,7 +556,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(ty::FloatTy::F64) => { use rustc_apfloat::Float; - let bits = value.try_to_scalar_int().unwrap().to_u64(); + let bits = value.valtree.unwrap_leaf().to_u64(); let value = rustc_apfloat::ieee::Double::from_bits(bits.into()); ctor = F64Range(value, value, RangeEnd::Included); fields = vec![]; @@ -564,7 +564,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } ty::Float(ty::FloatTy::F128) => { use rustc_apfloat::Float; - let bits = value.try_to_scalar_int().unwrap().to_u128(); + let bits = value.valtree.unwrap_leaf().to_u128(); let value = rustc_apfloat::ieee::Quad::from_bits(bits); ctor = F128Range(value, value, RangeEnd::Included); fields = vec![]; From 2330afab6388de5cd4f27233334b614b07d819d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Aug 2025 09:36:42 +0200 Subject: [PATCH 177/252] Apply suggestions from code review Co-authored-by: Boxy --- compiler/rustc_middle/src/thir.rs | 6 +++--- compiler/rustc_middle/src/ty/consts/valtree.rs | 2 +- compiler/rustc_mir_build/src/builder/matches/mod.rs | 4 ++-- compiler/rustc_mir_build/src/builder/matches/test.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 2c7b41193ebe6..f1d19800a7891 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1034,7 +1034,7 @@ impl<'tcx> PatRangeBoundary<'tcx> { Self::NegInfinity | Self::PosInfinity => None, } } - pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> u128 { + pub fn to_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> u128 { match self { Self::Finite(value) => value.try_to_scalar_int().unwrap().to_bits_unchecked(), Self::NegInfinity => { @@ -1077,8 +1077,8 @@ impl<'tcx> PatRangeBoundary<'tcx> { _ => {} } - let a = self.eval_bits(ty, tcx); - let b = other.eval_bits(ty, tcx); + let a = self.to_bits(ty, tcx); + let b = other.to_bits(ty, tcx); match ty.kind() { ty::Float(ty::FloatTy::F16) => { diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index bf20520f4cdc0..a14e47d70821d 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -135,7 +135,7 @@ pub type ConstToValTreeResult<'tcx> = Result, Ty<'tcx>>, Er /// A type-level constant value. /// /// Represents a typed, fully evaluated constant. -/// Note that this is used by pattern elaboration to represent values which cannot occur in types, +/// Note that this is also used by pattern elaboration to represent values which cannot occur in types, /// such as raw pointers and floats. #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable, Lift)] diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 2833b649ed7b1..6ee9674bb08ec 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1316,12 +1316,12 @@ enum TestKind<'tcx> { If, /// Test for equality with value, possibly after an unsizing coercion to - /// `ty`, + /// `cast_ty`, Eq { value: ty::Value<'tcx>, // Integer types are handled by `SwitchInt`, and constants with ADT // types and `&[T]` types are converted back into patterns, so this can - // only be `&str` or `f*`. + // only be `&str` or floats. cast_ty: Ty<'tcx>, }, diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index cefc3d0bf14b5..d03794fe2d584 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -695,7 +695,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val, .. }) => { + (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) => { if test_val == case_val { fully_matched = true; Some(TestBranch::Success) From 3a250b79390e9d0258ae463c875aac6c643956db Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Thu, 14 Aug 2025 12:26:51 +0300 Subject: [PATCH 178/252] rewrite test with `#![no_core]` --- .../run-make/wasm-unexpected-features/foo.rs | 43 +++++++++++++++++++ .../wasm-unexpected-features/rmake.rs | 32 +++++--------- .../wasm32_test/Cargo.toml | 13 ------ .../wasm32_test/src/lib.rs | 34 --------------- 4 files changed, 53 insertions(+), 69 deletions(-) create mode 100644 tests/run-make/wasm-unexpected-features/foo.rs delete mode 100644 tests/run-make/wasm-unexpected-features/wasm32_test/Cargo.toml delete mode 100644 tests/run-make/wasm-unexpected-features/wasm32_test/src/lib.rs diff --git a/tests/run-make/wasm-unexpected-features/foo.rs b/tests/run-make/wasm-unexpected-features/foo.rs new file mode 100644 index 0000000000000..5c7aa2d619046 --- /dev/null +++ b/tests/run-make/wasm-unexpected-features/foo.rs @@ -0,0 +1,43 @@ +#![no_core] +#![crate_type = "cdylib"] +#![feature(no_core, lang_items, allocator_internals, rustc_attrs)] +#![needs_allocator] +#![allow(internal_features)] + +#[rustc_std_internal_symbol] +unsafe fn __rust_alloc(_size: usize, _align: usize) -> *mut u8 { + 0 as *mut u8 +} + +unsafe extern "Rust" { + #[rustc_std_internal_symbol] + fn __rust_alloc_error_handler(size: usize, align: usize) -> !; +} + +#[used] +static mut BUF: [u8; 1024] = [0; 1024]; + +#[unsafe(no_mangle)] +extern "C" fn init() { + unsafe { + __rust_alloc_error_handler(0, 0); + } +} + +mod minicore { + #[lang = "pointee_sized"] + pub trait PointeeSized {} + + #[lang = "meta_sized"] + pub trait MetaSized: PointeeSized {} + + #[lang = "sized"] + pub trait Sized: MetaSized {} + + #[lang = "copy"] + pub trait Copy {} + impl Copy for u8 {} + + #[lang = "drop_in_place"] + fn drop_in_place(_: *mut T) {} +} diff --git a/tests/run-make/wasm-unexpected-features/rmake.rs b/tests/run-make/wasm-unexpected-features/rmake.rs index 142860c47ec0d..416b5ef4caa3d 100644 --- a/tests/run-make/wasm-unexpected-features/rmake.rs +++ b/tests/run-make/wasm-unexpected-features/rmake.rs @@ -2,31 +2,19 @@ use std::path::Path; -use run_make_support::{cargo, path, rfs, target, wasmparser}; +use run_make_support::{rfs, rustc, wasmparser}; fn main() { - let target_dir = path("target"); - - cargo() - .args([ - "rustc", - "--manifest-path", - "wasm32_test/Cargo.toml", - "--profile", - "release", - "--target", - "wasm32-wasip1", - "-Zbuild-std=core,alloc,panic_abort", - "--", - "-Clink-arg=--import-memory", - "-Clinker-plugin-lto=on", - ]) - .env("RUSTFLAGS", "-Ctarget-cpu=mvp") - .env("CARGO_TARGET_DIR", &target_dir) + rustc() + .input("foo.rs") + .target("wasm32-wasip1") + .target_cpu("mvp") + .opt_level("z") + .lto("fat") + .linker_plugin_lto("on") + .link_arg("--import-memory") .run(); - - let wasm32_program_path = target_dir.join(target()).join("release").join("wasm32_program.wasm"); - verify_features(&wasm32_program_path); + verify_features(Path::new("foo.wasm")); } fn verify_features(path: &Path) { diff --git a/tests/run-make/wasm-unexpected-features/wasm32_test/Cargo.toml b/tests/run-make/wasm-unexpected-features/wasm32_test/Cargo.toml deleted file mode 100644 index 9f1070e1c54c3..0000000000000 --- a/tests/run-make/wasm-unexpected-features/wasm32_test/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "wasm32_test" -version = "0.1.0" -edition = "2024" - -[lib] -crate-type = ["cdylib"] -name = "wasm32_program" - -[profile.release] -codegen-units = 1 -lto = "fat" -opt-level = "z" diff --git a/tests/run-make/wasm-unexpected-features/wasm32_test/src/lib.rs b/tests/run-make/wasm-unexpected-features/wasm32_test/src/lib.rs deleted file mode 100644 index 123c2c1b6ca0c..0000000000000 --- a/tests/run-make/wasm-unexpected-features/wasm32_test/src/lib.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![no_std] - -extern crate alloc; - -use core::alloc::{GlobalAlloc, Layout}; -use core::mem::MaybeUninit; - -#[global_allocator] -static ALLOC: GlobalDlmalloc = GlobalDlmalloc; - -struct GlobalDlmalloc; - -unsafe impl GlobalAlloc for GlobalDlmalloc { - #[inline] - unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { - core::ptr::null_mut() - } - - #[inline] - unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} -} - -#[used] -static mut BUF: MaybeUninit<[u8; 1024]> = MaybeUninit::uninit(); - -#[unsafe(no_mangle)] -extern "C" fn init() { - alloc::alloc::handle_alloc_error(Layout::new::<[u8; 64 * 1024]>()); -} - -#[panic_handler] -fn my_panic(_: &core::panic::PanicInfo) -> ! { - loop {} -} From 75b7d24a985ef9f6bab00414752dd74ceb47d114 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Thu, 14 Aug 2025 12:38:35 +0200 Subject: [PATCH 179/252] ci: clean windows disk space in background --- .github/workflows/ci.yml | 5 ++ .../scripts/free-disk-space-windows-start.py | 72 +++++++++++++++++ .../scripts/free-disk-space-windows-wait.py | 77 +++++++++++++++++++ src/ci/scripts/free-disk-space.sh | 2 +- .../scripts/free_disk_space_windows_util.py | 29 +++++++ 5 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 src/ci/scripts/free-disk-space-windows-start.py create mode 100644 src/ci/scripts/free-disk-space-windows-wait.py create mode 100644 src/ci/scripts/free_disk_space_windows_util.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6ce543071d841..cee987dbf12ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -223,6 +223,11 @@ jobs: cd src/ci/citool CARGO_INCREMENTAL=0 CARGO_TARGET_DIR=../../../build/citool cargo build + - name: wait for Windows disk cleanup to finish + if: ${{ matrix.free_disk && startsWith(matrix.os, 'windows-') }} + run: | + python3 src/ci/scripts/free-disk-space-windows-wait.py + - name: run the build run: | set +e diff --git a/src/ci/scripts/free-disk-space-windows-start.py b/src/ci/scripts/free-disk-space-windows-start.py new file mode 100644 index 0000000000000..fbaad722bffdb --- /dev/null +++ b/src/ci/scripts/free-disk-space-windows-start.py @@ -0,0 +1,72 @@ +""" +Start freeing disk space on Windows in the background by launching +the PowerShell cleanup script, and recording the PID in a file, +so later steps can wait for completion. +""" + +import subprocess +from pathlib import Path +from free_disk_space_windows_util import get_pid_file, get_log_file, run_main + + +def get_cleanup_script() -> Path: + script_dir = Path(__file__).resolve().parent + cleanup_script = script_dir / "free-disk-space-windows.ps1" + if not cleanup_script.exists(): + raise Exception(f"Cleanup script '{cleanup_script}' not found") + return cleanup_script + + +def write_pid(pid: int): + pid_file = get_pid_file() + if pid_file.exists(): + raise Exception(f"Pid file '{pid_file}' already exists") + pid_file.write_text(str(pid)) + print(f"wrote pid {pid} in file {pid_file}") + + +def launch_cleanup_process(): + cleanup_script = get_cleanup_script() + log_file_path = get_log_file() + # Launch the PowerShell cleanup in the background and redirect logs. + try: + with open(log_file_path, "w", encoding="utf-8") as log_file: + proc = subprocess.Popen( + [ + "pwsh", + # Suppress PowerShell startup banner/logo for cleaner logs. + "-NoLogo", + # Don't load user/system profiles. Ensures a clean, predictable environment. + "-NoProfile", + # Disable interactive prompts. Required for CI to avoid hangs. + "-NonInteractive", + # Execute the specified script file (next argument). + "-File", + str(cleanup_script), + ], + # Write child stdout to the log file. + stdout=log_file, + # Merge stderr into stdout for a single, ordered log stream. + stderr=subprocess.STDOUT, + ) + print( + f"Started free-disk-space cleanup in background. " + f"pid={proc.pid}; log_file={log_file_path}" + ) + return proc + except FileNotFoundError as e: + raise Exception("pwsh not found on PATH; cannot start disk cleanup.") from e + + +def main() -> int: + proc = launch_cleanup_process() + + # Write pid of the process to a file, so that later steps can read it and wait + # until the process completes. + write_pid(proc.pid) + + return 0 + + +if __name__ == "__main__": + run_main(main) diff --git a/src/ci/scripts/free-disk-space-windows-wait.py b/src/ci/scripts/free-disk-space-windows-wait.py new file mode 100644 index 0000000000000..b8612bb71c2c2 --- /dev/null +++ b/src/ci/scripts/free-disk-space-windows-wait.py @@ -0,0 +1,77 @@ +""" +Wait for the background Windows disk cleanup process. +""" + +import ctypes +import time +from free_disk_space_windows_util import get_pid_file, get_log_file, run_main + + +def is_process_running(pid: int) -> bool: + PROCESS_QUERY_LIMITED_INFORMATION = 0x1000 + processHandle = ctypes.windll.kernel32.OpenProcess( + PROCESS_QUERY_LIMITED_INFORMATION, 0, pid + ) + if processHandle == 0: + # The process is not running. + # If you don't have the sufficient rights to check if a process is running, + # zero is also returned. But in GitHub Actions we have these rights. + return False + else: + ctypes.windll.kernel32.CloseHandle(processHandle) + return True + + +def print_logs(): + """Print the logs from the cleanup script.""" + log_file = get_log_file() + if log_file.exists(): + print("free-disk-space logs:") + # Print entire log; replace undecodable bytes to avoid exceptions. + try: + with open(log_file, "r", encoding="utf-8", errors="replace") as f: + print(f.read()) + except Exception as e: + raise Exception(f"Failed to read log file '{log_file}'") from e + else: + print(f"::warning::Log file '{log_file}' not found") + + +def read_pid_from_file() -> int: + """Read the PID from the pid file.""" + + pid_file = get_pid_file() + if not pid_file.exists(): + raise Exception( + f"No background free-disk-space process to wait for: pid file {pid_file} not found" + ) + + pid_file_content = pid_file.read_text().strip() + + # Delete the file if it exists + pid_file.unlink(missing_ok=True) + + try: + # Read the first line and convert to int. + pid = int(pid_file_content.splitlines()[0]) + return pid + except Exception as e: + raise Exception( + f"Error while parsing the pid file with content '{pid_file_content!r}'" + ) from e + + +def main() -> int: + pid = read_pid_from_file() + + # Poll until process exits + while is_process_running(pid): + time.sleep(3) + + print_logs() + + return 0 + + +if __name__ == "__main__": + run_main(main) diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh index 062ad801cd8d2..9264fe4de6d8e 100755 --- a/src/ci/scripts/free-disk-space.sh +++ b/src/ci/scripts/free-disk-space.sh @@ -4,7 +4,7 @@ set -euo pipefail script_dir=$(dirname "$0") if [[ "${RUNNER_OS:-}" == "Windows" ]]; then - pwsh $script_dir/free-disk-space-windows.ps1 + python3 "$script_dir/free-disk-space-windows-start.py" else $script_dir/free-disk-space-linux.sh fi diff --git a/src/ci/scripts/free_disk_space_windows_util.py b/src/ci/scripts/free_disk_space_windows_util.py new file mode 100644 index 0000000000000..488187864c2f8 --- /dev/null +++ b/src/ci/scripts/free_disk_space_windows_util.py @@ -0,0 +1,29 @@ +""" +Utilities for Windows disk space cleanup scripts. +""" + +import os +from pathlib import Path +import sys + + +def get_temp_dir() -> Path: + """Get the temporary directory set by GitHub Actions.""" + return Path(os.environ.get("RUNNER_TEMP")) + + +def get_pid_file() -> Path: + return get_temp_dir() / "free-disk-space.pid" + + +def get_log_file() -> Path: + return get_temp_dir() / "free-disk-space.log" + + +def run_main(main_fn): + exit_code = 1 + try: + exit_code = main_fn() + except Exception as e: + print(f"::error::{e}") + sys.exit(exit_code) From 18fd6eab3a14fa86fca32b3884811aa1f8d29fea Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 14 Aug 2025 13:02:40 +0200 Subject: [PATCH 180/252] Revert "Correctly handle when there are no unstable items in the documented crate" This reverts commit cd79c7189db7b611f9199fd12ba56563afa18642. --- src/librustdoc/html/static/js/search.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 0011544d16e2f..10e01b4e26274 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2060,9 +2060,7 @@ class DocSearch { // Deprecated and unstable items and items with no description this.searchIndexDeprecated.set(crate, new RoaringBitmap(crateCorpus.c)); this.searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e)); - if (crateCorpus.u !== undefined && crateCorpus.u !== null) { - this.searchIndexUnstable.set(crate, new RoaringBitmap(crateCorpus.u)); - } + this.searchIndexUnstable.set(crate, new RoaringBitmap(crateCorpus.u)); let descIndex = 0; /** From 1975b06583cb558f82d8cc92ab5b672d9290acf3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 14 Aug 2025 13:02:56 +0200 Subject: [PATCH 181/252] Revert "rustdoc search: add performance note about searchIndexUnstable check" This reverts commit fdbc8d08a63a3d34b7aebabb2f18a768462a98c4. --- src/librustdoc/html/static/js/search.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 10e01b4e26274..516e857ee765a 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -3333,12 +3333,6 @@ class DocSearch { } // sort unstable items later - // FIXME: there is some doubt if this is the most effecient way to implement this. - // alternative options include: - // * put is_unstable on each item when the index is built. - // increases memory usage but avoids a hashmap lookup. - // * put is_unstable on each item before sorting. - // better worst case performance but worse average case performance. a = Number( // @ts-expect-error this.searchIndexUnstable.get(aaa.item.crate).contains(aaa.item.bitIndex), From 2820fcc8302d25acdefbcfd4351831441dc177c6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 14 Aug 2025 13:04:08 +0200 Subject: [PATCH 182/252] Revert "rustdoc: IndexItem::{stability -> is_unstable}" This reverts commit 5e8ebd5ecd8546591a6707ac9e1a3b8a64c72f76. --- src/librustdoc/formats/cache.rs | 2 +- src/librustdoc/html/render/mod.rs | 7 ++++++- src/librustdoc/html/render/search_index.rs | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 918b292466d31..1e674cc5e89a4 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -602,7 +602,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It search_type, aliases, deprecation, - is_unstable: item.stability(tcx).map(|x| x.is_unstable()).unwrap_or(false), + stability: item.stability(tcx), }; cache.search_index.push(index_item); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 9525984707583..41ebaeade1d34 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -139,7 +139,12 @@ pub(crate) struct IndexItem { pub(crate) search_type: Option, pub(crate) aliases: Box<[Symbol]>, pub(crate) deprecation: Option, - pub(crate) is_unstable: bool, + pub(crate) stability: Option, +} +impl IndexItem { + fn is_unstable(&self) -> bool { + matches!(&self.stability, Some(Stability { level: StabilityLevel::Unstable { .. }, .. })) + } } /// A type used for the search index. diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 93c9df8c04935..8d510a393df57 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -93,7 +93,7 @@ pub(crate) fn build_index( ), aliases: item.attrs.get_doc_aliases(), deprecation: item.deprecation(tcx), - is_unstable: item.stability(tcx).is_some_and(|x| x.is_unstable()), + stability: item.stability(tcx), }); } } @@ -713,7 +713,7 @@ pub(crate) fn build_index( // bitmasks always use 1-indexing for items, with 0 as the crate itself deprecated.push(u32::try_from(index + 1).unwrap()); } - if item.is_unstable { + if item.is_unstable() { unstable.push(u32::try_from(index + 1).unwrap()); } } From a195cf63b88ecfccebeae59e150a65ec5732779b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 14 Aug 2025 13:06:05 +0200 Subject: [PATCH 183/252] Revert "rustdoc search: prefer stable items in search results" This reverts commit 1140e90074b0cbcfdea8535e4b51877e2838227e. --- src/librustdoc/formats/cache.rs | 1 - src/librustdoc/html/render/mod.rs | 6 ------ src/librustdoc/html/render/search_index.rs | 6 ------ src/librustdoc/html/static/js/rustdoc.d.ts | 5 +---- src/librustdoc/html/static/js/search.js | 21 +-------------------- tests/rustdoc-js-std/core-transmute.js | 2 +- tests/rustdoc-js-std/transmute-fail.js | 2 +- tests/rustdoc-js-std/transmute.js | 2 +- tests/rustdoc-js/sort-stability.js | 9 --------- tests/rustdoc-js/sort-stability.rs | 16 ---------------- 10 files changed, 5 insertions(+), 65 deletions(-) delete mode 100644 tests/rustdoc-js/sort-stability.js delete mode 100644 tests/rustdoc-js/sort-stability.rs diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 1e674cc5e89a4..80399cf3842aa 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -602,7 +602,6 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It search_type, aliases, deprecation, - stability: item.stability(tcx), }; cache.search_index.push(index_item); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 41ebaeade1d34..a46253237db21 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -139,12 +139,6 @@ pub(crate) struct IndexItem { pub(crate) search_type: Option, pub(crate) aliases: Box<[Symbol]>, pub(crate) deprecation: Option, - pub(crate) stability: Option, -} -impl IndexItem { - fn is_unstable(&self) -> bool { - matches!(&self.stability, Some(Stability { level: StabilityLevel::Unstable { .. }, .. })) - } } /// A type used for the search index. diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 8d510a393df57..e2f86b8a8549e 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -93,7 +93,6 @@ pub(crate) fn build_index( ), aliases: item.attrs.get_doc_aliases(), deprecation: item.deprecation(tcx), - stability: item.stability(tcx), }); } } @@ -656,7 +655,6 @@ pub(crate) fn build_index( let mut parents_backref_queue = VecDeque::new(); let mut functions = String::with_capacity(self.items.len()); let mut deprecated = Vec::with_capacity(self.items.len()); - let mut unstable = Vec::with_capacity(self.items.len()); let mut type_backref_queue = VecDeque::new(); @@ -713,9 +711,6 @@ pub(crate) fn build_index( // bitmasks always use 1-indexing for items, with 0 as the crate itself deprecated.push(u32::try_from(index + 1).unwrap()); } - if item.is_unstable() { - unstable.push(u32::try_from(index + 1).unwrap()); - } } for (index, path) in &revert_extra_paths { @@ -754,7 +749,6 @@ pub(crate) fn build_index( crate_data.serialize_field("r", &re_exports)?; crate_data.serialize_field("b", &self.associated_item_disambiguators)?; crate_data.serialize_field("c", &bitmap_to_string(&deprecated))?; - crate_data.serialize_field("u", &bitmap_to_string(&unstable))?; crate_data.serialize_field("e", &bitmap_to_string(&self.empty_desc))?; crate_data.serialize_field("P", ¶m_names)?; if has_aliases { diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index b082b65ab576e..3d30a7adb9820 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -129,7 +129,7 @@ declare namespace rustdoc { /** * A single parsed "atom" in a search query. For example, - * + * * std::fmt::Formatter, Write -> Result<()> * ┏━━━━━━━━━━━━━━━━━━ ┌──── ┏━━━━━┅┅┅┅┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐ * ┃ │ ┗ QueryElement { ┊ @@ -449,8 +449,6 @@ declare namespace rustdoc { * of `p`) but is used for modules items like free functions. * * `c` is an array of item indices that are deprecated. - * - * `u` is an array of item indices that are unstable. */ type RawSearchIndexCrate = { doc: string, @@ -465,7 +463,6 @@ declare namespace rustdoc { p: Array<[number, string] | [number, string, number] | [number, string, number, number] | [number, string, number, number, string]>, b: Array<[number, String]>, c: string, - u: string, r: Array<[number, number]>, P: Array<[number, string]>, }; diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 516e857ee765a..505652c0f4a7c 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1464,11 +1464,6 @@ class DocSearch { * @type {Map} */ this.searchIndexEmptyDesc = new Map(); - /** - * @type {Map} - */ - this.searchIndexUnstable = new Map(); - /** * @type {Uint32Array} */ @@ -2057,10 +2052,9 @@ class DocSearch { }; const descShardList = [descShard]; - // Deprecated and unstable items and items with no description + // Deprecated items and items with no description this.searchIndexDeprecated.set(crate, new RoaringBitmap(crateCorpus.c)); this.searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e)); - this.searchIndexUnstable.set(crate, new RoaringBitmap(crateCorpus.u)); let descIndex = 0; /** @@ -3332,19 +3326,6 @@ class DocSearch { return a - b; } - // sort unstable items later - a = Number( - // @ts-expect-error - this.searchIndexUnstable.get(aaa.item.crate).contains(aaa.item.bitIndex), - ); - b = Number( - // @ts-expect-error - this.searchIndexUnstable.get(bbb.item.crate).contains(bbb.item.bitIndex), - ); - if (a !== b) { - return a - b; - } - // sort by crate (current crate comes first) a = Number(aaa.item.crate !== preferredCrate); b = Number(bbb.item.crate !== preferredCrate); diff --git a/tests/rustdoc-js-std/core-transmute.js b/tests/rustdoc-js-std/core-transmute.js index b15f398902c31..8c9910a32d7f1 100644 --- a/tests/rustdoc-js-std/core-transmute.js +++ b/tests/rustdoc-js-std/core-transmute.js @@ -3,9 +3,9 @@ const EXPECTED = [ { 'query': 'generic:T -> generic:U', 'others': [ - { 'path': 'core::mem', 'name': 'transmute' }, { 'path': 'core::intrinsics::simd', 'name': 'simd_as' }, { 'path': 'core::intrinsics::simd', 'name': 'simd_cast' }, + { 'path': 'core::mem', 'name': 'transmute' }, ], }, ]; diff --git a/tests/rustdoc-js-std/transmute-fail.js b/tests/rustdoc-js-std/transmute-fail.js index 459e8dc3f0029..ddfb276194818 100644 --- a/tests/rustdoc-js-std/transmute-fail.js +++ b/tests/rustdoc-js-std/transmute-fail.js @@ -6,9 +6,9 @@ const EXPECTED = [ // should-fail tag and the search query below: 'query': 'generic:T -> generic:T', 'others': [ - { 'path': 'std::mem', 'name': 'transmute' }, { 'path': 'std::intrinsics::simd', 'name': 'simd_as' }, { 'path': 'std::intrinsics::simd', 'name': 'simd_cast' }, + { 'path': 'std::mem', 'name': 'transmute' }, ], }, ]; diff --git a/tests/rustdoc-js-std/transmute.js b/tests/rustdoc-js-std/transmute.js index a85b02e29947e..f52e0ab14362d 100644 --- a/tests/rustdoc-js-std/transmute.js +++ b/tests/rustdoc-js-std/transmute.js @@ -5,9 +5,9 @@ const EXPECTED = [ // should-fail tag and the search query below: 'query': 'generic:T -> generic:U', 'others': [ - { 'path': 'std::mem', 'name': 'transmute' }, { 'path': 'std::intrinsics::simd', 'name': 'simd_as' }, { 'path': 'std::intrinsics::simd', 'name': 'simd_cast' }, + { 'path': 'std::mem', 'name': 'transmute' }, ], }, ]; diff --git a/tests/rustdoc-js/sort-stability.js b/tests/rustdoc-js/sort-stability.js deleted file mode 100644 index 8c095619a0866..0000000000000 --- a/tests/rustdoc-js/sort-stability.js +++ /dev/null @@ -1,9 +0,0 @@ -const EXPECTED = [ - { - 'query': 'foo', - 'others': [ - {"path": "sort_stability::old", "name": "foo"}, - {"path": "sort_stability::new", "name": "foo"}, - ], - }, -]; diff --git a/tests/rustdoc-js/sort-stability.rs b/tests/rustdoc-js/sort-stability.rs deleted file mode 100644 index 68662bb3aab6c..0000000000000 --- a/tests/rustdoc-js/sort-stability.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(staged_api)] -#![stable(feature = "foo_lib", since = "1.0.0")] - -#[stable(feature = "old_foo", since = "1.0.1")] -pub mod old { - /// Old, stable foo - #[stable(feature = "old_foo", since = "1.0.1")] - pub fn foo() {} -} - -#[unstable(feature = "new_foo", issue = "none")] -pub mod new { - /// New, unstable foo - #[unstable(feature = "new_foo", issue = "none")] - pub fn foo() {} -} From 8296ad04568597fbfab4460530032cd54f5cd26b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 8 Aug 2025 04:56:41 +1000 Subject: [PATCH 184/252] Print regions in `type_name`. Currently they are skipped, which is a bit weird, and it sometimes causes malformed output like `Foo<>` and `dyn Bar<, A = u32>`. Most regions are erased by the time `type_name` does its work. So all regions are now printed as `'_` in non-optional places. Not perfect, but better than the status quo. `c_name` is updated to trim lifetimes from MIR pass names, so that the `PASS_NAMES` sanity check still works. It is also renamed as `simplify_pass_type_name` and made non-const, because it doesn't need to be const and the non-const implementation is much shorter. The commit also renames `should_print_region` as `should_print_optional_region`, which makes it clearer that it only applies to some regions. Fixes #145168. --- .../rustc_const_eval/src/util/type_name.rs | 26 ++++++----- compiler/rustc_lint/src/context.rs | 8 ++-- compiler/rustc_middle/src/ty/print/pretty.rs | 14 +++--- .../rustc_mir_transform/src/pass_manager.rs | 45 ++++++++++++------- compiler/rustc_symbol_mangling/src/legacy.rs | 6 +-- .../src/error_reporting/infer/mod.rs | 8 ++-- library/core/src/any.rs | 6 +-- tests/ui/type/type-name-basic.rs | 22 +++++---- 8 files changed, 78 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 9d6674873b1e1..13cc607135a02 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -5,7 +5,7 @@ use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; use rustc_middle::bug; use rustc_middle::ty::print::{PrettyPrinter, PrintError, Printer}; -use rustc_middle::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt}; struct TypeNamePrinter<'tcx> { tcx: TyCtxt<'tcx>, @@ -18,9 +18,10 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { } fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { - // This is reachable (via `pretty_print_dyn_existential`) even though - // `::should_print_region` returns false. See #144994. - Ok(()) + // FIXME: most regions have been erased by the time this code runs. + // Just printing `'_` is a bit hacky but gives mostly good results, and + // doing better is difficult. See `should_print_optional_region`. + write!(self, "'_") } fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { @@ -125,10 +126,8 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { args: &[GenericArg<'tcx>], ) -> Result<(), PrintError> { print_prefix(self)?; - let args = - args.iter().cloned().filter(|arg| !matches!(arg.kind(), GenericArgKind::Lifetime(_))); - if args.clone().next().is_some() { - self.generic_delimiters(|cx| cx.comma_sep(args)) + if !args.is_empty() { + self.generic_delimiters(|cx| cx.comma_sep(args.iter().copied())) } else { Ok(()) } @@ -136,8 +135,15 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { } impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> { - fn should_print_region(&self, _region: ty::Region<'_>) -> bool { - false + fn should_print_optional_region(&self, _region: ty::Region<'_>) -> bool { + // Bound regions are always printed (as `'_`), which gives some idea that they are special, + // even though the `for` is omitted by the pretty printer. + // E.g. `for<'a, 'b> fn(&'a u32, &'b u32)` is printed as "fn(&'_ u32, &'_ u32)". + match _region.kind() { + ty::ReErased => false, + ty::ReBound(..) => true, + _ => unreachable!(), + } } fn generic_delimiters( diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index d9163d94710e8..cb159a0b91439 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -756,22 +756,22 @@ impl<'tcx> LateContext<'tcx> { } fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { - unreachable!(); // because `path_generic_args` ignores the `GenericArgs` + unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` } fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> { - unreachable!(); // because `path_generic_args` ignores the `GenericArgs` + unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` } fn print_dyn_existential( &mut self, _predicates: &'tcx ty::List>, ) -> Result<(), PrintError> { - unreachable!(); // because `path_generic_args` ignores the `GenericArgs` + unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` } fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> { - unreachable!(); // because `path_generic_args` ignores the `GenericArgs` + unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` } fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 0a976f3a0ac27..74caee7336a5f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -337,10 +337,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { false } - /// Returns `true` if the region should be printed in - /// optional positions, e.g., `&'a T` or `dyn Tr + 'b`. - /// This is typically the case for all non-`'_` regions. - fn should_print_region(&self, region: ty::Region<'tcx>) -> bool; + /// Returns `true` if the region should be printed in optional positions, + /// e.g., `&'a T` or `dyn Tr + 'b`. (Regions like the one in `Cow<'static, T>` + /// will always be printed.) + fn should_print_optional_region(&self, region: ty::Region<'tcx>) -> bool; fn reset_type_limit(&mut self) {} @@ -717,7 +717,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } ty::Ref(r, ty, mutbl) => { write!(self, "&")?; - if self.should_print_region(r) { + if self.should_print_optional_region(r) { r.print(self)?; write!(self, " ")?; } @@ -785,7 +785,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { }, ty::Adt(def, args) => self.print_def_path(def.did(), args)?, ty::Dynamic(data, r, repr) => { - let print_r = self.should_print_region(r); + let print_r = self.should_print_optional_region(r); if print_r { write!(self, "(")?; } @@ -2494,7 +2494,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { !self.type_length_limit.value_within_limit(self.printed_type_count) } - fn should_print_region(&self, region: ty::Region<'tcx>) -> bool { + fn should_print_optional_region(&self, region: ty::Region<'tcx>) -> bool { let highlight = self.region_highlight_mode; if highlight.region_highlighted(region).is_some() { return true; diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 7a8d3ba1ff1fa..5b3ddcc777be5 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -41,19 +41,40 @@ fn to_profiler_name(type_name: &'static str) -> &'static str { }) } -// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }` -const fn c_name(name: &'static str) -> &'static str { +// A function that simplifies a pass's type_name. E.g. `Baz`, `Baz<'_>`, +// `foo::bar::Baz`, and `foo::bar::Baz<'a, 'b>` all become `Baz`. +// +// It's `const` for perf reasons: it's called a lot, and doing the string +// operations at runtime causes a non-trivial slowdown. If +// `split_once`/`rsplit_once` become `const` its body could be simplified to +// this: +// ```ignore (fragment) +// let name = if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }; +// let name = if let Some((head, _)) = name.split_once('<') { head } else { name }; +// name +// ``` +const fn simplify_pass_type_name(name: &'static str) -> &'static str { // FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable. - // and inline into call site + + // Work backwards from the end. If a ':' is hit, strip it and everything before it. let bytes = name.as_bytes(); let mut i = bytes.len(); while i > 0 && bytes[i - 1] != b':' { - i = i - 1; + i -= 1; } let (_, bytes) = bytes.split_at(i); + + // Work forwards from the start of what's left. If a '<' is hit, strip it and everything after + // it. + let mut i = 0; + while i < bytes.len() && bytes[i] != b'<' { + i += 1; + } + let (bytes, _) = bytes.split_at(i); + match std::str::from_utf8(bytes) { Ok(name) => name, - Err(_) => name, + Err(_) => panic!(), } } @@ -62,12 +83,7 @@ const fn c_name(name: &'static str) -> &'static str { /// loop that goes over each available MIR and applies `run_pass`. pub(super) trait MirPass<'tcx> { fn name(&self) -> &'static str { - // FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable. - // See copypaste in `MirLint` - const { - let name = std::any::type_name::(); - c_name(name) - } + const { simplify_pass_type_name(std::any::type_name::()) } } fn profiler_name(&self) -> &'static str { @@ -101,12 +117,7 @@ pub(super) trait MirPass<'tcx> { /// disabled (via the `Lint` adapter). pub(super) trait MirLint<'tcx> { fn name(&self) -> &'static str { - // FIXME(const-hack) Simplify the implementation once more `str` methods get const-stable. - // See copypaste in `MirPass` - const { - let name = std::any::type_name::(); - c_name(name) - } + const { simplify_pass_type_name(std::any::type_name::()) } } fn is_enabled(&self, _sess: &Session) -> bool { diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 025fa2998263b..4d9741f1d11cc 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -235,7 +235,8 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { // This might be reachable (via `pretty_print_dyn_existential`) even though - // `::should_print_region` returns false. See #144994. + // `::should_print_optional_region` returns false and + // `print_path_with_generic_args` filters out lifetimes. See #144994. Ok(()) } @@ -389,7 +390,6 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { let args = args.iter().cloned().filter(|arg| !matches!(arg.kind(), GenericArgKind::Lifetime(_))); - if args.clone().next().is_some() { self.generic_delimiters(|cx| cx.comma_sep(args)) } else { @@ -459,7 +459,7 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { } impl<'tcx> PrettyPrinter<'tcx> for LegacySymbolMangler<'tcx> { - fn should_print_region(&self, _region: ty::Region<'_>) -> bool { + fn should_print_optional_region(&self, _region: ty::Region<'_>) -> bool { false } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 20e425bfad143..fe514e1ac72e5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -235,22 +235,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> { - unreachable!(); // because `path_generic_args` ignores the `GenericArgs` + unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` } fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> { - unreachable!(); // because `path_generic_args` ignores the `GenericArgs` + unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` } fn print_dyn_existential( &mut self, _predicates: &'tcx ty::List>, ) -> Result<(), PrintError> { - unreachable!(); // because `path_generic_args` ignores the `GenericArgs` + unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` } fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> { - unreachable!(); // because `path_generic_args` ignores the `GenericArgs` + unreachable!(); // because `print_path_with_generic_args` ignores the `GenericArgs` } fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> { diff --git a/library/core/src/any.rs b/library/core/src/any.rs index ceb9748e7feb9..e7d9763d46ef5 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -835,9 +835,9 @@ impl fmt::Debug for TypeId { /// /// The returned string must not be considered to be a unique identifier of a /// type as multiple types may map to the same type name. Similarly, there is no -/// guarantee that all parts of a type will appear in the returned string: for -/// example, lifetime specifiers are currently not included. In addition, the -/// output may change between versions of the compiler. +/// guarantee that all parts of a type will appear in the returned string. In +/// addition, the output may change between versions of the compiler. For +/// example, lifetime specifiers were omitted in some earlier versions. /// /// The current implementation uses the same infrastructure as compiler /// diagnostics and debuginfo, but this is not guaranteed. diff --git a/tests/ui/type/type-name-basic.rs b/tests/ui/type/type-name-basic.rs index 6a9f772e54219..e1310e1f36599 100644 --- a/tests/ui/type/type-name-basic.rs +++ b/tests/ui/type/type-name-basic.rs @@ -62,28 +62,32 @@ pub fn main() { t!(Vec>, "alloc::vec::Vec>"); t!(Foo, "type_name_basic::Foo"); - t!(Bar<'static>, "type_name_basic::Bar"); - t!(Baz<'static, u32>, "type_name_basic::Baz"); + t!(Bar<'static>, "type_name_basic::Bar<'_>"); + t!(Baz<'static, u32>, "type_name_basic::Baz<'_, u32>"); - // FIXME: lifetime omission means these all print badly. - t!(dyn TrL<'static>, "dyn type_name_basic::TrL<>"); - t!(dyn TrLA<'static, A = u32>, "dyn type_name_basic::TrLA<, A = u32>"); + t!(dyn TrL<'static>, "dyn type_name_basic::TrL<'_>"); + t!(dyn TrLA<'static, A = u32>, "dyn type_name_basic::TrLA<'_, A = u32>"); t!( dyn TrLT<'static, Cow<'static, ()>>, - "dyn type_name_basic::TrLT<, alloc::borrow::Cow<()>>" + "dyn type_name_basic::TrLT<'_, alloc::borrow::Cow<'_, ()>>" ); t!( dyn TrLTA<'static, u32, A = Cow<'static, ()>>, - "dyn type_name_basic::TrLTA<, u32, A = alloc::borrow::Cow<()>>" + "dyn type_name_basic::TrLTA<'_, u32, A = alloc::borrow::Cow<'_, ()>>" ); t!(fn(i32) -> i32, "fn(i32) -> i32"); - t!(dyn for<'a> Fn(&'a u32), "dyn core::ops::function::Fn(&u32)"); + t!(fn(&'static u32), "fn(&u32)"); + + // FIXME: these are sub-optimal, ideally the `for<...>` would be printed. + t!(for<'a> fn(&'a u32), "fn(&'_ u32)"); + t!(for<'a, 'b> fn(&'a u32, &'b u32), "fn(&'_ u32, &'_ u32)"); + t!(for<'a> fn(for<'b> fn(&'a u32, &'b u32)), "fn(fn(&'_ u32, &'_ u32))"); struct S<'a, T>(&'a T); impl<'a, T: Clone> S<'a, T> { fn test() { - t!(Cow<'a, T>, "alloc::borrow::Cow"); + t!(Cow<'a, T>, "alloc::borrow::Cow<'_, u32>"); } } S::::test(); From ecce90b3efed8d90fa213d8d79ad37bf625cac67 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 8 Aug 2025 21:27:29 +1000 Subject: [PATCH 185/252] coverage: Remove intermediate data structures from mapping creation --- .../src/coverage/mappings.rs | 60 +++++++------------ .../rustc_mir_transform/src/coverage/mod.rs | 36 +---------- .../rustc_mir_transform/src/coverage/spans.rs | 12 ++-- 3 files changed, 31 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 46fe7c40826a8..8dbe564f51749 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -1,51 +1,36 @@ use rustc_index::IndexVec; -use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind}; +use rustc_middle::mir::coverage::{ + BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind, Mapping, MappingKind, +}; use rustc_middle::mir::{self, BasicBlock, StatementKind}; use rustc_middle::ty::TyCtxt; -use rustc_span::Span; -use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::graph::CoverageGraph; use crate::coverage::hir_info::ExtractedHirInfo; use crate::coverage::spans::extract_refined_covspans; use crate::coverage::unexpand::unexpand_into_body_span; -/// Associates an ordinary executable code span with its corresponding BCB. -#[derive(Debug)] -pub(super) struct CodeMapping { - pub(super) span: Span, - pub(super) bcb: BasicCoverageBlock, -} - -#[derive(Debug)] -pub(super) struct BranchPair { - pub(super) span: Span, - pub(super) true_bcb: BasicCoverageBlock, - pub(super) false_bcb: BasicCoverageBlock, -} - #[derive(Default)] -pub(super) struct ExtractedMappings { - pub(super) code_mappings: Vec, - pub(super) branch_pairs: Vec, +pub(crate) struct ExtractedMappings { + pub(crate) mappings: Vec, } -/// Extracts coverage-relevant spans from MIR, and associates them with -/// their corresponding BCBs. -pub(super) fn extract_all_mapping_info_from_mir<'tcx>( +/// Extracts coverage-relevant spans from MIR, and uses them to create +/// coverage mapping data for inclusion in MIR. +pub(crate) fn extract_mappings_from_mir<'tcx>( tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>, hir_info: &ExtractedHirInfo, graph: &CoverageGraph, ) -> ExtractedMappings { - let mut code_mappings = vec![]; - let mut branch_pairs = vec![]; + let mut mappings = vec![]; // Extract ordinary code mappings from MIR statement/terminator spans. - extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut code_mappings); + extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut mappings); - branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, graph)); + extract_branch_mappings(mir_body, hir_info, graph, &mut mappings); - ExtractedMappings { code_mappings, branch_pairs } + ExtractedMappings { mappings } } fn resolve_block_markers( @@ -69,19 +54,18 @@ fn resolve_block_markers( block_markers } -pub(super) fn extract_branch_pairs( +pub(super) fn extract_branch_mappings( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, graph: &CoverageGraph, -) -> Vec { - let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return vec![] }; + mappings: &mut Vec, +) { + let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return }; let block_markers = resolve_block_markers(coverage_info_hi, mir_body); - coverage_info_hi - .branch_spans - .iter() - .filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| { + mappings.extend(coverage_info_hi.branch_spans.iter().filter_map( + |&BranchSpan { span: raw_span, true_marker, false_marker }| try { // For now, ignore any branch span that was introduced by // expansion. This makes things like assert macros less noisy. if !raw_span.ctxt().outer_expn_data().is_root() { @@ -94,7 +78,7 @@ pub(super) fn extract_branch_pairs( let true_bcb = bcb_from_marker(true_marker)?; let false_bcb = bcb_from_marker(false_marker)?; - Some(BranchPair { span, true_bcb, false_bcb }) - }) - .collect::>() + Mapping { span, kind: MappingKind::Branch { true_bcb, false_bcb } } + }, + )); } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 47a87a2e94d8b..c5fef29924478 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -1,4 +1,4 @@ -use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo, Mapping, MappingKind}; +use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo}; use rustc_middle::mir::{self, BasicBlock, Statement, StatementKind, TerminatorKind}; use rustc_middle::ty::TyCtxt; use tracing::{debug, debug_span, trace}; @@ -71,10 +71,8 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: //////////////////////////////////////////////////// // Extract coverage spans and other mapping info from MIR. - let extracted_mappings = - mappings::extract_all_mapping_info_from_mir(tcx, mir_body, &hir_info, &graph); - - let mappings = create_mappings(&extracted_mappings); + let ExtractedMappings { mappings } = + mappings::extract_mappings_from_mir(tcx, mir_body, &hir_info, &graph); if mappings.is_empty() { // No spans could be converted into valid mappings, so skip this function. debug!("no spans could be converted into valid mappings; skipping"); @@ -100,34 +98,6 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: })); } -/// For each coverage span extracted from MIR, create a corresponding mapping. -/// -/// FIXME(Zalathar): This used to be where BCBs in the extracted mappings were -/// resolved to a `CovTerm`. But that is now handled elsewhere, so this -/// function can potentially be simplified even further. -fn create_mappings(extracted_mappings: &ExtractedMappings) -> Vec { - // Fully destructure the mappings struct to make sure we don't miss any kinds. - let ExtractedMappings { code_mappings, branch_pairs } = extracted_mappings; - let mut mappings = Vec::new(); - - mappings.extend(code_mappings.iter().map( - // Ordinary code mappings are the simplest kind. - |&mappings::CodeMapping { span, bcb }| { - let kind = MappingKind::Code { bcb }; - Mapping { kind, span } - }, - )); - - mappings.extend(branch_pairs.iter().map( - |&mappings::BranchPair { span, true_bcb, false_bcb }| { - let kind = MappingKind::Branch { true_bcb, false_bcb }; - Mapping { kind, span } - }, - )); - - mappings -} - /// Inject any necessary coverage statements into MIR, so that they influence codegen. fn inject_coverage_statements<'tcx>(mir_body: &mut mir::Body<'tcx>, graph: &CoverageGraph) { for (bcb, data) in graph.iter_enumerated() { diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index ae9459dee842d..d1b04c8f5877f 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; -use rustc_middle::mir::coverage::START_BCB; +use rustc_middle::mir::coverage::{Mapping, MappingKind, START_BCB}; use rustc_middle::ty::TyCtxt; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span}; @@ -9,7 +9,7 @@ use tracing::instrument; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::hir_info::ExtractedHirInfo; use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir}; -use crate::coverage::{mappings, unexpand}; +use crate::coverage::unexpand; mod from_mir; @@ -18,7 +18,7 @@ pub(super) fn extract_refined_covspans<'tcx>( mir_body: &mir::Body<'tcx>, hir_info: &ExtractedHirInfo, graph: &CoverageGraph, - code_mappings: &mut Vec, + mappings: &mut Vec, ) { if hir_info.is_async_fn { // An async function desugars into a function that returns a future, @@ -26,7 +26,7 @@ pub(super) fn extract_refined_covspans<'tcx>( // outer function will be unhelpful, so just keep the signature span // and ignore all of the spans in the MIR body. if let Some(span) = hir_info.fn_sig_span { - code_mappings.push(mappings::CodeMapping { span, bcb: START_BCB }); + mappings.push(Mapping { span, kind: MappingKind::Code { bcb: START_BCB } }) } return; } @@ -111,9 +111,9 @@ pub(super) fn extract_refined_covspans<'tcx>( // Merge covspans that can be merged. covspans.dedup_by(|b, a| a.merge_if_eligible(b)); - code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { + mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { // Each span produced by the refiner represents an ordinary code region. - mappings::CodeMapping { span, bcb } + Mapping { span, kind: MappingKind::Code { bcb } } })); } From 7e29b8877ac388cd1c37786e01a2a4c527d4a53e Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 6 Aug 2025 15:33:31 +0200 Subject: [PATCH 186/252] ignore head usages of ignored candidates --- .../src/solve/assembly/mod.rs | 99 ++++-- .../src/solve/eval_ctxt/mod.rs | 6 +- .../src/solve/eval_ctxt/probe.rs | 18 +- .../rustc_next_trait_solver/src/solve/mod.rs | 26 +- .../src/solve/trait_goals.rs | 43 ++- .../rustc_type_ir/src/search_graph/mod.rs | 308 +++++++++++++----- .../rustc_type_ir/src/search_graph/stack.rs | 23 +- 7 files changed, 374 insertions(+), 149 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 5e08c3a03d8ac..a4a8317912a81 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -8,6 +8,7 @@ use std::ops::ControlFlow; use derive_where::derive_where; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; +use rustc_type_ir::search_graph::CandidateHeadUsages; use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::{ self as ty, Interner, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, @@ -33,10 +34,11 @@ enum AliasBoundKind { /// /// It consists of both the `source`, which describes how that goal would be proven, /// and the `result` when using the given `source`. -#[derive_where(Clone, Debug; I: Interner)] +#[derive_where(Debug; I: Interner)] pub(super) struct Candidate { pub(super) source: CandidateSource, pub(super) result: CanonicalResponse, + pub(super) head_usages: CandidateHeadUsages, } /// Methods used to assemble candidates for either trait or projection goals. @@ -116,8 +118,11 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal, assumption: I::Clause, - ) -> Result, NoSolution> { - Self::fast_reject_assumption(ecx, goal, assumption)?; + ) -> Result, CandidateHeadUsages> { + match Self::fast_reject_assumption(ecx, goal, assumption) { + Ok(()) => {} + Err(NoSolution) => return Err(CandidateHeadUsages::default()), + } // Dealing with `ParamEnv` candidates is a bit of a mess as we need to lazily // check whether the candidate is global while considering normalization. @@ -126,18 +131,23 @@ where // in `probe` even if the candidate does not apply before we get there. We handle this // by using a `Cell` here. We only ever write into it inside of `match_assumption`. let source = Cell::new(CandidateSource::ParamEnv(ParamEnvSource::Global)); - ecx.probe(|result: &QueryResult| inspect::ProbeKind::TraitCandidate { - source: source.get(), - result: *result, - }) - .enter(|ecx| { - Self::match_assumption(ecx, goal, assumption, |ecx| { - ecx.try_evaluate_added_goals()?; - source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + let (result, head_usages) = ecx + .probe(|result: &QueryResult| inspect::ProbeKind::TraitCandidate { + source: source.get(), + result: *result, }) - }) - .map(|result| Candidate { source: source.get(), result }) + .enter_single_candidate(|ecx| { + Self::match_assumption(ecx, goal, assumption, |ecx| { + ecx.try_evaluate_added_goals()?; + source.set(ecx.characterize_param_env_assumption(goal.param_env, assumption)?); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }) + }); + + match result { + Ok(result) => Ok(Candidate { source: source.get(), result, head_usages }), + Err(NoSolution) => Err(head_usages), + } } /// Try equating an assumption predicate against a goal's predicate. If it @@ -355,6 +365,19 @@ pub(super) enum AssembleCandidatesFrom { EnvAndBounds, } +/// This is currently used to track the [CandidateHeadUsages] of all failed `ParamEnv` +/// candidates. This is then used to ignore their head usages in case there's another +/// always applicable `ParamEnv` candidate. Look at how `param_env_head_usages` is +/// used in the code for more details. +/// +/// We could easily extend this to also ignore head usages of other ignored candidates. +/// However, we currently don't have any tests where this matters and the complexity of +/// doing so does not feel worth it for now. +#[derive(Debug)] +pub(super) struct FailedCandidateInfo { + pub param_env_head_usages: CandidateHeadUsages, +} + impl EvalCtxt<'_, D> where D: SolverDelegate, @@ -364,16 +387,20 @@ where &mut self, goal: Goal, assemble_from: AssembleCandidatesFrom, - ) -> Vec> { + ) -> (Vec>, FailedCandidateInfo) { + let mut candidates = vec![]; + let mut failed_candidate_info = + FailedCandidateInfo { param_env_head_usages: CandidateHeadUsages::default() }; let Ok(normalized_self_ty) = self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) else { - return vec![]; + return (candidates, failed_candidate_info); }; if normalized_self_ty.is_ty_var() { debug!("self type has been normalized to infer"); - return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); + candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity)); + return (candidates, failed_candidate_info); } let goal: Goal = goal @@ -382,16 +409,15 @@ where // normalizing the self type as well, since type variables are not uniquified. let goal = self.resolve_vars_if_possible(goal); - let mut candidates = vec![]; - if let TypingMode::Coherence = self.typing_mode() && let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) { - return vec![candidate]; + candidates.push(candidate); + return (candidates, failed_candidate_info); } self.assemble_alias_bound_candidates(goal, &mut candidates); - self.assemble_param_env_candidates(goal, &mut candidates); + self.assemble_param_env_candidates(goal, &mut candidates, &mut failed_candidate_info); match assemble_from { AssembleCandidatesFrom::All => { @@ -423,7 +449,7 @@ where AssembleCandidatesFrom::EnvAndBounds => {} } - candidates + (candidates, failed_candidate_info) } pub(super) fn forced_ambiguity( @@ -584,9 +610,15 @@ where &mut self, goal: Goal, candidates: &mut Vec>, + failed_candidate_info: &mut FailedCandidateInfo, ) { for assumption in goal.param_env.caller_bounds().iter() { - candidates.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption)); + match G::probe_and_consider_param_env_candidate(self, goal, assumption) { + Ok(candidate) => candidates.push(candidate), + Err(head_usages) => { + failed_candidate_info.param_env_head_usages.merge_usages(head_usages) + } + } } } @@ -661,7 +693,11 @@ where if let Ok(result) = self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) { - candidates.push(Candidate { source: CandidateSource::AliasBound, result }); + candidates.push(Candidate { + source: CandidateSource::AliasBound, + result, + head_usages: CandidateHeadUsages::default(), + }); } return; } @@ -959,7 +995,7 @@ where // Even when a trait bound has been proven using a where-bound, we // still need to consider alias-bounds for normalization, see // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`. - let mut candidates: Vec<_> = self + let (mut candidates, _) = self .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds); // We still need to prefer where-bounds over alias-bounds however. @@ -972,23 +1008,20 @@ where return inject_normalize_to_rigid_candidate(self); } - if let Some(response) = self.try_merge_candidates(&candidates) { + if let Some((response, _)) = self.try_merge_candidates(&candidates) { Ok(response) } else { self.flounder(&candidates) } } TraitGoalProvenVia::Misc => { - let mut candidates = + let (mut candidates, _) = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); // Prefer "orphaned" param-env normalization predicates, which are used // (for example, and ideally only) when proving item bounds for an impl. - let candidates_from_env: Vec<_> = candidates - .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_))) - .collect(); - if let Some(response) = self.try_merge_candidates(&candidates_from_env) { - return Ok(response); + if candidates.iter().any(|c| matches!(c.source, CandidateSource::ParamEnv(_))) { + candidates.retain(|c| matches!(c.source, CandidateSource::ParamEnv(_))); } // We drop specialized impls to allow normalization via a final impl here. In case @@ -997,7 +1030,7 @@ where // means we can just ignore inference constraints and don't have to special-case // constraining the normalized-to `term`. self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates); - if let Some(response) = self.try_merge_candidates(&candidates) { + if let Some((response, _)) = self.try_merge_candidates(&candidates) { Ok(response) } else { self.flounder(&candidates) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 8671cc7c3d309..a4738306181cc 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -8,7 +8,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; -use rustc_type_ir::search_graph::PathKind; +use rustc_type_ir::search_graph::{CandidateHeadUsages, PathKind}; use rustc_type_ir::{ self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -399,6 +399,10 @@ where result } + pub(super) fn ignore_candidate_head_usages(&mut self, usages: CandidateHeadUsages) { + self.search_graph.ignore_candidate_head_usages(usages); + } + /// Recursively evaluates `goal`, returning whether any inference vars have /// been constrained and the certainty of the result. fn evaluate_goal( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index ed0cedc407746..e5658ba32ff67 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -1,5 +1,6 @@ use std::marker::PhantomData; +use rustc_type_ir::search_graph::CandidateHeadUsages; use rustc_type_ir::{InferCtxtLike, Interner}; use tracing::instrument; @@ -25,6 +26,20 @@ where D: SolverDelegate, I: Interner, { + pub(in crate::solve) fn enter_single_candidate( + self, + f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T, + ) -> (T, CandidateHeadUsages) { + self.ecx.search_graph.enter_single_candidate(); + let mut candidate_usages = CandidateHeadUsages::default(); + let result = self.enter(|ecx| { + let result = f(ecx); + candidate_usages = ecx.search_graph.finish_single_candidate(); + result + }); + (result, candidate_usages) + } + pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> T) -> T { let ProbeCtxt { ecx: outer, probe_kind, _result } = self; @@ -78,7 +93,8 @@ where self, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult, ) -> Result, NoSolution> { - self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result }) + let (result, head_usages) = self.cx.enter_single_candidate(f); + result.map(|result| Candidate { source: self.source, result, head_usages }) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 2feebe270a6bb..c2745c878dc12 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -236,6 +236,12 @@ where } } +#[derive(Debug)] +enum MergeCandidateInfo { + AlwaysApplicable(usize), + EqualResponse, +} + impl EvalCtxt<'_, D> where D: SolverDelegate, @@ -248,23 +254,25 @@ where fn try_merge_candidates( &mut self, candidates: &[Candidate], - ) -> Option> { + ) -> Option<(CanonicalResponse, MergeCandidateInfo)> { if candidates.is_empty() { return None; } + let always_applicable = candidates.iter().enumerate().find(|(_, candidate)| { + candidate.result.value.certainty == Certainty::Yes + && has_no_inference_or_external_constraints(candidate.result) + }); + if let Some((i, c)) = always_applicable { + return Some((c.result, MergeCandidateInfo::AlwaysApplicable(i))); + } + let one: CanonicalResponse = candidates[0].result; if candidates[1..].iter().all(|candidate| candidate.result == one) { - return Some(one); + return Some((one, MergeCandidateInfo::EqualResponse)); } - candidates - .iter() - .find(|candidate| { - candidate.result.value.certainty == Certainty::Yes - && has_no_inference_or_external_constraints(candidate.result) - }) - .map(|candidate| candidate.result) + None } fn bail_with_ambiguity(&mut self, candidates: &[Candidate]) -> CanonicalResponse { diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 60bae738e61b8..03f7bc1f49e9c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -13,11 +13,13 @@ use tracing::{debug, instrument, trace}; use crate::delegate::SolverDelegate; use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes}; -use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate}; +use crate::solve::assembly::{ + self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate, FailedCandidateInfo, +}; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, - NoSolution, ParamEnvSource, QueryResult, has_only_region_constraints, + MergeCandidateInfo, NoSolution, ParamEnvSource, QueryResult, has_only_region_constraints, }; impl assembly::GoalKind for TraitPredicate @@ -1344,9 +1346,10 @@ where pub(super) fn merge_trait_candidates( &mut self, mut candidates: Vec>, + failed_candidate_info: FailedCandidateInfo, ) -> Result<(CanonicalResponse, Option), NoSolution> { if let TypingMode::Coherence = self.typing_mode() { - return if let Some(response) = self.try_merge_candidates(&candidates) { + return if let Some((response, _)) = self.try_merge_candidates(&candidates) { Ok((response, Some(TraitGoalProvenVia::Misc))) } else { self.flounder(&candidates).map(|r| (r, None)) @@ -1376,10 +1379,29 @@ where let where_bounds: Vec<_> = candidates .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_))) .collect(); - return if let Some(response) = self.try_merge_candidates(&where_bounds) { - Ok((response, Some(TraitGoalProvenVia::ParamEnv))) + if let Some((response, info)) = self.try_merge_candidates(&where_bounds) { + match info { + // If there's an always applicable candidate, the result of all + // other candidates does not matter. This means we can ignore + // them when checking whether we've reached a fixpoint. + MergeCandidateInfo::AlwaysApplicable(i) => { + for (j, c) in where_bounds.into_iter().enumerate() { + if i != j { + self.ignore_candidate_head_usages(c.head_usages) + } + } + // If a where-bound does not apply, we don't actually get a + // candidate for it. We manually track the head usages + // of all failed `ParamEnv` candidates instead. + self.ignore_candidate_head_usages( + failed_candidate_info.param_env_head_usages, + ); + } + MergeCandidateInfo::EqualResponse => {} + } + return Ok((response, Some(TraitGoalProvenVia::ParamEnv))); } else { - Ok((self.bail_with_ambiguity(&where_bounds), None)) + return Ok((self.bail_with_ambiguity(&where_bounds), None)); }; } @@ -1387,7 +1409,7 @@ where let alias_bounds: Vec<_> = candidates .extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound)) .collect(); - return if let Some(response) = self.try_merge_candidates(&alias_bounds) { + return if let Some((response, _)) = self.try_merge_candidates(&alias_bounds) { Ok((response, Some(TraitGoalProvenVia::AliasBound))) } else { Ok((self.bail_with_ambiguity(&alias_bounds), None)) @@ -1412,7 +1434,7 @@ where TraitGoalProvenVia::Misc }; - if let Some(response) = self.try_merge_candidates(&candidates) { + if let Some((response, _)) = self.try_merge_candidates(&candidates) { Ok((response, Some(proven_via))) } else { self.flounder(&candidates).map(|r| (r, None)) @@ -1424,8 +1446,9 @@ where &mut self, goal: Goal>, ) -> Result<(CanonicalResponse, Option), NoSolution> { - let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); - self.merge_trait_candidates(candidates) + let (candidates, failed_candidate_info) = + self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All); + self.merge_trait_candidates(candidates, failed_candidate_info) } fn try_stall_coroutine(&mut self, self_ty: I::Ty) -> Option, NoSolution>> { diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 24094eeea8d47..348178a527fbe 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -170,27 +170,76 @@ impl PathKind { /// This is used to avoid rerunning a cycle if there's /// just a single usage kind and the final result matches /// its provisional result. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum UsageKind { - Single(PathKind), - Mixed, +/// +/// While it tracks the amount of usages using `u32`, we only ever +/// care whether there are any. We only count them to be able to ignore +/// usages from irrelevant candidates while evaluating a goal. +/// +/// This cares about how nested goals relied on a cycle head. It does +/// not care about how frequently the nested goal relied on it. +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +struct HeadUsages { + inductive: u32, + unknown: u32, + coinductive: u32, + forced_ambiguity: u32, } -impl From for UsageKind { - fn from(path: PathKind) -> UsageKind { - UsageKind::Single(path) + +impl HeadUsages { + fn add_usage(&mut self, path: PathKind) { + match path { + PathKind::Inductive => self.inductive += 1, + PathKind::Unknown => self.unknown += 1, + PathKind::Coinductive => self.coinductive += 1, + PathKind::ForcedAmbiguity => self.forced_ambiguity += 1, + } + } + + /// This adds the usages which occurred while computing a nested goal. + /// + /// We don't actually care about how frequently the nested goal relied + /// on its cycle heads, only whether it did. + fn add_usages_from_nested(&mut self, usages: HeadUsages) { + let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = usages; + self.inductive += if inductive == 0 { 0 } else { 1 }; + self.unknown += if unknown == 0 { 0 } else { 1 }; + self.coinductive += if coinductive == 0 { 0 } else { 1 }; + self.forced_ambiguity += if forced_ambiguity == 0 { 0 } else { 1 }; + } + + fn ignore_usages(&mut self, usages: HeadUsages) { + let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = usages; + self.inductive = self.inductive.checked_sub(inductive).unwrap(); + self.unknown = self.unknown.checked_sub(unknown).unwrap(); + self.coinductive = self.coinductive.checked_sub(coinductive).unwrap(); + self.forced_ambiguity = self.forced_ambiguity.checked_sub(forced_ambiguity).unwrap(); + } + + fn is_empty(self) -> bool { + let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = self; + inductive == 0 && unknown == 0 && coinductive == 0 && forced_ambiguity == 0 } } -impl UsageKind { - #[must_use] - fn merge(self, other: impl Into) -> Self { - match (self, other.into()) { - (UsageKind::Mixed, _) | (_, UsageKind::Mixed) => UsageKind::Mixed, - (UsageKind::Single(lhs), UsageKind::Single(rhs)) => { - if lhs == rhs { - UsageKind::Single(lhs) - } else { - UsageKind::Mixed + +#[derive(Debug, Default)] +pub struct CandidateHeadUsages { + usages: Option>>, +} +impl CandidateHeadUsages { + pub fn merge_usages(&mut self, other: CandidateHeadUsages) { + if let Some(other_usages) = other.usages { + if let Some(ref mut self_usages) = self.usages { + #[allow(rustc::potential_query_instability)] + for (head_index, head) in other_usages.into_iter() { + let HeadUsages { inductive, unknown, coinductive, forced_ambiguity } = head; + let self_usages = self_usages.entry(head_index).or_default(); + self_usages.inductive += inductive; + self_usages.unknown += unknown; + self_usages.coinductive += coinductive; + self_usages.forced_ambiguity += forced_ambiguity; } + } else { + self.usages = Some(other_usages); } } } @@ -234,7 +283,12 @@ impl AvailableDepth { #[derive(Clone, Copy, Debug)] struct CycleHead { paths_to_head: PathsToNested, - usage_kind: UsageKind, + /// If the `usages` are empty, the result of that head does not matter + /// for the current goal. However, we still don't completely drop this + /// cycle head as whether or not it exists impacts which queries we + /// access, so ignoring it would cause incremental compilation verification + /// failures or hide query cycles. + usages: HeadUsages, } /// All cycle heads a given goal depends on, ordered by their stack depth. @@ -251,15 +305,19 @@ impl CycleHeads { self.heads.is_empty() } - fn highest_cycle_head(&self) -> StackDepth { - self.opt_highest_cycle_head().unwrap() + fn highest_cycle_head(&self) -> (StackDepth, CycleHead) { + self.heads.last_key_value().map(|(k, v)| (*k, *v)).unwrap() } - fn opt_highest_cycle_head(&self) -> Option { + fn highest_cycle_head_index(&self) -> StackDepth { + self.opt_highest_cycle_head_index().unwrap() + } + + fn opt_highest_cycle_head_index(&self) -> Option { self.heads.last_key_value().map(|(k, _)| *k) } - fn opt_lowest_cycle_head(&self) -> Option { + fn opt_lowest_cycle_head_index(&self) -> Option { self.heads.first_key_value().map(|(k, _)| *k) } @@ -272,20 +330,24 @@ impl CycleHeads { &mut self, head_index: StackDepth, path_from_entry: impl Into + Copy, - usage_kind: UsageKind, + usages: HeadUsages, ) { match self.heads.entry(head_index) { btree_map::Entry::Vacant(entry) => { - entry.insert(CycleHead { paths_to_head: path_from_entry.into(), usage_kind }); + entry.insert(CycleHead { paths_to_head: path_from_entry.into(), usages }); } btree_map::Entry::Occupied(entry) => { let head = entry.into_mut(); head.paths_to_head |= path_from_entry.into(); - head.usage_kind = head.usage_kind.merge(usage_kind); + head.usages.add_usages_from_nested(usages); } } } + fn ignore_usages(&mut self, head_index: StackDepth, usages: HeadUsages) { + self.heads.get_mut(&head_index).unwrap().usages.ignore_usages(usages) + } + fn iter(&self) -> impl Iterator + '_ { self.heads.iter().map(|(k, v)| (*k, *v)) } @@ -546,17 +608,22 @@ impl, X: Cx> SearchGraph { parent.encountered_overflow |= encountered_overflow; for (head_index, head) in heads { + if let Some(candidate_usages) = &mut parent.candidate_usages { + candidate_usages + .usages + .get_or_insert_default() + .entry(head_index) + .or_default() + .add_usages_from_nested(head.usages); + } match head_index.cmp(&parent_index) { Ordering::Less => parent.heads.insert( head_index, head.paths_to_head.extend_with(step_kind_from_parent), - head.usage_kind, + head.usages, ), Ordering::Equal => { - let usage_kind = parent - .has_been_used - .map_or(head.usage_kind, |prev| prev.merge(head.usage_kind)); - parent.has_been_used = Some(usage_kind); + parent.usages.get_or_insert_default().add_usages_from_nested(head.usages); } Ordering::Greater => unreachable!(), } @@ -613,6 +680,29 @@ impl, X: Cx> SearchGraph { stack.cycle_step_kinds(head).fold(step_kind_to_head, |curr, step| curr.extend(step)) } + pub fn enter_single_candidate(&mut self) { + let prev = self.stack.last_mut().unwrap().candidate_usages.replace(Default::default()); + debug_assert!(prev.is_none(), "existing candidate_usages: {prev:?}"); + } + + pub fn finish_single_candidate(&mut self) -> CandidateHeadUsages { + self.stack.last_mut().unwrap().candidate_usages.take().unwrap() + } + + pub fn ignore_candidate_head_usages(&mut self, usages: CandidateHeadUsages) { + if let Some(usages) = usages.usages { + let (entry_index, entry) = self.stack.last_mut_with_index().unwrap(); + #[allow(rustc::potential_query_instability)] + for (head_index, usages) in usages.into_iter() { + if head_index == entry_index { + entry.usages.unwrap().ignore_usages(usages); + } else { + entry.heads.ignore_usages(head_index, usages); + } + } + } + } + /// Probably the most involved method of the whole solver. /// /// While goals get computed via `D::compute_goal`, this function handles @@ -681,7 +771,8 @@ impl, X: Cx> SearchGraph { required_depth: 0, heads: Default::default(), encountered_overflow: false, - has_been_used: None, + usages: None, + candidate_usages: None, nested_goals: Default::default(), }); @@ -729,7 +820,7 @@ impl, X: Cx> SearchGraph { let path_from_head = Self::cycle_path_kind( &self.stack, step_kind_from_parent, - heads.highest_cycle_head(), + heads.highest_cycle_head_index(), ); let provisional_cache_entry = ProvisionalCacheEntry { encountered_overflow, heads, path_from_head, result }; @@ -767,11 +858,17 @@ impl, X: Cx> SearchGraph { /// When reevaluating a goal with a changed provisional result, all provisional cache entry /// which depend on this goal get invalidated. - fn clear_dependent_provisional_results(&mut self) { - let head = self.stack.next_index(); + /// + /// Note that we keep provisional cache entries which accessed this goal as a cycle head, but + /// don't depend on its value. + fn clear_dependent_provisional_results_for_rerun(&mut self) { + let rerun_index = self.stack.next_index(); #[allow(rustc::potential_query_instability)] self.provisional_cache.retain(|_, entries| { - entries.retain(|entry| entry.heads.highest_cycle_head() != head); + entries.retain(|entry| { + let (head_index, head) = entry.heads.highest_cycle_head(); + head_index != rerun_index || head.usages.is_empty() + }); !entries.is_empty() }); } @@ -808,50 +905,65 @@ impl, X: Cx> SearchGraph { path_from_head, result, } = entry; - let popped_head = if heads.highest_cycle_head() == popped_head_index { + let popped_head = if heads.highest_cycle_head_index() == popped_head_index { heads.remove_highest_cycle_head() } else { return true; }; // We're rebasing an entry `e` over a head `p`. This head - // has a number of own heads `h` it depends on. We need to - // make sure that the path kind of all paths `hph` remain the - // same after rebasing. + // has a number of own heads `h` it depends on. // - // After rebasing the cycles `hph` will go through `e`. We need to make - // sure that forall possible paths `hep`, `heph` is equal to `hph.` - let ep = popped_head.paths_to_head; - for (head_index, head) in stack_entry.heads.iter() { - let ph = head.paths_to_head; - let hp = Self::cycle_path_kind( - &self.stack, - stack_entry.step_kind_from_parent, - head_index, - ); - - // We first validate that all cycles while computing `p` would stay - // the same if we were to recompute it as a nested goal of `e`. - let he = hp.extend(*path_from_head); - for ph in ph.iter_paths() { - let hph = hp.extend(ph); - for ep in ep.iter_paths() { - let hep = ep.extend(he); - let heph = hep.extend(ph); - if hph != heph { - return false; + // This causes our provisional result to depend on the heads + // of `p` to avoid moving any goal which uses this cache entry to + // the global cache. + if popped_head.usages.is_empty() { + // The result of `e` does not depend on the value of `p`. This we can + // keep using the result of this provisional cache entry even if evaluating + // `p` as a nested goal of `e` would have a different result. + for (head_index, _) in stack_entry.heads.iter() { + heads.insert(head_index, PathsToNested::EMPTY, HeadUsages::default()); + } + } else { + // The entry `e` actually depends on the value of `p`. We need + // to make sure that the value of `p` wouldn't change even if we + // were to reevaluate it as a nested goal of `e` instead. For this + // we check that the path kind of all paths `hph` remain the + // same after rebasing. + // + // After rebasing the cycles `hph` will go through `e`. We need to make + // sure that forall possible paths `hep`, `heph` is equal to `hph.` + let ep = popped_head.paths_to_head; + for (head_index, head) in stack_entry.heads.iter() { + let ph = head.paths_to_head; + let hp = Self::cycle_path_kind( + &self.stack, + stack_entry.step_kind_from_parent, + head_index, + ); + // We first validate that all cycles while computing `p` would stay + // the same if we were to recompute it as a nested goal of `e`. + let he = hp.extend(*path_from_head); + for ph in ph.iter_paths() { + let hph = hp.extend(ph); + for ep in ep.iter_paths() { + let hep = ep.extend(he); + let heph = hep.extend(ph); + if hph != heph { + return false; + } } } - } - // If so, all paths reached while computing `p` have to get added - // the heads of `e` to make sure that rebasing `e` again also considers - // them. - let eph = ep.extend_with_paths(ph); - heads.insert(head_index, eph, head.usage_kind); + // If so, all paths reached while computing `p` have to get added + // the heads of `e` to make sure that rebasing `e` again also considers + // them. + let eph = ep.extend_with_paths(ph); + heads.insert(head_index, eph, head.usages); + } } - let Some(head) = heads.opt_highest_cycle_head() else { + let Some(head_index) = heads.opt_highest_cycle_head_index() else { return false; }; @@ -860,7 +972,7 @@ impl, X: Cx> SearchGraph { *path_from_head = path_from_head.extend(Self::cycle_path_kind( &self.stack, stack_entry.step_kind_from_parent, - head, + head_index, )); // Mutate the result of the provisional cache entry in case we did // not reach a fixpoint. @@ -884,7 +996,7 @@ impl, X: Cx> SearchGraph { for &ProvisionalCacheEntry { encountered_overflow, ref heads, path_from_head, result } in entries { - let head = heads.highest_cycle_head(); + let head_index = heads.highest_cycle_head_index(); if encountered_overflow { // This check is overly strict and very subtle. We need to make sure that if // a global cache entry depends on some goal without adding it to its @@ -896,14 +1008,17 @@ impl, X: Cx> SearchGraph { // current goal is already part of the same cycle. This check could be // improved but seems to be good enough for now. let last = self.stack.last().unwrap(); - if last.heads.opt_lowest_cycle_head().is_none_or(|lowest| lowest > head) { + if last.heads.opt_lowest_cycle_head_index().is_none_or(|lowest| lowest > head_index) + { continue; } } // A provisional cache entry is only valid if the current path from its // highest cycle head to the goal is the same. - if path_from_head == Self::cycle_path_kind(&self.stack, step_kind_from_parent, head) { + if path_from_head + == Self::cycle_path_kind(&self.stack, step_kind_from_parent, head_index) + { Self::update_parent_goal( &mut self.stack, step_kind_from_parent, @@ -912,7 +1027,7 @@ impl, X: Cx> SearchGraph { encountered_overflow, UpdateParentGoalCtxt::ProvisionalCacheHit, ); - debug!(?head, ?path_from_head, "provisional cache hit"); + debug!(?head_index, ?path_from_head, "provisional cache hit"); return Some(result); } } @@ -970,8 +1085,9 @@ impl, X: Cx> SearchGraph { // // We check if any of the paths taken while computing the global goal // would end up with an applicable provisional cache entry. - let head = heads.highest_cycle_head(); - let head_to_curr = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head); + let head_index = heads.highest_cycle_head_index(); + let head_to_curr = + Self::cycle_path_kind(&self.stack, step_kind_from_parent, head_index); let full_paths = path_from_global_entry.extend_with(head_to_curr); if full_paths.contains(head_to_provisional.into()) { debug!( @@ -1053,10 +1169,9 @@ impl, X: Cx> SearchGraph { // in case we're in the first fixpoint iteration for this goal. let path_kind = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head_index); debug!(?path_kind, "encountered cycle with depth {head_index:?}"); - let head = CycleHead { - paths_to_head: step_kind_from_parent.into(), - usage_kind: UsageKind::Single(path_kind), - }; + let mut usages = HeadUsages::default(); + usages.add_usage(path_kind); + let head = CycleHead { paths_to_head: step_kind_from_parent.into(), usages }; Self::update_parent_goal( &mut self.stack, step_kind_from_parent, @@ -1080,15 +1195,31 @@ impl, X: Cx> SearchGraph { &mut self, cx: X, stack_entry: &StackEntry, - usage_kind: UsageKind, + usages: HeadUsages, result: X::Result, ) -> bool { - if let Some(prev) = stack_entry.provisional_result { - prev == result - } else if let UsageKind::Single(kind) = usage_kind { - D::is_initial_provisional_result(cx, kind, stack_entry.input, result) + let provisional_result = stack_entry.provisional_result; + if usages.is_empty() { + true + } else if let Some(provisional_result) = provisional_result { + provisional_result == result } else { - false + let check = |k| D::is_initial_provisional_result(cx, k, stack_entry.input, result); + match usages { + HeadUsages { inductive: _, unknown: 0, coinductive: 0, forced_ambiguity: 0 } => { + check(PathKind::Inductive) + } + HeadUsages { inductive: 0, unknown: _, coinductive: 0, forced_ambiguity: 0 } => { + check(PathKind::Unknown) + } + HeadUsages { inductive: 0, unknown: 0, coinductive: _, forced_ambiguity: 0 } => { + check(PathKind::Coinductive) + } + HeadUsages { inductive: 0, unknown: 0, coinductive: 0, forced_ambiguity: _ } => { + check(PathKind::ForcedAmbiguity) + } + _ => false, + } } } @@ -1118,7 +1249,7 @@ impl, X: Cx> SearchGraph { // If the current goal is not the root of a cycle, we are done. // // There are no provisional cache entries which depend on this goal. - let Some(usage_kind) = stack_entry.has_been_used else { + let Some(usages) = stack_entry.usages else { return EvaluationResult::finalize(stack_entry, encountered_overflow, result); }; @@ -1133,7 +1264,7 @@ impl, X: Cx> SearchGraph { // is equal to the provisional result of the previous iteration, or because // this was only the root of either coinductive or inductive cycles, and the // final result is equal to the initial response for that case. - if self.reached_fixpoint(cx, &stack_entry, usage_kind, result) { + if self.reached_fixpoint(cx, &stack_entry, usages, result) { self.rebase_provisional_cache_entries(&stack_entry, |_, result| result); return EvaluationResult::finalize(stack_entry, encountered_overflow, result); } @@ -1171,7 +1302,7 @@ impl, X: Cx> SearchGraph { // Clear all provisional cache entries which depend on a previous provisional // result of this goal and rerun. - self.clear_dependent_provisional_results(); + self.clear_dependent_provisional_results_for_rerun(); debug!(?result, "fixpoint changed provisional results"); self.stack.push(StackEntry { @@ -1190,7 +1321,8 @@ impl, X: Cx> SearchGraph { // similar to the previous iterations when reevaluating, it's better // for caching if the reevaluation also starts out with `false`. encountered_overflow: false, - has_been_used: None, + usages: None, + candidate_usages: None, }); } } diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs index ea99dc6e7fd28..3fd8e2bd16e4e 100644 --- a/compiler/rustc_type_ir/src/search_graph/stack.rs +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -3,7 +3,9 @@ use std::ops::Index; use derive_where::derive_where; use rustc_index::IndexVec; -use crate::search_graph::{AvailableDepth, Cx, CycleHeads, NestedGoals, PathKind, UsageKind}; +use crate::search_graph::{ + AvailableDepth, CandidateHeadUsages, Cx, CycleHeads, HeadUsages, NestedGoals, PathKind, +}; rustc_index::newtype_index! { #[orderable] @@ -26,13 +28,13 @@ pub(super) struct StackEntry { /// The available depth of a given goal, immutable. pub available_depth: AvailableDepth, + /// The maximum depth required while evaluating this goal. + pub required_depth: usize, + /// Starts out as `None` and gets set when rerunning this /// goal in case we encounter a cycle. pub provisional_result: Option, - /// The maximum depth required while evaluating this goal. - pub required_depth: usize, - /// All cycle heads this goal depends on. Lazily updated and only /// up-to date for the top of the stack. pub heads: CycleHeads, @@ -40,9 +42,16 @@ pub(super) struct StackEntry { /// Whether evaluating this goal encountered overflow. Lazily updated. pub encountered_overflow: bool, - /// Whether this goal has been used as the root of a cycle. This gets - /// eagerly updated when encountering a cycle. - pub has_been_used: Option, + /// Whether and how this goal has been used as the root of a cycle. Lazily updated. + pub usages: Option, + + /// We want to be able to ignore head usages if they happen inside of candidates + /// which don't impact the result of a goal. This enables us to avoid rerunning goals + /// and is also used when rebasing provisional cache entries. + /// + /// To implement this, we track all usages while evaluating a candidate. If this candidate + /// then ends up ignored, we manually remove its usages from `usages` and `heads`. + pub candidate_usages: Option, /// The nested goals of this goal, see the doc comment of the type. pub nested_goals: NestedGoals, From ff560d3c9a662786ab1126b32320cc7cb0169678 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Mon, 11 Aug 2025 22:33:12 +0200 Subject: [PATCH 187/252] resolve prelude import at `build_reduced_graph` phase --- .../rustc_resolve/src/build_reduced_graph.rs | 23 +++++++++++-------- compiler/rustc_resolve/src/imports.rs | 20 +++++----------- library/core/src/lib.rs | 8 +++---- library/std/src/lib.rs | 7 +++--- tests/ui/extern-flag/empty-extern-arg.rs | 1 + tests/ui/extern-flag/empty-extern-arg.stderr | 4 +++- .../derive-helper-legacy-spurious.rs | 2 +- .../derive-helper-legacy-spurious.stderr | 8 +------ tests/ui/resolve/inner-attr-prelude-macro.rs | 11 +++++++++ tests/ui/unpretty/exhaustive.expanded.stdout | 6 ++--- tests/ui/unpretty/exhaustive.hir.stdout | 6 ++--- tests/ui/unpretty/exhaustive.rs | 6 ++--- 12 files changed, 53 insertions(+), 49 deletions(-) create mode 100644 tests/ui/resolve/inner-attr-prelude-macro.rs diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3fee2ab6afe1e..7bf366badb560 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -493,9 +493,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); } } - // We don't add prelude imports to the globs since they only affect lexical scopes, - // which are not relevant to import resolution. - ImportKind::Glob { is_prelude: true, .. } => {} ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(import), _ => unreachable!(), } @@ -658,13 +655,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.add_import(module_path, kind, use_tree.span, item, root_span, item.id, vis); } ast::UseTreeKind::Glob => { - let kind = ImportKind::Glob { - is_prelude: ast::attr::contains_name(&item.attrs, sym::prelude_import), - max_vis: Cell::new(None), - id, - }; - - self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); + if !ast::attr::contains_name(&item.attrs, sym::prelude_import) { + let kind = ImportKind::Glob { max_vis: Cell::new(None), id }; + self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); + } else { + // Resolve the prelude import early. + let path_res = + self.r.cm().maybe_resolve_path(&prefix, None, &self.parent_scope, None); + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = path_res { + self.r.prelude = Some(module); + } else { + self.r.dcx().span_err(use_tree.span, "cannot resolve a prelude import"); + } + } } ast::UseTreeKind::Nested { ref items, .. } => { // Ensure there is at most one `self` in the list diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 403d440bee786..7c93fdb88ee44 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -87,7 +87,6 @@ pub(crate) enum ImportKind<'ra> { id: NodeId, }, Glob { - is_prelude: bool, // The visibility of the greatest re-export. // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. max_vis: Cell>, @@ -125,12 +124,9 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { .field("nested", nested) .field("id", id) .finish(), - Glob { is_prelude, max_vis, id } => f - .debug_struct("Glob") - .field("is_prelude", is_prelude) - .field("max_vis", max_vis) - .field("id", id) - .finish(), + Glob { max_vis, id } => { + f.debug_struct("Glob").field("max_vis", max_vis).field("id", id).finish() + } ExternCrate { source, target, id } => f .debug_struct("ExternCrate") .field("source", source) @@ -1073,7 +1069,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ImportKind::Single { source, target, ref bindings, type_ns_only, id, .. } => { (source, target, bindings, type_ns_only, id) } - ImportKind::Glob { is_prelude, ref max_vis, id } => { + ImportKind::Glob { ref max_vis, id } => { if import.module_path.len() <= 1 { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. @@ -1096,8 +1092,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module: None, }); } - if !is_prelude - && let Some(max_vis) = max_vis.get() + if let Some(max_vis) = max_vis.get() && !max_vis.is_at_least(import.vis, self.tcx) { let def_id = self.local_def_id(id); @@ -1485,7 +1480,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_glob_import(&mut self, import: Import<'ra>) { // This function is only called for glob imports. - let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() }; + let ImportKind::Glob { id, .. } = import.kind else { unreachable!() }; let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else { self.dcx().emit_err(CannotGlobImportAllCrates { span: import.span }); @@ -1504,9 +1499,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if module == import.parent_scope.module { return; - } else if is_prelude { - self.prelude = Some(module); - return; } // Add to module's glob_importers diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d5bce6ad233e9..f40bcf6a4bb81 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -210,6 +210,10 @@ #[allow(unused_extern_crates)] extern crate self as core; +/* The core prelude, not as all-encompassing as the std prelude */ +// The compiler expects the prelude definition to be defined before it's use statement. +pub mod prelude; + #[prelude_import] #[allow(unused)] use prelude::rust_2024::*; @@ -295,10 +299,6 @@ pub mod f64; #[macro_use] pub mod num; -/* The core prelude, not as all-encompassing as the std prelude */ - -pub mod prelude; - /* Core modules for ownership management */ pub mod hint; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 07b38c658984d..40ad2d7146a66 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -428,6 +428,10 @@ // #![default_lib_allocator] +// The Rust prelude +// The compiler expects the prelude definition to be defined before it's use statement. +pub mod prelude; + // Explicitly import the prelude. The compiler uses this same unstable attribute // to import the prelude implicitly when building crates that depend on std. #[prelude_import] @@ -483,9 +487,6 @@ mod macros; #[macro_use] pub mod rt; -// The Rust prelude -pub mod prelude; - #[stable(feature = "rust1", since = "1.0.0")] pub use core::any; #[stable(feature = "core_array", since = "1.35.0")] diff --git a/tests/ui/extern-flag/empty-extern-arg.rs b/tests/ui/extern-flag/empty-extern-arg.rs index 2dee721ed03c0..10cc3be71135e 100644 --- a/tests/ui/extern-flag/empty-extern-arg.rs +++ b/tests/ui/extern-flag/empty-extern-arg.rs @@ -1,4 +1,5 @@ //~ ERROR extern location for std does not exist +//~^ ERROR cannot resolve a prelude import //@ compile-flags: --extern std= //@ needs-unwind since it affects the error output //@ ignore-emscripten missing eh_catch_typeinfo lang item diff --git a/tests/ui/extern-flag/empty-extern-arg.stderr b/tests/ui/extern-flag/empty-extern-arg.stderr index 79efcc5d8b041..3e0a0d6cd5f86 100644 --- a/tests/ui/extern-flag/empty-extern-arg.stderr +++ b/tests/ui/extern-flag/empty-extern-arg.stderr @@ -1,5 +1,7 @@ error: extern location for std does not exist: +error: cannot resolve a prelude import + error: `#[panic_handler]` function required, but not found error: unwinding panics are not supported without std @@ -7,5 +9,5 @@ error: unwinding panics are not supported without std = help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding = note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/proc-macro/derive-helper-legacy-spurious.rs b/tests/ui/proc-macro/derive-helper-legacy-spurious.rs index 8e902f3041932..0b55e775f38be 100644 --- a/tests/ui/proc-macro/derive-helper-legacy-spurious.rs +++ b/tests/ui/proc-macro/derive-helper-legacy-spurious.rs @@ -6,7 +6,7 @@ extern crate test_macros; #[derive(Empty)] -#[empty_helper] //~ ERROR cannot find attribute `empty_helper` in this scope +#[empty_helper] struct Foo {} fn main() {} diff --git a/tests/ui/proc-macro/derive-helper-legacy-spurious.stderr b/tests/ui/proc-macro/derive-helper-legacy-spurious.stderr index b34713b8ca68e..4cd89904ef3e1 100644 --- a/tests/ui/proc-macro/derive-helper-legacy-spurious.stderr +++ b/tests/ui/proc-macro/derive-helper-legacy-spurious.stderr @@ -4,11 +4,5 @@ error: cannot find attribute `dummy` in this scope LL | #![dummy] | ^^^^^ -error: cannot find attribute `empty_helper` in this scope - --> $DIR/derive-helper-legacy-spurious.rs:9:3 - | -LL | #[empty_helper] - | ^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/resolve/inner-attr-prelude-macro.rs b/tests/ui/resolve/inner-attr-prelude-macro.rs new file mode 100644 index 0000000000000..1047c908ad116 --- /dev/null +++ b/tests/ui/resolve/inner-attr-prelude-macro.rs @@ -0,0 +1,11 @@ +//@ check-pass +//! This test checks that macro names resolved from the libstd prelude +//! still work even if there's a crate-level custom inner attribute. + +#![feature(custom_inner_attributes)] + +#![rustfmt::skip] + +fn main() { + let _ = todo!(); +} diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout index 6b08f3e1cd76d..0327ad5f92bb3 100644 --- a/tests/ui/unpretty/exhaustive.expanded.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -34,9 +34,6 @@ extern crate std; #[prelude_import] use std::prelude::rust_2024::*; -#[prelude_import] -use self::prelude::*; - mod prelude { pub use std::prelude::rust_2024::*; @@ -47,6 +44,9 @@ mod prelude { } } +#[prelude_import] +use self::prelude::*; + mod attributes { //! inner single-line doc comment /*! diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index e9823c9575bc9..68356a33c9e60 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -33,9 +33,6 @@ extern crate std; #[prelude_import] use std::prelude::rust_2024::*; -#[prelude_import] -use self::prelude::*; - mod prelude { use std::prelude::rust_2024::*; @@ -48,6 +45,9 @@ mod prelude { } } +#[prelude_import] +use self::prelude::*; + /// inner single-line doc comment /** * inner multi-line doc comment diff --git a/tests/ui/unpretty/exhaustive.rs b/tests/ui/unpretty/exhaustive.rs index 5292ddad4f6b2..b19d4f9fe2c0c 100644 --- a/tests/ui/unpretty/exhaustive.rs +++ b/tests/ui/unpretty/exhaustive.rs @@ -29,9 +29,6 @@ #![feature(yeet_expr)] #![allow(incomplete_features)] -#[prelude_import] -use self::prelude::*; - mod prelude { pub use std::prelude::rust_2024::*; @@ -42,6 +39,9 @@ mod prelude { } } +#[prelude_import] +use self::prelude::*; + mod attributes { //! inner single-line doc comment /*! From f5bc29568c39b6791f6d639d9a5ce065f7d4d889 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 14 Aug 2025 12:19:02 +0800 Subject: [PATCH 188/252] Add test suggest-self-in-bare-function Signed-off-by: xizheyin --- .../parser/suggest-self-in-bare-function.rs | 25 ++++++++ .../suggest-self-in-bare-function.stderr | 62 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 tests/ui/parser/suggest-self-in-bare-function.rs create mode 100644 tests/ui/parser/suggest-self-in-bare-function.stderr diff --git a/tests/ui/parser/suggest-self-in-bare-function.rs b/tests/ui/parser/suggest-self-in-bare-function.rs new file mode 100644 index 0000000000000..e7f2a12bcd085 --- /dev/null +++ b/tests/ui/parser/suggest-self-in-bare-function.rs @@ -0,0 +1,25 @@ +// We should not suggest `self` in bare functions. +// And a note for RFC 1685 should not be shown. +// See #144968 + +//@ edition:2018 + +fn is_even(value) -> bool { //~ ERROR expected one of `:`, `@`, or `|`, found `)` + value % 2 == 0 +} + +struct S; + +impl S { + fn is_even(value) -> bool { //~ ERROR expected one of `:`, `@`, or `|`, found `)` + value % 2 == 0 + } +} + +trait T { + fn is_even(value) -> bool { //~ ERROR expected one of `:`, `@`, or `|`, found `)` + value % 2 == 0 + } +} + +fn main() {} diff --git a/tests/ui/parser/suggest-self-in-bare-function.stderr b/tests/ui/parser/suggest-self-in-bare-function.stderr new file mode 100644 index 0000000000000..ff2bfc48eee00 --- /dev/null +++ b/tests/ui/parser/suggest-self-in-bare-function.stderr @@ -0,0 +1,62 @@ +error: expected one of `:`, `@`, or `|`, found `)` + --> $DIR/suggest-self-in-bare-function.rs:7:17 + | +LL | fn is_even(value) -> bool { + | ^ expected one of `:`, `@`, or `|` + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name + | +LL | fn is_even(self: value) -> bool { + | +++++ +help: if this is a parameter name, give it a type + | +LL | fn is_even(value: TypeName) -> bool { + | ++++++++++ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn is_even(_: value) -> bool { + | ++ + +error: expected one of `:`, `@`, or `|`, found `)` + --> $DIR/suggest-self-in-bare-function.rs:14:21 + | +LL | fn is_even(value) -> bool { + | ^ expected one of `:`, `@`, or `|` + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name + | +LL | fn is_even(self: value) -> bool { + | +++++ +help: if this is a parameter name, give it a type + | +LL | fn is_even(value: TypeName) -> bool { + | ++++++++++ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn is_even(_: value) -> bool { + | ++ + +error: expected one of `:`, `@`, or `|`, found `)` + --> $DIR/suggest-self-in-bare-function.rs:20:21 + | +LL | fn is_even(value) -> bool { + | ^ expected one of `:`, `@`, or `|` + | + = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) +help: if this is a `self` type, give it a parameter name + | +LL | fn is_even(self: value) -> bool { + | +++++ +help: if this is a parameter name, give it a type + | +LL | fn is_even(value: TypeName) -> bool { + | ++++++++++ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn is_even(_: value) -> bool { + | ++ + +error: aborting due to 3 previous errors + From 3ce555f6313e78d3eed80fd22e22ef49f5bd3611 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 14 Aug 2025 21:30:52 +0800 Subject: [PATCH 189/252] Add FnContext in parser for diagnostic Signed-off-by: xizheyin --- compiler/rustc_parse/src/parser/attr.rs | 3 +- .../rustc_parse/src/parser/diagnostics.rs | 23 +++++-- compiler/rustc_parse/src/parser/item.rs | 68 +++++++++++++------ compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_parse/src/parser/path.rs | 12 +++- compiler/rustc_parse/src/parser/stmt.rs | 6 +- compiler/rustc_parse/src/parser/ty.rs | 14 +++- tests/ui/parser/inverted-parameters.rs | 1 - tests/ui/parser/inverted-parameters.stderr | 7 +- tests/ui/parser/lifetime-in-pattern.stderr | 5 -- tests/ui/parser/omitted-arg-in-item-fn.stderr | 5 -- tests/ui/parser/pat-lt-bracket-2.stderr | 5 -- .../suggest-self-in-bare-function.stderr | 6 -- tests/ui/span/issue-34264.stderr | 11 --- .../suggestions/issue-64252-self-type.stderr | 6 -- tests/ui/type/issue-102598.stderr | 1 - 16 files changed, 95 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 41d3889c44838..7f6afeba28cba 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -11,6 +11,7 @@ use tracing::debug; use super::{ AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle, Trailing, UsePreAttrPos, }; +use crate::parser::FnContext; use crate::{errors, exp, fluent_generated as fluent}; // Public for rustfmt usage @@ -200,7 +201,7 @@ impl<'a> Parser<'a> { AttrWrapper::empty(), true, false, - FnParseMode { req_name: |_| true, req_body: true }, + FnParseMode { req_name: |_| true, context: FnContext::Free, req_body: true }, ForceCollect::No, ) { Ok(Some(item)) => { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a32cd33a26089..220e4ac18fc3e 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -44,6 +44,7 @@ use crate::errors::{ UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, }; +use crate::parser::FnContext; use crate::parser::attr::InnerAttrPolicy; use crate::{exp, fluent_generated as fluent}; @@ -2246,6 +2247,7 @@ impl<'a> Parser<'a> { pat: Box, require_name: bool, first_param: bool, + fn_parse_mode: &crate::parser::item::FnParseMode, ) -> Option { // If we find a pattern followed by an identifier, it could be an (incorrect) // C-style parameter declaration. @@ -2268,7 +2270,14 @@ impl<'a> Parser<'a> { || self.token == token::Lt || self.token == token::CloseParen) { - let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)"; + let maybe_emit_anon_params_note = |this: &mut Self, err: &mut Diag<'_>| { + let ed = this.token.span.with_neighbor(this.prev_token.span).edition(); + if matches!(fn_parse_mode.context, crate::parser::item::FnContext::Trait) + && (fn_parse_mode.req_name)(ed) + { + err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); + } + }; let (ident, self_sugg, param_sugg, type_sugg, self_span, param_span, type_span) = match pat.kind { @@ -2305,7 +2314,7 @@ impl<'a> Parser<'a> { "_: ".to_string(), Applicability::MachineApplicable, ); - err.note(rfc_note); + maybe_emit_anon_params_note(self, err); } return None; @@ -2313,7 +2322,13 @@ impl<'a> Parser<'a> { }; // `fn foo(a, b) {}`, `fn foo(a, b) {}` or `fn foo(usize, usize) {}` - if first_param { + if first_param + // Only when the fn is a method, we emit this suggestion. + && matches!( + fn_parse_mode.context, + FnContext::Trait | FnContext::Impl + ) + { err.span_suggestion_verbose( self_span, "if this is a `self` type, give it a parameter name", @@ -2337,7 +2352,7 @@ impl<'a> Parser<'a> { type_sugg, Applicability::MachineApplicable, ); - err.note(rfc_note); + maybe_emit_anon_params_note(self, err); // Don't attempt to recover by using the `X` in `X` as the parameter name. return if self.token == token::Lt { None } else { Some(ident) }; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 607adaf08294b..ca89eb1e2cfd4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -116,7 +116,8 @@ impl<'a> Parser<'a> { impl<'a> Parser<'a> { pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option>> { - let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true }; + let fn_parse_mode = + FnParseMode { req_name: |_| true, context: FnContext::Free, req_body: true }; self.parse_item_(fn_parse_mode, force_collect).map(|i| i.map(Box::new)) } @@ -975,7 +976,8 @@ impl<'a> Parser<'a> { &mut self, force_collect: ForceCollect, ) -> PResult<'a, Option>>> { - let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true }; + let fn_parse_mode = + FnParseMode { req_name: |_| true, context: FnContext::Impl, req_body: true }; self.parse_assoc_item(fn_parse_mode, force_collect) } @@ -983,8 +985,11 @@ impl<'a> Parser<'a> { &mut self, force_collect: ForceCollect, ) -> PResult<'a, Option>>> { - let fn_parse_mode = - FnParseMode { req_name: |edition| edition >= Edition::Edition2018, req_body: false }; + let fn_parse_mode = FnParseMode { + req_name: |edition| edition >= Edition::Edition2018, + context: FnContext::Trait, + req_body: false, + }; self.parse_assoc_item(fn_parse_mode, force_collect) } @@ -1261,7 +1266,8 @@ impl<'a> Parser<'a> { &mut self, force_collect: ForceCollect, ) -> PResult<'a, Option>>> { - let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: false }; + let fn_parse_mode = + FnParseMode { req_name: |_| true, context: FnContext::Free, req_body: false }; Ok(self.parse_item_(fn_parse_mode, force_collect)?.map( |Item { attrs, id, span, vis, kind, tokens }| { let kind = match ForeignItemKind::try_from(kind) { @@ -2135,7 +2141,8 @@ impl<'a> Parser<'a> { let inherited_vis = Visibility { span: DUMMY_SP, kind: VisibilityKind::Inherited, tokens: None }; // We use `parse_fn` to get a span for the function - let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true }; + let fn_parse_mode = + FnParseMode { req_name: |_| true, context: FnContext::Free, req_body: true }; match self.parse_fn( &mut AttrVec::new(), fn_parse_mode, @@ -2403,6 +2410,9 @@ pub(crate) struct FnParseMode { /// * The span is from Edition 2015. In particular, you can get a /// 2015 span inside a 2021 crate using macros. pub(super) req_name: ReqName, + /// The context in which this function is parsed, used for diagnostics. + /// This indicates the fn is a free function or method and so on. + pub(super) context: FnContext, /// If this flag is set to `true`, then plain, semicolon-terminated function /// prototypes are not allowed here. /// @@ -2424,6 +2434,18 @@ pub(crate) struct FnParseMode { pub(super) req_body: bool, } +/// The context in which a function is parsed. +/// FIXME(estebank, xizheyin): Use more variants. +#[derive(Clone, Copy, PartialEq, Eq)] +pub(crate) enum FnContext { + /// Free context. + Free, + /// A Trait context. + Trait, + /// An Impl block. + Impl, +} + /// Parsing of functions and methods. impl<'a> Parser<'a> { /// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`. @@ -2439,11 +2461,8 @@ impl<'a> Parser<'a> { let header = self.parse_fn_front_matter(vis, case, FrontMatterParsingMode::Function)?; // `const ... fn` let ident = self.parse_ident()?; // `foo` let mut generics = self.parse_generics()?; // `<'a, T, ...>` - let decl = match self.parse_fn_decl( - fn_parse_mode.req_name, - AllowPlus::Yes, - RecoverReturnSign::Yes, - ) { + let decl = match self.parse_fn_decl(&fn_parse_mode, AllowPlus::Yes, RecoverReturnSign::Yes) + { Ok(decl) => decl, Err(old_err) => { // If we see `for Ty ...` then user probably meant `impl` item. @@ -2961,18 +2980,21 @@ impl<'a> Parser<'a> { /// Parses the parameter list and result type of a function declaration. pub(super) fn parse_fn_decl( &mut self, - req_name: ReqName, + fn_parse_mode: &FnParseMode, ret_allow_plus: AllowPlus, recover_return_sign: RecoverReturnSign, ) -> PResult<'a, Box> { Ok(Box::new(FnDecl { - inputs: self.parse_fn_params(req_name)?, + inputs: self.parse_fn_params(fn_parse_mode)?, output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes, recover_return_sign)?, })) } /// Parses the parameter list of a function, including the `(` and `)` delimiters. - pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, ThinVec> { + pub(super) fn parse_fn_params( + &mut self, + fn_parse_mode: &FnParseMode, + ) -> PResult<'a, ThinVec> { let mut first_param = true; // Parse the arguments, starting out with `self` being allowed... if self.token != TokenKind::OpenParen @@ -2988,7 +3010,7 @@ impl<'a> Parser<'a> { let (mut params, _) = self.parse_paren_comma_seq(|p| { p.recover_vcs_conflict_marker(); let snapshot = p.create_snapshot_for_diagnostic(); - let param = p.parse_param_general(req_name, first_param, true).or_else(|e| { + let param = p.parse_param_general(fn_parse_mode, first_param, true).or_else(|e| { let guar = e.emit(); // When parsing a param failed, we should check to make the span of the param // not contain '(' before it. @@ -3019,7 +3041,7 @@ impl<'a> Parser<'a> { /// - `recover_arg_parse` is used to recover from a failed argument parse. pub(super) fn parse_param_general( &mut self, - req_name: ReqName, + fn_parse_mode: &FnParseMode, first_param: bool, recover_arg_parse: bool, ) -> PResult<'a, Param> { @@ -3035,16 +3057,22 @@ impl<'a> Parser<'a> { let is_name_required = match this.token.kind { token::DotDotDot => false, - _ => req_name(this.token.span.with_neighbor(this.prev_token.span).edition()), + _ => (fn_parse_mode.req_name)( + this.token.span.with_neighbor(this.prev_token.span).edition(), + ), }; let (pat, ty) = if is_name_required || this.is_named_param() { debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); let (pat, colon) = this.parse_fn_param_pat_colon()?; if !colon { let mut err = this.unexpected().unwrap_err(); - return if let Some(ident) = - this.parameter_without_type(&mut err, pat, is_name_required, first_param) - { + return if let Some(ident) = this.parameter_without_type( + &mut err, + pat, + is_name_required, + first_param, + fn_parse_mode, + ) { let guar = err.emit(); Ok((dummy_arg(ident, guar), Trailing::No, UsePreAttrPos::No)) } else { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 0a8a0203013bf..41ed1f95a010f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -22,7 +22,7 @@ use std::{fmt, mem, slice}; use attr_wrapper::{AttrWrapper, UsePreAttrPos}; pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use expr::ForbiddenLetReason; -pub(crate) use item::FnParseMode; +pub(crate) use item::{FnContext, FnParseMode}; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::token::{ diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index a6ec3ea4245af..37fc723cd89fd 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -20,7 +20,9 @@ use crate::errors::{ PathFoundAttributeInParams, PathFoundCVariadicParams, PathSingleColon, PathTripleColon, }; use crate::exp; -use crate::parser::{CommaRecoveryMode, ExprKind, RecoverColon, RecoverComma}; +use crate::parser::{ + CommaRecoveryMode, ExprKind, FnContext, FnParseMode, RecoverColon, RecoverComma, +}; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] @@ -399,7 +401,13 @@ impl<'a> Parser<'a> { let dcx = self.dcx(); let parse_params_result = self.parse_paren_comma_seq(|p| { - let param = p.parse_param_general(|_| false, false, false); + // Inside parenthesized type arguments, we want types only, not names. + let mode = FnParseMode { + context: FnContext::Free, + req_name: |_| false, + req_body: false, + }; + let param = p.parse_param_general(&mode, false, false); param.map(move |param| { if !matches!(param.pat.kind, PatKind::Missing) { dcx.emit_err(FnPathFoundNamedParams { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 7aacb674253ef..b4943ff7de64f 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -19,8 +19,8 @@ use super::diagnostics::AttemptLocalParseRecovery; use super::pat::{PatternLocation, RecoverComma}; use super::path::PathStyle; use super::{ - AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode, - Trailing, UsePreAttrPos, + AttrWrapper, BlockMode, FnContext, FnParseMode, ForceCollect, Parser, Restrictions, + SemiColonMode, Trailing, UsePreAttrPos, }; use crate::errors::{self, MalformedLoopLabel}; use crate::exp; @@ -153,7 +153,7 @@ impl<'a> Parser<'a> { attrs.clone(), // FIXME: unwanted clone of attrs false, true, - FnParseMode { req_name: |_| true, req_body: true }, + FnParseMode { req_name: |_| true, context: FnContext::Free, req_body: true }, force_collect, )? { self.mk_stmt(lo.to(item.span), StmtKind::Item(Box::new(item))) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 0d479731e73e3..290f0a440aff0 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -19,6 +19,7 @@ use crate::errors::{ NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::parser::item::FrontMatterParsingMode; +use crate::parser::{FnContext, FnParseMode}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; /// Signals whether parsing a type should allow `+`. @@ -769,7 +770,12 @@ impl<'a> Parser<'a> { if self.may_recover() && self.token == TokenKind::Lt { self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?; } - let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?; + let mode = crate::parser::item::FnParseMode { + req_name: |_| false, + context: FnContext::Free, + req_body: false, + }; + let decl = self.parse_fn_decl(&mode, AllowPlus::No, recover_return_sign)?; let decl_span = span_start.to(self.prev_token.span); Ok(TyKind::FnPtr(Box::new(FnPtrTy { @@ -1314,7 +1320,8 @@ impl<'a> Parser<'a> { self.bump(); let args_lo = self.token.span; let snapshot = self.create_snapshot_for_diagnostic(); - match self.parse_fn_decl(|_| false, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) { + let mode = FnParseMode { req_name: |_| false, context: FnContext::Free, req_body: false }; + match self.parse_fn_decl(&mode, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) { Ok(decl) => { self.dcx().emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span }); Some(ast::Path { @@ -1400,8 +1407,9 @@ impl<'a> Parser<'a> { // Parse `(T, U) -> R`. let inputs_lo = self.token.span; + let mode = FnParseMode { req_name: |_| false, context: FnContext::Free, req_body: false }; let inputs: ThinVec<_> = - self.parse_fn_params(|_| false)?.into_iter().map(|input| input.ty).collect(); + self.parse_fn_params(&mode)?.into_iter().map(|input| input.ty).collect(); let inputs_span = inputs_lo.to(self.prev_token.span); let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?; let args = ast::ParenthesizedArgs { diff --git a/tests/ui/parser/inverted-parameters.rs b/tests/ui/parser/inverted-parameters.rs index bc2f53f0be1bb..5b2827b6fee01 100644 --- a/tests/ui/parser/inverted-parameters.rs +++ b/tests/ui/parser/inverted-parameters.rs @@ -23,7 +23,6 @@ fn pattern((i32, i32) (a, b)) {} fn fizz(i32) {} //~^ ERROR expected one of `:`, `@` //~| HELP if this is a parameter name, give it a type -//~| HELP if this is a `self` type, give it a parameter name //~| HELP if this is a type, explicitly ignore the parameter name fn missing_colon(quux S) {} diff --git a/tests/ui/parser/inverted-parameters.stderr b/tests/ui/parser/inverted-parameters.stderr index 7b969032d0f9c..93b95a756087d 100644 --- a/tests/ui/parser/inverted-parameters.stderr +++ b/tests/ui/parser/inverted-parameters.stderr @@ -34,11 +34,6 @@ error: expected one of `:`, `@`, or `|`, found `)` LL | fn fizz(i32) {} | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | fn fizz(self: i32) {} - | +++++ help: if this is a parameter name, give it a type | LL | fn fizz(i32: TypeName) {} @@ -49,7 +44,7 @@ LL | fn fizz(_: i32) {} | ++ error: expected one of `:`, `@`, or `|`, found `S` - --> $DIR/inverted-parameters.rs:29:23 + --> $DIR/inverted-parameters.rs:28:23 | LL | fn missing_colon(quux S) {} | -----^ diff --git a/tests/ui/parser/lifetime-in-pattern.stderr b/tests/ui/parser/lifetime-in-pattern.stderr index ffda28b202bda..0d01120a057b9 100644 --- a/tests/ui/parser/lifetime-in-pattern.stderr +++ b/tests/ui/parser/lifetime-in-pattern.stderr @@ -16,11 +16,6 @@ error: expected one of `:`, `@`, or `|`, found `)` LL | fn test(&'a str) { | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | fn test(self: &'a str) { - | +++++ help: if this is a parameter name, give it a type | LL - fn test(&'a str) { diff --git a/tests/ui/parser/omitted-arg-in-item-fn.stderr b/tests/ui/parser/omitted-arg-in-item-fn.stderr index 6f2a9f64c94bb..d6bc5d9c68fd8 100644 --- a/tests/ui/parser/omitted-arg-in-item-fn.stderr +++ b/tests/ui/parser/omitted-arg-in-item-fn.stderr @@ -4,11 +4,6 @@ error: expected one of `:`, `@`, or `|`, found `)` LL | fn foo(x) { | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | fn foo(self: x) { - | +++++ help: if this is a parameter name, give it a type | LL | fn foo(x: TypeName) { diff --git a/tests/ui/parser/pat-lt-bracket-2.stderr b/tests/ui/parser/pat-lt-bracket-2.stderr index 5fe97b2ef4c79..9e056bd63ec52 100644 --- a/tests/ui/parser/pat-lt-bracket-2.stderr +++ b/tests/ui/parser/pat-lt-bracket-2.stderr @@ -4,11 +4,6 @@ error: expected one of `:`, `@`, or `|`, found `<` LL | fn a(B<) {} | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | fn a(self: B<) {} - | +++++ help: if this is a type, explicitly ignore the parameter name | LL | fn a(_: B<) {} diff --git a/tests/ui/parser/suggest-self-in-bare-function.stderr b/tests/ui/parser/suggest-self-in-bare-function.stderr index ff2bfc48eee00..40cbe5575fd6b 100644 --- a/tests/ui/parser/suggest-self-in-bare-function.stderr +++ b/tests/ui/parser/suggest-self-in-bare-function.stderr @@ -4,11 +4,6 @@ error: expected one of `:`, `@`, or `|`, found `)` LL | fn is_even(value) -> bool { | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | fn is_even(self: value) -> bool { - | +++++ help: if this is a parameter name, give it a type | LL | fn is_even(value: TypeName) -> bool { @@ -24,7 +19,6 @@ error: expected one of `:`, `@`, or `|`, found `)` LL | fn is_even(value) -> bool { | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a `self` type, give it a parameter name | LL | fn is_even(self: value) -> bool { diff --git a/tests/ui/span/issue-34264.stderr b/tests/ui/span/issue-34264.stderr index c8046a1bddf85..cc41d3048df89 100644 --- a/tests/ui/span/issue-34264.stderr +++ b/tests/ui/span/issue-34264.stderr @@ -4,11 +4,6 @@ error: expected one of `:`, `@`, or `|`, found `<` LL | fn foo(Option, String) {} | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | fn foo(self: Option, String) {} - | +++++ help: if this is a type, explicitly ignore the parameter name | LL | fn foo(_: Option, String) {} @@ -20,7 +15,6 @@ error: expected one of `:`, `@`, or `|`, found `)` LL | fn foo(Option, String) {} | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a parameter name, give it a type | LL | fn foo(Option, String: TypeName) {} @@ -36,11 +30,6 @@ error: expected one of `:`, `@`, or `|`, found `,` LL | fn bar(x, y: usize) {} | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | fn bar(self: x, y: usize) {} - | +++++ help: if this is a parameter name, give it a type | LL | fn bar(x: TypeName, y: usize) {} diff --git a/tests/ui/suggestions/issue-64252-self-type.stderr b/tests/ui/suggestions/issue-64252-self-type.stderr index c3418dab0e8af..320d09b589b64 100644 --- a/tests/ui/suggestions/issue-64252-self-type.stderr +++ b/tests/ui/suggestions/issue-64252-self-type.stderr @@ -4,11 +4,6 @@ error: expected one of `:`, `@`, or `|`, found `<` LL | pub fn foo(Box) { } | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this is a `self` type, give it a parameter name - | -LL | pub fn foo(self: Box) { } - | +++++ help: if this is a type, explicitly ignore the parameter name | LL | pub fn foo(_: Box) { } @@ -20,7 +15,6 @@ error: expected one of `:`, `@`, or `|`, found `<` LL | fn bar(Box) { } | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a `self` type, give it a parameter name | LL | fn bar(self: Box) { } diff --git a/tests/ui/type/issue-102598.stderr b/tests/ui/type/issue-102598.stderr index a232395cedb1d..5623a7aa80d47 100644 --- a/tests/ui/type/issue-102598.stderr +++ b/tests/ui/type/issue-102598.stderr @@ -15,7 +15,6 @@ error: expected one of `:`, `@`, or `|`, found `)` LL | fn foo<'a>(_: impl 'a Sized) {} | ^ expected one of `:`, `@`, or `|` | - = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a parameter name, give it a type | LL | fn foo<'a>(_: impl 'a Sized: TypeName) {} From aa3691ea0857e0a26a372be3a84f239e775c24aa Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 14 Aug 2025 15:24:21 +0200 Subject: [PATCH 190/252] add regression test --- .../many-where-clauses-with-aliases-hang.rs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/ui/traits/next-solver/cycles/many-where-clauses-with-aliases-hang.rs diff --git a/tests/ui/traits/next-solver/cycles/many-where-clauses-with-aliases-hang.rs b/tests/ui/traits/next-solver/cycles/many-where-clauses-with-aliases-hang.rs new file mode 100644 index 0000000000000..36fa8b85f7ab8 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/many-where-clauses-with-aliases-hang.rs @@ -0,0 +1,43 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// A regression test for trait-system-refactor-initiative#210. +// +// Trying to prove `T: Trait<...>` ends up trying to apply all the where-clauses, +// most of which require normalizing some `Alias`. This then requires us +// to prove `T: Trait<...>` again. +// +// This results in a lot of solver cycles whose initial result differs from their +// final result. Reevaluating all of them results in exponential blowup and hangs. +// +// With #144991 we now don't reevaluate cycle heads if their provisional value +// didn't actually impact the final result, avoiding these reruns and allowing us +// to compile this in less than a second. + +struct A; +struct B; +struct C; + +type Alias = >::Assoc; +trait Trait { + type Assoc; +} + +fn foo() +where + T: Trait + Trait + Trait, + T: Trait>, + T: Trait>, + T: Trait>, + T: Trait>>, + T: Trait>>, + T: Trait>>, + T: Trait>>>, + T: Trait>>>, + T: Trait>>>, + T: Trait>>>>, + T: Trait>>>>, + T: Trait>>>>, +{ +} +fn main() {} From 8afe306c381416d151f955981e7b4e47867e9d97 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 14 Aug 2025 16:02:47 +0200 Subject: [PATCH 191/252] update comment --- .../rustc_next_trait_solver/src/solve/trait_goals.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 03f7bc1f49e9c..04ede365a2149 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1384,6 +1384,18 @@ where // If there's an always applicable candidate, the result of all // other candidates does not matter. This means we can ignore // them when checking whether we've reached a fixpoint. + // + // We always prefer the first always applicable candidate, even if a + // later candidate is also always applicable and would result in fewer + // reruns. We could slightly improve this by e.g. searching for another + // always applicable candidate which doesn't depend on any cycle heads. + // + // NOTE: This is optimization is observable in case there is an always + // applicable global candidate and another non-global candidate which only + // applies because of a provisional result. I can't even think of a test + // case where this would occur and even then, this would not be unsound. + // Supporting this makes the code more involved, so I am just going to + // ignore this for now. MergeCandidateInfo::AlwaysApplicable(i) => { for (j, c) in where_bounds.into_iter().enumerate() { if i != j { From f382d547d9a33660e7805455c556625c464f4187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 22:11:03 +0200 Subject: [PATCH 192/252] Remove `ONLY_HOSTS` value overrides that just set the default value and had no comment --- src/bootstrap/src/core/build_steps/run.rs | 1 - src/bootstrap/src/core/build_steps/synthetic_targets.rs | 1 - src/bootstrap/src/core/build_steps/test.rs | 3 --- 3 files changed, 5 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 962dd372849d2..7475a777dad12 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -107,7 +107,6 @@ pub struct Miri { impl Step for Miri { type Output = (); - const ONLY_HOSTS: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/miri") diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index 477ff9553a480..21733c5d9e3f7 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -21,7 +21,6 @@ pub(crate) struct MirOptPanicAbortSyntheticTarget { impl Step for MirOptPanicAbortSyntheticTarget { type Output = TargetSelection; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.never() diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index f1be0af31837b..24530a1bf9c9f 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -561,7 +561,6 @@ impl Miri { impl Step for Miri { type Output = (); - const ONLY_HOSTS: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/miri") @@ -681,7 +680,6 @@ pub struct CargoMiri { impl Step for CargoMiri { type Output = (); - const ONLY_HOSTS: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/miri/cargo-miri") @@ -1599,7 +1597,6 @@ pub struct MirOpt { impl Step for MirOpt { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.suite_path("tests/mir-opt") From e08c75533c41d9e209258acac98daf0fba5b99eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 22:14:18 +0200 Subject: [PATCH 193/252] Rename and document `ONLY_HOSTS` in bootstrap --- src/bootstrap/src/core/build_steps/check.rs | 6 +- src/bootstrap/src/core/build_steps/clippy.rs | 2 +- src/bootstrap/src/core/build_steps/compile.rs | 8 +- src/bootstrap/src/core/build_steps/dist.rs | 36 ++++----- src/bootstrap/src/core/build_steps/doc.rs | 10 +-- src/bootstrap/src/core/build_steps/gcc.rs | 2 +- src/bootstrap/src/core/build_steps/install.rs | 28 +++---- src/bootstrap/src/core/build_steps/llvm.rs | 6 +- src/bootstrap/src/core/build_steps/run.rs | 20 ++--- src/bootstrap/src/core/build_steps/test.rs | 78 +++++++++---------- src/bootstrap/src/core/build_steps/tool.rs | 20 ++--- src/bootstrap/src/core/build_steps/vendor.rs | 2 +- src/bootstrap/src/core/builder/mod.rs | 15 ++-- 13 files changed, 119 insertions(+), 114 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 6d393446d458e..1e08e8547dc72 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -172,7 +172,7 @@ impl Rustc { impl Step for Rustc { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -324,7 +324,7 @@ pub struct CodegenBackend { impl Step for CodegenBackend { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -410,7 +410,7 @@ macro_rules! tool_check_step { impl Step for $name { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; /// Most of the tool-checks using this macro are run by default. const DEFAULT: bool = true $( && $default )?; diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 23d9a032eb909..3c4aa0886c2a5 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -256,7 +256,7 @@ impl Rustc { impl Step for Rustc { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 2a236de01921e..c04f42ab05576 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -995,7 +995,7 @@ impl Step for Rustc { /// uplifting it from stage Y, causing the other stage to fail when attempting to link with /// stage X which was never actually built. type Output = u32; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1559,7 +1559,7 @@ pub struct GccCodegenBackend { impl Step for GccCodegenBackend { type Output = GccCodegenBackendOutput; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.alias("rustc_codegen_gcc").alias("cg_gcc") @@ -1644,7 +1644,7 @@ pub struct CraneliftCodegenBackend { impl Step for CraneliftCodegenBackend { type Output = BuildStamp; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.alias("rustc_codegen_cranelift").alias("cg_clif") @@ -2008,7 +2008,7 @@ pub struct Assemble { impl Step for Assemble { type Output = Compiler; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("compiler/rustc").path("compiler") diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 7fdfeabe29d9c..64c2cdd2ec795 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -140,7 +140,7 @@ pub struct RustcDocs { impl Step for RustcDocs { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -402,7 +402,7 @@ pub struct Rustc { impl Step for Rustc { type Output = GeneratedTarball; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.alias("rustc") @@ -794,7 +794,7 @@ pub struct RustcDev { impl Step for RustcDev { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.alias("rustc-dev") @@ -1024,7 +1024,7 @@ impl Step for Src { /// The output path of the src installer tarball type Output = GeneratedTarball; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.alias("rust-src") @@ -1085,7 +1085,7 @@ impl Step for PlainSourceTarball { /// Produces the location of the tarball generated type Output = GeneratedTarball; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -1233,7 +1233,7 @@ pub struct Cargo { impl Step for Cargo { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let default = should_build_extended_tool(run.builder, "cargo"); @@ -1287,7 +1287,7 @@ pub struct RustAnalyzer { impl Step for RustAnalyzer { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let default = should_build_extended_tool(run.builder, "rust-analyzer"); @@ -1330,7 +1330,7 @@ pub struct Clippy { impl Step for Clippy { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let default = should_build_extended_tool(run.builder, "clippy"); @@ -1378,7 +1378,7 @@ pub struct Miri { impl Step for Miri { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let default = should_build_extended_tool(run.builder, "miri"); @@ -1428,7 +1428,7 @@ pub struct CraneliftCodegenBackend { impl Step for CraneliftCodegenBackend { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { // We only want to build the cranelift backend in `x dist` if the backend was enabled @@ -1519,7 +1519,7 @@ pub struct Rustfmt { impl Step for Rustfmt { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let default = should_build_extended_tool(run.builder, "rustfmt"); @@ -1564,7 +1564,7 @@ pub struct Extended { impl Step for Extended { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -2301,7 +2301,7 @@ pub struct LlvmTools { impl Step for LlvmTools { type Output = Option; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -2406,7 +2406,7 @@ pub struct LlvmBitcodeLinker { impl Step for LlvmBitcodeLinker { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let default = should_build_extended_tool(run.builder, "llvm-bitcode-linker"); @@ -2458,7 +2458,7 @@ pub struct RustDev { impl Step for RustDev { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.alias("rust-dev") @@ -2561,7 +2561,7 @@ pub struct Bootstrap { impl Step for Bootstrap { type Output = Option; const DEFAULT: bool = false; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.alias("bootstrap") @@ -2601,7 +2601,7 @@ pub struct BuildManifest { impl Step for BuildManifest { type Output = GeneratedTarball; const DEFAULT: bool = false; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.alias("build-manifest") @@ -2633,7 +2633,7 @@ pub struct ReproducibleArtifacts { impl Step for ReproducibleArtifacts { type Output = Option; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.alias("reproducible-artifacts") diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 6f0d5203d1176..f6b27d8312063 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -830,7 +830,7 @@ impl Rustc { impl Step for Rustc { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -975,7 +975,7 @@ macro_rules! tool_doc { impl Step for $tool { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -1139,7 +1139,7 @@ pub struct ErrorIndex { impl Step for ErrorIndex { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -1181,7 +1181,7 @@ pub struct UnstableBookGen { impl Step for UnstableBookGen { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -1248,7 +1248,7 @@ impl RustcBook { impl Step for RustcBook { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 389afaecea336..2b36b0f2e2717 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -47,7 +47,7 @@ impl GccOutput { impl Step for Gcc { type Output = GccOutput; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/gcc").alias("gcc") diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 666f2715224e2..4457258e9cdd0 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -163,7 +163,7 @@ macro_rules! install { $($name:ident, $condition_name: ident = $path_or_alias: literal, $default_cond:expr, - only_hosts: $only_hosts:expr, + IS_HOST: $IS_HOST:expr, $run_item:block $(, $c:ident)*;)+) => { $( #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -183,7 +183,7 @@ macro_rules! install { impl Step for $name { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = $only_hosts; + const IS_HOST: bool = $IS_HOST; $(const $c: bool = true;)* fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -206,11 +206,11 @@ macro_rules! install { } install!((self, builder, _config), - Docs, path = "src/doc", _config.docs, only_hosts: false, { + Docs, path = "src/doc", _config.docs, IS_HOST: false, { let tarball = builder.ensure(dist::Docs { host: self.target }).expect("missing docs"); install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball); }; - Std, path = "library/std", true, only_hosts: false, { + Std, path = "library/std", true, IS_HOST: false, { // `expect` should be safe, only None when host != build, but this // only runs when host == build let tarball = builder.ensure(dist::Std { @@ -219,13 +219,13 @@ install!((self, builder, _config), }).expect("missing std"); install_sh(builder, "std", self.compiler.stage, Some(self.target), &tarball); }; - Cargo, alias = "cargo", Self::should_build(_config), only_hosts: true, { + Cargo, alias = "cargo", Self::should_build(_config), IS_HOST: true, { let tarball = builder .ensure(dist::Cargo { build_compiler: self.compiler, target: self.target }) .expect("missing cargo"); install_sh(builder, "cargo", self.compiler.stage, Some(self.target), &tarball); }; - RustAnalyzer, alias = "rust-analyzer", Self::should_build(_config), only_hosts: true, { + RustAnalyzer, alias = "rust-analyzer", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::RustAnalyzer { build_compiler: self.compiler, target: self.target }) { @@ -236,13 +236,13 @@ install!((self, builder, _config), ); } }; - Clippy, alias = "clippy", Self::should_build(_config), only_hosts: true, { + Clippy, alias = "clippy", Self::should_build(_config), IS_HOST: true, { let tarball = builder .ensure(dist::Clippy { build_compiler: self.compiler, target: self.target }) .expect("missing clippy"); install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball); }; - Miri, alias = "miri", Self::should_build(_config), only_hosts: true, { + Miri, alias = "miri", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::Miri { build_compiler: self.compiler, target: self.target }) { install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball); } else { @@ -252,7 +252,7 @@ install!((self, builder, _config), ); } }; - LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.host_target), only_hosts: true, { + LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.host_target), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) { install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball); } else { @@ -261,7 +261,7 @@ install!((self, builder, _config), ); } }; - Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, { + Rustfmt, alias = "rustfmt", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::Rustfmt { build_compiler: self.compiler, target: self.target @@ -273,13 +273,13 @@ install!((self, builder, _config), ); } }; - Rustc, path = "compiler/rustc", true, only_hosts: true, { + Rustc, path = "compiler/rustc", true, IS_HOST: true, { let tarball = builder.ensure(dist::Rustc { compiler: builder.compiler(builder.top_stage, self.target), }); install_sh(builder, "rustc", self.compiler.stage, Some(self.target), &tarball); }; - RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), only_hosts: true, { + RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::CraneliftCodegenBackend { build_compiler: self.compiler, target: self.target @@ -292,7 +292,7 @@ install!((self, builder, _config), ); } }; - LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), only_hosts: true, { + LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), IS_HOST: true, { if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { build_compiler: self.compiler, target: self.target }) { install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball); } else { @@ -311,7 +311,7 @@ pub struct Src { impl Step for Src { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let config = &run.builder.config; diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 16941a32bb16e..c476d1c1a2d8b 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -255,7 +255,7 @@ pub struct Llvm { impl Step for Llvm { type Output = LlvmResult; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/llvm-project").path("src/llvm-project/llvm") @@ -908,7 +908,7 @@ pub struct Enzyme { impl Step for Enzyme { type Output = PathBuf; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/enzyme/enzyme") @@ -1013,7 +1013,7 @@ pub struct Lld { impl Step for Lld { type Output = PathBuf; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/llvm-project/lld") diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 7475a777dad12..7f1a7d0025742 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -22,7 +22,7 @@ pub struct BuildManifest; impl Step for BuildManifest { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/build-manifest") @@ -61,7 +61,7 @@ pub struct BumpStage0; impl Step for BumpStage0 { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/bump-stage0") @@ -83,7 +83,7 @@ pub struct ReplaceVersionPlaceholder; impl Step for ReplaceVersionPlaceholder { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/replace-version-placeholder") @@ -174,7 +174,7 @@ pub struct CollectLicenseMetadata; impl Step for CollectLicenseMetadata { type Output = PathBuf; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/collect-license-metadata") @@ -205,7 +205,7 @@ pub struct GenerateCopyright; impl Step for GenerateCopyright { type Output = Vec; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/generate-copyright") @@ -269,7 +269,7 @@ pub struct GenerateWindowsSys; impl Step for GenerateWindowsSys { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/generate-windows-sys") @@ -331,7 +331,7 @@ pub struct UnicodeTableGenerator; impl Step for UnicodeTableGenerator { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/unicode-table-generator") @@ -353,7 +353,7 @@ pub struct FeaturesStatusDump; impl Step for FeaturesStatusDump { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/features-status-dump") @@ -415,7 +415,7 @@ impl Step for CoverageDump { type Output = (); const DEFAULT: bool = false; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/coverage-dump") @@ -437,7 +437,7 @@ pub struct Rustfmt; impl Step for Rustfmt { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/rustfmt") diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 24530a1bf9c9f..9bf1f889f761a 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -51,7 +51,7 @@ pub struct CrateBootstrap { impl Step for CrateBootstrap { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -109,7 +109,7 @@ pub struct Linkcheck { impl Step for Linkcheck { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = true; /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler. @@ -189,7 +189,7 @@ pub struct HtmlCheck { impl Step for HtmlCheck { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -236,7 +236,7 @@ pub struct Cargotest { impl Step for Cargotest { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/cargotest") @@ -313,7 +313,7 @@ impl Cargo { impl Step for Cargo { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path(Self::CRATE_PATH) @@ -410,7 +410,7 @@ pub struct RustAnalyzer { impl Step for RustAnalyzer { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -469,7 +469,7 @@ pub struct Rustfmt { impl Step for Rustfmt { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/rustfmt") @@ -809,7 +809,7 @@ pub struct Clippy { impl Step for Clippy { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -909,7 +909,7 @@ pub struct RustdocTheme { impl Step for RustdocTheme { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/rustdoc-themes") @@ -946,7 +946,7 @@ pub struct RustdocJSStd { impl Step for RustdocJSStd { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let default = run.builder.config.nodejs.is_some(); @@ -1006,7 +1006,7 @@ pub struct RustdocJSNotStd { impl Step for RustdocJSNotStd { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let default = run.builder.config.nodejs.is_some(); @@ -1061,7 +1061,7 @@ pub struct RustdocGUI { impl Step for RustdocGUI { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -1154,7 +1154,7 @@ pub struct Tidy; impl Step for Tidy { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; /// Runs the `tidy` tool. /// @@ -1272,7 +1272,7 @@ macro_rules! test { mode: $mode:expr, suite: $suite:expr, default: $default:expr - $( , only_hosts: $only_hosts:expr )? // default: false + $( , IS_HOST: $IS_HOST:expr )? // default: false $( , compare_mode: $compare_mode:expr )? // default: None $( , )? // optional trailing comma } @@ -1287,10 +1287,10 @@ macro_rules! test { impl Step for $name { type Output = (); const DEFAULT: bool = $default; - const ONLY_HOSTS: bool = (const { + const IS_HOST: bool = (const { #[allow(unused_assignments, unused_mut)] let mut value = false; - $( value = $only_hosts; )? + $( value = $IS_HOST; )? value }); @@ -1338,7 +1338,7 @@ pub struct CrateRunMakeSupport { impl Step for CrateRunMakeSupport { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/run-make-support") @@ -1375,7 +1375,7 @@ pub struct CrateBuildHelper { impl Step for CrateBuildHelper { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/build_helper") @@ -1443,7 +1443,7 @@ test!(UiFullDeps { mode: "ui", suite: "ui-fulldeps", default: true, - only_hosts: true, + IS_HOST: true, }); test!(Rustdoc { @@ -1451,14 +1451,14 @@ test!(Rustdoc { mode: "rustdoc", suite: "rustdoc", default: true, - only_hosts: true, + IS_HOST: true, }); test!(RustdocUi { path: "tests/rustdoc-ui", mode: "ui", suite: "rustdoc-ui", default: true, - only_hosts: true, + IS_HOST: true, }); test!(RustdocJson { @@ -1466,7 +1466,7 @@ test!(RustdocJson { mode: "rustdoc-json", suite: "rustdoc-json", default: true, - only_hosts: true, + IS_HOST: true, }); test!(Pretty { @@ -1474,7 +1474,7 @@ test!(Pretty { mode: "pretty", suite: "pretty", default: true, - only_hosts: true, + IS_HOST: true, }); test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true }); @@ -1505,7 +1505,7 @@ impl Step for Coverage { type Output = (); const DEFAULT: bool = true; /// Compiletest will automatically skip the "coverage-run" tests if necessary. - const ONLY_HOSTS: bool = false; + const IS_HOST: bool = false; fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> { // Support various invocation styles, including: @@ -1584,7 +1584,7 @@ test!(CoverageRunRustdoc { mode: "coverage-run", suite: "coverage-run-rustdoc", default: true, - only_hosts: true, + IS_HOST: true, }); // For the mir-opt suite we do not use macros, as we need custom behavior when blessing. @@ -2273,7 +2273,7 @@ struct BookTest { impl Step for BookTest { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.never() @@ -2439,7 +2439,7 @@ macro_rules! test_book { impl Step for $name { type Output = (); const DEFAULT: bool = $default; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path($path) @@ -2499,7 +2499,7 @@ pub struct ErrorIndex { impl Step for ErrorIndex { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { // Also add `error-index` here since that is what appears in the error message @@ -2595,7 +2595,7 @@ pub struct CrateLibrustc { impl Step for CrateLibrustc { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.crate_or_deps("rustc-main").path("compiler") @@ -2880,7 +2880,7 @@ pub struct CrateRustdoc { impl Step for CrateRustdoc { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.paths(&["src/librustdoc", "src/tools/rustdoc"]) @@ -2972,7 +2972,7 @@ pub struct CrateRustdocJsonTypes { impl Step for CrateRustdocJsonTypes { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/rustdoc-json-types") @@ -3161,7 +3161,7 @@ pub struct Bootstrap; impl Step for Bootstrap { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; /// Tests the build system itself. fn run(self, builder: &Builder<'_>) { @@ -3231,7 +3231,7 @@ pub struct TierCheck { impl Step for TierCheck { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/tier-check") @@ -3285,7 +3285,7 @@ pub struct LintDocs { impl Step for LintDocs { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/lint-docs") @@ -3311,7 +3311,7 @@ pub struct RustInstaller; impl Step for RustInstaller { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = true; /// Ensure the version placeholder replacement tool builds @@ -3431,7 +3431,7 @@ pub struct CodegenCranelift { impl Step for CodegenCranelift { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.paths(&["compiler/rustc_codegen_cranelift"]) @@ -3559,7 +3559,7 @@ pub struct CodegenGCC { impl Step for CodegenGCC { type Output = (); const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.paths(&["compiler/rustc_codegen_gcc"]) @@ -3692,7 +3692,7 @@ pub struct TestFloatParse { impl Step for TestFloatParse { type Output = (); - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -3758,7 +3758,7 @@ pub struct CollectLicenseMetadata; impl Step for CollectLicenseMetadata { type Output = PathBuf; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/collect-license-metadata") diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 793e6b629c991..d7afe1ff7db89 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -687,7 +687,7 @@ impl Step for Rustdoc { type Output = PathBuf; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/rustdoc").path("src/librustdoc") @@ -809,7 +809,7 @@ impl Cargo { impl Step for Cargo { type Output = ToolBuildResult; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -885,7 +885,7 @@ impl LldWrapper { impl Step for LldWrapper { type Output = BuiltLldWrapper; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/lld-wrapper") @@ -986,7 +986,7 @@ impl WasmComponentLd { impl Step for WasmComponentLd { type Output = ToolBuildResult; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/wasm-component-ld") @@ -1049,7 +1049,7 @@ impl RustAnalyzer { impl Step for RustAnalyzer { type Output = ToolBuildResult; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -1102,7 +1102,7 @@ impl Step for RustAnalyzerProcMacroSrv { type Output = ToolBuildResult; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -1192,7 +1192,7 @@ impl LlvmBitcodeLinker { impl Step for LlvmBitcodeLinker { type Output = ToolBuildResult; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; @@ -1246,7 +1246,7 @@ pub enum LibcxxVersion { impl Step for LibcxxVersionTool { type Output = LibcxxVersion; const DEFAULT: bool = false; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.never() @@ -1407,7 +1407,7 @@ macro_rules! tool_rustc_extended { impl Step for $name { type Output = ToolBuildResult; const DEFAULT: bool = true; // Overridden by `should_run_tool_build_step` - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { should_run_extended_rustc_tool( @@ -1575,7 +1575,7 @@ impl TestFloatParse { impl Step for TestFloatParse { type Output = ToolBuildResult; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; const DEFAULT: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 0caeb328811aa..7b860ceb94325 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -53,7 +53,7 @@ pub(crate) struct Vendor { impl Step for Vendor { type Output = VendorOutput; const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; + const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.alias("placeholder").default_condition(true) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 54bf1842ab31b..7462d549d0828 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -100,8 +100,13 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { /// by `Step::should_run`. const DEFAULT: bool = false; - /// If true, then this rule should be skipped if --target was specified, but --host was not - const ONLY_HOSTS: bool = false; + /// If this value is true, then the values of `run.target` passed to the `make_run` function of + /// this Step will be determined based on the `--host` flag. + /// If this value is false, then they will be determined based on the `--target` flag. + /// + /// A corollary of the above is that if this is set to true, then the step will be skipped if + /// `--target` was specified, but `--host` was explicitly set to '' (empty string). + const IS_HOST: bool = false; /// Primary function to implement `Step` logic. /// @@ -298,7 +303,7 @@ pub fn crate_description(crates: &[impl AsRef]) -> String { struct StepDescription { default: bool, - only_hosts: bool, + is_host: bool, should_run: fn(ShouldRun<'_>) -> ShouldRun<'_>, make_run: fn(RunConfig<'_>), name: &'static str, @@ -500,7 +505,7 @@ impl StepDescription { fn from(kind: Kind) -> StepDescription { StepDescription { default: S::DEFAULT, - only_hosts: S::ONLY_HOSTS, + is_host: S::IS_HOST, should_run: S::should_run, make_run: S::make_run, name: std::any::type_name::(), @@ -516,7 +521,7 @@ impl StepDescription { } // Determine the targets participating in this rule. - let targets = if self.only_hosts { &builder.hosts } else { &builder.targets }; + let targets = if self.is_host { &builder.hosts } else { &builder.targets }; for target in targets { let run = RunConfig { builder, paths: pathsets.clone(), target: *target }; From 1a226e07e037e8b99383d6267278f7ef18b7594c Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 14 Aug 2025 09:39:47 +0200 Subject: [PATCH 194/252] rustc-dev-guide :3 --- src/doc/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/index.md b/src/doc/index.md index 8ad5b427b552a..892057a8f4db3 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -172,9 +172,9 @@ unsafe Rust. It's also sometimes called "the 'nomicon." [The Unstable Book](unstable-book/index.html) has documentation for unstable features. -### The `rustc` Contribution Guide +### The `rustc` Development Guide -[The `rustc` Guide](https://rustc-dev-guide.rust-lang.org/) +[The `rustc-dev-guide`](https://rustc-dev-guide.rust-lang.org/) documents how the compiler works and how to contribute to it. This is useful if you want to build or modify the Rust compiler from source (e.g. to target something non-standard). From 9dfee2ef35d8176bbcfb601bdf58059513049a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Aug 2025 15:41:54 +0000 Subject: [PATCH 195/252] fix alignment test --- tests/ui/mir/alignment/packed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/mir/alignment/packed.rs b/tests/ui/mir/alignment/packed.rs index cf908365e1a5d..aa79880a21a22 100644 --- a/tests/ui/mir/alignment/packed.rs +++ b/tests/ui/mir/alignment/packed.rs @@ -12,7 +12,7 @@ fn main() { // Test that we can use addr_of! to get the address of a packed member which according to its // type is not aligned, but because it is a projection from a packed type is a valid place. let ptr0 = std::ptr::addr_of!(memory[0].tail); - let ptr1 = std::ptr::addr_of!(memory[0].tail); + let ptr1 = std::ptr::addr_of!(memory[1].tail); // Even if ptr0 happens to be aligned by chance, ptr1 is not. assert!(!ptr0.is_aligned() || !ptr1.is_aligned()); From eba1596ab1bc4c75ad69083014560f12f40aad2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 12 Jul 2025 01:14:13 +0000 Subject: [PATCH 196/252] Use `default_field_values` in `Resolver` --- compiler/rustc_resolve/src/lib.rs | 47 +++++++++++-------------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index cc30939f5e96c..ca9c124fca63c 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -16,6 +16,7 @@ #![feature(assert_matches)] #![feature(box_patterns)] #![feature(decl_macro)] +#![feature(default_field_values)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(rustc_attrs)] @@ -1075,7 +1076,7 @@ pub struct Resolver<'ra, 'tcx> { /// Assert that we are in speculative resolution mode. assert_speculative: bool, - prelude: Option>, + prelude: Option> = None, extern_prelude: FxIndexMap>, /// N.B., this is used only for better diagnostics, not name resolution itself. @@ -1087,10 +1088,10 @@ pub struct Resolver<'ra, 'tcx> { field_visibility_spans: FxHashMap>, /// All imports known to succeed or fail. - determined_imports: Vec>, + determined_imports: Vec> = Vec::new(), /// All non-determined imports. - indeterminate_imports: Vec>, + indeterminate_imports: Vec> = Vec::new(), // Spans for local variables found during pattern resolution. // Used for suggestions during error reporting. @@ -1141,19 +1142,19 @@ pub struct Resolver<'ra, 'tcx> { /// Maps glob imports to the names of items actually imported. glob_map: FxIndexMap>, - glob_error: Option, - visibilities_for_hashing: Vec<(LocalDefId, Visibility)>, + glob_error: Option = None, + visibilities_for_hashing: Vec<(LocalDefId, Visibility)> = Vec::new(), used_imports: FxHashSet, maybe_unused_trait_imports: FxIndexSet, /// Privacy errors are delayed until the end in order to deduplicate them. - privacy_errors: Vec>, + privacy_errors: Vec> = Vec::new(), /// Ambiguity errors are delayed for deduplication. - ambiguity_errors: Vec>, + ambiguity_errors: Vec> = Vec::new(), /// `use` injections are delayed for better placement and deduplication. - use_injections: Vec>, + use_injections: Vec> = Vec::new(), /// Crate-local macro expanded `macro_export` referred to by a module-relative path. - macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>, + macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(), arenas: &'ra ResolverArenas<'ra>, dummy_binding: NameBinding<'ra>, @@ -1205,9 +1206,9 @@ pub struct Resolver<'ra, 'tcx> { /// Avoid duplicated errors for "name already defined". name_already_seen: FxHashMap, - potentially_unused_imports: Vec>, + potentially_unused_imports: Vec> = Vec::new(), - potentially_unnecessary_qualifications: Vec>, + potentially_unnecessary_qualifications: Vec> = Vec::new(), /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. @@ -1216,7 +1217,7 @@ pub struct Resolver<'ra, 'tcx> { lint_buffer: LintBuffer, - next_node_id: NodeId, + next_node_id: NodeId = CRATE_NODE_ID, node_id_to_def_id: NodeMap>, @@ -1234,17 +1235,17 @@ pub struct Resolver<'ra, 'tcx> { item_generics_num_lifetimes: FxHashMap, delegation_fn_sigs: LocalDefIdMap, - main_def: Option, + main_def: Option = None, trait_impls: FxIndexMap>, /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. - proc_macros: Vec, + proc_macros: Vec = Vec::new(), confused_type_with_std_module: FxIndexMap, /// Whether lifetime elision was successful. lifetime_elision_allowed: FxHashSet, /// Names of items that were stripped out via cfg with their corresponding cfg meta item. - stripped_cfg_items: Vec>, + stripped_cfg_items: Vec> = Vec::new(), effective_visibilities: EffectiveVisibilities, doc_link_resolutions: FxIndexMap, @@ -1558,9 +1559,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { field_defaults: Default::default(), field_visibility_spans: FxHashMap::default(), - determined_imports: Vec::new(), - indeterminate_imports: Vec::new(), - pat_span_map: Default::default(), partial_res_map: Default::default(), import_res_map: Default::default(), @@ -1579,16 +1577,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ast_transform_scopes: FxHashMap::default(), glob_map: Default::default(), - glob_error: None, - visibilities_for_hashing: Default::default(), used_imports: FxHashSet::default(), maybe_unused_trait_imports: Default::default(), - privacy_errors: Vec::new(), - ambiguity_errors: Vec::new(), - use_injections: Vec::new(), - macro_expanded_macro_export_errors: BTreeSet::new(), - arenas, dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), builtin_types_bindings: PrimTy::ALL @@ -1632,8 +1623,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { derive_data: Default::default(), local_macro_def_scopes: FxHashMap::default(), name_already_seen: FxHashMap::default(), - potentially_unused_imports: Vec::new(), - potentially_unnecessary_qualifications: Default::default(), struct_constructors: Default::default(), unused_macros: Default::default(), unused_macro_rules: Default::default(), @@ -1643,16 +1632,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { builtin_attrs: Default::default(), containers_deriving_copy: Default::default(), lint_buffer: LintBuffer::default(), - next_node_id: CRATE_NODE_ID, node_id_to_def_id, disambiguator: DisambiguatorState::new(), placeholder_field_indices: Default::default(), invocation_parents, legacy_const_generic_args: Default::default(), item_generics_num_lifetimes: Default::default(), - main_def: Default::default(), trait_impls: Default::default(), - proc_macros: Default::default(), confused_type_with_std_module: Default::default(), lifetime_elision_allowed: Default::default(), stripped_cfg_items: Default::default(), @@ -1667,6 +1653,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span, mods_with_parse_errors: Default::default(), impl_trait_names: Default::default(), + .. }; let root_parent_scope = ParentScope::module(graph_root, resolver.arenas); From 68ebbae2e81b5e88681ec7a25d2aa19c0504a6b4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 7 Aug 2025 19:43:15 +0300 Subject: [PATCH 197/252] resolve: Introduce `RibKind::Block` to avoid confusing module items, blocks with items, and blocks without items. --- compiler/rustc_resolve/src/ident.rs | 5 ++- compiler/rustc_resolve/src/late.rs | 33 ++++++++++--------- .../rustc_resolve/src/late/diagnostics.rs | 10 ++---- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index dc01c94af5729..0dc5cf234f864 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -337,7 +337,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } module = match rib.kind { - RibKind::Module(module) => module, + RibKind::Module(module) | RibKind::Block(Some(module)) => module, RibKind::MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. @@ -1171,6 +1171,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { match rib.kind { RibKind::Normal + | RibKind::Block(..) | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) @@ -1263,6 +1264,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { let (has_generic_params, def_kind) = match rib.kind { RibKind::Normal + | RibKind::Block(..) | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) @@ -1356,6 +1358,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { let (has_generic_params, def_kind) = match rib.kind { RibKind::Normal + | RibKind::Block(..) | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1e4ab57a3160a..2a592fb40e748 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -192,6 +192,13 @@ pub(crate) enum RibKind<'ra> { /// No restriction needs to be applied. Normal, + /// We passed through an `ast::Block`. + /// Behaves like `Normal`, but also partially like `Module` if the block contains items. + /// `Block(None)` must be always processed in the same way as `Block(Some(module))` + /// with empty `module`. The module can be `None` only because creation of some definitely + /// empty modules is skipped as an optimization. + Block(Option>), + /// We passed through an impl or trait and are now in one of its /// methods or associated types. Allow references to ty params that impl or trait /// binds. Disallow any other upvars (including other ty params that are @@ -210,7 +217,7 @@ pub(crate) enum RibKind<'ra> { /// All other constants aren't allowed to use generic params at all. ConstantItem(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>), - /// We passed through a module. + /// We passed through a module item. Module(Module<'ra>), /// We passed through a `macro_rules!` statement @@ -242,6 +249,7 @@ impl RibKind<'_> { pub(crate) fn contains_params(&self) -> bool { match self { RibKind::Normal + | RibKind::Block(..) | RibKind::FnOrCoroutine | RibKind::ConstantItem(..) | RibKind::Module(_) @@ -258,15 +266,8 @@ impl RibKind<'_> { fn is_label_barrier(self) -> bool { match self { RibKind::Normal | RibKind::MacroDefinition(..) => false, - - RibKind::AssocItem - | RibKind::FnOrCoroutine - | RibKind::Item(..) - | RibKind::ConstantItem(..) - | RibKind::Module(..) - | RibKind::ForwardGenericParamBan(_) - | RibKind::ConstParamTy - | RibKind::InlineAsmSym => true, + RibKind::FnOrCoroutine | RibKind::ConstantItem(..) => true, + kind => bug!("unexpected rib kind: {kind:?}"), } } } @@ -2821,9 +2822,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // We also can't shadow bindings from associated parent items. for ns in [ValueNS, TypeNS] { for parent_rib in self.ribs[ns].iter().rev() { - // Break at mod level, to account for nested items which are + // Break at module or block level, to account for nested items which are // allowed to shadow generic param names. - if matches!(parent_rib.kind, RibKind::Module(..)) { + if matches!(parent_rib.kind, RibKind::Module(..) | RibKind::Block(..)) { break; } @@ -4652,16 +4653,16 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { debug!("(resolving block) entering block"); // Move down in the graph, if there's an anonymous module rooted here. let orig_module = self.parent_scope.module; - let anonymous_module = self.r.block_map.get(&block.id).cloned(); // clones a reference + let anonymous_module = self.r.block_map.get(&block.id).copied(); let mut num_macro_definition_ribs = 0; if let Some(anonymous_module) = anonymous_module { debug!("(resolving block) found anonymous module, moving down"); - self.ribs[ValueNS].push(Rib::new(RibKind::Module(anonymous_module))); - self.ribs[TypeNS].push(Rib::new(RibKind::Module(anonymous_module))); + self.ribs[ValueNS].push(Rib::new(RibKind::Block(Some(anonymous_module)))); + self.ribs[TypeNS].push(Rib::new(RibKind::Block(Some(anonymous_module)))); self.parent_scope.module = anonymous_module; } else { - self.ribs[ValueNS].push(Rib::new(RibKind::Normal)); + self.ribs[ValueNS].push(Rib::new(RibKind::Block(None))); } // Descend into the block. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6a753b380359f..9b201e40d1393 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -849,9 +849,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } // Try to find in last block rib - if let Some(rib) = &self.last_block_rib - && let RibKind::Normal = rib.kind - { + if let Some(rib) = &self.last_block_rib { for (ident, &res) in &rib.bindings { if let Res::Local(_) = res && path.len() == 1 @@ -900,7 +898,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if path.len() == 1 { for rib in self.ribs[ns].iter().rev() { let item = path[0].ident; - if let RibKind::Module(module) = rib.kind + if let RibKind::Module(module) | RibKind::Block(Some(module)) = rib.kind && let Some(did) = find_doc_alias_name(self.r, module, item.name) { return Some((did, item)); @@ -2458,9 +2456,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } - if let RibKind::Module(module) = rib.kind - && let ModuleKind::Block = module.kind - { + if let RibKind::Block(Some(module)) = rib.kind { self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt)); } else if let RibKind::Module(module) = rib.kind { // Encountered a module item, abandon ribs and look into that module and preludes. From e6c96c151a84a8090da8867f4e9529b78dccb8cf Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 7 Aug 2025 21:27:29 +0300 Subject: [PATCH 198/252] resolve: Inline `with_mod_rib` --- compiler/rustc_resolve/src/late.rs | 44 ++++++++++++------------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2a592fb40e748..5200f9340e115 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1528,19 +1528,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ret } - fn with_mod_rib(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { - let module = self.r.expect_module(self.r.local_def_id(id).to_def_id()); - // Move down in the graph. - let orig_module = replace(&mut self.parent_scope.module, module); - self.with_rib(ValueNS, RibKind::Module(module), |this| { - this.with_rib(TypeNS, RibKind::Module(module), |this| { - let ret = f(this); - this.parent_scope.module = orig_module; - ret - }) - }) - } - fn visit_generic_params(&mut self, params: &'ast [GenericParam], add_self_upper: bool) { // For type parameter defaults, we have to ban access // to following type parameters, as the GenericArgs can only @@ -2678,20 +2665,25 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ItemKind::Mod(..) => { - self.with_mod_rib(item.id, |this| { - if mod_inner_docs { - this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); - } - let old_macro_rules = this.parent_scope.macro_rules; - visit::walk_item(this, item); - // Maintain macro_rules scopes in the same way as during early resolution - // for diagnostics and doc links. - if item.attrs.iter().all(|attr| { - !attr.has_name(sym::macro_use) && !attr.has_name(sym::macro_escape) - }) { - this.parent_scope.macro_rules = old_macro_rules; - } + let module = self.r.expect_module(self.r.local_def_id(item.id).to_def_id()); + let orig_module = replace(&mut self.parent_scope.module, module); + self.with_rib(ValueNS, RibKind::Module(module), |this| { + this.with_rib(TypeNS, RibKind::Module(module), |this| { + if mod_inner_docs { + this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); + } + let old_macro_rules = this.parent_scope.macro_rules; + visit::walk_item(this, item); + // Maintain macro_rules scopes in the same way as during early resolution + // for diagnostics and doc links. + if item.attrs.iter().all(|attr| { + !attr.has_name(sym::macro_use) && !attr.has_name(sym::macro_escape) + }) { + this.parent_scope.macro_rules = old_macro_rules; + } + }) }); + self.parent_scope.module = orig_module; } ItemKind::Static(box ast::StaticItem { From 16529158168ade04d0646524177e67c766c39e6c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 7 Aug 2025 21:50:17 +0300 Subject: [PATCH 199/252] resolve: Restructure `resolve_ident_in_lexical_scope` for better clarity --- compiler/rustc_resolve/src/ident.rs | 79 ++++++++++++++--------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 0dc5cf234f864..c1b3aff4e69f6 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -318,7 +318,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let normalized_ident = Ident { span: normalized_span, ..ident }; // Walk backwards up the ribs in scope. - let mut module = self.graph_root; for (i, rib) in ribs.iter().enumerate().rev() { debug!("walk rib\n{:?}", rib.bindings); // Use the rib kind to determine whether we are resolving parameters @@ -334,51 +333,47 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { *original_rib_ident_def, ribs, ))); + } else if let RibKind::Block(Some(module)) = rib.kind + && let Ok(binding) = self.cm().resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(module), + ident, + ns, + parent_scope, + Shadowing::Unrestricted, + finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), + ignore_binding, + None, + ) + { + // The ident resolves to an item in a block. + return Some(LexicalScopeBinding::Item(binding)); + } else if let RibKind::Module(module) = rib.kind { + // Encountered a module item, abandon ribs and look into that module and preludes. + return self + .cm() + .early_resolve_ident_in_lexical_scope( + orig_ident, + ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)), + parent_scope, + finalize, + finalize.is_some(), + ignore_binding, + None, + ) + .ok() + .map(LexicalScopeBinding::Item); } - module = match rib.kind { - RibKind::Module(module) | RibKind::Block(Some(module)) => module, - RibKind::MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => { - // If an invocation of this macro created `ident`, give up on `ident` - // and switch to `ident`'s source from the macro definition. - ident.span.remove_mark(); - continue; - } - _ => continue, - }; - - match module.kind { - ModuleKind::Block => {} // We can see through blocks - _ => break, - } - - let item = self.cm().resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - parent_scope, - Shadowing::Unrestricted, - finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), - ignore_binding, - None, - ); - if let Ok(binding) = item { - // The ident resolves to an item. - return Some(LexicalScopeBinding::Item(binding)); + if let RibKind::MacroDefinition(def) = rib.kind + && def == self.macro_def(ident.span.ctxt()) + { + // If an invocation of this macro created `ident`, give up on `ident` + // and switch to `ident`'s source from the macro definition. + ident.span.remove_mark(); } } - self.cm() - .early_resolve_ident_in_lexical_scope( - orig_ident, - ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)), - parent_scope, - finalize, - finalize.is_some(), - ignore_binding, - None, - ) - .ok() - .map(LexicalScopeBinding::Item) + + unreachable!() } /// Resolve an identifier in lexical scope. From f369e066e697511063a2434dbd5bfdb82dc06794 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 11 Aug 2025 19:10:45 +0300 Subject: [PATCH 200/252] resolve: Add one more test case for "binding is available in a different scope" help --- tests/ui/resolve/issue-104700-inner_scope.rs | 7 +++++++ tests/ui/resolve/issue-104700-inner_scope.stderr | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/ui/resolve/issue-104700-inner_scope.rs b/tests/ui/resolve/issue-104700-inner_scope.rs index e8f28c113e3ad..fb77ab2626b5f 100644 --- a/tests/ui/resolve/issue-104700-inner_scope.rs +++ b/tests/ui/resolve/issue-104700-inner_scope.rs @@ -7,5 +7,12 @@ fn main() { if bar == 2 { //~ ERROR cannot find value println!("yes"); } + { + let baz = 3; + struct S; + } + if baz == 3 { //~ ERROR cannot find value + println!("yes"); + } test_func(1); //~ ERROR cannot find function } diff --git a/tests/ui/resolve/issue-104700-inner_scope.stderr b/tests/ui/resolve/issue-104700-inner_scope.stderr index 051b234fc72d8..b579f8e76d951 100644 --- a/tests/ui/resolve/issue-104700-inner_scope.stderr +++ b/tests/ui/resolve/issue-104700-inner_scope.stderr @@ -10,12 +10,24 @@ help: the binding `bar` is available in a different scope in the same function LL | let bar = 2; | ^^^ +error[E0425]: cannot find value `baz` in this scope + --> $DIR/issue-104700-inner_scope.rs:14:8 + | +LL | if baz == 3 { + | ^^^ + | +help: the binding `baz` is available in a different scope in the same function + --> $DIR/issue-104700-inner_scope.rs:11:13 + | +LL | let baz = 3; + | ^^^ + error[E0425]: cannot find function `test_func` in this scope - --> $DIR/issue-104700-inner_scope.rs:10:5 + --> $DIR/issue-104700-inner_scope.rs:17:5 | LL | test_func(1); | ^^^^^^^^^ not found in this scope -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0425`. From caadc8df3519f1c92ef59ea816eb628345d9f52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Aug 2025 18:43:46 +0000 Subject: [PATCH 201/252] Do not ICE on private type in field of unresolved struct --- compiler/rustc_resolve/src/diagnostics.rs | 6 ++--- .../non-exhaustive-ctor-not-found.rs | 8 +++++++ .../non-exhaustive-ctor-not-found.stderr | 22 +++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 tests/ui/structs/default-field-values/non-exhaustive-ctor-not-found.rs create mode 100644 tests/ui/structs/default-field-values/non-exhaustive-ctor-not-found.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c5fcbdfb42fe7..a437f86e37789 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2189,9 +2189,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let ast::ExprKind::Struct(struct_expr) = &expr.kind else { return }; // We don't have to handle type-relative paths because they're forbidden in ADT // expressions, but that would change with `#[feature(more_qualified_paths)]`. - let Some(Res::Def(_, def_id)) = - self.partial_res_map[&struct_expr.path.segments.iter().last().unwrap().id].full_res() - else { + let Some(segment) = struct_expr.path.segments.last() else { return }; + let Some(partial_res) = self.partial_res_map.get(&segment.id) else { return }; + let Some(Res::Def(_, def_id)) = partial_res.full_res() else { return; }; let Some(default_fields) = self.field_defaults(def_id) else { return }; diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor-not-found.rs b/tests/ui/structs/default-field-values/non-exhaustive-ctor-not-found.rs new file mode 100644 index 0000000000000..4c5926a91ea4e --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor-not-found.rs @@ -0,0 +1,8 @@ +// Regression test for https://github.com/rust-lang/rust/issues/145367 +mod m { + struct Priv2; +} +fn main() { + WithUse { one: m::Priv2 } //~ ERROR: cannot find struct, variant or union type `WithUse` in this scope + //~^ ERROR: unit struct `Priv2` is private +} diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor-not-found.stderr b/tests/ui/structs/default-field-values/non-exhaustive-ctor-not-found.stderr new file mode 100644 index 0000000000000..1f0c80092b73f --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor-not-found.stderr @@ -0,0 +1,22 @@ +error[E0422]: cannot find struct, variant or union type `WithUse` in this scope + --> $DIR/non-exhaustive-ctor-not-found.rs:6:5 + | +LL | WithUse { one: m::Priv2 } + | ^^^^^^^ not found in this scope + +error[E0603]: unit struct `Priv2` is private + --> $DIR/non-exhaustive-ctor-not-found.rs:6:23 + | +LL | WithUse { one: m::Priv2 } + | ^^^^^ private unit struct + | +note: the unit struct `Priv2` is defined here + --> $DIR/non-exhaustive-ctor-not-found.rs:3:5 + | +LL | struct Priv2; + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0422, E0603. +For more information about an error, try `rustc --explain E0422`. From 106731f714ddce004f7dde265b4528ed1cf0c320 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 9 Aug 2025 20:31:06 +0200 Subject: [PATCH 202/252] Improved `Target` type - Added a few more variants which are needed for various attributes - Previously a trait method with default block had the same target representation as a method in a `impl trait for` block, this has been changed (See `MethodKind`) - Added `plural_name` for more precision on the form of the name --- compiler/rustc_hir/src/target.rs | 152 ++++++++++++++++++++++-- compiler/rustc_passes/src/lang_items.rs | 2 +- 2 files changed, 143 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index d617f44f8d8e4..f68dad3a5e868 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -6,23 +6,34 @@ use std::fmt::{self, Display}; +use rustc_ast::visit::AssocCtxt; +use rustc_ast::{AssocItemKind, ForeignItemKind, ast}; +use rustc_macros::HashStable_Generic; + use crate::def::DefKind; use crate::{Item, ItemKind, TraitItem, TraitItemKind, hir}; -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug, Eq, HashStable_Generic)] pub enum GenericParamKind { Type, Lifetime, Const, } -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug, Eq, HashStable_Generic)] pub enum MethodKind { - Trait { body: bool }, + /// Method in a `trait Trait` block + Trait { + /// Whether a default is provided for this method + body: bool, + }, + /// Method in a `impl Trait for Type` block + TraitImpl, + /// Method in a `impl Type` block Inherent, } -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug, Eq, HashStable_Generic)] pub enum Target { ExternCrate, Use, @@ -57,6 +68,9 @@ pub enum Target { PatField, ExprField, WherePredicate, + MacroCall, + Crate, + Delegation { mac: bool }, } impl Display for Target { @@ -98,7 +112,10 @@ impl Target { | Target::Param | Target::PatField | Target::ExprField - | Target::WherePredicate => false, + | Target::MacroCall + | Target::Crate + | Target::WherePredicate + | Target::Delegation { .. } => false, } } @@ -146,6 +163,39 @@ impl Target { } } + pub fn from_ast_item(item: &ast::Item) -> Target { + match item.kind { + ast::ItemKind::ExternCrate(..) => Target::ExternCrate, + ast::ItemKind::Use(..) => Target::Use, + ast::ItemKind::Static { .. } => Target::Static, + ast::ItemKind::Const(..) => Target::Const, + ast::ItemKind::Fn { .. } => Target::Fn, + ast::ItemKind::Mod(..) => Target::Mod, + ast::ItemKind::ForeignMod { .. } => Target::ForeignMod, + ast::ItemKind::GlobalAsm { .. } => Target::GlobalAsm, + ast::ItemKind::TyAlias(..) => Target::TyAlias, + ast::ItemKind::Enum(..) => Target::Enum, + ast::ItemKind::Struct(..) => Target::Struct, + ast::ItemKind::Union(..) => Target::Union, + ast::ItemKind::Trait(..) => Target::Trait, + ast::ItemKind::TraitAlias(..) => Target::TraitAlias, + ast::ItemKind::Impl(ref i) => Target::Impl { of_trait: i.of_trait.is_some() }, + ast::ItemKind::MacCall(..) => Target::MacroCall, + ast::ItemKind::MacroDef(..) => Target::MacroDef, + ast::ItemKind::Delegation(..) => Target::Delegation { mac: false }, + ast::ItemKind::DelegationMac(..) => Target::Delegation { mac: true }, + } + } + + pub fn from_foreign_item_kind(kind: &ast::ForeignItemKind) -> Target { + match kind { + ForeignItemKind::Static(_) => Target::ForeignStatic, + ForeignItemKind::Fn(_) => Target::ForeignFn, + ForeignItemKind::TyAlias(_) => Target::ForeignTy, + ForeignItemKind::MacCall(_) => Target::MacroCall, + } + } + pub fn from_trait_item(trait_item: &TraitItem<'_>) -> Target { match trait_item.kind { TraitItemKind::Const(..) => Target::AssocConst, @@ -183,12 +233,40 @@ impl Target { } } + pub fn from_assoc_item_kind(kind: &ast::AssocItemKind, assoc_ctxt: AssocCtxt) -> Target { + match kind { + AssocItemKind::Const(_) => Target::AssocConst, + AssocItemKind::Fn(f) => Target::Method(match assoc_ctxt { + AssocCtxt::Trait => MethodKind::Trait { body: f.body.is_some() }, + AssocCtxt::Impl { of_trait } => { + if of_trait { + MethodKind::TraitImpl + } else { + MethodKind::Inherent + } + } + }), + AssocItemKind::Type(_) => Target::AssocTy, + AssocItemKind::Delegation(_) => Target::Delegation { mac: false }, + AssocItemKind::DelegationMac(_) => Target::Delegation { mac: true }, + AssocItemKind::MacCall(_) => Target::MacroCall, + } + } + + pub fn from_expr(expr: &ast::Expr) -> Self { + match &expr.kind { + ast::ExprKind::Closure(..) | ast::ExprKind::Gen(..) => Self::Closure, + ast::ExprKind::Paren(e) => Self::from_expr(&e), + _ => Self::Expression, + } + } + pub fn name(self) -> &'static str { match self { Target::ExternCrate => "extern crate", Target::Use => "use", - Target::Static => "static item", - Target::Const => "constant item", + Target::Static => "static", + Target::Const => "constant", Target::Fn => "function", Target::Closure => "closure", Target::Mod => "module", @@ -202,8 +280,7 @@ impl Target { Target::Union => "union", Target::Trait => "trait", Target::TraitAlias => "trait alias", - Target::Impl { of_trait: false } => "inherent implementation block", - Target::Impl { of_trait: true } => "trait implementation block", + Target::Impl { .. } => "implementation block", Target::Expression => "expression", Target::Statement => "statement", Target::Arm => "match arm", @@ -212,12 +289,13 @@ impl Target { MethodKind::Inherent => "inherent method", MethodKind::Trait { body: false } => "required trait method", MethodKind::Trait { body: true } => "provided trait method", + MethodKind::TraitImpl => "trait method in an impl block", }, Target::AssocTy => "associated type", Target::ForeignFn => "foreign function", Target::ForeignStatic => "foreign static item", Target::ForeignTy => "foreign type", - Target::GenericParam { kind, has_default: _ } => match kind { + Target::GenericParam { kind, .. } => match kind { GenericParamKind::Type => "type parameter", GenericParamKind::Lifetime => "lifetime parameter", GenericParamKind::Const => "const parameter", @@ -227,6 +305,60 @@ impl Target { Target::PatField => "pattern field", Target::ExprField => "struct field", Target::WherePredicate => "where predicate", + Target::MacroCall => "macro call", + Target::Crate => "crate", + Target::Delegation { .. } => "delegation", + } + } + + pub fn plural_name(self) -> &'static str { + match self { + Target::ExternCrate => "extern crates", + Target::Use => "use statements", + Target::Static => "statics", + Target::Const => "constants", + Target::Fn => "functions", + Target::Closure => "closures", + Target::Mod => "modules", + Target::ForeignMod => "foreign modules", + Target::GlobalAsm => "global asms", + Target::TyAlias => "type aliases", + Target::Enum => "enums", + Target::Variant => "enum variants", + Target::Struct => "structs", + Target::Field => "struct fields", + Target::Union => "unions", + Target::Trait => "traits", + Target::TraitAlias => "trait aliases", + Target::Impl { of_trait: false } => "inherent impl blocks", + Target::Impl { of_trait: true } => "trait impl blocks", + Target::Expression => "expressions", + Target::Statement => "statements", + Target::Arm => "match arms", + Target::AssocConst => "associated consts", + Target::Method(kind) => match kind { + MethodKind::Inherent => "inherent methods", + MethodKind::Trait { body: false } => "required trait methods", + MethodKind::Trait { body: true } => "provided trait methods", + MethodKind::TraitImpl => "trait methods in impl blocks", + }, + Target::AssocTy => "associated types", + Target::ForeignFn => "foreign functions", + Target::ForeignStatic => "foreign statics", + Target::ForeignTy => "foreign types", + Target::GenericParam { kind, has_default: _ } => match kind { + GenericParamKind::Type => "type parameters", + GenericParamKind::Lifetime => "lifetime parameters", + GenericParamKind::Const => "const parameters", + }, + Target::MacroDef => "macro defs", + Target::Param => "function params", + Target::PatField => "pattern fields", + Target::ExprField => "struct fields", + Target::WherePredicate => "where predicates", + Target::MacroCall => "macro calls", + Target::Crate => "crates", + Target::Delegation { .. } => "delegations", } } } diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 6fac01827a499..141a60a8ec3f9 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -329,7 +329,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { match &self.parent_item.unwrap().kind { ast::ItemKind::Impl(i) => { if i.of_trait.is_some() { - Target::Method(MethodKind::Trait { body }) + Target::Method(MethodKind::TraitImpl) } else { Target::Method(MethodKind::Inherent) } From e7ef23e90e5b63e86bd77061ab92b86190a4eb3c Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 9 Aug 2025 20:33:10 +0200 Subject: [PATCH 203/252] Pass the target type down to `parse_attribute_list` --- compiler/rustc_ast_lowering/src/block.rs | 3 +- compiler/rustc_ast_lowering/src/expr.rs | 17 +++++------ compiler/rustc_ast_lowering/src/item.rs | 31 ++++++++++++++------- compiler/rustc_ast_lowering/src/lib.rs | 10 +++++-- compiler/rustc_ast_lowering/src/pat.rs | 4 +-- compiler/rustc_attr_parsing/src/context.rs | 6 +++- compiler/rustc_resolve/src/def_collector.rs | 2 ++ 7 files changed, 48 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 2cc07694afbc9..f1e810a8b9ea9 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -1,5 +1,6 @@ use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind}; use rustc_hir as hir; +use rustc_hir::Target; use rustc_span::sym; use smallvec::SmallVec; @@ -109,7 +110,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs, l.span); + self.lower_attrs(hir_id, &l.attrs, l.span, Target::Statement); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 2ddbf083a09b1..cbd17d66b7548 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -7,7 +7,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{HirId, find_attr}; +use rustc_hir::{HirId, Target, find_attr}; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; @@ -74,7 +74,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if !e.attrs.is_empty() { let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); let new_attrs = self - .lower_attrs_vec(&e.attrs, e.span, ex.hir_id) + .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e)) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); @@ -97,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span); + let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e)); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -639,7 +639,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span); + self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm); let is_never_pattern = pat.is_never_pattern(); // We need to lower the body even if it's unneeded for never pattern in match, // ensure that we can get HirId for DefId if need (issue #137708). @@ -820,6 +820,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: unstable_span, }], span, + Target::Fn, ); } } @@ -1654,7 +1655,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1910,7 +1911,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs, e.span); + self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e)); expr } @@ -1967,7 +1968,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let val_ident = Ident::with_dummy_span(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let val_expr = self.expr_ident(span, val_ident, val_pat_nid); - self.lower_attrs(val_expr.hir_id, &attrs, span); + self.lower_attrs(val_expr.hir_id, &attrs, span, Target::Expression); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr) }; @@ -1998,7 +1999,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ret_expr = self.checked_return(Some(from_residual_expr)); self.arena.alloc(self.expr(try_span, ret_expr)) }; - self.lower_attrs(ret_expr.hir_id, &attrs, span); + self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 2cd2c41928e33..72817a0a9a053 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -5,7 +5,7 @@ use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin, find_attr}; +use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin, Target, find_attr}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; @@ -80,7 +80,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP); + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP, Target::Crate); hir::OwnerNode::Crate(module) }) } @@ -136,7 +136,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { let vis_span = self.lower_span(i.vis.span); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_ast_item(i)); let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind); let item = hir::Item { owner_id: hir_id.expect_owner(), @@ -621,7 +621,8 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = + self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind)); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(box Fn { sig, ident, generics, define_opaque, .. }) => { let fdec = &sig.decl; @@ -690,7 +691,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_variant(&mut self, item_kind: &ItemKind, v: &Variant) -> hir::Variant<'hir> { let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span); + self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -773,7 +774,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FieldDef<'hir> { let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -792,7 +793,12 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs( + hir_id, + &i.attrs, + i.span, + Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), + ); let trait_item_def_id = hir_id.expect_owner(); let (ident, generics, kind, has_default) = match &i.kind { @@ -1001,7 +1007,12 @@ impl<'hir> LoweringContext<'_, 'hir> { let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs( + hir_id, + &i.attrs, + i.span, + Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), + ); let (ident, (generics, kind)) = match &i.kind { AssocItemKind::Const(box ConstItem { @@ -1171,7 +1182,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span); + self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::Param); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1851,7 +1862,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::WherePredicate<'hir> { let hir_id = self.lower_node_id(pred.id); let span = self.lower_span(pred.span); - self.lower_attrs(hir_id, &pred.attrs, span); + self.lower_attrs(hir_id, &pred.attrs, span, Target::WherePredicate); let kind = self.arena.alloc(match &pred.kind { WherePredicateKind::BoundPredicate(WhereBoundPredicate { bound_generic_params, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 465d9dc82bc97..70595391b85bc 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -54,7 +54,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::lints::DelayedLint; use rustc_hir::{ self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource, - LifetimeSyntax, ParamName, TraitCandidate, + LifetimeSyntax, ParamName, Target, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -943,11 +943,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: HirId, attrs: &[Attribute], target_span: Span, + target: Target, ) -> &'hir [hir::Attribute] { if attrs.is_empty() { &[] } else { - let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id); + let lowered_attrs = + self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target); assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(lowered_attrs); @@ -972,12 +974,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { attrs: &[Attribute], target_span: Span, target_hir_id: HirId, + target: Target, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target_hir_id, + target, OmitDoc::Lower, |s| l.lower(s), |l| { @@ -1942,7 +1946,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span()); + self.lower_attrs(hir_id, ¶m.attrs, param.span(), Target::Param); hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index b6533060a76e5..b8f8624787565 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{self as hir, LangItem}; +use rustc_hir::{self as hir, LangItem, Target}; use rustc_middle::span_bug; use rustc_span::source_map::{Spanned, respan}; use rustc_span::{DesugaringKind, Ident, Span}; @@ -93,7 +93,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::PatField); hir::PatField { hir_id, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6045a8b28a225..dc98f2c8df120 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -9,7 +9,9 @@ use rustc_errors::{DiagCtxtHandle, Diagnostic}; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId}; +use rustc_hir::{ + AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId, MethodKind, Target, +}; use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -691,6 +693,7 @@ impl<'sess> AttributeParser<'sess, Early> { attrs, target_span, target_node_id, + Target::Crate, // Does not matter, we're not going to emit errors anyways OmitDoc::Skip, std::convert::identity, |_lint| { @@ -777,6 +780,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attrs: &[ast::Attribute], target_span: Span, target_id: S::Id, + target: Target, omit_doc: OmitDoc, lower_span: impl Copy + Fn(Span) -> Span, diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1e4513eb78707..14538df8187d8 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -5,6 +5,7 @@ use rustc_ast::*; use rustc_attr_parsing::{AttributeParser, Early, OmitDoc, ShouldEmit}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; +use rustc_hir::Target; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_middle::span_bug; @@ -138,6 +139,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, i.id, + Target::MacroDef, OmitDoc::Skip, std::convert::identity, |_l| { From 744d39ebe61ad8cc674797793c743493af078d74 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 9 Aug 2025 20:37:32 +0200 Subject: [PATCH 204/252] Allow attribute parsers to specify a list of allowed targets Every acceptor gets an `ALLOWED_TARGETS` specification which can specify per target whether it is allowed, warned, or errored. --- Cargo.lock | 1 + compiler/rustc_attr_parsing/Cargo.toml | 1 + compiler/rustc_attr_parsing/messages.ftl | 6 + .../rustc_attr_parsing/src/attributes/mod.rs | 21 +- compiler/rustc_attr_parsing/src/context.rs | 237 +++++++++++++++++- compiler/rustc_attr_parsing/src/lints.rs | 23 +- .../src/session_diagnostics.rs | 23 ++ compiler/rustc_hir/src/lints.rs | 5 +- 8 files changed, 304 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a878faecbc7f..8c980616e83bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3480,6 +3480,7 @@ dependencies = [ name = "rustc_attr_parsing" version = "0.0.0" dependencies = [ + "itertools", "rustc_abi", "rustc_ast", "rustc_ast_pretty", diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index cec9d62e6560c..bac89373b6789 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index de22ea322c792..4fb66a816522e 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -10,6 +10,12 @@ attr_parsing_empty_attribute = unused attribute .suggestion = remove this attribute +attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target} + .help = `#[{$name}]` can {$only}be applied to {$applied} +attr_parsing_invalid_target_lint = `#[{$name}]` attribute cannot be used on {$target} + .warn = {-attr_parsing_previously_accepted} + .help = `#[{$name}]` can {$only}be applied to {$applied} + attr_parsing_empty_confusables = expected at least one confusable name attr_parsing_expected_one_cfg_pattern = diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index f7946ade6d2b2..ed5d1d92b8caf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -21,7 +21,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; -use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics::UnusedMultiple; @@ -80,6 +80,8 @@ pub(crate) trait AttributeParser: Default + 'static { /// If an attribute has this symbol, the `accept` function will be called on it. const ATTRIBUTES: AcceptMapping; + const ALLOWED_TARGETS: AllowedTargets; + /// The parser has gotten a chance to accept the attributes on an item, /// here it can produce an attribute. /// @@ -116,6 +118,8 @@ pub(crate) trait SingleAttributeParser: 'static { /// and this specified whether to, for example, warn or error on the other one. const ON_DUPLICATE: OnDuplicate; + const ALLOWED_TARGETS: AllowedTargets; + /// The template this attribute parser should implement. Used for diagnostics. const TEMPLATE: AttributeTemplate; @@ -163,6 +167,7 @@ impl, S: Stage> AttributeParser for Single } }, )]; + const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { Some(self.1?.0) @@ -247,6 +252,7 @@ pub(crate) enum AttributeOrder { pub(crate) trait NoArgsAttributeParser: 'static { const PATH: &[Symbol]; const ON_DUPLICATE: OnDuplicate; + const ALLOWED_TARGETS: AllowedTargets; /// Create the [`AttributeKind`] given attribute's [`Span`]. const CREATE: fn(Span) -> AttributeKind; @@ -264,6 +270,7 @@ impl, S: Stage> SingleAttributeParser for Without const PATH: &[Symbol] = T::PATH; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = T::ON_DUPLICATE; + const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { @@ -293,6 +300,8 @@ pub(crate) trait CombineAttributeParser: 'static { /// where `x` is a vec of these individual reprs. const CONVERT: ConvertFn; + const ALLOWED_TARGETS: AllowedTargets; + /// The template this attribute parser should implement. Used for diagnostics. const TEMPLATE: AttributeTemplate; @@ -324,15 +333,13 @@ impl, S: Stage> Default for Combine { } impl, S: Stage> AttributeParser for Combine { - const ATTRIBUTES: AcceptMapping = &[( - T::PATH, - >::TEMPLATE, - |group: &mut Combine, cx, args| { + const ATTRIBUTES: AcceptMapping = + &[(T::PATH, T::TEMPLATE, |group: &mut Combine, cx, args| { // Keep track of the span of the first attribute, for diagnostics group.first_span.get_or_insert(cx.attr_span); group.items.extend(T::extend(cx, args)) - }, - )]; + })]; + const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if let Some(first_span) = self.first_span { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index dc98f2c8df120..bebe3350c4e0d 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -3,6 +3,7 @@ use std::collections::BTreeMap; use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; +use itertools::Itertools; use private::Sealed; use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId}; use rustc_errors::{DiagCtxtHandle, Diagnostic}; @@ -63,8 +64,11 @@ use crate::attributes::traits::{ }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; +use crate::context::MaybeWarn::{Allow, Error, Warn}; use crate::parser::{ArgParser, MetaItemParser, PathParser}; -use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem}; +use crate::session_diagnostics::{ + AttributeParseError, AttributeParseErrorReason, InvalidTarget, UnknownMetaItem, +}; type GroupType = LazyLock>; @@ -76,6 +80,7 @@ struct GroupTypeInner { struct GroupTypeInnerAccept { template: AttributeTemplate, accept_fn: AcceptFn, + allowed_targets: AllowedTargets, } type AcceptFn = @@ -123,7 +128,8 @@ macro_rules! attribute_parsers { STATE_OBJECT.with_borrow_mut(|s| { accept_fn(s, cx, args) }) - }) + }), + allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS, }); } @@ -645,6 +651,64 @@ impl ShouldEmit { } } +#[derive(Debug)] +pub(crate) enum AllowedTargets { + AllowList(&'static [MaybeWarn]), + AllowListWarnRest(&'static [MaybeWarn]), +} + +pub(crate) enum AllowedResult { + Allowed, + Warn, + Error, +} + +impl AllowedTargets { + pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult { + match self { + AllowedTargets::AllowList(list) => { + if list.contains(&Allow(target)) { + AllowedResult::Allowed + } else if list.contains(&Warn(target)) { + AllowedResult::Warn + } else { + AllowedResult::Error + } + } + AllowedTargets::AllowListWarnRest(list) => { + if list.contains(&Allow(target)) { + AllowedResult::Allowed + } else if list.contains(&Error(target)) { + AllowedResult::Error + } else { + AllowedResult::Warn + } + } + } + } + + pub(crate) fn allowed_targets(&self) -> Vec { + match self { + AllowedTargets::AllowList(list) => list, + AllowedTargets::AllowListWarnRest(list) => list, + } + .iter() + .filter_map(|target| match target { + Allow(target) => Some(*target), + Warn(_) => None, + Error(_) => None, + }) + .collect() + } +} + +#[derive(Debug, Eq, PartialEq)] +pub(crate) enum MaybeWarn { + Allow(Target), + Warn(Target), + Error(Target), +} + /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. pub struct AttributeParser<'sess, S: Stage = Late> { @@ -852,7 +916,48 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attr_path: path.get_attribute_path(), }; - (accept.accept_fn)(&mut cx, args) + (accept.accept_fn)(&mut cx, args); + + if self.stage.should_emit().should_emit() { + match accept.allowed_targets.is_allowed(target) { + AllowedResult::Allowed => {} + AllowedResult::Warn => { + let allowed_targets = + accept.allowed_targets.allowed_targets(); + let (applied, only) = allowed_targets_applied( + allowed_targets, + target, + self.features, + ); + emit_lint(AttributeLint { + id: target_id, + span: attr.span, + kind: AttributeLintKind::InvalidTarget { + name: parts[0], + target, + only: if only { "only " } else { "" }, + applied, + }, + }); + } + AllowedResult::Error => { + let allowed_targets = + accept.allowed_targets.allowed_targets(); + let (applied, only) = allowed_targets_applied( + allowed_targets, + target, + self.features, + ); + self.dcx().emit_err(InvalidTarget { + span: attr.span, + name: parts[0], + target: target.plural_name(), + only: if only { "only " } else { "" }, + applied, + }); + } + } + } } } else { // If we're here, we must be compiling a tool attribute... Or someone @@ -940,6 +1045,132 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } } +/// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to. +/// Does some heuristic-based filtering to remove uninteresting targets, and formats the targets into a string +pub(crate) fn allowed_targets_applied( + mut allowed_targets: Vec, + target: Target, + features: Option<&Features>, +) -> (String, bool) { + // Remove unstable targets from `allowed_targets` if their features are not enabled + if let Some(features) = features { + if !features.fn_delegation() { + allowed_targets.retain(|t| !matches!(t, Target::Delegation { .. })); + } + if !features.stmt_expr_attributes() { + allowed_targets.retain(|t| !matches!(t, Target::Expression | Target::Statement)); + } + } + + // We define groups of "similar" targets. + // If at least two of the targets are allowed, and the `target` is not in the group, + // we collapse the entire group to a single entry to simplify the target list + const FUNCTION_LIKE: &[Target] = &[ + Target::Fn, + Target::Closure, + Target::ForeignFn, + Target::Method(MethodKind::Inherent), + Target::Method(MethodKind::Trait { body: false }), + Target::Method(MethodKind::Trait { body: true }), + Target::Method(MethodKind::TraitImpl), + ]; + const METHOD_LIKE: &[Target] = &[ + Target::Method(MethodKind::Inherent), + Target::Method(MethodKind::Trait { body: false }), + Target::Method(MethodKind::Trait { body: true }), + Target::Method(MethodKind::TraitImpl), + ]; + const IMPL_LIKE: &[Target] = + &[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }]; + const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum]; + + let mut added_fake_targets = Vec::new(); + filter_targets( + &mut allowed_targets, + FUNCTION_LIKE, + "functions", + target, + &mut added_fake_targets, + ); + filter_targets(&mut allowed_targets, METHOD_LIKE, "methods", target, &mut added_fake_targets); + filter_targets(&mut allowed_targets, IMPL_LIKE, "impl blocks", target, &mut added_fake_targets); + filter_targets(&mut allowed_targets, ADT_LIKE, "data types", target, &mut added_fake_targets); + + // If there is now only 1 target left, show that as the only possible target + ( + added_fake_targets + .iter() + .copied() + .chain(allowed_targets.iter().map(|t| t.plural_name())) + .join(", "), + allowed_targets.len() + added_fake_targets.len() == 1, + ) +} + +fn filter_targets( + allowed_targets: &mut Vec, + target_group: &'static [Target], + target_group_name: &'static str, + target: Target, + added_fake_targets: &mut Vec<&'static str>, +) { + if target_group.contains(&target) { + return; + } + if allowed_targets.iter().filter(|at| target_group.contains(at)).count() < 2 { + return; + } + allowed_targets.retain(|t| !target_group.contains(t)); + added_fake_targets.push(target_group_name); +} + +/// This is the list of all targets to which a attribute can be applied +/// This is used for: +/// - `rustc_dummy`, which can be applied to all targets +/// - Attributes that are not parted to the new target system yet can use this list as a placeholder +pub(crate) const ALL_TARGETS: &'static [MaybeWarn] = &[ + Allow(Target::ExternCrate), + Allow(Target::Use), + Allow(Target::Static), + Allow(Target::Const), + Allow(Target::Fn), + Allow(Target::Closure), + Allow(Target::Mod), + Allow(Target::ForeignMod), + Allow(Target::GlobalAsm), + Allow(Target::TyAlias), + Allow(Target::Enum), + Allow(Target::Variant), + Allow(Target::Struct), + Allow(Target::Field), + Allow(Target::Union), + Allow(Target::Trait), + Allow(Target::TraitAlias), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Expression), + Allow(Target::Statement), + Allow(Target::Arm), + Allow(Target::AssocConst), + 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::AssocTy), + Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), + Allow(Target::ForeignTy), + Allow(Target::MacroDef), + Allow(Target::Param), + Allow(Target::PatField), + Allow(Target::ExprField), + Allow(Target::WherePredicate), + Allow(Target::MacroCall), + Allow(Target::Crate), + Allow(Target::Delegation { mac: false }), + Allow(Target::Delegation { mac: true }), +]; + /// Parse a single integer. /// /// Used by attributes that take a single integer as argument, such as diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 22f5531bc8079..733225bab598e 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -1,6 +1,7 @@ use rustc_errors::{DiagArgValue, LintEmitter}; -use rustc_hir::HirId; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; +use rustc_hir::{HirId, Target}; +use rustc_span::sym; use crate::session_diagnostics; @@ -34,5 +35,25 @@ pub fn emit_attribute_lint(lint: &AttributeLint, lint_emi *first_span, session_diagnostics::EmptyAttributeList { attr_span: *first_span }, ), + &AttributeLintKind::InvalidTarget { name, target, ref applied, only } => lint_emitter + .emit_node_span_lint( + // This check is here because `deprecated` had its own lint group and removing this would be a breaking change + if name == sym::deprecated + && ![Target::Closure, Target::Expression, Target::Statement, Target::Arm] + .contains(&target) + { + rustc_session::lint::builtin::USELESS_DEPRECATED + } else { + rustc_session::lint::builtin::UNUSED_ATTRIBUTES + }, + *id, + *span, + session_diagnostics::InvalidTargetLint { + name, + target: target.plural_name(), + applied: applied.clone(), + only, + }, + ), } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 41179844152ad..95e85667cd662 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -480,6 +480,29 @@ pub(crate) struct EmptyAttributeList { pub attr_span: Span, } +#[derive(LintDiagnostic)] +#[diag(attr_parsing_invalid_target_lint)] +#[warning] +#[help] +pub(crate) struct InvalidTargetLint { + pub name: Symbol, + pub target: &'static str, + pub applied: String, + pub only: &'static str, +} + +#[derive(Diagnostic)] +#[help] +#[diag(attr_parsing_invalid_target)] +pub(crate) struct InvalidTarget { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub target: &'static str, + pub applied: String, + pub only: &'static str, +} + #[derive(Diagnostic)] #[diag(attr_parsing_invalid_alignment_value, code = E0589)] pub(crate) struct InvalidAlignmentValue { diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index c55a41eb2b76b..e3cde2d3bb675 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -1,8 +1,8 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_macros::HashStable_Generic; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; -use crate::HirId; +use crate::{HirId, Target}; #[derive(Debug)] pub struct DelayedLints { @@ -34,4 +34,5 @@ pub enum AttributeLintKind { UnusedDuplicate { this: Span, other: Span, warning: bool }, IllFormedAttributeInput { suggestions: Vec }, EmptyAttribute { first_span: Span }, + InvalidTarget { name: Symbol, target: Target, applied: String, only: &'static str }, } From 35e04b67a6eeb1603d67f4220b05da9c1b77eed7 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 9 Aug 2025 20:37:48 +0200 Subject: [PATCH 205/252] Specify the list of allowed targets per attribute --- .../src/attributes/allow_unstable.rs | 22 +++++- .../rustc_attr_parsing/src/attributes/body.rs | 5 +- .../src/attributes/codegen_attrs.rs | 77 ++++++++++++++++++- .../src/attributes/confusables.rs | 7 +- .../src/attributes/deprecation.rs | 29 ++++++- .../src/attributes/dummy.rs | 4 +- .../src/attributes/inline.rs | 20 ++++- .../src/attributes/link_attrs.rs | 32 +++++++- .../src/attributes/lint_helpers.rs | 27 ++++++- .../src/attributes/loop_match.rs | 7 +- .../src/attributes/macro_attrs.rs | 19 ++++- .../src/attributes/must_use.rs | 4 +- .../src/attributes/no_implicit_prelude.rs | 7 +- .../src/attributes/non_exhaustive.rs | 13 +++- .../rustc_attr_parsing/src/attributes/path.rs | 7 +- .../src/attributes/proc_macro_attrs.rs | 12 ++- .../rustc_attr_parsing/src/attributes/repr.rs | 17 +++- .../src/attributes/rustc_internal.rs | 8 +- .../src/attributes/semantics.rs | 4 +- .../src/attributes/stability.rs | 43 ++++++++++- .../src/attributes/test_attrs.rs | 9 ++- .../src/attributes/traits.rs | 26 ++++++- .../src/attributes/transparency.rs | 6 +- 23 files changed, 361 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index b3393e93de8b7..4d995027814b9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -2,10 +2,12 @@ use std::iter; use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::AttributeKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; @@ -15,6 +17,12 @@ impl CombineAttributeParser for AllowInternalUnstableParser { type Item = (Symbol, Span); const CONVERT: ConvertFn = |items, span| AttributeKind::AllowInternalUnstable(items, span); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::MacroDef), + Allow(Target::Fn), + Warn(Target::Field), + Warn(Target::Arm), + ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); fn extend<'c>( @@ -32,6 +40,11 @@ impl CombineAttributeParser for UnstableFeatureBoundParser { const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound]; type Item = (Symbol, Span); const CONVERT: ConvertFn = |items, _| AttributeKind::UnstableFeatureBound(items); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Trait), + ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); fn extend<'c>( @@ -53,6 +66,13 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { type Item = Symbol; const CONVERT: ConvertFn = |items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span); + 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)), + ]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]); fn extend<'c>( diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs index ab9330216f6c6..88540384621db 100644 --- a/compiler/rustc_attr_parsing/src/attributes/body.rs +++ b/compiler/rustc_attr_parsing/src/attributes/body.rs @@ -1,15 +1,18 @@ //! Attributes that can be found in function body. +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use super::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; +use crate::context::MaybeWarn::Allow; +use crate::context::{AllowedTargets, Stage}; pub(crate) struct CoroutineParser; impl NoArgsAttributeParser for CoroutineParser { const PATH: &[Symbol] = &[sym::coroutine]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]); const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span); } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index a9f77195d1bcb..6ea073896c2f5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,5 +1,6 @@ use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::{AttributeKind, CoverageAttrKind, OptimizeAttr, UsedBy}; +use rustc_hir::{MethodKind, Target}; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; @@ -7,7 +8,8 @@ use super::{ AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; -use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport}; @@ -17,6 +19,13 @@ impl SingleAttributeParser for OptimizeParser { const PATH: &[Symbol] = &[sym::optimize]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Closure), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Method(MethodKind::Inherent)), + ]); const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { @@ -49,6 +58,15 @@ pub(crate) struct ColdParser; impl NoArgsAttributeParser for ColdParser { const PATH: &[Symbol] = &[sym::cold]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + 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), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold; } @@ -58,6 +76,17 @@ impl SingleAttributeParser for CoverageParser { const PATH: &[Symbol] = &[sym::coverage]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Closure), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Mod), + Allow(Target::Crate), + ]); const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { @@ -97,6 +126,16 @@ impl SingleAttributeParser for ExportNameParser { const PATH: &[rustc_span::Symbol] = &[sym::export_name]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Static), + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Warn(Target::Field), + Warn(Target::Arm), + Warn(Target::MacroDef), + ]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { @@ -138,6 +177,12 @@ impl AttributeParser for NakedParser { this.span = Some(cx.attr_span); } })]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + ]); fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option { // FIXME(jdonszelmann): upgrade this list to *parsed* attributes @@ -230,6 +275,18 @@ pub(crate) struct TrackCallerParser; impl NoArgsAttributeParser for TrackCallerParser { const PATH: &[Symbol] = &[sym::track_caller]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + 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::ForeignFn), + Allow(Target::Closure), + Warn(Target::MacroDef), + Warn(Target::Arm), + Warn(Target::Field), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller; } @@ -237,6 +294,12 @@ pub(crate) struct NoMangleParser; impl NoArgsAttributeParser for NoMangleParser { const PATH: &[Symbol] = &[sym::no_mangle]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Fn), + Allow(Target::Static), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::TraitImpl)), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle; } @@ -310,6 +373,7 @@ impl AttributeParser for UsedParser { } }, )]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Static)]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { // Ratcheting behaviour, if both `linker` and `compiler` are specified, use `linker` @@ -373,4 +437,15 @@ impl CombineAttributeParser for TargetFeatureParser { } features } + + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Warn(Target::Statement), + Warn(Target::Field), + Warn(Target::Arm), + Warn(Target::MacroDef), + ]); } diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index edd22172ca26f..00f949c82c5a7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -1,12 +1,13 @@ use rustc_feature::template; use rustc_hir::attrs::AttributeKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; use super::{AcceptMapping, AttributeParser}; -use crate::context::{FinalizeContext, Stage}; +use crate::context::MaybeWarn::Allow; +use crate::context::{AllowedTargets, FinalizeContext, Stage}; use crate::session_diagnostics; - #[derive(Default)] pub(crate) struct ConfusablesParser { confusables: ThinVec, @@ -41,6 +42,8 @@ impl AttributeParser for ConfusablesParser { this.first_span.get_or_insert(cx.attr_span); }, )]; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.confusables.is_empty() { diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index e57ea8bbb5cf0..8101c91460f26 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,13 +1,14 @@ use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation}; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use super::util::parse_version; use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Error}; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; - pub(crate) struct DeprecationParser; fn get( @@ -38,6 +39,30 @@ impl SingleAttributeParser for DeprecationParser { const PATH: &[Symbol] = &[sym::deprecated]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Fn), + Allow(Target::Mod), + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + Allow(Target::Const), + Allow(Target::Static), + Allow(Target::MacroDef), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::TyAlias), + Allow(Target::Use), + Allow(Target::ForeignFn), + Allow(Target::Field), + Allow(Target::Trait), + Allow(Target::AssocTy), + Allow(Target::AssocConst), + Allow(Target::Variant), + Allow(Target::Impl { of_trait: false }), //FIXME This does not make sense + Allow(Target::Crate), + Error(Target::WherePredicate), + ]); const TEMPLATE: AttributeTemplate = template!( Word, List: &[r#"since = "version""#, r#"note = "reason""#, r#"since = "version", note = "reason""#], diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index bbcd9ab530c54..85842b1b5c5f2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -3,14 +3,14 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct DummyParser; impl SingleAttributeParser for DummyParser { const PATH: &[Symbol] = &[sym::rustc_dummy]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really fn convert(_: &mut AcceptContext<'_, '_, S>, _: &ArgParser<'_>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index e9a45f20bff0d..6a659a95b856f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -5,19 +5,34 @@ use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::{AttributeKind, InlineAttr}; use rustc_hir::lints::AttributeLintKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Symbol, sym}; use super::{AcceptContext, AttributeOrder, OnDuplicate}; use crate::attributes::SingleAttributeParser; -use crate::context::Stage; +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct InlineParser; impl SingleAttributeParser for InlineParser { const PATH: &'static [Symbol] = &[sym::inline]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Closure), + Allow(Target::Delegation { mac: false }), + Warn(Target::Method(MethodKind::Trait { body: false })), + Warn(Target::ForeignFn), + Warn(Target::Field), + Warn(Target::MacroDef), + Warn(Target::Arm), + Warn(Target::AssocConst), + ]); const TEMPLATE: AttributeTemplate = template!( Word, List: &["always", "never"], @@ -63,6 +78,7 @@ impl SingleAttributeParser for RustcForceInlineParser { const PATH: &'static [Symbol] = &[sym::rustc_force_inline]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index e4ced2e37c55d..552b9dfabc293 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -1,21 +1,26 @@ use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; use rustc_hir::attrs::{AttributeKind, Linkage}; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{ AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; -use crate::context::{AcceptContext, Stage, parse_single_integer}; +use crate::context::MaybeWarn::Allow; +use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage, parse_single_integer}; use crate::parser::ArgParser; use crate::session_diagnostics::{LinkOrdinalOutOfRange, NullOnLinkSection}; - pub(crate) struct LinkNameParser; impl SingleAttributeParser for LinkNameParser { const PATH: &[Symbol] = &[sym::link_name]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), + ]); const TEMPLATE: AttributeTemplate = template!( NameValueStr: "name", "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute" @@ -41,6 +46,8 @@ impl SingleAttributeParser for LinkSectionParser { const PATH: &[Symbol] = &[sym::link_section]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Static), Allow(Target::Fn)]); const TEMPLATE: AttributeTemplate = template!( NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute" @@ -70,6 +77,7 @@ pub(crate) struct ExportStableParser; impl NoArgsAttributeParser for ExportStableParser { const PATH: &[Symbol] = &[sym::export_stable]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable; } @@ -77,6 +85,7 @@ pub(crate) struct FfiConstParser; impl NoArgsAttributeParser for FfiConstParser { const PATH: &[Symbol] = &[sym::ffi_const]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst; } @@ -84,6 +93,7 @@ pub(crate) struct FfiPureParser; impl NoArgsAttributeParser for FfiPureParser { const PATH: &[Symbol] = &[sym::ffi_pure]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure; } @@ -91,6 +101,12 @@ pub(crate) struct StdInternalSymbolParser; impl NoArgsAttributeParser for StdInternalSymbolParser { const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::ForeignFn), + Allow(Target::Static), + Allow(Target::ForeignStatic), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol; } @@ -100,6 +116,8 @@ impl SingleAttributeParser for LinkOrdinalParser { const PATH: &[Symbol] = &[sym::link_ordinal]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]); const TEMPLATE: AttributeTemplate = template!( List: &["ordinal"], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute" @@ -138,6 +156,16 @@ impl SingleAttributeParser for LinkageParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + 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), + ]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: [ "available_externally", diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 9530fec07d61f..2b586d4003cda 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -1,13 +1,21 @@ use rustc_hir::attrs::AttributeKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; - +use crate::context::MaybeWarn::{Allow, Error}; +use crate::context::{AllowedTargets, Stage}; pub(crate) struct AsPtrParser; impl NoArgsAttributeParser for AsPtrParser { const PATH: &[Symbol] = &[sym::rustc_as_ptr]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + 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)), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::AsPtr; } @@ -15,6 +23,11 @@ pub(crate) struct PubTransparentParser; impl NoArgsAttributeParser for PubTransparentParser { const PATH: &[Symbol] = &[sym::rustc_pub_transparent]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::PubTransparent; } @@ -22,6 +35,11 @@ pub(crate) struct PassByValueParser; impl NoArgsAttributeParser for PassByValueParser { const PATH: &[Symbol] = &[sym::rustc_pass_by_value]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::TyAlias), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::PassByValue; } @@ -29,5 +47,10 @@ pub(crate) struct AutomaticallyDerivedParser; impl NoArgsAttributeParser for AutomaticallyDerivedParser { const PATH: &[Symbol] = &[sym::automatically_derived]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Impl { of_trait: true }), + Error(Target::Crate), + Error(Target::WherePredicate), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::AutomaticallyDerived; } diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs index 868c113a6d133..242e2f2c1bc0b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs +++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs @@ -1,13 +1,15 @@ +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; - +use crate::context::MaybeWarn::Allow; +use crate::context::{AllowedTargets, Stage}; pub(crate) struct LoopMatchParser; impl NoArgsAttributeParser for LoopMatchParser { const PATH: &[Symbol] = &[sym::loop_match]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Expression)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::LoopMatch; } @@ -15,5 +17,6 @@ pub(crate) struct ConstContinueParser; impl NoArgsAttributeParser for ConstContinueParser { const PATH: &[Symbol] = &[sym::const_continue]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Expression)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstContinue; } diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index a1166bf9ac5d8..c9b5dd35fa1d9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,18 +1,20 @@ use rustc_errors::DiagArgValue; use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::{AttributeKind, MacroUseArgs}; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; use crate::attributes::{AcceptMapping, AttributeParser, NoArgsAttributeParser, OnDuplicate}; -use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::context::MaybeWarn::{Allow, Error, Warn}; +use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; - pub(crate) struct MacroEscapeParser; impl NoArgsAttributeParser for MacroEscapeParser { const PATH: &[Symbol] = &[sym::macro_escape]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS; const CREATE: fn(Span) -> AttributeKind = AttributeKind::MacroEscape; } @@ -35,6 +37,12 @@ const MACRO_USE_TEMPLATE: AttributeTemplate = template!( Word, List: &["name1, name2, ..."], "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute" ); +const MACRO_USE_ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Mod), + Allow(Target::ExternCrate), + Allow(Target::Crate), + Error(Target::WherePredicate), +]); impl AttributeParser for MacroUseParser { const ATTRIBUTES: AcceptMapping = &[( @@ -111,6 +119,7 @@ impl AttributeParser for MacroUseParser { } }, )]; + const ALLOWED_TARGETS: AllowedTargets = MACRO_USE_ALLOWED_TARGETS; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state }) @@ -122,5 +131,11 @@ pub(crate) struct AllowInternalUnsafeParser; impl NoArgsAttributeParser for AllowInternalUnsafeParser { const PATH: &[Symbol] = &[sym::allow_internal_unsafe]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::MacroDef), + Warn(Target::Field), + Warn(Target::Arm), + ]); const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span); } diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index c88bb5a69e523..b6cfc78059066 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -4,16 +4,16 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; - pub(crate) struct MustUseParser; impl SingleAttributeParser for MustUseParser { const PATH: &[Symbol] = &[sym::must_use]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const TEMPLATE: AttributeTemplate = template!( Word, NameValueStr: "reason", "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute" diff --git a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs index 40f8d00685eae..589faf38f730a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs @@ -1,13 +1,16 @@ +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; - +use crate::context::MaybeWarn::Allow; +use crate::context::{AllowedTargets, Stage}; pub(crate) struct NoImplicitPreludeParser; impl NoArgsAttributeParser for NoImplicitPreludeParser { const PATH: &[rustc_span::Symbol] = &[sym::no_implicit_prelude]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoImplicitPrelude; } diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 361ac8e959dc5..41e9ca4de410e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,13 +1,22 @@ +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; - +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{AllowedTargets, Stage}; pub(crate) struct NonExhaustiveParser; impl NoArgsAttributeParser for NonExhaustiveParser { const PATH: &[Symbol] = &[sym::non_exhaustive]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Enum), + Allow(Target::Struct), + Allow(Target::Variant), + Warn(Target::Field), + Warn(Target::Arm), + Warn(Target::MacroDef), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; } diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index c1c3de8cbfc7e..f9191d1abed30 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -1,17 +1,20 @@ use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Error}; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct PathParser; impl SingleAttributeParser for PathParser { const PATH: &[Symbol] = &[sym::path]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Error(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!( NameValueStr: "file", "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute" diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index b267980914c6d..4624fa3628758 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -1,4 +1,5 @@ use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; @@ -6,13 +7,15 @@ use thin_vec::ThinVec; use crate::attributes::{ AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct ProcMacroParser; impl NoArgsAttributeParser for ProcMacroParser { const PATH: &[Symbol] = &[sym::proc_macro]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro; } @@ -20,6 +23,8 @@ pub(crate) struct ProcMacroAttributeParser; impl NoArgsAttributeParser for ProcMacroAttributeParser { const PATH: &[Symbol] = &[sym::proc_macro_attribute]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute; } @@ -28,6 +33,8 @@ impl SingleAttributeParser for ProcMacroDeriveParser { const PATH: &[Symbol] = &[sym::proc_macro_derive]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Warn(Target::Crate)]); const TEMPLATE: AttributeTemplate = template!( List: &["TraitName", "TraitName, attributes(name1, name2, ...)"], "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros" @@ -48,6 +55,7 @@ impl SingleAttributeParser for RustcBuiltinMacroParser { const PATH: &[Symbol] = &[sym::rustc_builtin_macro]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); const TEMPLATE: AttributeTemplate = template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]); diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 996d2af5f3767..7ab58ed93474d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -2,14 +2,15 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::{AttributeKind, IntType, ReprAttr}; +use rustc_hir::{MethodKind, Target}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::{AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, FinalizeContext}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::Allow; +use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser}; use crate::session_diagnostics; use crate::session_diagnostics::IncorrectReprFormatGenericCause; - /// Parse #[repr(...)] forms. /// /// Valid repr contents: any of the primitive integral type names (see @@ -60,6 +61,10 @@ impl CombineAttributeParser for ReprParser { reprs } + + //FIXME Still checked fully in `check_attr.rs` + //This one is slightly more complicated because the allowed targets depend on the arguments + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); } macro_rules! int_pat { @@ -318,6 +323,14 @@ impl AlignParser { impl AttributeParser for AlignParser { const ATTRIBUTES: AcceptMapping = &[(Self::PATH, Self::TEMPLATE, Self::parse)]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + 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::ForeignFn), + ]); fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { let (align, span) = self.0?; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 1a668b4416f0c..efd7b650e4418 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -1,17 +1,19 @@ use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage, parse_single_integer}; +use crate::context::MaybeWarn::Allow; +use crate::context::{AcceptContext, AllowedTargets, Stage, parse_single_integer}; use crate::parser::ArgParser; - pub(crate) struct RustcLayoutScalarValidRangeStart; impl SingleAttributeParser for RustcLayoutScalarValidRangeStart { const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["start"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { @@ -26,6 +28,7 @@ impl SingleAttributeParser for RustcLayoutScalarValidRangeEnd { const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(List: &["end"]); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { @@ -40,6 +43,7 @@ impl SingleAttributeParser for RustcObjectLifetimeDefaultParser { const PATH: &[rustc_span::Symbol] = &[sym::rustc_object_lifetime_default]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]); const TEMPLATE: AttributeTemplate = template!(Word); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index 70a8a00209964..d4ad861a3a220 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -2,11 +2,11 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::Stage; - +use crate::context::{ALL_TARGETS, AllowedTargets, Stage}; pub(crate) struct MayDangleParser; impl NoArgsAttributeParser for MayDangleParser { const PATH: &[Symbol] = &[sym::may_dangle]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle; } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index c6707f5048b35..5a26178f84b58 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -4,15 +4,16 @@ use rustc_errors::ErrorGuaranteed; use rustc_feature::template; use rustc_hir::attrs::AttributeKind; use rustc_hir::{ - DefaultBodyStability, PartialConstStability, Stability, StabilityLevel, StableSince, - UnstableReason, VERSION_PLACEHOLDER, + DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel, + StableSince, Target, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_span::{Ident, Span, Symbol, sym}; use super::util::parse_version; use super::{AcceptMapping, AttributeParser, OnDuplicate}; use crate::attributes::NoArgsAttributeParser; -use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::context::MaybeWarn::Allow; +use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -26,6 +27,35 @@ macro_rules! reject_outside_std { }; } +const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::Union), + 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::Impl { of_trait: false }), + Allow(Target::Impl { of_trait: true }), + Allow(Target::MacroDef), + Allow(Target::Crate), + Allow(Target::Mod), + Allow(Target::Use), // FIXME I don't think this does anything? + Allow(Target::Const), + Allow(Target::AssocConst), + Allow(Target::AssocTy), + Allow(Target::Trait), + Allow(Target::TraitAlias), + Allow(Target::TyAlias), + Allow(Target::Variant), + Allow(Target::Field), + Allow(Target::Param), + Allow(Target::Static), + Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), +]); + #[derive(Default)] pub(crate) struct StabilityParser { allowed_through_unstable_modules: Option, @@ -87,6 +117,7 @@ impl AttributeParser for StabilityParser { }, ), ]; + const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS; fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option { if let Some(atum) = self.allowed_through_unstable_modules { @@ -142,6 +173,7 @@ impl AttributeParser for BodyStabilityParser { } }, )]; + const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { let (stability, span) = self.stability?; @@ -154,6 +186,10 @@ pub(crate) struct ConstStabilityIndirectParser; impl NoArgsAttributeParser for ConstStabilityIndirectParser { const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + ]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ConstStabilityIndirect; } @@ -213,6 +249,7 @@ impl AttributeParser for ConstStabilityParser { this.promotable = true; }), ]; + const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS; fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option { if self.promotable { diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 3267855fb0db4..8b666c3868baf 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -1,18 +1,21 @@ use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::AttributeLintKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Error}; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct IgnoreParser; impl SingleAttributeParser for IgnoreParser { const PATH: &[Symbol] = &[sym::ignore]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]); const TEMPLATE: AttributeTemplate = template!( Word, NameValueStr: "reason", "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute" @@ -54,6 +57,8 @@ impl SingleAttributeParser for ShouldPanicParser { const PATH: &[Symbol] = &[sym::should_panic]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]); const TEMPLATE: AttributeTemplate = template!( Word, List: &[r#"expected = "reason""#], NameValueStr: "reason", "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute" diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 8514d799aa485..ee9d7ba99cdc1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -2,19 +2,21 @@ use core::mem; use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::AttributeKind; +use rustc_hir::{MethodKind, Target}; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{ AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::{Allow, Warn}; +use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct SkipDuringMethodDispatchParser; impl SingleAttributeParser for SkipDuringMethodDispatchParser { const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]); @@ -58,6 +60,7 @@ pub(crate) struct ParenSugarParser; impl NoArgsAttributeParser for ParenSugarParser { const PATH: &[Symbol] = &[sym::rustc_paren_sugar]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ParenSugar; } @@ -65,6 +68,7 @@ pub(crate) struct TypeConstParser; impl NoArgsAttributeParser for TypeConstParser { const PATH: &[Symbol] = &[sym::type_const]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocConst)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::TypeConst; } @@ -74,6 +78,12 @@ pub(crate) struct MarkerParser; impl NoArgsAttributeParser for MarkerParser { const PATH: &[Symbol] = &[sym::marker]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Trait), + Warn(Target::Field), + Warn(Target::Arm), + Warn(Target::MacroDef), + ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::Marker; } @@ -81,6 +91,7 @@ pub(crate) struct DenyExplicitImplParser; impl NoArgsAttributeParser for DenyExplicitImplParser { const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl; } @@ -88,6 +99,7 @@ pub(crate) struct DoNotImplementViaObjectParser; impl NoArgsAttributeParser for DoNotImplementViaObjectParser { const PATH: &[Symbol] = &[sym::rustc_do_not_implement_via_object]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject; } @@ -98,6 +110,7 @@ pub(crate) struct ConstTraitParser; impl NoArgsAttributeParser for ConstTraitParser { const PATH: &[Symbol] = &[sym::const_trait]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstTrait; } @@ -107,6 +120,7 @@ pub(crate) struct SpecializationTraitParser; impl NoArgsAttributeParser for SpecializationTraitParser { const PATH: &[Symbol] = &[sym::rustc_specialization_trait]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::SpecializationTrait; } @@ -114,6 +128,7 @@ pub(crate) struct UnsafeSpecializationMarkerParser; impl NoArgsAttributeParser for UnsafeSpecializationMarkerParser { const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::UnsafeSpecializationMarker; } @@ -123,6 +138,7 @@ pub(crate) struct CoinductiveParser; impl NoArgsAttributeParser for CoinductiveParser { const PATH: &[Symbol] = &[sym::rustc_coinductive]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::Coinductive; } @@ -130,6 +146,8 @@ pub(crate) struct AllowIncoherentImplParser; impl NoArgsAttributeParser for AllowIncoherentImplParser { const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl; } @@ -137,6 +155,7 @@ pub(crate) struct CoherenceIsCoreParser; impl NoArgsAttributeParser for CoherenceIsCoreParser { const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore; } @@ -144,6 +163,8 @@ pub(crate) struct FundamentalParser; impl NoArgsAttributeParser for FundamentalParser { const PATH: &[Symbol] = &[sym::fundamental]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Struct), Allow(Target::Trait)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental; } @@ -151,5 +172,6 @@ pub(crate) struct PointeeParser; impl NoArgsAttributeParser for PointeeParser { const PATH: &[Symbol] = &[sym::pointee]; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs` const CREATE: fn(Span) -> AttributeKind = AttributeKind::Pointee; } diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index d4d68eb8b27d7..0ffcf434b5216 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,12 +1,13 @@ use rustc_feature::{AttributeTemplate, template}; +use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; use rustc_span::hygiene::Transparency; use rustc_span::{Symbol, sym}; use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, Stage}; +use crate::context::MaybeWarn::Allow; +use crate::context::{AcceptContext, AllowedTargets, Stage}; use crate::parser::ArgParser; - pub(crate) struct TransparencyParser; // FIXME(jdonszelmann): make these proper diagnostics @@ -18,6 +19,7 @@ impl SingleAttributeParser for TransparencyParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Custom(|cx, used, unused| { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); }); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]); const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["transparent", "semitransparent", "opaque"]); From 5245c399720cf4f2414c2a4d9b4a5007ad942956 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 9 Aug 2025 20:40:47 +0200 Subject: [PATCH 206/252] Remove the old target checking logic --- compiler/rustc_builtin_macros/messages.ftl | 2 - compiler/rustc_builtin_macros/src/errors.rs | 8 - .../src/proc_macro_harness.rs | 7 +- .../src/error_codes/E0518.md | 4 +- .../src/error_codes/E0701.md | 4 +- .../src/error_codes/E0739.md | 4 +- .../src/error_codes/E0755.md | 4 +- .../src/error_codes/E0756.md | 4 +- .../src/error_codes/E0788.md | 4 +- compiler/rustc_hir/src/hir.rs | 14 +- compiler/rustc_passes/messages.ftl | 152 +-- compiler/rustc_passes/src/check_attr.rs | 943 ++---------------- compiler/rustc_passes/src/errors.rs | 298 +----- 13 files changed, 138 insertions(+), 1310 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index ae186d744c40e..eb3c40cc593d3 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -259,8 +259,6 @@ builtin_macros_only_one_argument = {$name} takes 1 argument builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]` -builtin_macros_proc_macro_attribute_only_be_used_on_bare_functions = the `#[{$path}]` attribute may only be used on bare functions - builtin_macros_proc_macro_attribute_only_usable_with_crate_type = the `#[{$path}]` attribute is only usable with crates of the `proc-macro` crate type builtin_macros_requires_cfg_pattern = diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 6bcf4d3e0a2ee..bb520db75b96c 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -905,14 +905,6 @@ pub(crate) struct TakesNoArguments<'a> { pub name: &'a str, } -#[derive(Diagnostic)] -#[diag(builtin_macros_proc_macro_attribute_only_be_used_on_bare_functions)] -pub(crate) struct AttributeOnlyBeUsedOnBareFunctions<'a> { - #[primary_span] - pub span: Span, - pub path: &'a str, -} - #[derive(Diagnostic)] #[diag(builtin_macros_proc_macro_attribute_only_usable_with_crate_type)] pub(crate) struct AttributeOnlyUsableWithCrateType<'a> { diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index f440adf6cf0b1..6ac3e17503d09 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -231,12 +231,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { let fn_ident = if let ast::ItemKind::Fn(fn_) = &item.kind { fn_.ident } else { - self.dcx - .create_err(errors::AttributeOnlyBeUsedOnBareFunctions { - span: attr.span, - path: &pprust::path_to_string(&attr.get_normal_item().path), - }) - .emit(); + // Error handled by general target checking logic return; }; diff --git a/compiler/rustc_error_codes/src/error_codes/E0518.md b/compiler/rustc_error_codes/src/error_codes/E0518.md index f04329bc4e618..87dc231578ac0 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0518.md +++ b/compiler/rustc_error_codes/src/error_codes/E0518.md @@ -1,9 +1,11 @@ +#### Note: this error code is no longer emitted by the compiler. + An `#[inline(..)]` attribute was incorrectly placed on something other than a function or method. Example of erroneous code: -```compile_fail,E0518 +```ignore (no longer emitted) #[inline(always)] struct Foo; diff --git a/compiler/rustc_error_codes/src/error_codes/E0701.md b/compiler/rustc_error_codes/src/error_codes/E0701.md index 4965e64310591..e1be0e915f440 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0701.md +++ b/compiler/rustc_error_codes/src/error_codes/E0701.md @@ -1,9 +1,11 @@ +#### Note: this error code is no longer emitted by the compiler. + This error indicates that a `#[non_exhaustive]` attribute was incorrectly placed on something other than a struct or enum. Erroneous code example: -```compile_fail,E0701 +```ignore (no longer emitted) #[non_exhaustive] trait Foo { } ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0739.md b/compiler/rustc_error_codes/src/error_codes/E0739.md index 406d3d52779db..5403405ca9dc1 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0739.md +++ b/compiler/rustc_error_codes/src/error_codes/E0739.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + `#[track_caller]` must be applied to a function Erroneous code example: -```compile_fail,E0739 +```ignore (no longer emitted) #[track_caller] struct Bar { a: u8, diff --git a/compiler/rustc_error_codes/src/error_codes/E0755.md b/compiler/rustc_error_codes/src/error_codes/E0755.md index b67f078c78ec7..bd93626a8db4d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0755.md +++ b/compiler/rustc_error_codes/src/error_codes/E0755.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + The `ffi_pure` attribute was used on a non-foreign function. Erroneous code example: -```compile_fail,E0755 +```ignore (no longer emitted) #![feature(ffi_pure)] #[unsafe(ffi_pure)] // error! diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md index aadde038d12c9..daafc2a5ac092 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0756.md +++ b/compiler/rustc_error_codes/src/error_codes/E0756.md @@ -1,9 +1,11 @@ +#### Note: this error code is no longer emitted by the compiler. + The `ffi_const` attribute was used on something other than a foreign function declaration. Erroneous code example: -```compile_fail,E0756 +```ignore (no longer emitted) #![feature(ffi_const)] #[unsafe(ffi_const)] // error! diff --git a/compiler/rustc_error_codes/src/error_codes/E0788.md b/compiler/rustc_error_codes/src/error_codes/E0788.md index ba138aed2d12f..1afa961f9b7c5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0788.md +++ b/compiler/rustc_error_codes/src/error_codes/E0788.md @@ -1,3 +1,5 @@ +#### Note: this error code is no longer emitted by the compiler. + A `#[coverage(off|on)]` attribute was found in a position where it is not allowed. @@ -10,7 +12,7 @@ Coverage attributes can be applied to: Example of erroneous code: -```compile_fail,E0788 +```ignore (no longer emitted) unsafe extern "C" { #[coverage(off)] fn foreign_fn(); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 0cc03ef7b5b24..2c8986b7c7d01 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1232,6 +1232,13 @@ impl Attribute { _ => None, } } + + pub fn is_parsed_attr(&self) -> bool { + match self { + Attribute::Parsed(_) => true, + Attribute::Unparsed(_) => false, + } + } } impl AttributeExt for Attribute { @@ -1302,13 +1309,8 @@ impl AttributeExt for Attribute { match &self { Attribute::Unparsed(u) => u.span, // FIXME: should not be needed anymore when all attrs are parsed - Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, - Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => *span, - Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, - Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span, - Attribute::Parsed(AttributeKind::ShouldPanic { span, .. }) => *span, - Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span, + Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, Attribute::Parsed(AttributeKind::AllowInternalUnsafe(span)) => *span, Attribute::Parsed(AttributeKind::Linkage(_, span)) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index eb03235de0cb9..7481b0ea96018 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -13,22 +13,6 @@ passes_abi_ne = passes_abi_of = fn_abi_of({$fn_name}) = {$fn_abi} -passes_align_attr_application = - `#[rustc_align(...)]` should be applied to a function item - .label = not a function item - -passes_align_on_fields = - attribute should be applied to a function or method - .warn = {-passes_previously_accepted} - -passes_align_should_be_repr_align = - `#[rustc_align(...)]` is not supported on {$item} items - .suggestion = use `#[repr(align(...))]` instead - -passes_allow_incoherent_impl = - `rustc_allow_incoherent_impl` attribute should be applied to impl items - .label = the only currently supported targets are inherent methods - passes_macro_only_attribute = attribute should be applied to a macro .label = not a macro @@ -78,18 +62,10 @@ passes_change_fields_to_be_of_unit_type = *[other] fields } -passes_cold = - {passes_should_be_applied_to_fn} - .warn = {-passes_previously_accepted} - .label = {passes_should_be_applied_to_fn.label} - passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to macro definitions .label = not a macro definition -passes_confusables = attribute should be applied to an inherent method - .label = not an inherent method - passes_const_continue_attr = `#[const_continue]` should be applied to a break expression .label = not a break expression @@ -98,16 +74,6 @@ passes_const_stable_not_stable = attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]` .label = attribute specified here -passes_coroutine_on_non_closure = - attribute should be applied to closures - .label = not a closure - -passes_coverage_attribute_not_allowed = - coverage attribute not allowed here - .not_fn_impl_mod = not a function, impl block, or module - .no_body = function has no body - .help = coverage attribute can be applied to a function (with body), impl block, or module - passes_dead_codes = { $multiple -> *[true] multiple {$descr}s are @@ -129,9 +95,6 @@ passes_debug_visualizer_placement = passes_debug_visualizer_unreadable = couldn't read {$file}: {$error} -passes_deprecated = - attribute is ignored here - passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect .suggestion = remove the unnecessary deprecation attribute @@ -304,10 +267,6 @@ passes_duplicate_lang_item_crate_depends = passes_enum_variant_same_name = it is impossible to refer to the {$dead_descr} `{$dead_name}` because it is shadowed by this enum variant with the same name -passes_export_name = - attribute should be applied to a free function, impl method or static - .label = not a free function, impl method or static - passes_extern_main = the `main` function cannot be declared in an `extern` block @@ -317,21 +276,10 @@ passes_feature_previously_declared = passes_feature_stable_twice = feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since} -passes_ffi_const_invalid_target = - `#[ffi_const]` may only be used on foreign functions - -passes_ffi_pure_invalid_target = - `#[ffi_pure]` may only be used on foreign functions - passes_has_incoherent_inherent_impl = `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits .label = only adts, extern types and traits are supported -passes_ignored_attr = - `#[{$sym}]` is ignored on struct fields and match arms - .warn = {-passes_previously_accepted} - .note = {-passes_see_issue(issue: "80564")} - passes_ignored_attr_with_macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs .warn = {-passes_previously_accepted} @@ -373,22 +321,10 @@ passes_incorrect_target = passes_ineffective_unstable_impl = an `#[unstable]` annotation here has no effect .note = see issue #55436 for more information -passes_inline_ignored_constants = - `#[inline]` is ignored on constants - .warn = {-passes_previously_accepted} - .note = {-passes_see_issue(issue: "65833")} - passes_inline_ignored_for_exported = `#[inline]` is ignored on externally exported functions .help = externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]` -passes_inline_ignored_function_prototype = - `#[inline]` is ignored on function prototypes - -passes_inline_not_fn_or_closure = - attribute should be applied to function or closure - .label = not a function or closure - passes_inner_crate_level_attr = crate-level attribute should be in the root module @@ -438,25 +374,6 @@ passes_link = .warn = {-passes_previously_accepted} .label = not an `extern` block -passes_link_name = - attribute should be applied to a foreign function or static - .warn = {-passes_previously_accepted} - .label = not a foreign function or static - .help = try `#[link(name = "{$value}")]` instead - -passes_link_ordinal = - attribute should be applied to a foreign function or static - .label = not a foreign function or static - -passes_link_section = - attribute should be applied to a function or static - .warn = {-passes_previously_accepted} - .label = not a function or static - -passes_linkage = - attribute should be applied to a function or static - .label = not a function definition or static - passes_loop_match_attr = `#[loop_match]` should be applied to a loop .label = not a loop @@ -468,9 +385,6 @@ passes_macro_export_on_decl_macro = `#[macro_export]` has no effect on declarative macro definitions .note = declarative macros follow the same exporting rules as regular items -passes_macro_use = - `#[{$name}]` only has an effect on `extern crate` and modules - passes_may_dangle = `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl @@ -509,7 +423,7 @@ passes_must_not_suspend = .label = is not a struct, enum, union, or trait passes_must_use_no_effect = - `#[must_use]` has no effect when applied to {$article} {$target} + `#[must_use]` has no effect when applied to {$target} .suggestion = remove the attribute passes_no_link = @@ -530,18 +444,6 @@ passes_no_main_function = .teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/ .non_function_main = non-function item at `crate::main` is found -passes_no_mangle = - attribute should be applied to a free function, impl method or static - .warn = {-passes_previously_accepted} - .label = not a free function, impl method or static - -passes_no_mangle_foreign = - `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} - .warn = {-passes_previously_accepted} - .label = foreign {$foreign_item_kind} - .note = symbol names in extern blocks are not mangled - .suggestion = remove this attribute - passes_no_sanitize = `#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind} .label = not {$accepted_kind} @@ -557,19 +459,6 @@ passes_non_exported_macro_invalid_attrs = passes_object_lifetime_err = {$repr} -passes_only_has_effect_on = - `#[{$attr_name}]` only has an effect on {$target_name -> - [function] functions - [module] modules - [trait_implementation_block] trait implementation blocks - [inherent_implementation_block] inherent implementation blocks - *[unspecified] (unspecified--this is a compiler bug) - } - -passes_optimize_invalid_target = - attribute applied to an invalid target - .label = invalid target - passes_outer_crate_level_attr = crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` @@ -585,10 +474,6 @@ passes_parent_info = *[other] {$descr}s } in this {$parent_descr} -passes_pass_by_value = - `pass_by_value` attribute should be applied to a struct, enum or type alias - .label = is not a struct, enum or type alias - passes_proc_macro_bad_sig = {$kind} has incorrect signature passes_remove_fields = @@ -605,7 +490,7 @@ passes_repr_align_greater_than_target_max = .note = `isize::MAX` is {$size} for the current target passes_repr_align_should_be_align = - `#[repr(align(...))]` is not supported on {$item} items + `#[repr(align(...))]` is not supported on {$item} .help = use `#[rustc_align(...)]` instead passes_repr_conflicting = @@ -620,18 +505,10 @@ passes_rustc_const_stable_indirect_pairing = passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled -passes_rustc_force_inline = - attribute should be applied to a function - .label = not a function definition - passes_rustc_force_inline_coro = attribute cannot be applied to a `async`, `gen` or `async gen` function .label = `async`, `gen` or `async gen` function -passes_rustc_layout_scalar_valid_range_not_struct = - attribute should be applied to a struct - .label = not a struct - passes_rustc_legacy_const_generics_index = #[rustc_legacy_const_generics] must have one index for each generic parameter .label = generic parameters @@ -665,14 +542,6 @@ passes_rustc_pub_transparent = attribute should be applied to `#[repr(transparent)]` types .label = not a `#[repr(transparent)]` type -passes_rustc_std_internal_symbol = - attribute should be applied to functions or statics - .label = not a function or static - -passes_rustc_unstable_feature_bound = - attribute should be applied to `impl`, trait or free function - .label = not an `impl`, trait or free function - passes_should_be_applied_to_fn = attribute should be applied to a function definition .label = {$on_crate -> @@ -684,24 +553,12 @@ passes_should_be_applied_to_static = attribute should be applied to a static .label = not a static -passes_should_be_applied_to_struct_enum = - attribute should be applied to a struct or enum - .label = not a struct or enum - passes_should_be_applied_to_trait = attribute should be applied to a trait .label = not a trait -passes_stability_promotable = - attribute cannot be applied to an expression - passes_string_interpolation_only_works = string interpolation only works in `format!` invocations -passes_target_feature_on_statement = - {passes_should_be_applied_to_fn} - .warn = {-passes_previously_accepted} - .label = {passes_should_be_applied_to_fn.label} - passes_trait_impl_const_stability_mismatch = const stability on the impl does not match the const stability on the trait passes_trait_impl_const_stability_mismatch_impl_stable = this impl is (implicitly) stable... passes_trait_impl_const_stability_mismatch_impl_unstable = this impl is unstable... @@ -826,11 +683,6 @@ passes_unused_variable_try_prefix = unused variable: `{$name}` .label = unused variable .suggestion = if this is intentional, prefix it with an underscore - -passes_used_static = - attribute must be applied to a `static` variable - .label = but this is a {$target} - passes_useless_assignment = useless assignment of {$is_field_assign -> [true] field diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index df1db65c06e01..0e28c51e981f8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use std::slice; use rustc_abi::{Align, ExternAbi, Size}; -use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast, join_path_syms}; +use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; @@ -40,7 +40,6 @@ use rustc_session::lint; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, - USELESS_DEPRECATED, }; use rustc_session::parse::feature_err; use rustc_span::edition::Edition; @@ -50,7 +49,6 @@ use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; use tracing::debug; -use crate::errors::AlignOnFields; use crate::{errors, fluent_generated as fluent}; #[derive(LintDiagnostic)] @@ -134,56 +132,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::ProcMacroAttribute(_)) => { self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute); } - Attribute::Parsed(AttributeKind::ProcMacroDerive { span: attr_span, .. }) => { - self.check_generic_attr( - hir_id, - sym::proc_macro_derive, - *attr_span, - target, - Target::Fn, - ); + Attribute::Parsed(AttributeKind::ProcMacroDerive { .. }) => { self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) } - Attribute::Parsed( - AttributeKind::SkipDuringMethodDispatch { span: attr_span, .. } - | AttributeKind::Coinductive(attr_span) - | AttributeKind::ConstTrait(attr_span) - | AttributeKind::DenyExplicitImpl(attr_span) - | AttributeKind::DoNotImplementViaObject(attr_span), - ) => { - self.check_must_be_applied_to_trait(*attr_span, span, target); - } - &Attribute::Parsed( - AttributeKind::SpecializationTrait(attr_span) - | AttributeKind::UnsafeSpecializationMarker(attr_span) - | AttributeKind::ParenSugar(attr_span), - ) => { - // FIXME: more validation is needed - self.check_must_be_applied_to_trait(attr_span, span, target); - } &Attribute::Parsed(AttributeKind::TypeConst(attr_span)) => { self.check_type_const(hir_id, attr_span, target) } - &Attribute::Parsed(AttributeKind::Marker(attr_span)) => { - self.check_marker(hir_id, attr_span, span, target) - } - Attribute::Parsed(AttributeKind::Fundamental | AttributeKind::CoherenceIsCore) => { - // FIXME: add validation - } - &Attribute::Parsed(AttributeKind::AllowIncoherentImpl(attr_span)) => { - self.check_allow_incoherent_impl(attr_span, span, target) - } - Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => { - self.check_confusables(*first_span, target); - } - Attribute::Parsed(AttributeKind::AutomaticallyDerived(attr_span)) => self - .check_generic_attr( - hir_id, - sym::automatically_derived, - *attr_span, - target, - Target::Impl { of_trait: true }, - ), Attribute::Parsed( AttributeKind::Stability { span: attr_span, @@ -193,13 +147,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { span: attr_span, stability: PartialConstStability { level, feature, .. }, }, - ) => self.check_stability(*attr_span, span, level, *feature, target), + ) => self.check_stability(*attr_span, span, level, *feature), Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} // handled separately below Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => { - self.check_inline(hir_id, *attr_span, span, kind, target) - } - Attribute::Parsed(AttributeKind::Optimize(_, attr_span)) => { - self.check_optimize(hir_id, *attr_span, span, target) + self.check_inline(hir_id, *attr_span, kind, target) } Attribute::Parsed(AttributeKind::LoopMatch(attr_span)) => { self.check_loop_match(hir_id, *attr_span, target) @@ -207,11 +158,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => { self.check_const_continue(hir_id, *attr_span, target) } - Attribute::Parsed(AttributeKind::AllowInternalUnsafe(attr_span)) => { - self.check_allow_internal_unsafe(hir_id, *attr_span, span, target, attrs) - } - Attribute::Parsed(AttributeKind::AllowInternalUnstable(_, first_span)) => { - self.check_allow_internal_unstable(hir_id, *first_span, span, target, attrs) + Attribute::Parsed(AttributeKind::AllowInternalUnsafe(attr_span) | AttributeKind::AllowInternalUnstable(.., attr_span)) => { + self.check_macro_only_attr(*attr_span, span, target, attrs) } Attribute::Parsed(AttributeKind::AllowConstFnUnstable(_, first_span)) => { self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target) @@ -220,11 +168,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_deprecated(hir_id, attr, span, target) } Attribute::Parsed(AttributeKind::TargetFeature(_, attr_span)) => { - self.check_target_feature(hir_id, *attr_span, span, target, attrs) - } - Attribute::Parsed(AttributeKind::DocComment { .. }) => { /* `#[doc]` is actually a lot more than just doc comments, so is checked below*/ - } - Attribute::Parsed(AttributeKind::Repr { .. }) => { /* handled below this loop and elsewhere */ + self.check_target_feature(hir_id, *attr_span, target, attrs) } Attribute::Parsed(AttributeKind::RustcObjectLifetimeDefault) => { self.check_object_lifetime_default(hir_id); @@ -232,59 +176,26 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::PubTransparent(attr_span)) => { self.check_rustc_pub_transparent(attr_span, span, attrs) } - Attribute::Parsed(AttributeKind::Cold(attr_span)) => { - self.check_cold(hir_id, *attr_span, span, target) - } - Attribute::Parsed(AttributeKind::ExportName { span: attr_span, .. }) => { - self.check_export_name(hir_id, *attr_span, span, target) - } Attribute::Parsed(AttributeKind::Align { align, span: attr_span }) => { - self.check_align(span, hir_id, target, *align, *attr_span) - } - Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => { - self.check_link_section(hir_id, *attr_span, span, target) - } - Attribute::Parsed(AttributeKind::MacroUse { span, .. }) => { - self.check_macro_use(hir_id, sym::macro_use, *span, target) + self.check_align(*align, *attr_span) } - Attribute::Parsed(AttributeKind::MacroEscape(span)) => { - self.check_macro_use(hir_id, sym::macro_escape, *span, target) - } - Attribute::Parsed(AttributeKind::Naked(attr_span)) => { - self.check_naked(hir_id, *attr_span, span, target) - } - Attribute::Parsed(AttributeKind::NoImplicitPrelude(attr_span)) => self - .check_generic_attr( - hir_id, - sym::no_implicit_prelude, - *attr_span, - target, - Target::Mod, - ), - Attribute::Parsed(AttributeKind::Path(_, attr_span)) => { - self.check_generic_attr(hir_id, sym::path, *attr_span, target, Target::Mod) + Attribute::Parsed(AttributeKind::Naked(..)) => { + self.check_naked(hir_id, target) } Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => { - self.check_track_caller(hir_id, *attr_span, attrs, span, target) + self.check_track_caller(hir_id, *attr_span, attrs, target) } Attribute::Parsed(AttributeKind::NonExhaustive(attr_span)) => { - self.check_non_exhaustive(hir_id, *attr_span, span, target, item) - } - Attribute::Parsed( - AttributeKind::RustcLayoutScalarValidRangeStart(_num, attr_span) - | AttributeKind::RustcLayoutScalarValidRangeEnd(_num, attr_span), - ) => self.check_rustc_layout_scalar_valid_range(*attr_span, span, target), - Attribute::Parsed(AttributeKind::ExportStable) => { - // handled in `check_export` - } - &Attribute::Parsed(AttributeKind::FfiConst(attr_span)) => { - self.check_ffi_const(attr_span, target) + self.check_non_exhaustive(*attr_span, span, target, item) } &Attribute::Parsed(AttributeKind::FfiPure(attr_span)) => { - self.check_ffi_pure(attr_span, attrs, target) + self.check_ffi_pure(attr_span, attrs) } - Attribute::Parsed(AttributeKind::UnstableFeatureBound(syms)) => { - self.check_unstable_feature_bound(syms.first().unwrap().1, span, target) + Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { + self.check_may_dangle(hir_id, *attr_span) + } + Attribute::Parsed(AttributeKind::MustUse { span, .. }) => { + self.check_must_use(hir_id, *span, target) } Attribute::Parsed( AttributeKind::BodyStability { .. } @@ -292,49 +203,52 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::MacroTransparency(_) | AttributeKind::Pointee(..) | AttributeKind::Dummy - | AttributeKind::RustcBuiltinMacro { .. }, + | AttributeKind::RustcBuiltinMacro { .. } + | AttributeKind::Ignore { .. } + | AttributeKind::Path(..) + | AttributeKind::NoImplicitPrelude(..) + | AttributeKind::AutomaticallyDerived(..) + | AttributeKind::Marker(..) + | AttributeKind::SkipDuringMethodDispatch { .. } + | AttributeKind::Coinductive(..) + | AttributeKind::ConstTrait(..) + | AttributeKind::DenyExplicitImpl(..) + | AttributeKind::DoNotImplementViaObject(..) + | AttributeKind::SpecializationTrait(..) + | AttributeKind::UnsafeSpecializationMarker(..) + | AttributeKind::ParenSugar(..) + | AttributeKind::AllowIncoherentImpl(..) + | AttributeKind::Confusables { .. } + // `#[doc]` is actually a lot more than just doc comments, so is checked below + | AttributeKind::DocComment {..} + // handled below this loop and elsewhere + | AttributeKind::Repr { .. } + | AttributeKind::Cold(..) + | AttributeKind::ExportName { .. } + | AttributeKind::CoherenceIsCore + | AttributeKind::Fundamental + | AttributeKind::Optimize(..) + | AttributeKind::LinkSection { .. } + | AttributeKind::MacroUse { .. } + | AttributeKind::MacroEscape( .. ) + | AttributeKind::RustcLayoutScalarValidRangeStart(..) + | AttributeKind::RustcLayoutScalarValidRangeEnd(..) + | AttributeKind::ExportStable + | AttributeKind::FfiConst(..) + | AttributeKind::UnstableFeatureBound(..) + | AttributeKind::AsPtr(..) + | AttributeKind::LinkName { .. } + | AttributeKind::LinkOrdinal { .. } + | AttributeKind::NoMangle(..) + | AttributeKind::Used { .. } + | AttributeKind::PassByValue (..) + | AttributeKind::StdInternalSymbol (..) + | AttributeKind::Coverage (..) + | AttributeKind::ShouldPanic { .. } + | AttributeKind::Coroutine(..) + | AttributeKind::Linkage(..), ) => { /* do nothing */ } - Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { - self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) - } - Attribute::Parsed(AttributeKind::LinkName { span: attr_span, name }) => { - self.check_link_name(hir_id, *attr_span, *name, span, target) - } - Attribute::Parsed(AttributeKind::LinkOrdinal { span: attr_span, .. }) => { - self.check_link_ordinal(*attr_span, span, target) - } - Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { - self.check_may_dangle(hir_id, *attr_span) - } - Attribute::Parsed(AttributeKind::Ignore { span, .. }) => { - self.check_generic_attr(hir_id, sym::ignore, *span, target, Target::Fn) - } - Attribute::Parsed(AttributeKind::MustUse { span, .. }) => { - self.check_must_use(hir_id, *span, target) - } - Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => { - self.check_no_mangle(hir_id, *attr_span, span, target) - } - Attribute::Parsed(AttributeKind::Used { span: attr_span, .. }) => { - self.check_used(*attr_span, target, span); - } - Attribute::Parsed(AttributeKind::ShouldPanic { span: attr_span, .. }) => self - .check_generic_attr(hir_id, sym::should_panic, *attr_span, target, Target::Fn), - &Attribute::Parsed(AttributeKind::PassByValue(attr_span)) => { - self.check_pass_by_value(attr_span, span, target) - } - &Attribute::Parsed(AttributeKind::StdInternalSymbol(attr_span)) => { - self.check_rustc_std_internal_symbol(attr_span, span, target) - } - &Attribute::Parsed(AttributeKind::Coverage(attr_span, _)) => { - self.check_coverage(attr_span, span, target) - } - &Attribute::Parsed(AttributeKind::Coroutine(attr_span)) => { - self.check_coroutine(attr_span, target) - } - &Attribute::Parsed(AttributeKind::Linkage(_, attr_span)) => { - self.check_linkage(attr_span, span, target); - } + Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -390,10 +304,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_has_incoherent_inherent_impls, ..] => { self.check_has_incoherent_inherent_impls(attr, span, target) } - [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span(), attrs, target), - [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), [sym::link, ..] => self.check_link(hir_id, attr, span, target), - [sym::path, ..] => self.check_generic_attr_unparsed(hir_id, attr, target, Target::Mod), [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) @@ -485,7 +396,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } self.check_repr(attrs, span, target, item, hir_id); - self.check_rustc_force_inline(hir_id, attrs, span, target); + self.check_rustc_force_inline(hir_id, attrs, target); self.check_mix_no_mangle_export(hir_id, attrs); } @@ -498,15 +409,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); } - fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::IgnoredAttr { sym }, - ); - } - /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl and that it has no /// arguments. fn check_do_not_recommend( @@ -554,14 +456,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if an `#[inline]` is applied to a function or a closure. - fn check_inline( - &self, - hir_id: HirId, - attr_span: Span, - defn_span: Span, - kind: &InlineAttr, - target: Target, - ) { + fn check_inline(&self, hir_id: HirId, attr_span: Span, kind: &InlineAttr, target: Target) { match target { Target::Fn | Target::Closure @@ -583,81 +478,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } - Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::IgnoredInlineAttrFnProto, - ) - } - // FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with - // just a lint, because we previously erroneously allowed it and some crates used it - // accidentally, to be compatible with crates depending on them, we can't throw an - // error here. - Target::AssocConst => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::IgnoredInlineAttrConstants, - ), - // FIXME(#80564): Same for fields, arms, and macro defs - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "inline") - } - _ => { - self.dcx().emit_err(errors::InlineNotFnOrClosure { attr_span, defn_span }); - } - } - } - - /// Checks that `#[coverage(..)]` is applied to a function/closure/method, - /// or to an impl block or module. - fn check_coverage(&self, attr_span: Span, target_span: Span, target: Target) { - let mut not_fn_impl_mod = None; - let mut no_body = None; - - match target { - Target::Fn - | Target::Closure - | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) - | Target::Impl { .. } - | Target::Mod => return, - - // These are "functions", but they aren't allowed because they don't - // have a body, so the usual explanation would be confusing. - Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { - no_body = Some(target_span); - } - - _ => { - not_fn_impl_mod = Some(target_span); - } - } - - self.dcx().emit_err(errors::CoverageAttributeNotAllowed { - attr_span, - not_fn_impl_mod, - no_body, - help: (), - }); - } - - /// Checks that `#[optimize(..)]` is applied to a function/closure/method, - /// or to an impl block or module. - fn check_optimize(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { - let is_valid = matches!( - target, - Target::Fn - | Target::Closure - | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) - ); - if !is_valid { - self.dcx().emit_err(errors::OptimizeInvalidTarget { - attr_span, - defn_span: span, - on_crate: hir_id == CRATE_HIR_ID, - }); + _ => {} } } @@ -697,51 +518,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// FIXME: Remove when all attributes are ported to the new parser - fn check_generic_attr_unparsed( - &self, - hir_id: HirId, - attr: &Attribute, - target: Target, - allowed_target: Target, - ) { - if target != allowed_target { - let attr_name = join_path_syms(attr.path()); - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::OnlyHasEffectOn { - attr_name, - target_name: allowed_target.name().replace(' ', "_"), - }, - ); - } - } - - fn check_generic_attr( - &self, - hir_id: HirId, - attr_name: Symbol, - attr_span: Span, - target: Target, - allowed_target: Target, - ) { - if target != allowed_target { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::OnlyHasEffectOn { - attr_name: attr_name.to_string(), - target_name: allowed_target.name().replace(' ', "_"), - }, - ); - } - } - /// Checks if `#[naked]` is applied to a function definition. - fn check_naked(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { + fn check_naked(&self, hir_id: HirId, target: Target) { match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { @@ -760,13 +538,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { .emit(); } } - _ => { - self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span, - defn_span: span, - on_crate: hir_id == CRATE_HIR_ID, - }); - } + _ => {} } } @@ -809,7 +581,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { hir_id: HirId, attr_span: Span, attrs: &[Attribute], - span: Span, target: Target, ) { match target { @@ -829,28 +600,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }); } } - Target::Method(..) | Target::ForeignFn | Target::Closure => {} - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[track_caller]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "track_caller"); - } - _ => { - self.dcx().emit_err(errors::TrackedCallerWrongLocation { - attr_span, - defn_span: span, - on_crate: hir_id == CRATE_HIR_ID, - }); - } + _ => {} } } /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. fn check_non_exhaustive( &self, - hir_id: HirId, attr_span: Span, span: Span, target: Target, @@ -871,36 +627,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }); } } - Target::Enum | Target::Variant => {} - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[non_exhaustive]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "non_exhaustive"); - } - _ => { - self.dcx() - .emit_err(errors::NonExhaustiveWrongLocation { attr_span, defn_span: span }); - } - } - } - - /// Checks if the `#[marker]` attribute on an `item` is valid. - fn check_marker(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { - match target { - Target::Trait => {} - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[marker]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "marker"); - } - _ => { - self.dcx() - .emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span: span }); - } + _ => {} } } @@ -909,7 +636,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &self, hir_id: HirId, attr_span: Span, - span: Span, target: Target, attrs: &[Attribute], ) { @@ -932,30 +658,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }); } } - // FIXME: #[target_feature] was previously erroneously allowed on statements and some - // crates used this, so only emit a warning. - Target::Statement => { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::TargetFeatureOnStatement, - ); - } - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[target_feature]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "target_feature"); - } - _ => { - self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span, - defn_span: span, - on_crate: hir_id == CRATE_HIR_ID, - }); - } + _ => {} } } @@ -1059,7 +762,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::GenericParam { .. } | Target::MacroDef | Target::PatField - | Target::ExprField => None, + | Target::ExprField + | Target::Crate + | Target::MacroCall + | Target::Delegation { .. } => None, } { tcx.dcx().emit_err(errors::DocAliasBadLocation { span, attr_str, location }); return; @@ -1535,25 +1241,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Warns against some misuses of `#[pass_by_value]` - fn check_pass_by_value(&self, attr_span: Span, span: Span, target: Target) { - match target { - Target::Struct | Target::Enum | Target::TyAlias => {} - _ => { - self.dcx().emit_err(errors::PassByValue { attr_span, span }); - } - } - } - - fn check_allow_incoherent_impl(&self, attr_span: Span, span: Span, target: Target) { - match target { - Target::Method(MethodKind::Inherent) => {} - _ => { - self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span, span }); - } - } - } - fn check_has_incoherent_inherent_impls(&self, attr: &Attribute, span: Span, target: Target) { match target { Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {} @@ -1565,23 +1252,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute], target: Target) { - if target != Target::ForeignFn { - self.dcx().emit_err(errors::FfiPureInvalidTarget { attr_span }); - return; - } + fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute]) { if find_attr!(attrs, AttributeKind::FfiConst(_)) { // `#[ffi_const]` functions cannot be `#[ffi_pure]` self.dcx().emit_err(errors::BothFfiConstAndPure { attr_span }); } } - fn check_ffi_const(&self, attr_span: Span, target: Target) { - if target != Target::ForeignFn { - self.dcx().emit_err(errors::FfiConstInvalidTarget { attr_span }); - } - } - /// Warns against some misuses of `#[must_use]` fn check_must_use(&self, hir_id: HirId, attr_span: Span, target: Target) { if matches!( @@ -1609,22 +1286,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } - let article = match target { - Target::ExternCrate - | Target::Enum - | Target::Impl { .. } - | Target::Expression - | Target::Arm - | Target::AssocConst - | Target::AssocTy => "an", - _ => "a", - }; - self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, attr_span, - errors::MustUseNoEffect { article, target, attr_span }, + errors::MustUseNoEffect { target: target.plural_name(), attr_span }, ); } @@ -1659,30 +1325,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::InvalidMayDangle { attr_span }); } - /// Checks if `#[cold]` is applied to a non-function. - fn check_cold(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { - match target { - Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {} - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[cold]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "cold"); - } - _ => { - // FIXME: #[cold] was previously allowed on non-functions and some crates used - // this, so only emit a warning. - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::Cold { span, on_crate: hir_id == CRATE_HIR_ID }, - ); - } - } - } - /// Checks if `#[link]` is applied to an item other than a foreign module. fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { if target == Target::ForeignMod @@ -1701,38 +1343,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); } - /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. - fn check_link_name( - &self, - hir_id: HirId, - attr_span: Span, - name: Symbol, - span: Span, - target: Target, - ) { - match target { - Target::ForeignFn | Target::ForeignStatic => {} - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[link_name]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_name"); - } - _ => { - // FIXME: #[link_name] was previously allowed on non-functions/statics and some crates - // used this, so only emit a warning. - let help_span = matches!(target, Target::ForeignMod).then_some(attr_span); - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::LinkName { span, help_span, value: name.as_str() }, - ); - } - } - } - /// Checks if `#[no_link]` is applied to an `extern crate`. fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { match target { @@ -1750,35 +1360,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn is_impl_item(&self, hir_id: HirId) -> bool { - matches!(self.tcx.hir_node(hir_id), hir::Node::ImplItem(..)) - } - - /// Checks if `#[export_name]` is applied to a function or static. - fn check_export_name(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { - match target { - Target::Static | Target::Fn => {} - Target::Method(..) if self.is_impl_item(hir_id) => {} - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[export_name]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "export_name"); - } - _ => { - self.dcx().emit_err(errors::ExportName { attr_span, span }); - } - } - } - - fn check_rustc_layout_scalar_valid_range(&self, attr_span: Span, span: Span, target: Target) { - if target != Target::Struct { - self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { attr_span, span }); - return; - } - } - /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument. fn check_rustc_legacy_const_generics( &self, @@ -1913,106 +1494,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[link_section]` is applied to a function or static. - fn check_link_section(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { - match target { - Target::Static | Target::Fn | Target::Method(..) => {} - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[link_section]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_section"); - } - _ => { - // FIXME: #[link_section] was previously allowed on non-functions/statics and some - // crates used this, so only emit a warning. - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::LinkSection { span }, - ); - } - } - } - - /// Checks if `#[no_mangle]` is applied to a function or static. - fn check_no_mangle(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) { - match target { - Target::Static | Target::Fn => {} - Target::Method(..) if self.is_impl_item(hir_id) => {} - // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[no_mangle]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "no_mangle"); - } - // FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error - // The error should specify that the item that is wrong is specifically a *foreign* fn/static - // otherwise the error seems odd - Target::ForeignFn | Target::ForeignStatic => { - let foreign_item_kind = match target { - Target::ForeignFn => "function", - Target::ForeignStatic => "static", - _ => unreachable!(), - }; - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::NoMangleForeign { span, attr_span, foreign_item_kind }, - ); - } - _ => { - // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some - // crates used this, so only emit a warning. - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::NoMangle { span }, - ); - } - } - } - - /// Checks if the `#[align]` attributes on `item` are valid. - // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity - fn check_align( - &self, - span: Span, - hir_id: HirId, - target: Target, - align: Align, - attr_span: Span, - ) { - match target { - Target::Fn | Target::Method(_) | Target::ForeignFn => {} - Target::Field => { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - AlignOnFields { span }, - ); - } - Target::Struct | Target::Union | Target::Enum => { - self.dcx().emit_err(errors::AlignShouldBeReprAlign { - span: attr_span, - item: target.name(), - align_bytes: align.bytes(), - }); - } - _ => { - self.dcx().emit_err(errors::AlignAttrApplication { hint_span: attr_span, span }); - } - } - - self.check_align_value(align, attr_span); - } - /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, @@ -2067,7 +1548,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::Fn | Target::Method(_) => { self.dcx().emit_err(errors::ReprAlignShouldBeAlign { span: *repr_span, - item: target.name(), + item: target.plural_name(), }); } _ => { @@ -2078,7 +1559,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - self.check_align_value(*align, *repr_span); + self.check_align(*align, *repr_span); } ReprAttr::ReprPacked(_) => { if target != Target::Struct && target != Target::Union { @@ -2137,7 +1618,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::Fn | Target::Method(_) => { self.dcx().emit_err(errors::ReprAlignShouldBeAlign { span: first_attr_span, - item: target.name(), + item: target.plural_name(), }); } _ => { @@ -2184,7 +1665,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_align_value(&self, align: Align, span: Span) { + fn check_align(&self, align: Align, span: Span) { if align.bytes() > 2_u64.pow(29) { // for values greater than 2^29, a different error will be emitted, make sure that happens self.dcx().span_delayed_bug( @@ -2203,61 +1684,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_used(&self, attr_span: Span, target: Target, target_span: Span) { - if target != Target::Static { - self.dcx().emit_err(errors::UsedStatic { - attr_span, - span: target_span, - target: target.name(), - }); - } - } - - /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. - /// (Allows proc_macro functions) - fn check_allow_internal_unstable( - &self, - hir_id: HirId, - attr_span: Span, - span: Span, - target: Target, - attrs: &[Attribute], - ) { - self.check_macro_only_attr( - hir_id, - attr_span, - span, - target, - attrs, - "allow_internal_unstable", - ) - } - - /// Outputs an error for `#[allow_internal_unsafe]` which can only be applied to macros. - /// (Allows proc_macro functions) - fn check_allow_internal_unsafe( - &self, - hir_id: HirId, - attr_span: Span, - span: Span, - target: Target, - attrs: &[Attribute], - ) { - self.check_macro_only_attr(hir_id, attr_span, span, target, attrs, "allow_internal_unsafe") - } - /// Outputs an error for attributes that can only be applied to macros, such as /// `#[allow_internal_unsafe]` and `#[allow_internal_unstable]`. /// (Allows proc_macro functions) // FIXME(jdonszelmann): if possible, move to attr parsing fn check_macro_only_attr( &self, - hir_id: HirId, attr_span: Span, span: Span, target: Target, attrs: &[Attribute], - attr_name: &str, ) { match target { Target::Fn => { @@ -2267,23 +1703,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } } - // continue out of the match - } - // return on decl macros - Target::MacroDef => return, - // FIXME(#80564): We permit struct fields and match arms to have an - // `#[allow_internal_unstable]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm => { - self.inline_attr_str_error_without_macro_def(hir_id, attr_span, attr_name); - return; + self.tcx.dcx().emit_err(errors::MacroOnlyAttribute { attr_span, span }); } - // otherwise continue out of the match _ => {} } - - self.tcx.dcx().emit_err(errors::MacroOnlyAttribute { attr_span, span }); } /// Checks if the items on the `#[debugger_visualizer]` attribute are valid. @@ -2310,66 +1733,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: Target, ) { match target { - Target::Fn | Target::Method(_) - if self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) => {} - // FIXME(#80564): We permit struct fields and match arms to have an - // `#[allow_internal_unstable]` attribute with just a lint, because we previously - // erroneously allowed it and some crates used it accidentally, to be compatible - // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm | Target::MacroDef => self - .inline_attr_str_error_with_macro_def(hir_id, attr_span, "allow_internal_unstable"), - _ => { - self.tcx.dcx().emit_err(errors::RustcAllowConstFnUnstable { attr_span, span }); - } - } - } - - fn check_unstable_feature_bound(&self, attr_span: Span, span: Span, target: Target) { - match target { - // FIXME(staged_api): There's no reason we can't support more targets here. We're just - // being conservative to begin with. - Target::Fn | Target::Impl { .. } | Target::Trait => {} - Target::ExternCrate - | Target::Use - | Target::Static - | Target::Const - | Target::Closure - | Target::Mod - | Target::ForeignMod - | Target::GlobalAsm - | Target::TyAlias - | Target::Enum - | Target::Variant - | Target::Struct - | Target::Field - | Target::Union - | Target::TraitAlias - | Target::Expression - | Target::Statement - | Target::Arm - | Target::AssocConst - | Target::Method(_) - | Target::AssocTy - | Target::ForeignFn - | Target::ForeignStatic - | Target::ForeignTy - | Target::GenericParam { .. } - | Target::MacroDef - | Target::Param - | Target::PatField - | Target::ExprField - | Target::WherePredicate => { - self.tcx.dcx().emit_err(errors::RustcUnstableFeatureBound { attr_span, span }); - } - } - } - - fn check_rustc_std_internal_symbol(&self, attr_span: Span, span: Span, target: Target) { - match target { - Target::Fn | Target::Static | Target::ForeignFn | Target::ForeignStatic => {} - _ => { - self.tcx.dcx().emit_err(errors::RustcStdInternalSymbol { attr_span, span }); + Target::Fn | Target::Method(_) => { + if !self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) { + self.tcx.dcx().emit_err(errors::RustcAllowConstFnUnstable { attr_span, span }); + } } + _ => {} } } @@ -2379,15 +1748,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { item_span: Span, level: &StabilityLevel, feature: Symbol, - target: Target, ) { - match target { - Target::Expression => { - self.dcx().emit_err(errors::StabilityPromotable { attr_span }); - } - _ => {} - } - // Stable *language* features shouldn't be used as unstable library features. // (Not doing this for stable library features is checked by tidy.) if level.is_unstable() @@ -2399,40 +1760,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_link_ordinal(&self, attr_span: Span, _span: Span, target: Target) { - match target { - Target::ForeignFn | Target::ForeignStatic => {} - _ => { - self.dcx().emit_err(errors::LinkOrdinal { attr_span }); - } - } - } - - fn check_confusables(&self, span: Span, target: Target) { - if !matches!(target, Target::Method(MethodKind::Inherent)) { - self.dcx().emit_err(errors::Confusables { attr_span: span }); - } - } - fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) { match target { - Target::Closure | Target::Expression | Target::Statement | Target::Arm => { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::Deprecated, - ); - } - Target::Impl { of_trait: true } - | Target::GenericParam { has_default: false, kind: _ } => { - self.tcx.emit_node_span_lint( - USELESS_DEPRECATED, - hir_id, - attr.span(), - errors::DeprecatedAnnotationHasNoEffect { span: attr.span() }, - ); - } Target::AssocConst | Target::Method(..) | Target::AssocTy if matches!( self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id)), @@ -2440,7 +1769,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) => { self.tcx.emit_node_span_lint( - USELESS_DEPRECATED, + UNUSED_ATTRIBUTES, hir_id, attr.span(), errors::DeprecatedAnnotationHasNoEffect { span: attr.span() }, @@ -2450,20 +1779,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_macro_use(&self, hir_id: HirId, name: Symbol, attr_span: Span, target: Target) { - match target { - Target::ExternCrate | Target::Mod => {} - _ => { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr_span, - errors::MacroUse { name }, - ); - } - } - } - fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) { if target != Target::MacroDef { self.tcx.emit_node_span_lint( @@ -2683,15 +1998,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_coroutine(&self, attr_span: Span, target: Target) { - match target { - Target::Closure => return, - _ => { - self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr_span }); - } - } - } - fn check_type_const(&self, hir_id: HirId, attr_span: Span, target: Target) { let tcx = self.tcx; if target == Target::AssocConst @@ -2709,19 +2015,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_linkage(&self, attr_span: Span, span: Span, target: Target) { - match target { - Target::Fn - | Target::Method(..) - | Target::Static - | Target::ForeignStatic - | Target::ForeignFn => {} - _ => { - self.dcx().emit_err(errors::Linkage { attr_span, span }); - } - } - } - fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) { if !find_attr!(attrs, AttributeKind::Repr { reprs, .. } => reprs.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent)) .unwrap_or(false) @@ -2730,43 +2023,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_rustc_force_inline( - &self, - hir_id: HirId, - attrs: &[Attribute], - span: Span, - target: Target, - ) { - match ( + fn check_rustc_force_inline(&self, hir_id: HirId, attrs: &[Attribute], target: Target) { + if let (Target::Closure, None) = ( target, find_attr!(attrs, AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span), ) { - (Target::Closure, None) => { - let is_coro = matches!( - self.tcx.hir_expect_expr(hir_id).kind, - hir::ExprKind::Closure(hir::Closure { - kind: hir::ClosureKind::Coroutine(..) - | hir::ClosureKind::CoroutineClosure(..), - .. - }) - ); - let parent_did = self.tcx.hir_get_parent_item(hir_id).to_def_id(); - let parent_span = self.tcx.def_span(parent_did); + let is_coro = matches!( + self.tcx.hir_expect_expr(hir_id).kind, + hir::ExprKind::Closure(hir::Closure { + kind: hir::ClosureKind::Coroutine(..) | hir::ClosureKind::CoroutineClosure(..), + .. + }) + ); + let parent_did = self.tcx.hir_get_parent_item(hir_id).to_def_id(); + let parent_span = self.tcx.def_span(parent_did); - if let Some(attr_span) = find_attr!( - self.tcx.get_all_attrs(parent_did), - AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span - ) && is_coro - { - self.dcx() - .emit_err(errors::RustcForceInlineCoro { attr_span, span: parent_span }); - } - } - (Target::Fn, _) => (), - (_, Some(attr_span)) => { - self.dcx().emit_err(errors::RustcForceInline { attr_span, span }); + if let Some(attr_span) = find_attr!( + self.tcx.get_all_attrs(parent_did), + AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span + ) && is_coro + { + self.dcx().emit_err(errors::RustcForceInlineCoro { attr_span, span: parent_span }); } - (_, None) => (), } } @@ -2816,8 +2094,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let node_span = self.tcx.hir_span(hir_id); if !matches!(target, Target::Expression) { - self.dcx().emit_err(errors::LoopMatchAttr { attr_span, node_span }); - return; + return; // Handled in target checking during attr parse } if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Loop(..)) { @@ -2829,8 +2106,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let node_span = self.tcx.hir_span(hir_id); if !matches!(target, Target::Expression) { - self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span }); - return; + return; // Handled in target checking during attr parse } if !matches!(self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Break(..)) { @@ -2873,6 +2149,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { .hir_attrs(where_predicate.hir_id) .iter() .filter(|attr| !ATTRS_ALLOWED.iter().any(|&sym| attr.has_name(sym))) + .filter(|attr| !attr.is_parsed_attr()) .map(|attr| attr.span()) .collect::>(); if !spans.is_empty() { @@ -3003,10 +2280,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { }) = attr { (*first_attr_span, sym::repr) - } else if let Attribute::Parsed(AttributeKind::Path(.., span)) = attr { - (*span, sym::path) - } else if let Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) = attr { - (*span, sym::automatically_derived) } else { continue; }; diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 37216656e57fe..c5d5155d0e5a5 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -75,58 +75,6 @@ pub(crate) struct IgnoredAttrWithMacro<'a> { pub sym: &'a str, } -#[derive(LintDiagnostic)] -#[diag(passes_ignored_attr)] -pub(crate) struct IgnoredAttr<'a> { - pub sym: &'a str, -} - -#[derive(LintDiagnostic)] -#[diag(passes_inline_ignored_function_prototype)] -pub(crate) struct IgnoredInlineAttrFnProto; - -#[derive(LintDiagnostic)] -#[diag(passes_inline_ignored_constants)] -#[warning] -#[note] -pub(crate) struct IgnoredInlineAttrConstants; - -#[derive(Diagnostic)] -#[diag(passes_inline_not_fn_or_closure, code = E0518)] -pub(crate) struct InlineNotFnOrClosure { - #[primary_span] - pub attr_span: Span, - #[label] - pub defn_span: Span, -} - -/// "coverage attribute not allowed here" -#[derive(Diagnostic)] -#[diag(passes_coverage_attribute_not_allowed, code = E0788)] -pub(crate) struct CoverageAttributeNotAllowed { - #[primary_span] - pub attr_span: Span, - /// "not a function, impl block, or module" - #[label(passes_not_fn_impl_mod)] - pub not_fn_impl_mod: Option, - /// "function has no body" - #[label(passes_no_body)] - pub no_body: Option, - /// "coverage attribute can be applied to a function (with body), impl block, or module" - #[help] - pub help: (), -} - -#[derive(Diagnostic)] -#[diag(passes_optimize_invalid_target)] -pub(crate) struct OptimizeInvalidTarget { - #[primary_span] - pub attr_span: Span, - #[label] - pub defn_span: Span, - pub on_crate: bool, -} - #[derive(Diagnostic)] #[diag(passes_should_be_applied_to_fn)] pub(crate) struct AttrShouldBeAppliedToFn { @@ -137,25 +85,6 @@ pub(crate) struct AttrShouldBeAppliedToFn { pub on_crate: bool, } -#[derive(Diagnostic)] -#[diag(passes_should_be_applied_to_fn, code = E0739)] -pub(crate) struct TrackedCallerWrongLocation { - #[primary_span] - pub attr_span: Span, - #[label] - pub defn_span: Span, - pub on_crate: bool, -} - -#[derive(Diagnostic)] -#[diag(passes_should_be_applied_to_struct_enum, code = E0701)] -pub(crate) struct NonExhaustiveWrongLocation { - #[primary_span] - pub attr_span: Span, - #[label] - pub defn_span: Span, -} - #[derive(Diagnostic)] #[diag(passes_non_exhaustive_with_default_field_values)] pub(crate) struct NonExhaustiveWithDefaultFieldValues { @@ -174,10 +103,6 @@ pub(crate) struct AttrShouldBeAppliedToTrait { pub defn_span: Span, } -#[derive(LintDiagnostic)] -#[diag(passes_target_feature_on_statement)] -pub(crate) struct TargetFeatureOnStatement; - #[derive(Diagnostic)] #[diag(passes_should_be_applied_to_static)] pub(crate) struct AttrShouldBeAppliedToStatic { @@ -416,24 +341,6 @@ pub(crate) struct DocTestUnknownInclude { #[diag(passes_doc_invalid)] pub(crate) struct DocInvalid; -#[derive(Diagnostic)] -#[diag(passes_pass_by_value)] -pub(crate) struct PassByValue { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_allow_incoherent_impl)] -pub(crate) struct AllowIncoherentImpl { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_has_incoherent_inherent_impl)] pub(crate) struct HasIncoherentInherentImpl { @@ -450,25 +357,10 @@ pub(crate) struct BothFfiConstAndPure { pub attr_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_ffi_pure_invalid_target, code = E0755)] -pub(crate) struct FfiPureInvalidTarget { - #[primary_span] - pub attr_span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_ffi_const_invalid_target, code = E0756)] -pub(crate) struct FfiConstInvalidTarget { - #[primary_span] - pub attr_span: Span, -} - #[derive(LintDiagnostic)] #[diag(passes_must_use_no_effect)] pub(crate) struct MustUseNoEffect { - pub article: &'static str, - pub target: rustc_hir::Target, + pub target: &'static str, #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] pub attr_span: Span, } @@ -482,15 +374,6 @@ pub(crate) struct MustNotSuspend { pub span: Span, } -#[derive(LintDiagnostic)] -#[diag(passes_cold)] -#[warning] -pub(crate) struct Cold { - #[label] - pub span: Span, - pub on_crate: bool, -} - #[derive(LintDiagnostic)] #[diag(passes_link)] #[warning] @@ -499,17 +382,6 @@ pub(crate) struct Link { pub span: Option, } -#[derive(LintDiagnostic)] -#[diag(passes_link_name)] -#[warning] -pub(crate) struct LinkName<'a> { - #[help] - pub help_span: Option, - #[label] - pub span: Span, - pub value: &'a str, -} - #[derive(Diagnostic)] #[diag(passes_no_link)] pub(crate) struct NoLink { @@ -519,24 +391,6 @@ pub(crate) struct NoLink { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_export_name)] -pub(crate) struct ExportName { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_rustc_layout_scalar_valid_range_not_struct)] -pub(crate) struct RustcLayoutScalarValidRangeNotStruct { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_rustc_legacy_const_generics_only)] pub(crate) struct RustcLegacyConstGenericsOnly { @@ -578,42 +432,6 @@ pub(crate) struct RustcDirtyClean { pub span: Span, } -#[derive(LintDiagnostic)] -#[diag(passes_link_section)] -#[warning] -pub(crate) struct LinkSection { - #[label] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(passes_no_mangle_foreign)] -#[warning] -#[note] -pub(crate) struct NoMangleForeign { - #[label] - pub span: Span, - #[suggestion(code = "", applicability = "machine-applicable")] - pub attr_span: Span, - pub foreign_item_kind: &'static str, -} - -#[derive(LintDiagnostic)] -#[diag(passes_no_mangle)] -#[warning] -pub(crate) struct NoMangle { - #[label] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(passes_align_on_fields)] -#[warning] -pub(crate) struct AlignOnFields { - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_repr_conflicting, code = E0566)] pub(crate) struct ReprConflicting { @@ -634,16 +452,6 @@ pub(crate) struct InvalidReprAlignForTarget { #[diag(passes_repr_conflicting, code = E0566)] pub(crate) struct ReprConflictingLint; -#[derive(Diagnostic)] -#[diag(passes_used_static)] -pub(crate) struct UsedStatic { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, - pub target: &'static str, -} - #[derive(Diagnostic)] #[diag(passes_macro_only_attribute)] pub(crate) struct MacroOnlyAttribute { @@ -688,24 +496,6 @@ pub(crate) struct RustcAllowConstFnUnstable { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_rustc_unstable_feature_bound)] -pub(crate) struct RustcUnstableFeatureBound { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_rustc_std_internal_symbol)] -pub(crate) struct RustcStdInternalSymbol { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_rustc_pub_transparent)] pub(crate) struct RustcPubTransparent { @@ -715,15 +505,6 @@ pub(crate) struct RustcPubTransparent { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_rustc_force_inline)] -pub(crate) struct RustcForceInline { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_rustc_force_inline_coro)] pub(crate) struct RustcForceInlineCoro { @@ -733,53 +514,6 @@ pub(crate) struct RustcForceInlineCoro { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_link_ordinal)] -pub(crate) struct LinkOrdinal { - #[primary_span] - pub attr_span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_confusables)] -pub(crate) struct Confusables { - #[primary_span] - pub attr_span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_coroutine_on_non_closure)] -pub(crate) struct CoroutineOnNonClosure { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_linkage)] -pub(crate) struct Linkage { - #[primary_span] - pub attr_span: Span, - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_stability_promotable)] -pub(crate) struct StabilityPromotable { - #[primary_span] - pub attr_span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(passes_deprecated)] -pub(crate) struct Deprecated; - -#[derive(LintDiagnostic)] -#[diag(passes_macro_use)] -pub(crate) struct MacroUse { - pub name: Symbol, -} - #[derive(LintDiagnostic)] pub(crate) enum MacroExport { #[diag(passes_macro_export)] @@ -1282,13 +1016,6 @@ pub(crate) struct UselessAssignment<'a> { pub ty: Ty<'a>, } -#[derive(LintDiagnostic)] -#[diag(passes_only_has_effect_on)] -pub(crate) struct OnlyHasEffectOn { - pub attr_name: String, - pub target_name: String, -} - #[derive(LintDiagnostic)] #[diag(passes_inline_ignored_for_exported)] #[help] @@ -1843,26 +1570,3 @@ pub(crate) struct ReprAlignShouldBeAlign { pub span: Span, pub item: &'static str, } - -#[derive(Diagnostic)] -#[diag(passes_align_should_be_repr_align)] -pub(crate) struct AlignShouldBeReprAlign { - #[primary_span] - #[suggestion( - style = "verbose", - applicability = "machine-applicable", - code = "#[repr(align({align_bytes}))]" - )] - pub span: Span, - pub item: &'static str, - pub align_bytes: u64, -} - -#[derive(Diagnostic)] -#[diag(passes_align_attr_application)] -pub(crate) struct AlignAttrApplication { - #[primary_span] - pub hint_span: Span, - #[label] - pub span: Span, -} From 4bb7bf64e07fee97439ee6e647aa2b58cbaac54d Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 9 Aug 2025 20:41:01 +0200 Subject: [PATCH 207/252] Update uitests Signed-off-by: Jonathan Brouwer --- tests/crashes/138510.rs | 7 - .../check-doc-alias-attr-location.stderr | 4 +- tests/ui/asm/naked-invalid-attr.rs | 12 +- tests/ui/asm/naked-invalid-attr.stderr | 73 +- tests/ui/attributes/attrs-on-params.rs | 2 +- tests/ui/attributes/attrs-on-params.stderr | 9 +- .../cold-attribute-application-54044.rs | 12 +- .../cold-attribute-application-54044.stderr | 12 +- tests/ui/attributes/empty-repr.rs | 14 + tests/ui/attributes/empty-repr.stderr | 14 + .../inline-attribute-enum-variant-error.rs | 2 +- ...inline-attribute-enum-variant-error.stderr | 8 +- .../ui/attributes/inline/attr-usage-inline.rs | 2 +- .../inline/attr-usage-inline.stderr | 6 +- .../issue-105594-invalid-attr-validation.rs | 2 +- ...ssue-105594-invalid-attr-validation.stderr | 7 +- tests/ui/attributes/linkage.rs | 12 +- tests/ui/attributes/linkage.stderr | 49 +- tests/ui/attributes/lint_on_root.rs | 1 + tests/ui/attributes/lint_on_root.stderr | 10 +- tests/ui/attributes/malformed-attrs.rs | 5 +- tests/ui/attributes/malformed-attrs.stderr | 186 ++- tests/ui/attributes/malformed-fn-align.rs | 10 +- tests/ui/attributes/malformed-fn-align.stderr | 50 +- tests/ui/attributes/multiple-invalid.rs | 4 +- tests/ui/attributes/multiple-invalid.stderr | 23 +- tests/ui/attributes/optimize.rs | 8 +- tests/ui/attributes/optimize.stderr | 30 +- tests/ui/attributes/positions/used.rs | 10 +- tests/ui/attributes/positions/used.stderr | 30 +- tests/ui/attributes/rustc_confusables.rs | 3 +- tests/ui/attributes/rustc_confusables.stderr | 4 +- .../rustc_skip_during_method_dispatch.rs | 2 +- .../rustc_skip_during_method_dispatch.stderr | 7 +- tests/ui/coroutine/invalid_attr_usage.rs | 4 +- tests/ui/coroutine/invalid_attr_usage.stderr | 8 +- tests/ui/coverage-attr/allowed-positions.rs | 34 +- .../ui/coverage-attr/allowed-positions.stderr | 163 +- tests/ui/coverage-attr/name-value.rs | 7 + tests/ui/coverage-attr/name-value.stderr | 76 +- tests/ui/coverage-attr/word-only.rs | 7 + tests/ui/coverage-attr/word-only.stderr | 76 +- tests/ui/deprecation/deprecation-sanity.rs | 5 +- .../ui/deprecation/deprecation-sanity.stderr | 28 +- tests/ui/error-codes/E0518.rs | 9 - tests/ui/error-codes/E0518.stderr | 20 - tests/ui/error-codes/E0718.stderr | 2 +- tests/ui/extern/extern-no-mangle.rs | 12 +- tests/ui/extern/extern-no-mangle.stderr | 30 +- tests/ui/extern/issue-47725.rs | 17 +- tests/ui/extern/issue-47725.stderr | 34 +- ...ure-gate-allow-internal-unstable-struct.rs | 2 +- ...gate-allow-internal-unstable-struct.stderr | 7 +- ...sue-43106-gating-of-builtin-attrs-error.rs | 50 +- ...43106-gating-of-builtin-attrs-error.stderr | 293 ++-- .../issue-43106-gating-of-builtin-attrs.rs | 311 ++-- ...issue-43106-gating-of-builtin-attrs.stderr | 1320 +++++++++-------- ...issue-43106-gating-of-proc_macro_derive.rs | 19 +- ...e-43106-gating-of-proc_macro_derive.stderr | 48 +- tests/ui/ffi-attrs/ffi_const.rs | 6 +- tests/ui/ffi-attrs/ffi_const.stderr | 13 +- tests/ui/ffi-attrs/ffi_pure.rs | 6 +- tests/ui/ffi-attrs/ffi_pure.stderr | 13 +- tests/ui/force-inlining/invalid.rs | 60 +- tests/ui/force-inlining/invalid.stderr | 372 ++--- ...lid_rustc_layout_scalar_valid_range.stderr | 19 +- tests/ui/issues/issue-31769.rs | 2 +- tests/ui/issues/issue-31769.stderr | 9 +- tests/ui/issues/issue-43988.rs | 4 +- tests/ui/issues/issue-43988.stderr | 48 +- tests/ui/issues/issue-78957.rs | 18 +- tests/ui/issues/issue-78957.stderr | 84 +- .../windows/link-ordinal-not-foreign-fn.rs | 6 +- .../link-ordinal-not-foreign-fn.stderr | 12 +- .../ui/lint/inline-trait-and-foreign-items.rs | 18 +- .../inline-trait-and-foreign-items.stderr | 75 +- .../ui/lint/unused/unused-attr-macro-rules.rs | 6 +- .../unused/unused-attr-macro-rules.stderr | 14 +- .../unused/unused_attributes-must_use.stderr | 42 +- .../warn-unused-inline-on-fn-prototypes.rs | 6 +- ...warn-unused-inline-on-fn-prototypes.stderr | 11 +- tests/ui/loop-match/invalid-attribute.rs | 24 +- tests/ui/loop-match/invalid-attribute.stderr | 160 +- tests/ui/macros/issue-68060.rs | 3 +- tests/ui/macros/issue-68060.stderr | 7 +- .../marker-attribute-on-non-trait.rs | 12 +- .../marker-attribute-on-non-trait.stderr | 42 +- .../panic-handler-wrong-location.stderr | 2 +- .../illegal-proc-macro-derive-use.rs | 2 +- .../illegal-proc-macro-derive-use.stderr | 4 +- .../invalid-attribute.rs | 4 +- .../invalid-attribute.stderr | 24 +- .../rfc-2091-track-caller/only-for-fns.rs | 2 +- .../rfc-2091-track-caller/only-for-fns.stderr | 7 +- .../check-doc-alias-attr-location.stderr | 4 +- tests/ui/target-feature/invalid-attribute.rs | 51 +- .../target-feature/invalid-attribute.stderr | 189 ++- tests/ui/traits/alias/not-a-marker.rs | 2 +- tests/ui/traits/alias/not-a-marker.stderr | 7 +- tests/ui/traits/const-traits/attr-misuse.rs | 4 +- .../ui/traits/const-traits/attr-misuse.stderr | 20 +- .../unstable_inherent_method.rs | 4 +- .../unstable_inherent_method.stderr | 14 +- .../ui/where-clauses/unsupported_attribute.rs | 20 +- .../unsupported_attribute.stderr | 100 +- 105 files changed, 2473 insertions(+), 2291 deletions(-) delete mode 100644 tests/crashes/138510.rs create mode 100644 tests/ui/attributes/empty-repr.rs create mode 100644 tests/ui/attributes/empty-repr.stderr delete mode 100644 tests/ui/error-codes/E0518.rs delete mode 100644 tests/ui/error-codes/E0518.stderr diff --git a/tests/crashes/138510.rs b/tests/crashes/138510.rs deleted file mode 100644 index f429e8bb33b56..0000000000000 --- a/tests/crashes/138510.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #138510 -fn main() -where - #[repr()] - _: Sized, -{ -} diff --git a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr index 9d3ce5e63ef73..85c9516236c94 100644 --- a/tests/rustdoc-ui/check-doc-alias-attr-location.stderr +++ b/tests/rustdoc-ui/check-doc-alias-attr-location.stderr @@ -4,13 +4,13 @@ error: `#[doc(alias = "...")]` isn't allowed on foreign module LL | #[doc(alias = "foo")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on inherent implementation block +error: `#[doc(alias = "...")]` isn't allowed on implementation block --> $DIR/check-doc-alias-attr-location.rs:10:7 | LL | #[doc(alias = "bar")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on trait implementation block +error: `#[doc(alias = "...")]` isn't allowed on implementation block --> $DIR/check-doc-alias-attr-location.rs:16:7 | LL | #[doc(alias = "foobar")] diff --git a/tests/ui/asm/naked-invalid-attr.rs b/tests/ui/asm/naked-invalid-attr.rs index 6ac9cb9e3a9c5..c9e0949abfb1e 100644 --- a/tests/ui/asm/naked-invalid-attr.rs +++ b/tests/ui/asm/naked-invalid-attr.rs @@ -1,25 +1,25 @@ // Checks that the #[unsafe(naked)] attribute can be placed on function definitions only. // //@ needs-asm-support -#![unsafe(naked)] //~ ERROR should be applied to a function definition +#![unsafe(naked)] //~ ERROR attribute cannot be used on use std::arch::naked_asm; extern "C" { - #[unsafe(naked)] //~ ERROR should be applied to a function definition + #[unsafe(naked)] //~ ERROR attribute cannot be used on fn f(); } -#[unsafe(naked)] //~ ERROR should be applied to a function definition +#[unsafe(naked)] //~ ERROR attribute cannot be used on #[repr(C)] struct S { - #[unsafe(naked)] //~ ERROR should be applied to a function definition + #[unsafe(naked)] //~ ERROR attribute cannot be used on a: u32, b: u32, } trait Invoke { - #[unsafe(naked)] //~ ERROR should be applied to a function definition + #[unsafe(naked)] //~ ERROR attribute cannot be used on extern "C" fn invoke(&self); } @@ -48,7 +48,7 @@ impl S { } fn main() { - #[unsafe(naked)] //~ ERROR should be applied to a function definition + #[unsafe(naked)] //~ ERROR attribute cannot be used on || {}; } diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index 2571c8fa9896d..936a36cd92ed3 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -4,65 +4,62 @@ error[E0433]: failed to resolve: use of unresolved module or unlinked crate `a` LL | #[::a] | ^ use of unresolved module or unlinked crate `a` -error[E0736]: attribute incompatible with `#[unsafe(naked)]` - --> $DIR/naked-invalid-attr.rs:56:3 +error: `#[naked]` attribute cannot be used on crates + --> $DIR/naked-invalid-attr.rs:4:1 | -LL | #[::a] - | ^^^ the `::a` attribute is incompatible with `#[unsafe(naked)]` -... -LL | #[unsafe(naked)] - | ---------------- function marked with `#[unsafe(naked)]` here - -error: attribute should be applied to a function definition - --> $DIR/naked-invalid-attr.rs:13:1 +LL | #![unsafe(naked)] + | ^^^^^^^^^^^^^^^^^ | -LL | #[unsafe(naked)] - | ^^^^^^^^^^^^^^^^ -LL | #[repr(C)] -LL | / struct S { -LL | | #[unsafe(naked)] -LL | | a: u32, -LL | | b: u32, -LL | | } - | |_- not a function definition + = help: `#[naked]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/naked-invalid-attr.rs:16:5 +error: `#[naked]` attribute cannot be used on foreign functions + --> $DIR/naked-invalid-attr.rs:9:5 | LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ -LL | a: u32, - | ------ not a function definition + | + = help: `#[naked]` can be applied to methods, functions -error: attribute should be applied to a function definition - --> $DIR/naked-invalid-attr.rs:51:5 +error: `#[naked]` attribute cannot be used on structs + --> $DIR/naked-invalid-attr.rs:13:1 + | +LL | #[unsafe(naked)] + | ^^^^^^^^^^^^^^^^ + | + = help: `#[naked]` can only be applied to functions + +error: `#[naked]` attribute cannot be used on struct fields + --> $DIR/naked-invalid-attr.rs:16:5 | LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ -LL | || {}; - | ----- not a function definition + | + = help: `#[naked]` can only be applied to functions -error: attribute should be applied to a function definition +error: `#[naked]` attribute cannot be used on required trait methods --> $DIR/naked-invalid-attr.rs:22:5 | LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ -LL | extern "C" fn invoke(&self); - | ---------------------------- not a function definition + | + = help: `#[naked]` can be applied to functions, inherent methods, provided trait methods, trait methods in impl blocks -error: attribute should be applied to a function definition - --> $DIR/naked-invalid-attr.rs:9:5 +error: `#[naked]` attribute cannot be used on closures + --> $DIR/naked-invalid-attr.rs:51:5 | LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ -LL | fn f(); - | ------- not a function definition + | + = help: `#[naked]` can be applied to methods, functions -error: attribute should be applied to a function definition - --> $DIR/naked-invalid-attr.rs:4:1 +error[E0736]: attribute incompatible with `#[unsafe(naked)]` + --> $DIR/naked-invalid-attr.rs:56:3 | -LL | #![unsafe(naked)] - | ^^^^^^^^^^^^^^^^^ cannot be applied to crates +LL | #[::a] + | ^^^ the `::a` attribute is incompatible with `#[unsafe(naked)]` +... +LL | #[unsafe(naked)] + | ---------------- function marked with `#[unsafe(naked)]` here error: aborting due to 8 previous errors diff --git a/tests/ui/attributes/attrs-on-params.rs b/tests/ui/attributes/attrs-on-params.rs index 158a4500bde77..c8e9810327c2a 100644 --- a/tests/ui/attributes/attrs-on-params.rs +++ b/tests/ui/attributes/attrs-on-params.rs @@ -1,7 +1,7 @@ // This checks that incorrect params on function parameters are caught fn function(#[inline] param: u32) { - //~^ ERROR attribute should be applied to function or closure + //~^ ERROR attribute cannot be used on //~| ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes } diff --git a/tests/ui/attributes/attrs-on-params.stderr b/tests/ui/attributes/attrs-on-params.stderr index 306e862cb58d4..91f87a954c55d 100644 --- a/tests/ui/attributes/attrs-on-params.stderr +++ b/tests/ui/attributes/attrs-on-params.stderr @@ -4,14 +4,13 @@ error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed LL | fn function(#[inline] param: u32) { | ^^^^^^^^^ -error[E0518]: attribute should be applied to function or closure +error: `#[inline]` attribute cannot be used on function params --> $DIR/attrs-on-params.rs:3:13 | LL | fn function(#[inline] param: u32) { - | ^^^^^^^^^----------- - | | - | not a function or closure + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0518`. diff --git a/tests/ui/attributes/cold-attribute-application-54044.rs b/tests/ui/attributes/cold-attribute-application-54044.rs index 2e644b91c0774..cf027ac02b056 100644 --- a/tests/ui/attributes/cold-attribute-application-54044.rs +++ b/tests/ui/attributes/cold-attribute-application-54044.rs @@ -2,13 +2,13 @@ #![deny(unused_attributes)] //~ NOTE lint level is defined here #[cold] -//~^ ERROR attribute should be applied to a function -//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -struct Foo; //~ NOTE not a function +//~^ ERROR attribute cannot be used on +//~| WARN previously accepted +struct Foo; fn main() { #[cold] - //~^ ERROR attribute should be applied to a function - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - 5; //~ NOTE not a function + //~^ ERROR attribute cannot be used on + //~| WARN previously accepted + 5; } diff --git a/tests/ui/attributes/cold-attribute-application-54044.stderr b/tests/ui/attributes/cold-attribute-application-54044.stderr index efdf5e0de527f..367686f02cb10 100644 --- a/tests/ui/attributes/cold-attribute-application-54044.stderr +++ b/tests/ui/attributes/cold-attribute-application-54044.stderr @@ -1,29 +1,25 @@ -error: attribute should be applied to a function definition +error: `#[cold]` attribute cannot be used on structs --> $DIR/cold-attribute-application-54044.rs:4:1 | LL | #[cold] | ^^^^^^^ -... -LL | struct Foo; - | ----------- not a function definition | = 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 only be applied to functions note: the lint level is defined here --> $DIR/cold-attribute-application-54044.rs:2:9 | LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -error: attribute should be applied to a function definition +error: `#[cold]` attribute cannot be used on expressions --> $DIR/cold-attribute-application-54044.rs:10:5 | LL | #[cold] | ^^^^^^^ -... -LL | 5; - | - not a function definition | = 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 only be applied to functions error: aborting due to 2 previous errors diff --git a/tests/ui/attributes/empty-repr.rs b/tests/ui/attributes/empty-repr.rs new file mode 100644 index 0000000000000..e6ba1baf031ab --- /dev/null +++ b/tests/ui/attributes/empty-repr.rs @@ -0,0 +1,14 @@ +// Regression test for https://github.com/rust-lang/rust/issues/138510 + +#![feature(where_clause_attrs)] +#![deny(unused_attributes)] + +fn main() { +} + +fn test() where +#[repr()] +//~^ ERROR unused attribute +(): Sized { + +} diff --git a/tests/ui/attributes/empty-repr.stderr b/tests/ui/attributes/empty-repr.stderr new file mode 100644 index 0000000000000..92901fa170c25 --- /dev/null +++ b/tests/ui/attributes/empty-repr.stderr @@ -0,0 +1,14 @@ +error: unused attribute + --> $DIR/empty-repr.rs:10:1 + | +LL | #[repr()] + | ^^^^^^^^^ help: remove this attribute + | +note: the lint level is defined here + --> $DIR/empty-repr.rs:4:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/attributes/inline-attribute-enum-variant-error.rs b/tests/ui/attributes/inline-attribute-enum-variant-error.rs index 305b285d2a4f6..fd2cd49be16d2 100644 --- a/tests/ui/attributes/inline-attribute-enum-variant-error.rs +++ b/tests/ui/attributes/inline-attribute-enum-variant-error.rs @@ -2,7 +2,7 @@ enum Foo { #[inline] - //~^ ERROR attribute should be applied + //~^ ERROR attribute cannot be used on Variant, } diff --git a/tests/ui/attributes/inline-attribute-enum-variant-error.stderr b/tests/ui/attributes/inline-attribute-enum-variant-error.stderr index a4564d8f72254..03954388c2efa 100644 --- a/tests/ui/attributes/inline-attribute-enum-variant-error.stderr +++ b/tests/ui/attributes/inline-attribute-enum-variant-error.stderr @@ -1,12 +1,10 @@ -error[E0518]: attribute should be applied to function or closure +error: `#[inline]` attribute cannot be used on enum variants --> $DIR/inline-attribute-enum-variant-error.rs:4:5 | LL | #[inline] | ^^^^^^^^^ -LL | -LL | Variant, - | ------- not a function or closure + | + = help: `#[inline]` can only be applied to functions error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0518`. diff --git a/tests/ui/attributes/inline/attr-usage-inline.rs b/tests/ui/attributes/inline/attr-usage-inline.rs index d8ca0fce1631d..8217b9834ff24 100644 --- a/tests/ui/attributes/inline/attr-usage-inline.rs +++ b/tests/ui/attributes/inline/attr-usage-inline.rs @@ -4,7 +4,7 @@ #[inline] fn f() {} -#[inline] //~ ERROR: attribute should be applied to function or closure +#[inline] //~ ERROR: attribute cannot be used on struct S; struct I { diff --git a/tests/ui/attributes/inline/attr-usage-inline.stderr b/tests/ui/attributes/inline/attr-usage-inline.stderr index 2123438032cb3..9fca17d90ca13 100644 --- a/tests/ui/attributes/inline/attr-usage-inline.stderr +++ b/tests/ui/attributes/inline/attr-usage-inline.stderr @@ -1,10 +1,10 @@ -error[E0518]: attribute should be applied to function or closure +error: `#[inline]` attribute cannot be used on structs --> $DIR/attr-usage-inline.rs:7:1 | LL | #[inline] | ^^^^^^^^^ -LL | struct S; - | --------- not a function or closure + | + = help: `#[inline]` can only be applied to functions error[E0518]: attribute should be applied to function or closure --> $DIR/attr-usage-inline.rs:21:1 diff --git a/tests/ui/attributes/issue-105594-invalid-attr-validation.rs b/tests/ui/attributes/issue-105594-invalid-attr-validation.rs index cb196471fd75e..f9e01cd1507ec 100644 --- a/tests/ui/attributes/issue-105594-invalid-attr-validation.rs +++ b/tests/ui/attributes/issue-105594-invalid-attr-validation.rs @@ -3,5 +3,5 @@ fn main() {} -#[track_caller] //~ ERROR attribute should be applied to a function +#[track_caller] //~ ERROR attribute cannot be used on static _A: () = (); diff --git a/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr b/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr index 1248967c47b19..337d3808d28f6 100644 --- a/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr +++ b/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr @@ -1,11 +1,10 @@ -error[E0739]: attribute should be applied to a function definition +error: `#[track_caller]` attribute cannot be used on statics --> $DIR/issue-105594-invalid-attr-validation.rs:6:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ -LL | static _A: () = (); - | ------------------- not a function definition + | + = help: `#[track_caller]` can only be applied to functions error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0739`. diff --git a/tests/ui/attributes/linkage.rs b/tests/ui/attributes/linkage.rs index 0d5ce699fa808..932bfa88fc5f0 100644 --- a/tests/ui/attributes/linkage.rs +++ b/tests/ui/attributes/linkage.rs @@ -3,16 +3,16 @@ #![deny(unused_attributes)] #![allow(dead_code)] -#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static +#[linkage = "weak"] //~ ERROR attribute cannot be used on type InvalidTy = (); -#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static +#[linkage = "weak"] //~ ERROR attribute cannot be used on mod invalid_module {} -#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static +#[linkage = "weak"] //~ ERROR attribute cannot be used on struct F; -#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static +#[linkage = "weak"] //~ ERROR attribute cannot be used on impl F { #[linkage = "weak"] fn valid(&self) {} @@ -24,7 +24,7 @@ fn f() { { 1 }; - //~^^^^ ERROR attribute should be applied to a function or static + //~^^^^ ERROR attribute cannot be used on } extern "C" { @@ -38,5 +38,5 @@ extern "C" { fn main() { let _ = #[linkage = "weak"] (|| 1); - //~^^ ERROR attribute should be applied to a function or static + //~^^ ERROR attribute cannot be used on } diff --git a/tests/ui/attributes/linkage.stderr b/tests/ui/attributes/linkage.stderr index d5595529f400a..2e7ff0e793614 100644 --- a/tests/ui/attributes/linkage.stderr +++ b/tests/ui/attributes/linkage.stderr @@ -1,55 +1,50 @@ -error: attribute should be applied to a function or static +error: `#[linkage]` attribute cannot be used on type aliases --> $DIR/linkage.rs:6:1 | LL | #[linkage = "weak"] | ^^^^^^^^^^^^^^^^^^^ -LL | type InvalidTy = (); - | -------------------- not a function definition or static + | + = help: `#[linkage]` can be applied to functions, statics, foreign statics -error: attribute should be applied to a function or static +error: `#[linkage]` attribute cannot be used on modules --> $DIR/linkage.rs:9:1 | LL | #[linkage = "weak"] | ^^^^^^^^^^^^^^^^^^^ -LL | mod invalid_module {} - | --------------------- not a function definition or static + | + = help: `#[linkage]` can be applied to functions, statics, foreign statics -error: attribute should be applied to a function or static +error: `#[linkage]` attribute cannot be used on structs --> $DIR/linkage.rs:12:1 | LL | #[linkage = "weak"] | ^^^^^^^^^^^^^^^^^^^ -LL | struct F; - | --------- not a function definition or static + | + = help: `#[linkage]` can be applied to functions, statics, foreign statics -error: attribute should be applied to a function or static +error: `#[linkage]` attribute cannot be used on inherent impl blocks --> $DIR/linkage.rs:15:1 | -LL | #[linkage = "weak"] - | ^^^^^^^^^^^^^^^^^^^ -LL | / impl F { -LL | | #[linkage = "weak"] -LL | | fn valid(&self) {} -LL | | } - | |_- not a function definition or static +LL | #[linkage = "weak"] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[linkage]` can be applied to functions, statics, foreign statics -error: attribute should be applied to a function or static +error: `#[linkage]` attribute cannot be used on expressions --> $DIR/linkage.rs:23:5 | -LL | #[linkage = "weak"] - | ^^^^^^^^^^^^^^^^^^^ -LL | / { -LL | | 1 -LL | | }; - | |_____- not a function definition or static +LL | #[linkage = "weak"] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[linkage]` can be applied to functions, statics, foreign statics -error: attribute should be applied to a function or static +error: `#[linkage]` attribute cannot be used on closures --> $DIR/linkage.rs:39:13 | LL | let _ = #[linkage = "weak"] | ^^^^^^^^^^^^^^^^^^^ -LL | (|| 1); - | ------ not a function definition or static + | + = help: `#[linkage]` can be applied to methods, functions, statics, foreign statics, foreign functions error: aborting due to 6 previous errors diff --git a/tests/ui/attributes/lint_on_root.rs b/tests/ui/attributes/lint_on_root.rs index 9029da7dc97d3..bafdb46883ff5 100644 --- a/tests/ui/attributes/lint_on_root.rs +++ b/tests/ui/attributes/lint_on_root.rs @@ -3,5 +3,6 @@ #![inline = ""] //~^ ERROR: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` [ill_formed_attribute_input] //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//~| ERROR attribute cannot be used on fn main() {} diff --git a/tests/ui/attributes/lint_on_root.stderr b/tests/ui/attributes/lint_on_root.stderr index 91b72730530b2..9d8d1495c1bfe 100644 --- a/tests/ui/attributes/lint_on_root.stderr +++ b/tests/ui/attributes/lint_on_root.stderr @@ -1,3 +1,11 @@ +error: `#[inline]` attribute cannot be used on crates + --> $DIR/lint_on_root.rs:3:1 + | +LL | #![inline = ""] + | ^^^^^^^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` --> $DIR/lint_on_root.rs:3:1 | @@ -8,7 +16,7 @@ LL | #![inline = ""] = note: for more information, see issue #57571 = note: `#[deny(ill_formed_attribute_input)]` on by default -error: aborting due to 1 previous error +error: aborting due to 2 previous errors Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index 3261b29fe7e0b..3293f75fba944 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -35,6 +35,7 @@ //~^ ERROR `allow_internal_unstable` expects a list of feature names #[rustc_confusables] //~^ ERROR malformed +//~| ERROR attribute cannot be used on #[deprecated = 5] //~^ ERROR malformed #[doc] @@ -42,9 +43,10 @@ //~| WARN this was previously accepted by the compiler #[rustc_macro_transparency] //~^ ERROR malformed +//~| ERROR attribute cannot be used on #[repr] //~^ ERROR malformed -//~| ERROR is not supported on function items +//~| ERROR is not supported on functions #[rustc_as_ptr = 5] //~^ ERROR malformed #[inline = 5] @@ -68,6 +70,7 @@ //~^ ERROR malformed #[used()] //~^ ERROR malformed +//~| ERROR attribute cannot be used on #[crate_name] //~^ ERROR malformed #[doc] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index aa4891459aaf2..9c31765149b7e 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -1,5 +1,5 @@ error[E0539]: malformed `cfg` attribute input - --> $DIR/malformed-attrs.rs:99:1 + --> $DIR/malformed-attrs.rs:102:1 | LL | #[cfg] | ^^^^^^ @@ -10,7 +10,7 @@ LL | #[cfg] = note: for more information, visit error: malformed `cfg_attr` attribute input - --> $DIR/malformed-attrs.rs:101:1 + --> $DIR/malformed-attrs.rs:104:1 | LL | #[cfg_attr] | ^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | #[cfg_attr(condition, attribute, other_attribute, ...)] | ++++++++++++++++++++++++++++++++++++++++++++ error[E0463]: can't find crate for `wloop` - --> $DIR/malformed-attrs.rs:208:1 + --> $DIR/malformed-attrs.rs:211:1 | LL | extern crate wloop; | ^^^^^^^^^^^^^^^^^^^ can't find crate @@ -42,7 +42,7 @@ LL | #![windows_subsystem = "windows"] | +++++++++++ error: malformed `crate_name` attribute input - --> $DIR/malformed-attrs.rs:71:1 + --> $DIR/malformed-attrs.rs:74:1 | LL | #[crate_name] | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` @@ -50,13 +50,13 @@ LL | #[crate_name] = note: for more information, visit error: malformed `no_sanitize` attribute input - --> $DIR/malformed-attrs.rs:89:1 + --> $DIR/malformed-attrs.rs:92:1 | LL | #[no_sanitize] | ^^^^^^^^^^^^^^ help: must be of the form: `#[no_sanitize(address, kcfi, memory, thread)]` error: malformed `instruction_set` attribute input - --> $DIR/malformed-attrs.rs:103:1 + --> $DIR/malformed-attrs.rs:106:1 | LL | #[instruction_set] | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]` @@ -64,13 +64,13 @@ LL | #[instruction_set] = note: for more information, visit error: malformed `patchable_function_entry` attribute input - --> $DIR/malformed-attrs.rs:105:1 + --> $DIR/malformed-attrs.rs:108:1 | LL | #[patchable_function_entry] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` error: malformed `must_not_suspend` attribute input - --> $DIR/malformed-attrs.rs:129:1 + --> $DIR/malformed-attrs.rs:132:1 | LL | #[must_not_suspend()] | ^^^^^^^^^^^^^^^^^^^^^ @@ -85,13 +85,13 @@ LL + #[must_not_suspend] | error: malformed `cfi_encoding` attribute input - --> $DIR/malformed-attrs.rs:131:1 + --> $DIR/malformed-attrs.rs:134:1 | LL | #[cfi_encoding] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]` error: malformed `allow` attribute input - --> $DIR/malformed-attrs.rs:175:1 + --> $DIR/malformed-attrs.rs:178:1 | LL | #[allow] | ^^^^^^^^ @@ -107,7 +107,7 @@ LL | #[allow(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error: malformed `expect` attribute input - --> $DIR/malformed-attrs.rs:177:1 + --> $DIR/malformed-attrs.rs:180:1 | LL | #[expect] | ^^^^^^^^^ @@ -123,7 +123,7 @@ LL | #[expect(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error: malformed `warn` attribute input - --> $DIR/malformed-attrs.rs:179:1 + --> $DIR/malformed-attrs.rs:182:1 | LL | #[warn] | ^^^^^^^ @@ -139,7 +139,7 @@ LL | #[warn(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error: malformed `deny` attribute input - --> $DIR/malformed-attrs.rs:181:1 + --> $DIR/malformed-attrs.rs:184:1 | LL | #[deny] | ^^^^^^^ @@ -155,7 +155,7 @@ LL | #[deny(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error: malformed `forbid` attribute input - --> $DIR/malformed-attrs.rs:183:1 + --> $DIR/malformed-attrs.rs:186:1 | LL | #[forbid] | ^^^^^^^^^ @@ -171,7 +171,7 @@ LL | #[forbid(lint1, lint2, lint3, reason = "...")] | +++++++++++++++++++++++++++++++++++++ error: malformed `debugger_visualizer` attribute input - --> $DIR/malformed-attrs.rs:185:1 + --> $DIR/malformed-attrs.rs:188:1 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]` @@ -179,13 +179,13 @@ LL | #[debugger_visualizer] = note: for more information, visit error: malformed `thread_local` attribute input - --> $DIR/malformed-attrs.rs:200:1 + --> $DIR/malformed-attrs.rs:203:1 | LL | #[thread_local()] | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[thread_local]` error: malformed `no_link` attribute input - --> $DIR/malformed-attrs.rs:204:1 + --> $DIR/malformed-attrs.rs:207:1 | LL | #[no_link()] | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]` @@ -193,7 +193,7 @@ LL | #[no_link()] = note: for more information, visit error: malformed `macro_export` attribute input - --> $DIR/malformed-attrs.rs:211:1 + --> $DIR/malformed-attrs.rs:214:1 | LL | #[macro_export = 18] | ^^^^^^^^^^^^^^^^^^^^ @@ -209,25 +209,25 @@ LL + #[macro_export] | error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:96:1 + --> $DIR/malformed-attrs.rs:99:1 | LL | #[proc_macro = 18] | ^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:113:1 + --> $DIR/malformed-attrs.rs:116:1 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/malformed-attrs.rs:120:1 + --> $DIR/malformed-attrs.rs:123:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint - --> $DIR/malformed-attrs.rs:213:1 + --> $DIR/malformed-attrs.rs:216:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,7 +236,7 @@ LL | #[allow_internal_unsafe = 1] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:40:1 + --> $DIR/malformed-attrs.rs:41:1 | LL | #[doc] | ^^^^^^ @@ -247,7 +247,7 @@ LL | #[doc] = note: `#[deny(ill_formed_attribute_input)]` on by default error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:73:1 + --> $DIR/malformed-attrs.rs:76:1 | LL | #[doc] | ^^^^^^ @@ -257,7 +257,7 @@ LL | #[doc] = note: for more information, visit error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/malformed-attrs.rs:80:1 + --> $DIR/malformed-attrs.rs:83:1 | LL | #[link] | ^^^^^^^ @@ -267,7 +267,7 @@ LL | #[link] = note: for more information, visit error: invalid argument - --> $DIR/malformed-attrs.rs:185:1 + --> $DIR/malformed-attrs.rs:188:1 | LL | #[debugger_visualizer] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -303,8 +303,16 @@ LL | #[rustc_confusables] | expected this to be a list | help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` +error: `#[rustc_confusables]` attribute cannot be used on functions + --> $DIR/malformed-attrs.rs:36:1 + | +LL | #[rustc_confusables] + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_confusables]` can only be applied to inherent methods + error[E0539]: malformed `deprecated` attribute input - --> $DIR/malformed-attrs.rs:38:1 + --> $DIR/malformed-attrs.rs:39:1 | LL | #[deprecated = 5] | ^^^^^^^^^^^^^^^-^ @@ -328,7 +336,7 @@ LL + #[deprecated(since = "version", note = "reason")] = and 1 other candidate error[E0539]: malformed `rustc_macro_transparency` attribute input - --> $DIR/malformed-attrs.rs:43:1 + --> $DIR/malformed-attrs.rs:44:1 | LL | #[rustc_macro_transparency] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -342,8 +350,16 @@ LL | #[rustc_macro_transparency = "semitransparent"] LL | #[rustc_macro_transparency = "transparent"] | +++++++++++++++ +error: `#[rustc_macro_transparency]` attribute cannot be used on functions + --> $DIR/malformed-attrs.rs:44:1 + | +LL | #[rustc_macro_transparency] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_macro_transparency]` can only be applied to macro defs + error[E0539]: malformed `repr` attribute input - --> $DIR/malformed-attrs.rs:45:1 + --> $DIR/malformed-attrs.rs:47:1 | LL | #[repr] | ^^^^^^^ expected this to be a list @@ -362,7 +378,7 @@ LL | #[repr(align(...))] = and 2 other candidates error[E0565]: malformed `rustc_as_ptr` attribute input - --> $DIR/malformed-attrs.rs:48:1 + --> $DIR/malformed-attrs.rs:50:1 | LL | #[rustc_as_ptr = 5] | ^^^^^^^^^^^^^^^---^ @@ -371,7 +387,7 @@ LL | #[rustc_as_ptr = 5] | help: must be of the form: `#[rustc_as_ptr]` error[E0539]: malformed `rustc_align` attribute input - --> $DIR/malformed-attrs.rs:53:1 + --> $DIR/malformed-attrs.rs:55:1 | LL | #[rustc_align] | ^^^^^^^^^^^^^^ @@ -380,7 +396,7 @@ LL | #[rustc_align] | help: must be of the form: `#[rustc_align()]` error[E0539]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:55:1 + --> $DIR/malformed-attrs.rs:57:1 | LL | #[optimize] | ^^^^^^^^^^^ expected this to be a list @@ -395,7 +411,7 @@ LL | #[optimize(speed)] | +++++++ error[E0565]: malformed `cold` attribute input - --> $DIR/malformed-attrs.rs:57:1 + --> $DIR/malformed-attrs.rs:59:1 | LL | #[cold = 1] | ^^^^^^^---^ @@ -404,13 +420,13 @@ LL | #[cold = 1] | help: must be of the form: `#[cold]` error: valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` - --> $DIR/malformed-attrs.rs:59:1 + --> $DIR/malformed-attrs.rs:61:1 | LL | #[must_use()] | ^^^^^^^^^^^^^ error[E0565]: malformed `no_mangle` attribute input - --> $DIR/malformed-attrs.rs:61:1 + --> $DIR/malformed-attrs.rs:63:1 | LL | #[no_mangle = 1] | ^^^^^^^^^^^^---^ @@ -419,7 +435,7 @@ LL | #[no_mangle = 1] | help: must be of the form: `#[no_mangle]` error[E0565]: malformed `naked` attribute input - --> $DIR/malformed-attrs.rs:63:1 + --> $DIR/malformed-attrs.rs:65:1 | LL | #[unsafe(naked())] | ^^^^^^^^^^^^^^--^^ @@ -428,7 +444,7 @@ LL | #[unsafe(naked())] | help: must be of the form: `#[naked]` error[E0565]: malformed `track_caller` attribute input - --> $DIR/malformed-attrs.rs:65:1 + --> $DIR/malformed-attrs.rs:67:1 | LL | #[track_caller()] | ^^^^^^^^^^^^^^--^ @@ -437,13 +453,13 @@ LL | #[track_caller()] | help: must be of the form: `#[track_caller]` error[E0539]: malformed `export_name` attribute input - --> $DIR/malformed-attrs.rs:67:1 + --> $DIR/malformed-attrs.rs:69:1 | LL | #[export_name()] | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]` error[E0805]: malformed `used` attribute input - --> $DIR/malformed-attrs.rs:69:1 + --> $DIR/malformed-attrs.rs:71:1 | LL | #[used()] | ^^^^^^--^ @@ -460,8 +476,16 @@ LL - #[used()] LL + #[used] | +error: `#[used]` attribute cannot be used on functions + --> $DIR/malformed-attrs.rs:71:1 + | +LL | #[used()] + | ^^^^^^^^^ + | + = help: `#[used]` can only be applied to statics + error[E0539]: malformed `target_feature` attribute input - --> $DIR/malformed-attrs.rs:76:1 + --> $DIR/malformed-attrs.rs:79:1 | LL | #[target_feature] | ^^^^^^^^^^^^^^^^^ @@ -470,7 +494,7 @@ LL | #[target_feature] | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]` error[E0565]: malformed `export_stable` attribute input - --> $DIR/malformed-attrs.rs:78:1 + --> $DIR/malformed-attrs.rs:81:1 | LL | #[export_stable = 1] | ^^^^^^^^^^^^^^^^---^ @@ -479,7 +503,7 @@ LL | #[export_stable = 1] | help: must be of the form: `#[export_stable]` error[E0539]: malformed `link_name` attribute input - --> $DIR/malformed-attrs.rs:83:1 + --> $DIR/malformed-attrs.rs:86:1 | LL | #[link_name] | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` @@ -487,7 +511,7 @@ LL | #[link_name] = note: for more information, visit error[E0539]: malformed `link_section` attribute input - --> $DIR/malformed-attrs.rs:85:1 + --> $DIR/malformed-attrs.rs:88:1 | LL | #[link_section] | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]` @@ -495,7 +519,7 @@ LL | #[link_section] = note: for more information, visit error[E0539]: malformed `coverage` attribute input - --> $DIR/malformed-attrs.rs:87:1 + --> $DIR/malformed-attrs.rs:90:1 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -508,7 +532,7 @@ LL | #[coverage(on)] | ++++ error[E0565]: malformed `no_implicit_prelude` attribute input - --> $DIR/malformed-attrs.rs:94:1 + --> $DIR/malformed-attrs.rs:97:1 | LL | #[no_implicit_prelude = 23] | ^^^^^^^^^^^^^^^^^^^^^^----^ @@ -517,7 +541,7 @@ LL | #[no_implicit_prelude = 23] | help: must be of the form: `#[no_implicit_prelude]` error[E0565]: malformed `proc_macro` attribute input - --> $DIR/malformed-attrs.rs:96:1 + --> $DIR/malformed-attrs.rs:99:1 | LL | #[proc_macro = 18] | ^^^^^^^^^^^^^----^ @@ -526,7 +550,7 @@ LL | #[proc_macro = 18] | help: must be of the form: `#[proc_macro]` error[E0565]: malformed `coroutine` attribute input - --> $DIR/malformed-attrs.rs:108:5 + --> $DIR/malformed-attrs.rs:111:5 | LL | #[coroutine = 63] || {} | ^^^^^^^^^^^^----^ @@ -535,7 +559,7 @@ LL | #[coroutine = 63] || {} | help: must be of the form: `#[coroutine]` error[E0565]: malformed `proc_macro_attribute` attribute input - --> $DIR/malformed-attrs.rs:113:1 + --> $DIR/malformed-attrs.rs:116:1 | LL | #[proc_macro_attribute = 19] | ^^^^^^^^^^^^^^^^^^^^^^^----^ @@ -544,7 +568,7 @@ LL | #[proc_macro_attribute = 19] | help: must be of the form: `#[proc_macro_attribute]` error[E0539]: malformed `must_use` attribute input - --> $DIR/malformed-attrs.rs:116:1 + --> $DIR/malformed-attrs.rs:119:1 | LL | #[must_use = 1] | ^^^^^^^^^^^^^-^ @@ -562,7 +586,7 @@ LL + #[must_use] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/malformed-attrs.rs:120:1 + --> $DIR/malformed-attrs.rs:123:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ expected this to be a list @@ -576,7 +600,7 @@ LL | #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | ++++++++++++++++++++++++++++++++++++++++++ error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input - --> $DIR/malformed-attrs.rs:125:1 + --> $DIR/malformed-attrs.rs:128:1 | LL | #[rustc_layout_scalar_valid_range_start] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -585,7 +609,7 @@ LL | #[rustc_layout_scalar_valid_range_start] | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input - --> $DIR/malformed-attrs.rs:127:1 + --> $DIR/malformed-attrs.rs:130:1 | LL | #[rustc_layout_scalar_valid_range_end] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -594,7 +618,7 @@ LL | #[rustc_layout_scalar_valid_range_end] | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` error[E0565]: malformed `marker` attribute input - --> $DIR/malformed-attrs.rs:152:1 + --> $DIR/malformed-attrs.rs:155:1 | LL | #[marker = 3] | ^^^^^^^^^---^ @@ -603,7 +627,7 @@ LL | #[marker = 3] | help: must be of the form: `#[marker]` error[E0565]: malformed `fundamental` attribute input - --> $DIR/malformed-attrs.rs:154:1 + --> $DIR/malformed-attrs.rs:157:1 | LL | #[fundamental()] | ^^^^^^^^^^^^^--^ @@ -612,7 +636,7 @@ LL | #[fundamental()] | help: must be of the form: `#[fundamental]` error[E0565]: malformed `ffi_pure` attribute input - --> $DIR/malformed-attrs.rs:162:5 + --> $DIR/malformed-attrs.rs:165:5 | LL | #[unsafe(ffi_pure = 1)] | ^^^^^^^^^^^^^^^^^^---^^ @@ -621,7 +645,7 @@ LL | #[unsafe(ffi_pure = 1)] | help: must be of the form: `#[ffi_pure]` error[E0539]: malformed `link_ordinal` attribute input - --> $DIR/malformed-attrs.rs:164:5 + --> $DIR/malformed-attrs.rs:167:5 | LL | #[link_ordinal] | ^^^^^^^^^^^^^^^ @@ -632,7 +656,7 @@ LL | #[link_ordinal] = note: for more information, visit error[E0565]: malformed `ffi_const` attribute input - --> $DIR/malformed-attrs.rs:168:5 + --> $DIR/malformed-attrs.rs:171:5 | LL | #[unsafe(ffi_const = 1)] | ^^^^^^^^^^^^^^^^^^^---^^ @@ -641,7 +665,7 @@ LL | #[unsafe(ffi_const = 1)] | help: must be of the form: `#[ffi_const]` error[E0539]: malformed `linkage` attribute input - --> $DIR/malformed-attrs.rs:170:5 + --> $DIR/malformed-attrs.rs:173:5 | LL | #[linkage] | ^^^^^^^^^^ expected this to be of the form `linkage = "..."` @@ -659,7 +683,7 @@ LL | #[linkage = "external"] = and 5 other candidates error[E0565]: malformed `automatically_derived` attribute input - --> $DIR/malformed-attrs.rs:188:1 + --> $DIR/malformed-attrs.rs:191:1 | LL | #[automatically_derived = 18] | ^^^^^^^^^^^^^^^^^^^^^^^^----^ @@ -668,7 +692,7 @@ LL | #[automatically_derived = 18] | help: must be of the form: `#[automatically_derived]` error[E0565]: malformed `non_exhaustive` attribute input - --> $DIR/malformed-attrs.rs:194:1 + --> $DIR/malformed-attrs.rs:197:1 | LL | #[non_exhaustive = 1] | ^^^^^^^^^^^^^^^^^---^ @@ -677,13 +701,13 @@ LL | #[non_exhaustive = 1] | help: must be of the form: `#[non_exhaustive]` error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]` - --> $DIR/malformed-attrs.rs:206:1 + --> $DIR/malformed-attrs.rs:209:1 | LL | #[macro_use = 1] | ^^^^^^^^^^^^^^^^ error[E0565]: malformed `allow_internal_unsafe` attribute input - --> $DIR/malformed-attrs.rs:213:1 + --> $DIR/malformed-attrs.rs:216:1 | LL | #[allow_internal_unsafe = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^---^ @@ -692,7 +716,7 @@ LL | #[allow_internal_unsafe = 1] | help: must be of the form: `#[allow_internal_unsafe]` error[E0565]: malformed `type_const` attribute input - --> $DIR/malformed-attrs.rs:140:5 + --> $DIR/malformed-attrs.rs:143:5 | LL | #[type_const = 1] | ^^^^^^^^^^^^^---^ @@ -712,20 +736,20 @@ LL | | #[coroutine = 63] || {} LL | | } | |_- not a `const fn` -error: `#[repr(align(...))]` is not supported on function items - --> $DIR/malformed-attrs.rs:45:1 +error: `#[repr(align(...))]` is not supported on functions + --> $DIR/malformed-attrs.rs:47:1 | LL | #[repr] | ^^^^^^^ | help: use `#[rustc_align(...)]` instead - --> $DIR/malformed-attrs.rs:45:1 + --> $DIR/malformed-attrs.rs:47:1 | LL | #[repr] | ^^^^^^^ warning: `#[diagnostic::do_not_recommend]` does not expect any arguments - --> $DIR/malformed-attrs.rs:146:1 + --> $DIR/malformed-attrs.rs:149:1 | LL | #[diagnostic::do_not_recommend()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -733,7 +757,7 @@ LL | #[diagnostic::do_not_recommend()] = note: `#[warn(malformed_diagnostic_attributes)]` on by default warning: missing options for `on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:135:1 + --> $DIR/malformed-attrs.rs:138:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -741,7 +765,7 @@ LL | #[diagnostic::on_unimplemented] = help: at least one of the `message`, `note` and `label` options are expected warning: malformed `on_unimplemented` attribute - --> $DIR/malformed-attrs.rs:137:1 + --> $DIR/malformed-attrs.rs:140:1 | LL | #[diagnostic::on_unimplemented = 1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -749,7 +773,7 @@ LL | #[diagnostic::on_unimplemented = 1] = help: only `message`, `note` and `label` are allowed as options error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` - --> $DIR/malformed-attrs.rs:50:1 + --> $DIR/malformed-attrs.rs:52:1 | LL | #[inline = 5] | ^^^^^^^^^^^^^ @@ -758,7 +782,7 @@ LL | #[inline = 5] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:91:1 + --> $DIR/malformed-attrs.rs:94:1 | LL | #[ignore()] | ^^^^^^^^^^^ @@ -767,7 +791,7 @@ LL | #[ignore()] = note: for more information, see issue #57571 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:220:1 + --> $DIR/malformed-attrs.rs:223:1 | LL | #[ignore = 1] | ^^^^^^^^^^^^^ @@ -776,7 +800,7 @@ LL | #[ignore = 1] = note: for more information, see issue #57571 error[E0308]: mismatched types - --> $DIR/malformed-attrs.rs:108:23 + --> $DIR/malformed-attrs.rs:111:23 | LL | fn test() { | - help: a return type might be missing here: `-> _` @@ -784,15 +808,15 @@ LL | #[coroutine = 63] || {} | ^^^^^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{coroutine@$DIR/malformed-attrs.rs:108:23: 108:25}` + found coroutine `{coroutine@$DIR/malformed-attrs.rs:111:23: 111:25}` -error: aborting due to 74 previous errors; 3 warnings emitted +error: aborting due to 77 previous errors; 3 warnings emitted Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805. For more information about an error, try `rustc --explain E0308`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:40:1 + --> $DIR/malformed-attrs.rs:41:1 | LL | #[doc] | ^^^^^^ @@ -804,7 +828,7 @@ LL | #[doc] Future breakage diagnostic: error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]` - --> $DIR/malformed-attrs.rs:73:1 + --> $DIR/malformed-attrs.rs:76:1 | LL | #[doc] | ^^^^^^ @@ -816,7 +840,7 @@ LL | #[doc] Future breakage diagnostic: error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]` - --> $DIR/malformed-attrs.rs:80:1 + --> $DIR/malformed-attrs.rs:83:1 | LL | #[link] | ^^^^^^^ @@ -828,7 +852,7 @@ LL | #[link] Future breakage diagnostic: error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` - --> $DIR/malformed-attrs.rs:50:1 + --> $DIR/malformed-attrs.rs:52:1 | LL | #[inline = 5] | ^^^^^^^^^^^^^ @@ -839,7 +863,7 @@ LL | #[inline = 5] Future breakage diagnostic: error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:91:1 + --> $DIR/malformed-attrs.rs:94:1 | LL | #[ignore()] | ^^^^^^^^^^^ @@ -850,7 +874,7 @@ LL | #[ignore()] Future breakage diagnostic: error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` - --> $DIR/malformed-attrs.rs:220:1 + --> $DIR/malformed-attrs.rs:223:1 | LL | #[ignore = 1] | ^^^^^^^^^^^^^ diff --git a/tests/ui/attributes/malformed-fn-align.rs b/tests/ui/attributes/malformed-fn-align.rs index cf143b28e5484..adce84763abd0 100644 --- a/tests/ui/attributes/malformed-fn-align.rs +++ b/tests/ui/attributes/malformed-fn-align.rs @@ -23,7 +23,7 @@ fn f2() {} #[rustc_align(0)] //~ ERROR invalid alignment value: not a power of two fn f3() {} -#[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on function items +#[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on functions fn f4() {} #[rustc_align(-1)] //~ ERROR expected unsuffixed literal, found `-` @@ -41,14 +41,14 @@ fn f7() {} #[rustc_align(16)] fn f8() {} -#[rustc_align(16)] //~ ERROR `#[rustc_align(...)]` is not supported on struct items +#[rustc_align(16)] //~ ERROR attribute cannot be used on struct S1; -#[rustc_align(32)] //~ ERROR `#[rustc_align(...)]` should be applied to a function item +#[rustc_align(32)] //~ ERROR attribute cannot be used on const FOO: i32 = 42; -#[rustc_align(32)] //~ ERROR `#[rustc_align(...)]` should be applied to a function item +#[rustc_align(32)] //~ ERROR attribute cannot be used on mod test {} -#[rustc_align(32)] //~ ERROR `#[rustc_align(...)]` should be applied to a function item +#[rustc_align(32)] //~ ERROR attribute cannot be used on use ::std::iter; diff --git a/tests/ui/attributes/malformed-fn-align.stderr b/tests/ui/attributes/malformed-fn-align.stderr index d995a7bf0703f..346fe2b4b7fdd 100644 --- a/tests/ui/attributes/malformed-fn-align.stderr +++ b/tests/ui/attributes/malformed-fn-align.stderr @@ -69,53 +69,49 @@ error[E0589]: invalid alignment value: not a power of two LL | #[rustc_align(3)] | ^ -error: `#[repr(align(...))]` is not supported on function items - --> $DIR/malformed-fn-align.rs:26:8 - | -LL | #[repr(align(16))] - | ^^^^^^^^^ - | -help: use `#[rustc_align(...)]` instead - --> $DIR/malformed-fn-align.rs:26:8 - | -LL | #[repr(align(16))] - | ^^^^^^^^^ - -error: `#[rustc_align(...)]` is not supported on struct items +error: `#[rustc_align]` attribute cannot be used on structs --> $DIR/malformed-fn-align.rs:44:1 | LL | #[rustc_align(16)] | ^^^^^^^^^^^^^^^^^^ | -help: use `#[repr(align(...))]` instead - | -LL - #[rustc_align(16)] -LL + #[repr(align(16))] - | + = help: `#[rustc_align]` can only be applied to functions -error: `#[rustc_align(...)]` should be applied to a function item +error: `#[rustc_align]` attribute cannot be used on constants --> $DIR/malformed-fn-align.rs:47:1 | LL | #[rustc_align(32)] | ^^^^^^^^^^^^^^^^^^ -LL | const FOO: i32 = 42; - | -------------------- not a function item + | + = help: `#[rustc_align]` can only be applied to functions -error: `#[rustc_align(...)]` should be applied to a function item +error: `#[rustc_align]` attribute cannot be used on modules --> $DIR/malformed-fn-align.rs:50:1 | LL | #[rustc_align(32)] | ^^^^^^^^^^^^^^^^^^ -LL | mod test {} - | ----------- not a function item + | + = help: `#[rustc_align]` can only be applied to functions -error: `#[rustc_align(...)]` should be applied to a function item +error: `#[rustc_align]` attribute cannot be used on use statements --> $DIR/malformed-fn-align.rs:53:1 | LL | #[rustc_align(32)] | ^^^^^^^^^^^^^^^^^^ -LL | use ::std::iter; - | ---------------- not a function item + | + = help: `#[rustc_align]` can only be applied to functions + +error: `#[repr(align(...))]` is not supported on functions + --> $DIR/malformed-fn-align.rs:26:8 + | +LL | #[repr(align(16))] + | ^^^^^^^^^ + | +help: use `#[rustc_align(...)]` instead + --> $DIR/malformed-fn-align.rs:26:8 + | +LL | #[repr(align(16))] + | ^^^^^^^^^ error: aborting due to 15 previous errors diff --git a/tests/ui/attributes/multiple-invalid.rs b/tests/ui/attributes/multiple-invalid.rs index ae044eb843bd9..49d1aeed60412 100644 --- a/tests/ui/attributes/multiple-invalid.rs +++ b/tests/ui/attributes/multiple-invalid.rs @@ -2,9 +2,9 @@ // on an item. #[inline] -//~^ ERROR attribute should be applied to function or closure [E0518] +//~^ ERROR attribute cannot be used on #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on const FOO: u8 = 0; fn main() { } diff --git a/tests/ui/attributes/multiple-invalid.stderr b/tests/ui/attributes/multiple-invalid.stderr index f4f7dd7c4f1f8..182d39b14bc53 100644 --- a/tests/ui/attributes/multiple-invalid.stderr +++ b/tests/ui/attributes/multiple-invalid.stderr @@ -1,21 +1,18 @@ -error: attribute should be applied to a function definition +error: `#[inline]` attribute cannot be used on constants + --> $DIR/multiple-invalid.rs:4:1 + | +LL | #[inline] + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + +error: `#[target_feature]` attribute cannot be used on constants --> $DIR/multiple-invalid.rs:6:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | const FOO: u8 = 0; - | ------------------ not a function definition - -error[E0518]: attribute should be applied to function or closure - --> $DIR/multiple-invalid.rs:4:1 | -LL | #[inline] - | ^^^^^^^^^ -... -LL | const FOO: u8 = 0; - | ------------------ not a function or closure + = help: `#[target_feature]` can only be applied to functions error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0518`. diff --git a/tests/ui/attributes/optimize.rs b/tests/ui/attributes/optimize.rs index 7a1cc1be9eec5..78e05f111e7bf 100644 --- a/tests/ui/attributes/optimize.rs +++ b/tests/ui/attributes/optimize.rs @@ -5,11 +5,11 @@ //@ edition: 2018 -#[optimize(speed)] //~ ERROR attribute applied to an invalid target +#[optimize(speed)] //~ ERROR attribute cannot be used on struct F; fn invalid() { - #[optimize(speed)] //~ ERROR attribute applied to an invalid target + #[optimize(speed)] //~ ERROR attribute cannot be used on { 1 }; @@ -18,10 +18,10 @@ fn invalid() { #[optimize(speed)] fn valid() {} -#[optimize(speed)] //~ ERROR attribute applied to an invalid target +#[optimize(speed)] //~ ERROR attribute cannot be used on mod valid_module {} -#[optimize(speed)] //~ ERROR attribute applied to an invalid target +#[optimize(speed)] //~ ERROR attribute cannot be used on impl F {} fn main() { diff --git a/tests/ui/attributes/optimize.stderr b/tests/ui/attributes/optimize.stderr index ad9309d27a5a8..2ded1a973f33d 100644 --- a/tests/ui/attributes/optimize.stderr +++ b/tests/ui/attributes/optimize.stderr @@ -1,36 +1,34 @@ -error: attribute applied to an invalid target +error: `#[optimize]` attribute cannot be used on structs --> $DIR/optimize.rs:8:1 | LL | #[optimize(speed)] | ^^^^^^^^^^^^^^^^^^ -LL | struct F; - | --------- invalid target + | + = help: `#[optimize]` can only be applied to functions -error: attribute applied to an invalid target +error: `#[optimize]` attribute cannot be used on expressions --> $DIR/optimize.rs:12:5 | -LL | #[optimize(speed)] - | ^^^^^^^^^^^^^^^^^^ -LL | / { -LL | | 1 -LL | | }; - | |_____- invalid target +LL | #[optimize(speed)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: `#[optimize]` can only be applied to functions -error: attribute applied to an invalid target +error: `#[optimize]` attribute cannot be used on modules --> $DIR/optimize.rs:21:1 | LL | #[optimize(speed)] | ^^^^^^^^^^^^^^^^^^ -LL | mod valid_module {} - | ------------------- invalid target + | + = help: `#[optimize]` can only be applied to functions -error: attribute applied to an invalid target +error: `#[optimize]` attribute cannot be used on inherent impl blocks --> $DIR/optimize.rs:24:1 | LL | #[optimize(speed)] | ^^^^^^^^^^^^^^^^^^ -LL | impl F {} - | --------- invalid target + | + = help: `#[optimize]` can only be applied to functions error: aborting due to 4 previous errors diff --git a/tests/ui/attributes/positions/used.rs b/tests/ui/attributes/positions/used.rs index 7950fa773a109..7e106d278f279 100644 --- a/tests/ui/attributes/positions/used.rs +++ b/tests/ui/attributes/positions/used.rs @@ -4,20 +4,20 @@ #[used] static FOO: u32 = 0; // OK -#[used] //~ ERROR attribute must be applied to a `static` variable +#[used] //~ ERROR attribute cannot be used on fn foo() {} -#[used] //~ ERROR attribute must be applied to a `static` variable +#[used] //~ ERROR attribute cannot be used on struct Foo {} -#[used] //~ ERROR attribute must be applied to a `static` variable +#[used] //~ ERROR attribute cannot be used on trait Bar {} -#[used] //~ ERROR attribute must be applied to a `static` variable +#[used] //~ ERROR attribute cannot be used on impl Bar for Foo {} // Regression test for . extern "C" { - #[used] //~ ERROR attribute must be applied to a `static` variable + #[used] //~ ERROR attribute cannot be used on static BAR: i32; } diff --git a/tests/ui/attributes/positions/used.stderr b/tests/ui/attributes/positions/used.stderr index 64460c178cb03..79011f3a758f5 100644 --- a/tests/ui/attributes/positions/used.stderr +++ b/tests/ui/attributes/positions/used.stderr @@ -1,42 +1,42 @@ -error: attribute must be applied to a `static` variable +error: `#[used]` attribute cannot be used on functions --> $DIR/used.rs:7:1 | LL | #[used] | ^^^^^^^ -LL | fn foo() {} - | ----------- but this is a function + | + = help: `#[used]` can only be applied to statics -error: attribute must be applied to a `static` variable +error: `#[used]` attribute cannot be used on structs --> $DIR/used.rs:10:1 | LL | #[used] | ^^^^^^^ -LL | struct Foo {} - | ------------- but this is a struct + | + = help: `#[used]` can only be applied to statics -error: attribute must be applied to a `static` variable +error: `#[used]` attribute cannot be used on traits --> $DIR/used.rs:13:1 | LL | #[used] | ^^^^^^^ -LL | trait Bar {} - | ------------ but this is a trait + | + = help: `#[used]` can only be applied to statics -error: attribute must be applied to a `static` variable +error: `#[used]` attribute cannot be used on trait impl blocks --> $DIR/used.rs:16:1 | LL | #[used] | ^^^^^^^ -LL | impl Bar for Foo {} - | ------------------- but this is a trait implementation block + | + = help: `#[used]` can only be applied to statics -error: attribute must be applied to a `static` variable +error: `#[used]` attribute cannot be used on foreign statics --> $DIR/used.rs:21:5 | LL | #[used] | ^^^^^^^ -LL | static BAR: i32; - | ---------------- but this is a foreign static item + | + = help: `#[used]` can only be applied to statics error: aborting due to 5 previous errors diff --git a/tests/ui/attributes/rustc_confusables.rs b/tests/ui/attributes/rustc_confusables.rs index a8095936cff7a..91c66a75cc3a6 100644 --- a/tests/ui/attributes/rustc_confusables.rs +++ b/tests/ui/attributes/rustc_confusables.rs @@ -43,5 +43,6 @@ impl Bar { } #[rustc_confusables("blah")] -//~^ ERROR attribute should be applied to an inherent method +//~^ ERROR attribute cannot be used on +//~| HELP can only be applied to fn not_inherent_impl_method() {} diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr index 3ed4efeb4dbc6..c714257ee77d9 100644 --- a/tests/ui/attributes/rustc_confusables.stderr +++ b/tests/ui/attributes/rustc_confusables.stderr @@ -22,11 +22,13 @@ LL | #[rustc_confusables(invalid_meta_item)] | | expected a string literal here | help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` -error: attribute should be applied to an inherent method +error: `#[rustc_confusables]` attribute cannot be used on functions --> $DIR/rustc_confusables.rs:45:1 | LL | #[rustc_confusables("blah")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_confusables]` can only be applied to inherent methods error[E0599]: no method named `inser` found for struct `rustc_confusables_across_crate::BTreeSet` in the current scope --> $DIR/rustc_confusables.rs:12:7 diff --git a/tests/ui/attributes/rustc_skip_during_method_dispatch.rs b/tests/ui/attributes/rustc_skip_during_method_dispatch.rs index 25b473d5a5851..e1bd0ca3896b0 100644 --- a/tests/ui/attributes/rustc_skip_during_method_dispatch.rs +++ b/tests/ui/attributes/rustc_skip_during_method_dispatch.rs @@ -32,7 +32,7 @@ trait String {} trait OK {} #[rustc_skip_during_method_dispatch(array)] -//~^ ERROR: attribute should be applied to a trait +//~^ ERROR: attribute cannot be used on impl OK for () {} fn main() {} diff --git a/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr b/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr index 2f5d79684899f..094987e944fdf 100644 --- a/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr +++ b/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr @@ -61,14 +61,13 @@ LL | #[rustc_skip_during_method_dispatch("array")] | | didn't expect a literal here | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]` -error: attribute should be applied to a trait +error: `#[rustc_skip_during_method_dispatch]` attribute cannot be used on trait impl blocks --> $DIR/rustc_skip_during_method_dispatch.rs:34:1 | LL | #[rustc_skip_during_method_dispatch(array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | impl OK for () {} - | ----------------- not a trait + | + = help: `#[rustc_skip_during_method_dispatch]` can only be applied to traits error: aborting due to 8 previous errors diff --git a/tests/ui/coroutine/invalid_attr_usage.rs b/tests/ui/coroutine/invalid_attr_usage.rs index 995a3aa3100fc..5081c17de4bae 100644 --- a/tests/ui/coroutine/invalid_attr_usage.rs +++ b/tests/ui/coroutine/invalid_attr_usage.rs @@ -3,9 +3,9 @@ #![feature(coroutines)] #[coroutine] -//~^ ERROR: attribute should be applied to closures +//~^ ERROR: attribute cannot be used on struct Foo; #[coroutine] -//~^ ERROR: attribute should be applied to closures +//~^ ERROR: attribute cannot be used on fn main() {} diff --git a/tests/ui/coroutine/invalid_attr_usage.stderr b/tests/ui/coroutine/invalid_attr_usage.stderr index 316a0117e5d41..46fc80c1bad49 100644 --- a/tests/ui/coroutine/invalid_attr_usage.stderr +++ b/tests/ui/coroutine/invalid_attr_usage.stderr @@ -1,14 +1,18 @@ -error: attribute should be applied to closures +error: `#[coroutine]` attribute cannot be used on structs --> $DIR/invalid_attr_usage.rs:5:1 | LL | #[coroutine] | ^^^^^^^^^^^^ + | + = help: `#[coroutine]` can only be applied to closures -error: attribute should be applied to closures +error: `#[coroutine]` attribute cannot be used on functions --> $DIR/invalid_attr_usage.rs:9:1 | LL | #[coroutine] | ^^^^^^^^^^^^ + | + = help: `#[coroutine]` can only be applied to closures error: aborting due to 2 previous errors diff --git a/tests/ui/coverage-attr/allowed-positions.rs b/tests/ui/coverage-attr/allowed-positions.rs index f1169fa657006..cfbc7f5e6c0c7 100644 --- a/tests/ui/coverage-attr/allowed-positions.rs +++ b/tests/ui/coverage-attr/allowed-positions.rs @@ -11,24 +11,24 @@ #[coverage(off)] mod submod {} -#[coverage(off)] //~ ERROR coverage attribute not allowed here [E0788] +#[coverage(off)] //~ ERROR attribute cannot be used on type MyTypeAlias = (); -#[coverage(off)] //~ ERROR [E0788] +#[coverage(off)] //~ ERROR attribute cannot be used on trait MyTrait { - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on const TRAIT_ASSOC_CONST: u32; - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on type TraitAssocType; - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on fn trait_method(&self); #[coverage(off)] fn trait_method_with_default(&self) {} - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on fn trait_assoc_fn(); } @@ -36,7 +36,7 @@ trait MyTrait { impl MyTrait for () { const TRAIT_ASSOC_CONST: u32 = 0; - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on type TraitAssocType = Self; #[coverage(off)] @@ -53,14 +53,14 @@ trait HasAssocType { } impl HasAssocType for () { - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on type T = impl Copy; fn constrain_assoc_type() -> Self::T {} } -#[coverage(off)] //~ ERROR [E0788] +#[coverage(off)] //~ ERROR attribute cannot be used on struct MyStruct { - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on field: u32, } @@ -73,25 +73,25 @@ impl MyStruct { } extern "C" { - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on static X: u32; - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on type T; - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on fn foreign_fn(); } #[coverage(off)] fn main() { - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on let _ = (); // Currently not allowed on let statements, even if they bind to a closure. // It might be nice to support this as a special case someday, but trying // to define the precise boundaries of that special case might be tricky. - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on let _let_closure = || (); // In situations where attributes can already be applied to expressions, @@ -107,10 +107,10 @@ fn main() { //~^ ERROR attributes on expressions are experimental [E0658] match () { - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on () => (), } - #[coverage(off)] //~ ERROR [E0788] + #[coverage(off)] //~ ERROR attribute cannot be used on return (); } diff --git a/tests/ui/coverage-attr/allowed-positions.stderr b/tests/ui/coverage-attr/allowed-positions.stderr index 34562a4da1b8a..aaef3ad020346 100644 --- a/tests/ui/coverage-attr/allowed-positions.stderr +++ b/tests/ui/coverage-attr/allowed-positions.stderr @@ -8,185 +8,142 @@ LL | let _closure_expr = #[coverage(off)] || (); = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0788]: coverage attribute not allowed here +error: `#[coverage]` attribute cannot be used on type aliases --> $DIR/allowed-positions.rs:14:1 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | type MyTypeAlias = (); - | ---------------------- not a function, impl block, or module | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here +error: `#[coverage]` attribute cannot be used on traits --> $DIR/allowed-positions.rs:17:1 | -LL | #[coverage(off)] - | ^^^^^^^^^^^^^^^^ -LL | / trait MyTrait { -LL | | #[coverage(off)] -LL | | const TRAIT_ASSOC_CONST: u32; -... | -LL | | fn trait_assoc_fn(); -LL | | } - | |_- not a function, impl block, or module +LL | #[coverage(off)] + | ^^^^^^^^^^^^^^^^ | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:61:1 +error: `#[coverage]` attribute cannot be used on associated consts + --> $DIR/allowed-positions.rs:19:5 | -LL | #[coverage(off)] - | ^^^^^^^^^^^^^^^^ -LL | / struct MyStruct { -LL | | #[coverage(off)] -LL | | field: u32, -LL | | } - | |_- not a function, impl block, or module +LL | #[coverage(off)] + | ^^^^^^^^^^^^^^^^ | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:63:5 +error: `#[coverage]` attribute cannot be used on associated types + --> $DIR/allowed-positions.rs:22:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | field: u32, - | ---------- not a function, impl block, or module | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:88:5 +error: `#[coverage]` attribute cannot be used on required trait methods + --> $DIR/allowed-positions.rs:25:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | let _ = (); - | ----------- not a function, impl block, or module | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to impl blocks, functions, closures, provided trait methods, trait methods in impl blocks, inherent methods, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:94:5 +error: `#[coverage]` attribute cannot be used on required trait methods + --> $DIR/allowed-positions.rs:31:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | let _let_closure = || (); - | ------------------------- not a function, impl block, or module | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to impl blocks, functions, closures, provided trait methods, trait methods in impl blocks, inherent methods, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:110:9 +error: `#[coverage]` attribute cannot be used on associated types + --> $DIR/allowed-positions.rs:39:5 | -LL | #[coverage(off)] - | ^^^^^^^^^^^^^^^^ -LL | () => (), - | -------- not a function, impl block, or module +LL | #[coverage(off)] + | ^^^^^^^^^^^^^^^^ | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:114:5 +error: `#[coverage]` attribute cannot be used on associated types + --> $DIR/allowed-positions.rs:56:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | return (); - | --------- not a function, impl block, or module | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:19:5 +error: `#[coverage]` attribute cannot be used on structs + --> $DIR/allowed-positions.rs:61:1 | -LL | #[coverage(off)] - | ^^^^^^^^^^^^^^^^ -LL | const TRAIT_ASSOC_CONST: u32; - | ----------------------------- not a function, impl block, or module +LL | #[coverage(off)] + | ^^^^^^^^^^^^^^^^ | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:22:5 +error: `#[coverage]` attribute cannot be used on struct fields + --> $DIR/allowed-positions.rs:63:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | type TraitAssocType; - | -------------------- not a function, impl block, or module | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:25:5 +error: `#[coverage]` attribute cannot be used on foreign statics + --> $DIR/allowed-positions.rs:76:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | fn trait_method(&self); - | ----------------------- function has no body | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:31:5 +error: `#[coverage]` attribute cannot be used on foreign types + --> $DIR/allowed-positions.rs:79:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | fn trait_assoc_fn(); - | -------------------- function has no body | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:39:5 +error: `#[coverage]` attribute cannot be used on foreign functions + --> $DIR/allowed-positions.rs:82:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | type TraitAssocType = Self; - | --------------------------- not a function, impl block, or module | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to methods, impl blocks, functions, closures, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:56:5 +error: `#[coverage]` attribute cannot be used on statements + --> $DIR/allowed-positions.rs:88:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | type T = impl Copy; - | ------------------- not a function, impl block, or module | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:76:5 +error: `#[coverage]` attribute cannot be used on statements + --> $DIR/allowed-positions.rs:94:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | static X: u32; - | -------------- not a function, impl block, or module | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:79:5 +error: `#[coverage]` attribute cannot be used on match arms + --> $DIR/allowed-positions.rs:110:9 | -LL | #[coverage(off)] - | ^^^^^^^^^^^^^^^^ -LL | type T; - | ------- not a function, impl block, or module +LL | #[coverage(off)] + | ^^^^^^^^^^^^^^^^ | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates -error[E0788]: coverage attribute not allowed here - --> $DIR/allowed-positions.rs:82:5 +error: `#[coverage]` attribute cannot be used on expressions + --> $DIR/allowed-positions.rs:114:5 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ -LL | fn foreign_fn(); - | ---------------- function has no body | - = help: coverage attribute can be applied to a function (with body), impl block, or module + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates error: aborting due to 18 previous errors -Some errors have detailed explanations: E0658, E0788. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/coverage-attr/name-value.rs b/tests/ui/coverage-attr/name-value.rs index 8171dbbf69278..6e81ab8961672 100644 --- a/tests/ui/coverage-attr/name-value.rs +++ b/tests/ui/coverage-attr/name-value.rs @@ -20,6 +20,7 @@ mod my_mod_inner { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input +//~| ERROR attribute cannot be used on struct MyStruct; #[coverage = "off"] @@ -27,18 +28,22 @@ struct MyStruct; impl MyStruct { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input + //~| ERROR attribute cannot be used on const X: u32 = 7; } #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input +//~| ERROR attribute cannot be used on trait MyTrait { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input + //~| ERROR attribute cannot be used on const X: u32; #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input + //~| ERROR attribute cannot be used on type T; } @@ -47,10 +52,12 @@ trait MyTrait { impl MyTrait for MyStruct { #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input + //~| ERROR attribute cannot be used on const X: u32 = 8; #[coverage = "off"] //~^ ERROR malformed `coverage` attribute input + //~| ERROR attribute cannot be used on type T = (); } diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr index a838ec5df8ead..2dac2401e3cd9 100644 --- a/tests/ui/coverage-attr/name-value.stderr +++ b/tests/ui/coverage-attr/name-value.stderr @@ -43,8 +43,16 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | +error: `#[coverage]` attribute cannot be used on structs + --> $DIR/name-value.rs:21:1 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/name-value.rs:25:1 + --> $DIR/name-value.rs:26:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -59,7 +67,7 @@ LL + #[coverage(on)] | error[E0539]: malformed `coverage` attribute input - --> $DIR/name-value.rs:28:5 + --> $DIR/name-value.rs:29:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -73,8 +81,16 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | +error: `#[coverage]` attribute cannot be used on associated consts + --> $DIR/name-value.rs:29:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/name-value.rs:33:1 + --> $DIR/name-value.rs:35:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -88,8 +104,16 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | +error: `#[coverage]` attribute cannot be used on traits + --> $DIR/name-value.rs:35:1 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/name-value.rs:36:5 + --> $DIR/name-value.rs:39:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -103,8 +127,16 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | +error: `#[coverage]` attribute cannot be used on associated consts + --> $DIR/name-value.rs:39:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/name-value.rs:40:5 + --> $DIR/name-value.rs:44:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -118,8 +150,16 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | +error: `#[coverage]` attribute cannot be used on associated types + --> $DIR/name-value.rs:44:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/name-value.rs:45:1 + --> $DIR/name-value.rs:50:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -134,7 +174,7 @@ LL + #[coverage(on)] | error[E0539]: malformed `coverage` attribute input - --> $DIR/name-value.rs:48:5 + --> $DIR/name-value.rs:53:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -148,8 +188,16 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | +error: `#[coverage]` attribute cannot be used on associated consts + --> $DIR/name-value.rs:53:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/name-value.rs:52:5 + --> $DIR/name-value.rs:58:5 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -163,8 +211,16 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | +error: `#[coverage]` attribute cannot be used on associated types + --> $DIR/name-value.rs:58:5 + | +LL | #[coverage = "off"] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/name-value.rs:57:1 + --> $DIR/name-value.rs:64:1 | LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -178,6 +234,6 @@ LL - #[coverage = "off"] LL + #[coverage(on)] | -error: aborting due to 12 previous errors +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/coverage-attr/word-only.rs b/tests/ui/coverage-attr/word-only.rs index 81bd558b8b002..e47279f74ca9b 100644 --- a/tests/ui/coverage-attr/word-only.rs +++ b/tests/ui/coverage-attr/word-only.rs @@ -20,6 +20,7 @@ mod my_mod_inner { #[coverage] //~^ ERROR malformed `coverage` attribute input +//~| ERROR attribute cannot be used on struct MyStruct; #[coverage] @@ -27,18 +28,22 @@ struct MyStruct; impl MyStruct { #[coverage] //~^ ERROR malformed `coverage` attribute input + //~| ERROR attribute cannot be used on const X: u32 = 7; } #[coverage] //~^ ERROR malformed `coverage` attribute input +//~| ERROR attribute cannot be used on trait MyTrait { #[coverage] //~^ ERROR malformed `coverage` attribute input + //~| ERROR attribute cannot be used on const X: u32; #[coverage] //~^ ERROR malformed `coverage` attribute input + //~| ERROR attribute cannot be used on type T; } @@ -47,10 +52,12 @@ trait MyTrait { impl MyTrait for MyStruct { #[coverage] //~^ ERROR malformed `coverage` attribute input + //~| ERROR attribute cannot be used on const X: u32 = 8; #[coverage] //~^ ERROR malformed `coverage` attribute input + //~| ERROR attribute cannot be used on type T = (); } diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr index dd161360a5c4b..e916a817e3678 100644 --- a/tests/ui/coverage-attr/word-only.stderr +++ b/tests/ui/coverage-attr/word-only.stderr @@ -39,8 +39,16 @@ LL | #[coverage(off)] LL | #[coverage(on)] | ++++ +error: `#[coverage]` attribute cannot be used on structs + --> $DIR/word-only.rs:21:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/word-only.rs:25:1 + --> $DIR/word-only.rs:26:1 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -53,7 +61,7 @@ LL | #[coverage(on)] | ++++ error[E0539]: malformed `coverage` attribute input - --> $DIR/word-only.rs:28:5 + --> $DIR/word-only.rs:29:5 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -65,8 +73,16 @@ LL | #[coverage(off)] LL | #[coverage(on)] | ++++ +error: `#[coverage]` attribute cannot be used on associated consts + --> $DIR/word-only.rs:29:5 + | +LL | #[coverage] + | ^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/word-only.rs:33:1 + --> $DIR/word-only.rs:35:1 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -78,8 +94,16 @@ LL | #[coverage(off)] LL | #[coverage(on)] | ++++ +error: `#[coverage]` attribute cannot be used on traits + --> $DIR/word-only.rs:35:1 + | +LL | #[coverage] + | ^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/word-only.rs:36:5 + --> $DIR/word-only.rs:39:5 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -91,8 +115,16 @@ LL | #[coverage(off)] LL | #[coverage(on)] | ++++ +error: `#[coverage]` attribute cannot be used on associated consts + --> $DIR/word-only.rs:39:5 + | +LL | #[coverage] + | ^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/word-only.rs:40:5 + --> $DIR/word-only.rs:44:5 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -104,8 +136,16 @@ LL | #[coverage(off)] LL | #[coverage(on)] | ++++ +error: `#[coverage]` attribute cannot be used on associated types + --> $DIR/word-only.rs:44:5 + | +LL | #[coverage] + | ^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/word-only.rs:45:1 + --> $DIR/word-only.rs:50:1 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -118,7 +158,7 @@ LL | #[coverage(on)] | ++++ error[E0539]: malformed `coverage` attribute input - --> $DIR/word-only.rs:48:5 + --> $DIR/word-only.rs:53:5 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -130,8 +170,16 @@ LL | #[coverage(off)] LL | #[coverage(on)] | ++++ +error: `#[coverage]` attribute cannot be used on associated consts + --> $DIR/word-only.rs:53:5 + | +LL | #[coverage] + | ^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/word-only.rs:52:5 + --> $DIR/word-only.rs:58:5 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -143,8 +191,16 @@ LL | #[coverage(off)] LL | #[coverage(on)] | ++++ +error: `#[coverage]` attribute cannot be used on associated types + --> $DIR/word-only.rs:58:5 + | +LL | #[coverage] + | ^^^^^^^^^^^ + | + = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + error[E0539]: malformed `coverage` attribute input - --> $DIR/word-only.rs:57:1 + --> $DIR/word-only.rs:64:1 | LL | #[coverage] | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument @@ -156,6 +212,6 @@ LL | #[coverage(off)] LL | #[coverage(on)] | ++++ -error: aborting due to 12 previous errors +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs index 80198ab81968f..9698a37602503 100644 --- a/tests/ui/deprecation/deprecation-sanity.rs +++ b/tests/ui/deprecation/deprecation-sanity.rs @@ -1,3 +1,5 @@ +#![deny(unused_attributes)] + // Various checks that deprecation attributes are used correctly mod bogus_attribute_types_1 { @@ -32,7 +34,8 @@ fn f1() { } struct X; -#[deprecated = "hello"] //~ ERROR this `#[deprecated]` annotation has no effect +#[deprecated = "hello"] //~ ERROR attribute cannot be used on +//~| WARN previously accepted impl Default for X { fn default() -> Self { X diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index 856f51a4b249e..1d44215731df4 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -1,11 +1,11 @@ error[E0541]: unknown meta item 'reason' - --> $DIR/deprecation-sanity.rs:4:43 + --> $DIR/deprecation-sanity.rs:6:43 | LL | #[deprecated(since = "a", note = "a", reason)] | ^^^^^^ expected one of `since`, `note` error[E0539]: malformed `deprecated` attribute input - --> $DIR/deprecation-sanity.rs:7:5 + --> $DIR/deprecation-sanity.rs:9:5 | LL | #[deprecated(since = "a", note)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^----^^ @@ -29,7 +29,7 @@ LL + #[deprecated(since = "version", note = "reason")] = and 1 other candidate error[E0539]: malformed `deprecated` attribute input - --> $DIR/deprecation-sanity.rs:10:5 + --> $DIR/deprecation-sanity.rs:12:5 | LL | #[deprecated(since, note = "a")] | ^^^^^^^^^^^^^-----^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL + #[deprecated(since = "version", note = "reason")] = and 1 other candidate error[E0539]: malformed `deprecated` attribute input - --> $DIR/deprecation-sanity.rs:13:5 + --> $DIR/deprecation-sanity.rs:15:5 | LL | #[deprecated(since = "a", note(b))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ @@ -77,7 +77,7 @@ LL + #[deprecated(since = "version", note = "reason")] = and 1 other candidate error[E0539]: malformed `deprecated` attribute input - --> $DIR/deprecation-sanity.rs:16:5 + --> $DIR/deprecation-sanity.rs:18:5 | LL | #[deprecated(since(b), note = "a")] | ^^^^^^^^^^^^^--------^^^^^^^^^^^^^^ @@ -101,7 +101,7 @@ LL + #[deprecated(since = "version", note = "reason")] = and 1 other candidate error[E0539]: malformed `deprecated` attribute input - --> $DIR/deprecation-sanity.rs:19:5 + --> $DIR/deprecation-sanity.rs:21:5 | LL | #[deprecated(note = b"test")] | ^^^^^^^^^^^^^^^^^^^^-^^^^^^^^ @@ -111,7 +111,7 @@ LL | #[deprecated(note = b"test")] = note: expected a normal string literal, not a byte string literal error[E0565]: malformed `deprecated` attribute input - --> $DIR/deprecation-sanity.rs:22:5 + --> $DIR/deprecation-sanity.rs:24:5 | LL | #[deprecated("test")] | ^^^^^^^^^^^^^------^^ @@ -135,19 +135,19 @@ LL + #[deprecated(since = "version", note = "reason")] = and 1 other candidate error: multiple `deprecated` attributes - --> $DIR/deprecation-sanity.rs:27:1 + --> $DIR/deprecation-sanity.rs:29:1 | LL | #[deprecated(since = "a", note = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/deprecation-sanity.rs:26:1 + --> $DIR/deprecation-sanity.rs:28:1 | LL | #[deprecated(since = "a", note = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0538]: malformed `deprecated` attribute input - --> $DIR/deprecation-sanity.rs:30:1 + --> $DIR/deprecation-sanity.rs:32:1 | LL | #[deprecated(since = "a", since = "b", note = "c")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^ @@ -170,12 +170,14 @@ LL + #[deprecated(since = "version", note = "reason")] | = and 1 other candidate -error: this `#[deprecated]` annotation has no effect - --> $DIR/deprecation-sanity.rs:35:1 +error: `#[deprecated]` attribute cannot be used on trait impl blocks + --> $DIR/deprecation-sanity.rs:37:1 | LL | #[deprecated = "hello"] - | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove the unnecessary deprecation attribute + | ^^^^^^^^^^^^^^^^^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates = note: `#[deny(useless_deprecated)]` on by default error: aborting due to 10 previous errors diff --git a/tests/ui/error-codes/E0518.rs b/tests/ui/error-codes/E0518.rs deleted file mode 100644 index 9c99702ada81f..0000000000000 --- a/tests/ui/error-codes/E0518.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[inline(always)] //~ ERROR: E0518 -struct Foo; - -#[inline(never)] //~ ERROR: E0518 -impl Foo { -} - -fn main() { -} diff --git a/tests/ui/error-codes/E0518.stderr b/tests/ui/error-codes/E0518.stderr deleted file mode 100644 index 561446f8175db..0000000000000 --- a/tests/ui/error-codes/E0518.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0518]: attribute should be applied to function or closure - --> $DIR/E0518.rs:1:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ -LL | struct Foo; - | ----------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/E0518.rs:4:1 - | -LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ -LL | / impl Foo { -LL | | } - | |_- not a function or closure - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0518`. diff --git a/tests/ui/error-codes/E0718.stderr b/tests/ui/error-codes/E0718.stderr index ec7462765f81f..e7784d193ba7b 100644 --- a/tests/ui/error-codes/E0718.stderr +++ b/tests/ui/error-codes/E0718.stderr @@ -2,7 +2,7 @@ error[E0718]: `owned_box` lang item must be applied to a struct --> $DIR/E0718.rs:4:1 | LL | #[lang = "owned_box"] - | ^^^^^^^^^^^^^^^^^^^^^ attribute should be applied to a struct, not a static item + | ^^^^^^^^^^^^^^^^^^^^^ attribute should be applied to a struct, not a static error: aborting due to 1 previous error diff --git a/tests/ui/extern/extern-no-mangle.rs b/tests/ui/extern/extern-no-mangle.rs index dba9689a07555..6f2d125b92306 100644 --- a/tests/ui/extern/extern-no-mangle.rs +++ b/tests/ui/extern/extern-no-mangle.rs @@ -9,21 +9,21 @@ extern "C" { #[no_mangle] - //~^ WARNING `#[no_mangle]` has no effect on a foreign static - //~^^ WARNING this was previously accepted by the compiler + //~^ WARNING attribute cannot be used on + //~| WARN previously accepted pub static FOO: u8; #[no_mangle] - //~^ WARNING `#[no_mangle]` has no effect on a foreign function - //~^^ WARNING this was previously accepted by the compiler + //~^ WARNING attribute cannot be used on + //~| WARN previously accepted pub fn bar(); } fn no_new_warn() { // Should emit the generic "not a function or static" warning #[no_mangle] - //~^ WARNING attribute should be applied to a free function, impl method or static - //~^^ WARNING this was previously accepted by the compiler + //~^ WARNING attribute cannot be used on + //~| WARN previously accepted let x = 0_u8; } diff --git a/tests/ui/extern/extern-no-mangle.stderr b/tests/ui/extern/extern-no-mangle.stderr index f20ee158ac433..b07cf0d4b4dad 100644 --- a/tests/ui/extern/extern-no-mangle.stderr +++ b/tests/ui/extern/extern-no-mangle.stderr @@ -1,42 +1,34 @@ -warning: attribute should be applied to a free function, impl method or static - --> $DIR/extern-no-mangle.rs:24:5 +warning: `#[no_mangle]` attribute cannot be used on foreign statics + --> $DIR/extern-no-mangle.rs:11:5 | LL | #[no_mangle] | ^^^^^^^^^^^^ -... -LL | let x = 0_u8; - | ------------- not a free function, impl method or static | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[no_mangle]` can be applied to functions, statics note: the lint level is defined here --> $DIR/extern-no-mangle.rs:1:9 | LL | #![warn(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -warning: `#[no_mangle]` has no effect on a foreign static - --> $DIR/extern-no-mangle.rs:11:5 +warning: `#[no_mangle]` attribute cannot be used on foreign functions + --> $DIR/extern-no-mangle.rs:16:5 | LL | #[no_mangle] - | ^^^^^^^^^^^^ help: remove this attribute -... -LL | pub static FOO: u8; - | ------------------- foreign static + | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: symbol names in extern blocks are not mangled + = help: `#[no_mangle]` can be applied to methods, functions, statics -warning: `#[no_mangle]` has no effect on a foreign function - --> $DIR/extern-no-mangle.rs:16:5 +warning: `#[no_mangle]` attribute cannot be used on statements + --> $DIR/extern-no-mangle.rs:24:5 | LL | #[no_mangle] - | ^^^^^^^^^^^^ help: remove this attribute -... -LL | pub fn bar(); - | ------------- foreign function + | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: symbol names in extern blocks are not mangled + = help: `#[no_mangle]` can be applied to functions, statics warning: 3 warnings emitted diff --git a/tests/ui/extern/issue-47725.rs b/tests/ui/extern/issue-47725.rs index 8ac866dc7d92f..b0a0af930defb 100644 --- a/tests/ui/extern/issue-47725.rs +++ b/tests/ui/extern/issue-47725.rs @@ -1,22 +1,25 @@ #![warn(unused_attributes)] //~ NOTE lint level is defined here #[link_name = "foo"] -//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] -//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -struct Foo; //~ NOTE not a foreign function or static +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can be applied to +struct Foo; #[link_name = "foobar"] -//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] -//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -//~| HELP try `#[link(name = "foobar")]` instead +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can be applied to extern "C" { fn foo() -> u32; } -//~^^^ NOTE not a foreign function or static #[link_name] //~^ ERROR malformed `link_name` attribute input //~| HELP must be of the form +//~| WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can be applied to //~| NOTE for more information, visit extern "C" { fn bar() -> u32; diff --git a/tests/ui/extern/issue-47725.stderr b/tests/ui/extern/issue-47725.stderr index c5af54b8029ea..704b1d81b6398 100644 --- a/tests/ui/extern/issue-47725.stderr +++ b/tests/ui/extern/issue-47725.stderr @@ -6,40 +6,38 @@ LL | #[link_name] | = note: for more information, visit -warning: attribute should be applied to a foreign function or static +warning: `#[link_name]` attribute cannot be used on structs --> $DIR/issue-47725.rs:3:1 | LL | #[link_name = "foo"] | ^^^^^^^^^^^^^^^^^^^^ -... -LL | struct Foo; - | ----------- not a foreign function or static | = 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_name]` can be applied to foreign functions, foreign statics note: the lint level is defined here --> $DIR/issue-47725.rs:1:9 | LL | #![warn(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -warning: attribute should be applied to a foreign function or static - --> $DIR/issue-47725.rs:8:1 +warning: `#[link_name]` attribute cannot be used on foreign modules + --> $DIR/issue-47725.rs:9:1 | -LL | #[link_name = "foobar"] - | ^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | / extern "C" { -LL | | fn foo() -> u32; -LL | | } - | |_- not a foreign function or static +LL | #[link_name = "foobar"] + | ^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -help: try `#[link(name = "foobar")]` instead - --> $DIR/issue-47725.rs:8:1 + = help: `#[link_name]` can be applied to foreign functions, foreign statics + +warning: `#[link_name]` attribute cannot be used on foreign modules + --> $DIR/issue-47725.rs:17:1 | -LL | #[link_name = "foobar"] - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_name] + | ^^^^^^^^^^^^ + | + = 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_name]` can be applied to foreign functions, foreign statics -error: aborting due to 1 previous error; 2 warnings emitted +error: aborting due to 1 previous error; 3 warnings emitted For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs index 81b7fe3db2ba8..91caba81cb6b8 100644 --- a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs +++ b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs @@ -4,7 +4,7 @@ // FIXME(jdonszelmann): empty attributes are currently ignored, since when its empty no actual // change is applied. This should be fixed when later moving this check to attribute parsing. #[allow_internal_unstable(something)] //~ ERROR allow_internal_unstable side-steps -//~| ERROR attribute should +//~| ERROR attribute cannot be used on struct S; fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr index 076f2df28e3f3..cb8cf29e99d22 100644 --- a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr +++ b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr @@ -7,14 +7,13 @@ LL | #[allow_internal_unstable(something)] = help: add `#![feature(allow_internal_unstable)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: attribute should be applied to a macro +error: `#[allow_internal_unstable]` attribute cannot be used on structs --> $DIR/feature-gate-allow-internal-unstable-struct.rs:6:1 | LL | #[allow_internal_unstable(something)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | struct S; - | --------- not a macro + | + = help: `#[allow_internal_unstable]` can be applied to macro defs, functions error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs index 7fb11b7bde73b..130dd48b0fe28 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs @@ -1,6 +1,4 @@ //~ NOTE: not an `extern crate` item -//~^ NOTE: not a free function, impl method or static -//~^^ NOTE: not a function or closure // This is testing whether various builtin attributes signals an // error or warning when put in "weird" places. // @@ -19,29 +17,25 @@ #![repr()] //~^ ERROR: `repr` attribute cannot be used at crate level #![path = "3800"] -//~^ ERROR: `path` attribute cannot be used at crate level +//~^ ERROR: attribute cannot be used on #![automatically_derived] -//~^ ERROR: `automatically_derived` attribute cannot be used at crate level +//~^ ERROR: attribute cannot be used on #![no_mangle] #![no_link] //~^ ERROR: attribute should be applied to an `extern crate` item #![export_name = "2200"] -//~^ ERROR: attribute should be applied to a free function, impl method or static +//~^ ERROR: attribute cannot be used on #![inline] -//~^ ERROR: attribute should be applied to function or closure +//~^ ERROR: attribute cannot be used on #[inline] -//~^ ERROR attribute should be applied to function or closure +//~^ ERROR attribute cannot be used on mod inline { - //~^ NOTE not a function or closure - //~| NOTE the inner attribute doesn't annotate this module - //~| NOTE the inner attribute doesn't annotate this module - //~| NOTE the inner attribute doesn't annotate this module + //~^ NOTE the inner attribute doesn't annotate this module //~| NOTE the inner attribute doesn't annotate this module //~| NOTE the inner attribute doesn't annotate this module mod inner { #![inline] } - //~^ ERROR attribute should be applied to function or closure - //~| NOTE not a function or closure + //~^ ERROR attribute cannot be used on #[inline = "2100"] fn f() { } //~^ ERROR valid forms for the attribute are @@ -50,16 +44,13 @@ mod inline { //~| NOTE for more information, see issue #57571 #[inline] struct S; - //~^ ERROR attribute should be applied to function or closure - //~| NOTE not a function or closure + //~^ ERROR attribute cannot be used on #[inline] type T = S; - //~^ ERROR attribute should be applied to function or closure - //~| NOTE not a function or closure + //~^ ERROR attribute cannot be used on #[inline] impl S { } - //~^ ERROR attribute should be applied to function or closure - //~| NOTE not a function or closure + //~^ ERROR attribute cannot be used on } #[no_link] @@ -89,36 +80,27 @@ mod no_link { } #[export_name = "2200"] -//~^ ERROR attribute should be applied to a free function, impl method or static +//~^ ERROR attribute cannot be used on mod export_name { - //~^ NOTE not a free function, impl method or static - mod inner { #![export_name="2200"] } - //~^ ERROR attribute should be applied to a free function, impl method or static - //~| NOTE not a free function, impl method or static + //~^ ERROR attribute cannot be used on #[export_name = "2200"] fn f() { } #[export_name = "2200"] struct S; - //~^ ERROR attribute should be applied to a free function, impl method or static - //~| NOTE not a free function, impl method or static + //~^ ERROR attribute cannot be used on #[export_name = "2200"] type T = S; - //~^ ERROR attribute should be applied to a free function, impl method or static - //~| NOTE not a free function, impl method or static + //~^ ERROR attribute cannot be used on #[export_name = "2200"] impl S { } - //~^ ERROR attribute should be applied to a free function, impl method or static - //~| NOTE not a free function, impl method or static + //~^ ERROR attribute cannot be used on trait Tr { #[export_name = "2200"] fn foo(); - //~^ ERROR attribute should be applied to a free function, impl method or static - //~| NOTE not a free function, impl method or static + //~^ ERROR attribute cannot be used on #[export_name = "2200"] fn bar() {} - //~^ ERROR attribute should be applied to a free function, impl method or static - //~| NOTE not a free function, impl method or static } } diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 7550e26f4a797..13dce72a8825a 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -1,5 +1,5 @@ error[E0658]: use of an internal attribute - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1 | LL | #![rustc_main] | ^^^^^^^^^^^^^^ @@ -8,19 +8,128 @@ LL | #![rustc_main] = note: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable = note: the `#[rustc_main]` attribute is used internally to specify test entry point function -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1 +error: `#[path]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 | -LL | #[inline] - | ^^^^^^^^^ -LL | -LL | / mod inline { -... | -LL | | } - | |_- not a function or closure +LL | #![path = "3800"] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[path]` can only be applied to modules + +error: `#[automatically_derived]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1 + | +LL | #![automatically_derived] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[automatically_derived]` can only be applied to trait impl blocks + +error: `#[export_name]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1 + | +LL | #![export_name = "2200"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[export_name]` can be applied to functions, statics + +error: `#[inline]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1 + | +LL | #![inline] + | ^^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + +error: `#[inline]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1 + | +LL | #[inline] + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + +error: `#[inline]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:37:17 + | +LL | mod inner { #![inline] } + | ^^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + +error: `#[inline]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5 + | +LL | #[inline] struct S; + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + +error: `#[inline]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:49:5 + | +LL | #[inline] type T = S; + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + +error: `#[inline]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:52:5 + | +LL | #[inline] impl S { } + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + +error: `#[export_name]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:1 + | +LL | #[export_name = "2200"] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[export_name]` can be applied to functions, statics + +error: `#[export_name]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:85:17 + | +LL | mod inner { #![export_name="2200"] } + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[export_name]` can be applied to functions, statics + +error: `#[export_name]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:90:5 + | +LL | #[export_name = "2200"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[export_name]` can be applied to functions, statics + +error: `#[export_name]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:93:5 + | +LL | #[export_name = "2200"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[export_name]` can be applied to functions, statics + +error: `#[export_name]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:5 + | +LL | #[export_name = "2200"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[export_name]` can be applied to functions, statics + +error: `#[export_name]` attribute cannot be used on required trait methods + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:9 + | +LL | #[export_name = "2200"] fn foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[export_name]` can be applied to statics, functions, inherent methods, provided trait methods, trait methods in impl blocks error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:65:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:56:1 | LL | #[no_link] | ^^^^^^^^^^ @@ -33,22 +142,8 @@ LL | | mod inner { #![no_link] } LL | | } | |_- not an `extern crate` item -error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:1 - | -LL | #[export_name = "2200"] - | ^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / mod export_name { -LL | | -LL | | -LL | | mod inner { #![export_name="2200"] } -... | -LL | | } - | |_- not a free function, impl method or static - error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:125:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:107:8 | LL | #[repr(C)] | ^ @@ -61,7 +156,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:149:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:8 | LL | #[repr(Rust)] | ^^^^ @@ -74,25 +169,13 @@ LL | | } | |_- not a struct, enum, or union error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1 | LL | #![no_link] | ^^^^^^^^^^^ not an `extern crate` item -error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1 - | -LL | #![export_name = "2200"] - | ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1 - | -LL | #![inline] - | ^^^^^^^^^^ not a function or closure - error: `macro_export` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:10:1 | LL | #![macro_export] | ^^^^^^^^^^^^^^^^ @@ -107,7 +190,7 @@ LL + #[macro_export] | error: `rustc_main` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1 | LL | #![rustc_main] | ^^^^^^^^^^^^^^ @@ -122,7 +205,7 @@ LL + #[rustc_main] | error: `repr` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1 | LL | #![repr()] | ^^^^^^^^^^ @@ -136,176 +219,86 @@ LL - #![repr()] LL + #[repr()] | -error: `path` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1 - | -LL | #![path = "3800"] - | ^^^^^^^^^^^^^^^^^ -... -LL | mod inline { - | ------ the inner attribute doesn't annotate this module - | -help: perhaps you meant to use an outer attribute - | -LL - #![path = "3800"] -LL + #[path = "3800"] - | - -error: `automatically_derived` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1 - | -LL | #![automatically_derived] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | mod inline { - | ------ the inner attribute doesn't annotate this module - | -help: perhaps you meant to use an outer attribute - | -LL - #![automatically_derived] -LL + #[automatically_derived] - | - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:42:17 - | -LL | mod inner { #![inline] } - | ------------^^^^^^^^^^-- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:52:5 - | -LL | #[inline] struct S; - | ^^^^^^^^^ --------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:56:5 - | -LL | #[inline] type T = S; - | ^^^^^^^^^ ----------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:5 - | -LL | #[inline] impl S { } - | ^^^^^^^^^ ---------- not a function or closure - error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:70:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:61:17 | LL | mod inner { #![no_link] } | ------------^^^^^^^^^^^-- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:74:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:65:5 | LL | #[no_link] fn f() { } | ^^^^^^^^^^ ---------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:69:5 | LL | #[no_link] struct S; | ^^^^^^^^^^ --------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:73:5 | LL | #[no_link]type T = S; | ^^^^^^^^^^----------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:77:5 | LL | #[no_link] impl S { } | ^^^^^^^^^^ ---------- not an `extern crate` item -error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:17 - | -LL | mod inner { #![export_name="2200"] } - | ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static - -error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:102:5 - | -LL | #[export_name = "2200"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static - -error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:5 - | -LL | #[export_name = "2200"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static - -error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:5 - | -LL | #[export_name = "2200"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static - -error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:9 - | -LL | #[export_name = "2200"] fn foo(); - | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static - -error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:119:9 - | -LL | #[export_name = "2200"] fn bar() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static - error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:111:25 | LL | mod inner { #![repr(C)] } | --------------------^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:133:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:12 | LL | #[repr(C)] fn f() { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:139:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:121:12 | LL | #[repr(C)] type T = S; | ^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:143:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:125:12 | LL | #[repr(C)] impl S { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:153:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:135:25 | LL | mod inner { #![repr(Rust)] } | --------------------^^^^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:157:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:139:12 | LL | #[repr(Rust)] fn f() { } | ^^^^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:163:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:145:12 | LL | #[repr(Rust)] type T = S; | ^^^^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:167:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:149:12 | LL | #[repr(Rust)] impl S { } | ^^^^ ---------- not a struct, enum, or union error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:5 | LL | #[inline = "2100"] fn f() { } | ^^^^^^^^^^^^^^^^^^ @@ -314,13 +307,13 @@ LL | #[inline = "2100"] fn f() { } = note: for more information, see issue #57571 = note: `#[deny(ill_formed_attribute_input)]` on by default -error: aborting due to 38 previous errors +error: aborting due to 37 previous errors -Some errors have detailed explanations: E0517, E0518, E0658. +Some errors have detailed explanations: E0517, E0658. For more information about an error, try `rustc --explain E0517`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:5 | LL | #[inline = "2100"] fn f() { } | ^^^^^^^^^^^^^^^^^^ 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 c91fd600068cd..8702d852a896e 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 @@ -1,7 +1,4 @@ -//~ NOTE not a function -//~| NOTE not a foreign function or static -//~| NOTE cannot be applied to crates -//~| NOTE not an `extern` block +//~ NOTE not an `extern` block // This test enumerates as many compiler-builtin ungated attributes as // possible (that is, all the mutually compatible ones), and checks // that we get "expected" (*) warnings for each in the various weird @@ -50,25 +47,34 @@ #![macro_use] // (allowed if no argument; see issue-43160-gating-of-macro_use.rs) // skipping testing of cfg // skipping testing of cfg_attr -#![should_panic] //~ WARN `#[should_panic]` only has an effect -#![ignore] //~ WARN `#[ignore]` only has an effect on functions +#![should_panic] //~ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can only be applied to +#![ignore] //~ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can only be applied to #![no_implicit_prelude] #![reexport_test_harness_main = "2900"] // see gated-link-args.rs // see issue-43106-gating-of-macro_escape.rs for crate-level; but non crate-level is below at "2700" // (cannot easily test gating of crate-level #[no_std]; but non crate-level is below at "2600") -#![proc_macro_derive(Test)] //~ WARN `#[proc_macro_derive]` only has an effect +#![proc_macro_derive(Test)] //~ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can only be applied to #![doc = "2400"] -#![cold] //~ WARN attribute should be applied to a function -//~^ WARN this was previously accepted +#![cold] //~ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can only be applied to #![link()] //~ WARN attribute should be applied to an `extern` block //~^ WARN this was previously accepted #![link_name = "1900"] -//~^ WARN attribute should be applied to a foreign function -//~^^ WARN this was previously accepted by the compiler +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can be applied to #![link_section = "1800"] -//~^ WARN attribute should be applied to a function or static -//~^^ WARN this was previously accepted by the compiler +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can be applied to #![must_use] //~^ WARN `#[must_use]` has no effect //~| HELP remove the attribute @@ -175,16 +181,24 @@ mod macro_use { mod inner { #![macro_use] } #[macro_use] fn f() { } - //~^ WARN `#[macro_use]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[macro_use] struct S; - //~^ WARN `#[macro_use]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[macro_use] type T = S; - //~^ WARN `#[macro_use]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[macro_use] impl S { } - //~^ WARN `#[macro_use]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to } #[macro_export] @@ -243,116 +257,158 @@ mod path { mod inner { #![path="3800"] } #[path = "3800"] fn f() { } - //~^ WARN `#[path]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[path = "3800"] struct S; - //~^ WARN `#[path]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[path = "3800"] type T = S; - //~^ WARN `#[path]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[path = "3800"] impl S { } - //~^ WARN `#[path]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to } #[automatically_derived] -//~^ WARN `#[automatically_derived]` only has an effect +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can only be applied to mod automatically_derived { mod inner { #![automatically_derived] } - //~^ WARN `#[automatically_derived] + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[automatically_derived] fn f() { } - //~^ WARN `#[automatically_derived] + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[automatically_derived] struct S; - //~^ WARN `#[automatically_derived] + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[automatically_derived] type T = S; - //~^ WARN `#[automatically_derived] + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[automatically_derived] trait W { } - //~^ WARN `#[automatically_derived] + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[automatically_derived] impl S { } - //~^ WARN `#[automatically_derived] + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[automatically_derived] impl W for S { } } #[no_mangle] -//~^ WARN attribute should be applied to a free function, impl method or static [unused_attributes] -//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can be applied to mod no_mangle { - //~^ NOTE not a free function, impl method or static mod inner { #![no_mangle] } - //~^ WARN attribute should be applied to a free function, impl method or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a free function, impl method or static + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[no_mangle] fn f() { } #[no_mangle] struct S; - //~^ WARN attribute should be applied to a free function, impl method or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a free function, impl method or static + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[no_mangle] type T = S; - //~^ WARN attribute should be applied to a free function, impl method or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a free function, impl method or static + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[no_mangle] impl S { } - //~^ WARN attribute should be applied to a free function, impl method or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a free function, impl method or static + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to trait Tr { #[no_mangle] fn foo(); - //~^ WARN attribute should be applied to a free function, impl method or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a free function, impl method or static + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[no_mangle] fn bar() {} - //~^ WARN attribute should be applied to a free function, impl method or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a free function, impl method or static + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to } } #[should_panic] -//~^ WARN `#[should_panic]` only has an effect on +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can only be applied to mod should_panic { mod inner { #![should_panic] } - //~^ WARN `#[should_panic]` only has an effect on + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can only be applied to #[should_panic] fn f() { } #[should_panic] struct S; - //~^ WARN `#[should_panic]` only has an effect on + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can only be applied to #[should_panic] type T = S; - //~^ WARN `#[should_panic]` only has an effect on + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can only be applied to #[should_panic] impl S { } - //~^ WARN `#[should_panic]` only has an effect on + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can only be applied to } #[ignore] -//~^ WARN `#[ignore]` only has an effect on functions +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can only be applied to mod ignore { mod inner { #![ignore] } - //~^ WARN `#[ignore]` only has an effect on functions + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[ignore] fn f() { } #[ignore] struct S; - //~^ WARN `#[ignore]` only has an effect on functions + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[ignore] type T = S; - //~^ WARN `#[ignore]` only has an effect on functions + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to #[ignore] impl S { } - //~^ WARN `#[ignore]` only has an effect on functions + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can only be applied to } #[no_implicit_prelude] @@ -360,16 +416,24 @@ mod no_implicit_prelude { mod inner { #![no_implicit_prelude] } #[no_implicit_prelude] fn f() { } - //~^ WARN `#[no_implicit_prelude]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[no_implicit_prelude] struct S; - //~^ WARN `#[no_implicit_prelude]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[no_implicit_prelude] type T = S; - //~^ WARN `#[no_implicit_prelude]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[no_implicit_prelude] impl S { } - //~^ WARN `#[no_implicit_prelude]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to } #[reexport_test_harness_main = "2900"] @@ -400,16 +464,24 @@ mod macro_escape { //~| HELP try an outer attribute: `#[macro_use]` #[macro_escape] fn f() { } - //~^ WARN `#[macro_escape]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[macro_escape] struct S; - //~^ WARN `#[macro_escape]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[macro_escape] type T = S; - //~^ WARN `#[macro_escape]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to #[macro_escape] impl S { } - //~^ WARN `#[macro_escape]` only has an effect + //~^ WARN attribute cannot be used on +//~| WARN previously accepted + //~| HELP can be applied to } #[no_std] @@ -449,100 +521,97 @@ mod doc { } #[cold] -//~^ WARN attribute should be applied to a function -//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can only be applied to mod cold { - //~^ NOTE not a function mod inner { #![cold] } - //~^ WARN attribute should be applied to a function - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a function + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can only be applied to #[cold] fn f() { } #[cold] struct S; - //~^ WARN attribute should be applied to a function - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a function + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can only be applied to #[cold] type T = S; - //~^ WARN attribute should be applied to a function - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a function + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can only be applied to #[cold] impl S { } - //~^ WARN attribute should be applied to a function - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a function + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can only be applied to } #[link_name = "1900"] -//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] -//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can be applied to mod link_name { - //~^ NOTE not a foreign function or static - #[link_name = "1900"] - //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| HELP try `#[link(name = "1900")]` instead + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to extern "C" { } - //~^ NOTE not a foreign function or static mod inner { #![link_name="1900"] } - //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a foreign function or static + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to #[link_name = "1900"] fn f() { } - //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a foreign function or static + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to #[link_name = "1900"] struct S; - //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a foreign function or static + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to #[link_name = "1900"] type T = S; - //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a foreign function or static + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to #[link_name = "1900"] impl S { } - //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a foreign function or static + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to } #[link_section = "1800"] -//~^ WARN attribute should be applied to a function or static [unused_attributes] -//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//~^ WARN attribute cannot be used on +//~| WARN previously accepted +//~| HELP can be applied to mod link_section { - //~^ NOTE not a function or static - mod inner { #![link_section="1800"] } - //~^ WARN attribute should be applied to a function or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a function or static + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to #[link_section = "1800"] fn f() { } #[link_section = "1800"] struct S; - //~^ WARN attribute should be applied to a function or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a function or static + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to #[link_section = "1800"] type T = S; - //~^ WARN attribute should be applied to a function or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a function or static + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to #[link_section = "1800"] impl S { } - //~^ WARN attribute should be applied to a function or static [unused_attributes] - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| NOTE not a function or static + //~^ WARN attribute cannot be used on + //~| WARN previously accepted + //~| HELP can be applied to } 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 e0ea5382faa95..8e2bffb91ca51 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 @@ -1,5 +1,5 @@ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -7,292 +7,211 @@ LL | mod inner { #![macro_escape] } = help: try an outer attribute: `#[macro_use]` warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:9 | LL | #![warn(x5400)] | ^^^^^ | note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:28 | LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:10 | LL | #![allow(x5300)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:11 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:11 | LL | #![forbid(x5200)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:9 | LL | #![deny(x5100)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:97:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:103:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:100:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:106:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:103:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:106:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:115:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:118:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:134:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:137:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:153:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:156:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:172:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:175:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:1 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:9 | LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:1 - | -LL | #[automatically_derived] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:282:1 - | -LL | #[no_mangle] - | ^^^^^^^^^^^^ -... -LL | / mod no_mangle { -LL | | -LL | | mod inner { #![no_mangle] } -... | -LL | | } - | |_- not a free function, impl method or static - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:322:1 - | -LL | #[should_panic] - | ^^^^^^^^^^^^^^^ - -warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:340:1 - | -LL | #[ignore] - | ^^^^^^^^^ - warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:375:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:415:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:1 | LL | #[no_std] | ^^^^^^^^^ -warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:451:1 - | -LL | #[cold] - | ^^^^^^^ -... -LL | / mod cold { -LL | | -LL | | -LL | | mod inner { #![cold] } -... | -LL | | } - | |_- not a function definition - | - = 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 a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:1 - | -LL | #[link_name = "1900"] - | ^^^^^^^^^^^^^^^^^^^^^ -... -LL | / mod link_name { -LL | | -LL | | -LL | | #[link_name = "1900"] -... | -LL | | } - | |_- not a foreign function or static - | - = 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 a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:1 - | -LL | #[link_section = "1800"] - | ^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | / mod link_section { -LL | | -LL | | -LL | | mod inner { #![link_section="1800"] } -... | -LL | | } - | |_- not a function or static - | - = 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:551:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:1 | LL | #[link()] | ^^^^^^^^^ @@ -307,867 +226,1044 @@ 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: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:602:1 +warning: `#[must_use]` has no effect when applied to modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:1 | LL | #[must_use] | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:1 | LL | #[windows_subsystem = "windows"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:709:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:678:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:747:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:786:1 | LL | #[no_builtins] | ^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:824:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:68:1 | LL | #![link()] | ^^^^^^^^^^ not an `extern` block | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 - | -LL | #![ignore] - | ^^^^^^^^^^ - -warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1 - | -LL | #![link_name = "1900"] - | ^^^^^^^^^^^^^^^^^^^^^^ not a foreign function or static - | - = 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 a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 - | -LL | #![link_section = "1800"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a function or static - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -warning: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 +warning: `#[must_use]` has no effect when applied to modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:78:1 | LL | #![must_use] | ^^^^^^^^^^^^ -warning: `#[proc_macro_derive]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 - | -LL | #![proc_macro_derive(Test)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 - | -LL | #![should_panic] - | ^^^^^^^^^^^^^^^^ - -warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 - | -LL | #![cold] - | ^^^^^^^^ cannot be applied to crates - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:86:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:92:12 | LL | #![feature(rust1)] | ^^^^^ | = note: `#[warn(stable_features)]` on by default -warning: `#[macro_use]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:5 - | -LL | #[macro_use] fn f() { } - | ^^^^^^^^^^^^ - -warning: `#[macro_use]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:180:5 - | -LL | #[macro_use] struct S; - | ^^^^^^^^^^^^ - -warning: `#[macro_use]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:183:5 - | -LL | #[macro_use] type T = S; - | ^^^^^^^^^^^^ - -warning: `#[macro_use]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:186:5 - | -LL | #[macro_use] impl S { } - | ^^^^^^^^^^^^ - warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:17 | LL | mod inner { #![macro_export] } | ^^^^^^^^^^^^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:210:5 | LL | #[macro_export] fn f() { } | ^^^^^^^^^^^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:199:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:5 | LL | #[macro_export] struct S; | ^^^^^^^^^^^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:5 | LL | #[macro_export] type T = S; | ^^^^^^^^^^^^^^^ warning: `#[macro_export]` only has an effect on macro definitions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:5 | LL | #[macro_export] impl S { } | ^^^^^^^^^^^^^^^ -warning: `#[path]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:5 +warning: crate-level attribute should be in the root module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:17 | -LL | #[path = "3800"] fn f() { } - | ^^^^^^^^^^^^^^^^ +LL | mod inner { #![reexport_test_harness_main="2900"] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[path]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:445:5 | -LL | #[path = "3800"] struct S; - | ^^^^^^^^^^^^^^^^ +LL | #[reexport_test_harness_main = "2900"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[path]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:448:5 | -LL | #[path = "3800"] type T = S; - | ^^^^^^^^^^^^^^^^ +LL | #[reexport_test_harness_main = "2900"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[path]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:254:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:451:5 | -LL | #[path = "3800"] impl S { } - | ^^^^^^^^^^^^^^^^ +LL | #[reexport_test_harness_main = "2900"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:17 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:454:5 | -LL | mod inner { #![automatically_derived] } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[reexport_test_harness_main = "2900"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:264:5 +warning: crate-level attribute should be in the root module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:490:17 | -LL | #[automatically_derived] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | mod inner { #![no_std] } + | ^^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:267:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5 | -LL | #[automatically_derived] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[no_std] fn f() { } + | ^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:270:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:496:5 | -LL | #[automatically_derived] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[no_std] struct S; + | ^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:273:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5 | -LL | #[automatically_derived] trait W { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[no_std] type T = S; + | ^^^^^^^^^ -warning: `#[automatically_derived]` only has an effect on trait implementation blocks - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:276:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5 | -LL | #[automatically_derived] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[no_std] impl S { } + | ^^^^^^^^^ -warning: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:287:17 +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:17 | -LL | mod inner { #![no_mangle] } - | ------------^^^^^^^^^^^^^-- not a free function, impl method or static +LL | mod inner { #![link()] } + | ------------^^^^^^^^^^-- not an `extern` block | = 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 a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:294:5 +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:5 | -LL | #[no_mangle] struct S; - | ^^^^^^^^^^^^ --------- not a free function, impl method or static +LL | #[link()] fn f() { } + | ^^^^^^^^^ ---------- not an `extern` block | = 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 a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:299:5 +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:636:5 | -LL | #[no_mangle] type T = S; - | ^^^^^^^^^^^^ ----------- not a free function, impl method or static +LL | #[link()] struct S; + | ^^^^^^^^^ --------- not an `extern` block | = 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 a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:304:5 +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5 | -LL | #[no_mangle] impl S { } - | ^^^^^^^^^^^^ ---------- not a free function, impl method or static +LL | #[link()] type T = S; + | ^^^^^^^^^ ----------- not an `extern` block | = 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 a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:310:9 +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5 | -LL | #[no_mangle] fn foo(); - | ^^^^^^^^^^^^ --------- not a free function, impl method or static +LL | #[link()] impl S { } + | ^^^^^^^^^ ---------- not an `extern` block | = 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 a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:315:9 +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:651:5 | -LL | #[no_mangle] fn bar() {} - | ^^^^^^^^^^^^ ----------- not a free function, impl method or static +LL | #[link()] 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: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:17 +warning: `#[must_use]` has no effect when applied to modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:674:17 | -LL | mod inner { #![should_panic] } - | ^^^^^^^^^^^^^^^^ +LL | mod inner { #![must_use] } + | ^^^^^^^^^^^^ -warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:330:5 +warning: `#[must_use]` has no effect when applied to type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5 | -LL | #[should_panic] struct S; - | ^^^^^^^^^^^^^^^ +LL | #[must_use] type T = S; + | ^^^^^^^^^^^ -warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:5 +warning: `#[must_use]` has no effect when applied to inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5 | -LL | #[should_panic] type T = S; - | ^^^^^^^^^^^^^^^ +LL | #[must_use] impl S { } + | ^^^^^^^^^^^ -warning: `#[should_panic]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:336:5 +warning: crate-level attribute should be in the root module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:691:17 | -LL | #[should_panic] impl S { } - | ^^^^^^^^^^^^^^^ +LL | mod inner { #![windows_subsystem="windows"] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:343:17 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:694:5 | -LL | mod inner { #![ignore] } - | ^^^^^^^^^^ +LL | #[windows_subsystem = "windows"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:348:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:697:5 | -LL | #[ignore] struct S; - | ^^^^^^^^^ +LL | #[windows_subsystem = "windows"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5 | -LL | #[ignore] type T = S; - | ^^^^^^^^^ +LL | #[windows_subsystem = "windows"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[ignore]` only has an effect on functions - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:354:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:703:5 | -LL | #[ignore] impl S { } - | ^^^^^^^^^ +LL | #[windows_subsystem = "windows"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:362:5 +warning: crate-level attribute should be in the root module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:17 | -LL | #[no_implicit_prelude] fn f() { } +LL | mod inner { #![crate_name="0900"] } + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:5 + | +LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:365:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5 | -LL | #[no_implicit_prelude] struct S; +LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:368:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5 | -LL | #[no_implicit_prelude] type T = S; +LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[no_implicit_prelude]` only has an effect on modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:371:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 | -LL | #[no_implicit_prelude] impl S { } +LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:378:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:17 | -LL | mod inner { #![reexport_test_harness_main="2900"] } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | mod inner { #![crate_type="0800"] } + | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:381:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:5 | -LL | #[reexport_test_harness_main = "2900"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[crate_type = "0800"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:384:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | -LL | #[reexport_test_harness_main = "2900"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[crate_type = "0800"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5 | -LL | #[reexport_test_harness_main = "2900"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[crate_type = "0800"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:390:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5 | -LL | #[reexport_test_harness_main = "2900"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[crate_type = "0800"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^ -warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:5 +warning: crate-level attribute should be in the root module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:17 | -LL | #[macro_escape] fn f() { } - | ^^^^^^^^^^^^^^^ +LL | mod inner { #![feature(x0600)] } + | ^^^^^^^^^^^^^^^^^^ -warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:5 | -LL | #[macro_escape] struct S; - | ^^^^^^^^^^^^^^^ +LL | #[feature(x0600)] fn f() { } + | ^^^^^^^^^^^^^^^^^ -warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5 | -LL | #[macro_escape] type T = S; - | ^^^^^^^^^^^^^^^ +LL | #[feature(x0600)] struct S; + | ^^^^^^^^^^^^^^^^^ -warning: `#[macro_escape]` only has an effect on `extern crate` and modules - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5 +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5 | -LL | #[macro_escape] impl S { } - | ^^^^^^^^^^^^^^^ +LL | #[feature(x0600)] type T = S; + | ^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 + | +LL | #[feature(x0600)] impl S { } + | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:418:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:17 | -LL | mod inner { #![no_std] } - | ^^^^^^^^^^ +LL | mod inner { #![no_main] } + | ^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:5 | -LL | #[no_std] fn f() { } - | ^^^^^^^^^ +LL | #[no_main] fn f() { } + | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:5 | -LL | #[no_std] struct S; - | ^^^^^^^^^ +LL | #[no_main] struct S; + | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:5 | -LL | #[no_std] type T = S; - | ^^^^^^^^^ +LL | #[no_main] type T = S; + | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:782:5 | -LL | #[no_std] impl S { } - | ^^^^^^^^^ +LL | #[no_main] impl S { } + | ^^^^^^^^^^ -warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:457:17 +warning: crate-level attribute should be in the root module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:17 | -LL | mod inner { #![cold] } - | ------------^^^^^^^^-- not a function definition +LL | mod inner { #![no_builtins] } + | ^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:792:5 + | +LL | #[no_builtins] fn f() { } + | ^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:5 + | +LL | #[no_builtins] struct S; + | ^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:798:5 + | +LL | #[no_builtins] type T = S; + | ^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:5 + | +LL | #[no_builtins] impl S { } + | ^^^^^^^^^^^^^^ + +warning: crate-level attribute should be in the root module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:808:17 + | +LL | mod inner { #![recursion_limit="0200"] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:811:5 + | +LL | #[recursion_limit="0200"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:5 + | +LL | #[recursion_limit="0200"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:817:5 + | +LL | #[recursion_limit="0200"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:820:5 + | +LL | #[recursion_limit="0200"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be in the root module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:17 + | +LL | mod inner { #![type_length_limit="0100"] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5 + | +LL | #[type_length_limit="0100"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:833:5 + | +LL | #[type_length_limit="0100"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:836:5 + | +LL | #[type_length_limit="0100"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:5 + | +LL | #[type_length_limit="0100"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: `#[macro_use]` attribute cannot be used on functions + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:183:5 + | +LL | #[macro_use] 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! + = help: `#[macro_use]` can be applied to modules, extern crates, crates -warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:5 +warning: `#[macro_use]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:5 | -LL | #[cold] struct S; - | ^^^^^^^ --------- not a function definition +LL | #[macro_use] 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! + = help: `#[macro_use]` can be applied to modules, extern crates, crates -warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:5 +warning: `#[macro_use]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:5 | -LL | #[cold] type T = S; - | ^^^^^^^ ----------- not a function definition +LL | #[macro_use] 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! + = help: `#[macro_use]` can be applied to modules, extern crates, crates -warning: attribute should be applied to a function definition - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 +warning: `#[macro_use]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:5 | -LL | #[cold] impl S { } - | ^^^^^^^ ---------- not a function definition +LL | #[macro_use] 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! + = help: `#[macro_use]` can be applied to modules, extern crates, crates -warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 +warning: `#[path]` attribute cannot be used on functions + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:259:5 | -LL | #[link_name = "1900"] - | ^^^^^^^^^^^^^^^^^^^^^ -... -LL | extern "C" { } - | -------------- not a foreign function or static +LL | #[path = "3800"] 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! -help: try `#[link(name = "1900")]` instead - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 + = help: `#[path]` can only be applied to modules + +warning: `#[path]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:264:5 | -LL | #[link_name = "1900"] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[path = "3800"] 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! + = help: `#[path]` can only be applied to modules -warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:17 +warning: `#[path]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5 | -LL | mod inner { #![link_name="1900"] } - | ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static +LL | #[path = "3800"] 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! + = help: `#[path]` can only be applied to modules -warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:498:5 +warning: `#[path]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:274:5 | -LL | #[link_name = "1900"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static +LL | #[path = "3800"] 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! + = help: `#[path]` can only be applied to modules -warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:5 +warning: `#[automatically_derived]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:280:1 | -LL | #[link_name = "1900"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static +LL | #[automatically_derived] + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[automatically_derived]` can only be applied to trait impl blocks -warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:5 +warning: `#[automatically_derived]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:285:17 | -LL | #[link_name = "1900"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static +LL | mod inner { #![automatically_derived] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[automatically_derived]` can only be applied to trait impl blocks -warning: attribute should be applied to a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:513:5 +warning: `#[automatically_derived]` attribute cannot be used on functions + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:290:5 | -LL | #[link_name = "1900"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static +LL | #[automatically_derived] 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! + = help: `#[automatically_derived]` can only be applied to trait impl blocks -warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:525:17 +warning: `#[automatically_derived]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:295:5 | -LL | mod inner { #![link_section="1800"] } - | ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static +LL | #[automatically_derived] 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! + = help: `#[automatically_derived]` can only be applied to trait impl blocks -warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:5 +warning: `#[automatically_derived]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:300:5 | -LL | #[link_section = "1800"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static +LL | #[automatically_derived] 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! + = help: `#[automatically_derived]` can only be applied to trait impl blocks -warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:537:5 +warning: `#[automatically_derived]` attribute cannot be used on traits + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:305:5 | -LL | #[link_section = "1800"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static +LL | #[automatically_derived] trait W { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[automatically_derived]` can only be applied to trait impl blocks -warning: attribute should be applied to a function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:542:5 +warning: `#[automatically_derived]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:310:5 | -LL | #[link_section = "1800"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static +LL | #[automatically_derived] 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! + = help: `#[automatically_derived]` can only be applied to trait impl blocks -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:557:17 +warning: `#[no_mangle]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:318:1 | -LL | mod inner { #![link()] } - | ------------^^^^^^^^^^-- not an `extern` block +LL | #[no_mangle] + | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[no_mangle]` can be applied to functions, statics -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:562:5 +warning: `#[no_mangle]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:323:17 | -LL | #[link()] fn f() { } - | ^^^^^^^^^ ---------- not an `extern` block +LL | mod inner { #![no_mangle] } + | ^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[no_mangle]` can be applied to functions, statics -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:567:5 +warning: `#[no_mangle]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:330:5 | -LL | #[link()] struct S; - | ^^^^^^^^^ --------- not an `extern` block +LL | #[no_mangle] 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! + = help: `#[no_mangle]` can be applied to functions, statics -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:572:5 +warning: `#[no_mangle]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5 | -LL | #[link()] type T = S; - | ^^^^^^^^^ ----------- not an `extern` block +LL | #[no_mangle] 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! + = help: `#[no_mangle]` can be applied to functions, statics -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:5 +warning: `#[no_mangle]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:340:5 | -LL | #[link()] impl S { } - | ^^^^^^^^^ ---------- not an `extern` block +LL | #[no_mangle] 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! + = help: `#[no_mangle]` can be applied to functions, statics -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:582:5 +warning: `#[no_mangle]` attribute cannot be used on required trait methods + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:346:9 | -LL | #[link()] extern "Rust" {} - | ^^^^^^^^^ +LL | #[no_mangle] fn foo(); + | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[no_mangle]` can be applied to functions, statics, inherent methods, trait methods in impl blocks -warning: `#[must_use]` has no effect when applied to a module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:605:17 +warning: `#[no_mangle]` attribute cannot be used on provided trait methods + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:9 | -LL | mod inner { #![must_use] } - | ^^^^^^^^^^^^ +LL | #[no_mangle] fn bar() {} + | ^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[no_mangle]` can be applied to functions, statics, inherent methods, trait methods in impl blocks -warning: `#[must_use]` has no effect when applied to a type alias - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:612:5 +warning: `#[should_panic]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:1 | -LL | #[must_use] type T = S; - | ^^^^^^^^^^^ +LL | #[should_panic] + | ^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[should_panic]` can only be applied to functions -warning: `#[must_use]` has no effect when applied to an inherent implementation block - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:5 +warning: `#[should_panic]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:363:17 | -LL | #[must_use] impl S { } - | ^^^^^^^^^^^ +LL | mod inner { #![should_panic] } + | ^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[should_panic]` can only be applied to functions -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:622:17 +warning: `#[should_panic]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 | -LL | mod inner { #![windows_subsystem="windows"] } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[should_panic] 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! + = help: `#[should_panic]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:625:5 +warning: `#[should_panic]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:375:5 | -LL | #[windows_subsystem = "windows"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[should_panic] 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! + = help: `#[should_panic]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:628:5 +warning: `#[should_panic]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5 | -LL | #[windows_subsystem = "windows"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[should_panic] 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! + = help: `#[should_panic]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:5 +warning: `#[ignore]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:1 | -LL | #[windows_subsystem = "windows"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[ignore] + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[ignore]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:5 +warning: `#[ignore]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:17 | -LL | #[windows_subsystem = "windows"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | mod inner { #![ignore] } + | ^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[ignore]` can only be applied to functions -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:17 +warning: `#[ignore]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5 | -LL | mod inner { #![crate_name="0900"] } - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[ignore] 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! + = help: `#[ignore]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5 +warning: `#[ignore]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:403:5 | -LL | #[crate_name = "0900"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[ignore] 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! + = help: `#[ignore]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:5 +warning: `#[ignore]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5 | -LL | #[crate_name = "0900"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[ignore] 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! + = help: `#[ignore]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 +warning: `#[no_implicit_prelude]` attribute cannot be used on functions + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:418:5 | -LL | #[crate_name = "0900"] type T = S; +LL | #[no_implicit_prelude] 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! + = help: `#[no_implicit_prelude]` can be applied to modules, crates -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:5 +warning: `#[no_implicit_prelude]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 | -LL | #[crate_name = "0900"] impl S { } +LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:662:17 | -LL | mod inner { #![crate_type="0800"] } - | ^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[no_implicit_prelude]` can be applied to modules, crates -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5 +warning: `#[no_implicit_prelude]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:428:5 | -LL | #[crate_type = "0800"] fn f() { } +LL | #[no_implicit_prelude] 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! + = help: `#[no_implicit_prelude]` can be applied to modules, crates -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:5 +warning: `#[no_implicit_prelude]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 | -LL | #[crate_type = "0800"] struct S; +LL | #[no_implicit_prelude] 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! + = help: `#[no_implicit_prelude]` can be applied to modules, crates -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5 +warning: `#[macro_escape]` attribute cannot be used on functions + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5 | -LL | #[crate_type = "0800"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[macro_escape] 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! + = help: `#[macro_escape]` can be applied to modules, extern crates, crates -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:674:5 +warning: `#[macro_escape]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5 | -LL | #[crate_type = "0800"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[macro_escape] 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! + = help: `#[macro_escape]` can be applied to modules, extern crates, crates -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:17 +warning: `#[macro_escape]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5 | -LL | mod inner { #![feature(x0600)] } - | ^^^^^^^^^^^^^^^^^^ +LL | #[macro_escape] 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! + = help: `#[macro_escape]` can be applied to modules, extern crates, crates -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5 +warning: `#[macro_escape]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:481:5 | -LL | #[feature(x0600)] fn f() { } - | ^^^^^^^^^^^^^^^^^ +LL | #[macro_escape] 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! + = help: `#[macro_escape]` can be applied to modules, extern crates, crates -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5 +warning: `#[cold]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:523:1 | -LL | #[feature(x0600)] struct S; - | ^^^^^^^^^^^^^^^^^ +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 only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:5 +warning: `#[cold]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:529:17 | -LL | #[feature(x0600)] type T = S; - | ^^^^^^^^^^^^^^^^^ +LL | mod inner { #![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 only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5 +warning: `#[cold]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:5 | -LL | #[feature(x0600)] impl S { } - | ^^^^^^^^^^^^^^^^^ +LL | #[cold] 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! + = help: `#[cold]` can only be applied to functions -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:17 +warning: `#[cold]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5 | -LL | mod inner { #![no_main] } - | ^^^^^^^^^^^ +LL | #[cold] 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! + = help: `#[cold]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5 +warning: `#[cold]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:546:5 | -LL | #[no_main] fn f() { } - | ^^^^^^^^^^ +LL | #[cold] 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! + = help: `#[cold]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5 +warning: `#[link_name]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:552:1 | -LL | #[no_main] struct S; - | ^^^^^^^^^^ +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = 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_name]` can be applied to foreign functions, foreign statics -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5 +warning: `#[link_name]` attribute cannot be used on foreign modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:557:5 | -LL | #[no_main] type T = S; - | ^^^^^^^^^^ +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = 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_name]` can be applied to foreign functions, foreign statics -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5 +warning: `#[link_name]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:563:17 | -LL | #[no_main] impl S { } - | ^^^^^^^^^^ +LL | mod inner { #![link_name="1900"] } + | ^^^^^^^^^^^^^^^^^^^^ + | + = 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_name]` can be applied to foreign functions, foreign statics -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17 +warning: `#[link_name]` attribute cannot be used on functions + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:568:5 | -LL | mod inner { #![no_builtins] } - | ^^^^^^^^^^^^^^^ +LL | #[link_name = "1900"] 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! + = help: `#[link_name]` can be applied to foreign functions, foreign statics -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5 +warning: `#[link_name]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:573:5 | -LL | #[no_builtins] fn f() { } - | ^^^^^^^^^^^^^^ +LL | #[link_name = "1900"] 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! + = help: `#[link_name]` can be applied to foreign functions, foreign statics -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5 +warning: `#[link_name]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:578:5 | -LL | #[no_builtins] struct S; - | ^^^^^^^^^^^^^^ +LL | #[link_name = "1900"] 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! + = help: `#[link_name]` can be applied to foreign functions, foreign statics -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 +warning: `#[link_name]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:583:5 | -LL | #[no_builtins] type T = S; - | ^^^^^^^^^^^^^^ +LL | #[link_name = "1900"] 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! + = help: `#[link_name]` can be applied to foreign functions, foreign statics -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 +warning: `#[link_section]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:589:1 | -LL | #[no_builtins] impl S { } - | ^^^^^^^^^^^^^^ +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 statics, functions -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:17 +warning: `#[link_section]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:594:17 | -LL | mod inner { #![recursion_limit="0200"] } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | mod inner { #![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 statics, functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:5 +warning: `#[link_section]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:5 | -LL | #[recursion_limit="0200"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = "1800"] 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! + = help: `#[link_section]` can be applied to statics, functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 +warning: `#[link_section]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:606:5 | -LL | #[recursion_limit="0200"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = "1800"] 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! + = help: `#[link_section]` can be applied to statics, functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:5 +warning: `#[link_section]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5 | -LL | #[recursion_limit="0200"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[link_section = "1800"] 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! + = help: `#[link_section]` can be applied to statics, functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5 +warning: `#[should_panic]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1 | -LL | #[recursion_limit="0200"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![should_panic] + | ^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[should_panic]` can only be applied to functions -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17 +warning: `#[ignore]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 | -LL | mod inner { #![type_length_limit="0100"] } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![ignore] + | ^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[ignore]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:5 +warning: `#[proc_macro_derive]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:61:1 | -LL | #[type_length_limit="0100"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![proc_macro_derive(Test)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[proc_macro_derive]` can only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5 +warning: `#[cold]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 | -LL | #[type_length_limit="0100"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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 only be applied to functions -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:5 +warning: `#[link_name]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1 | -LL | #[type_length_limit="0100"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = 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_name]` can be applied to foreign functions, foreign statics -warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 +warning: `#[link_section]` attribute cannot be used on crates + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:74:1 | -LL | #[type_length_limit="0100"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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 statics, functions warning: 173 warnings emitted diff --git a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs index 392880e1b3b5a..35392b4eff697 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs @@ -1,34 +1,29 @@ -// At time of authorship, #[proc_macro_derive = "2500"] will emit an -// error when it occurs on a mod (apart from crate-level), but will -// not descend further into the mod for other occurrences of the same -// error. -// -// This file sits on its own because the "weird" occurrences here +// This file sits on its own because the occurrences here // signal errors, making it incompatible with the "warnings only" // nature of issue-43106-gating-of-builtin-attrs.rs #[proc_macro_derive(Test)] -//~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions +//~^ ERROR attribute cannot be used on mod proc_macro_derive1 { mod inner { #![proc_macro_derive(Test)] } - // (no error issued here if there was one on outer module) + //~^ ERROR attribute cannot be used on } mod proc_macro_derive2 { mod inner { #![proc_macro_derive(Test)] } - //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions + //~^ ERROR attribute cannot be used on #[proc_macro_derive(Test)] fn f() { } //~^ ERROR the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` #[proc_macro_derive(Test)] struct S; - //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions + //~^ ERROR attribute cannot be used on #[proc_macro_derive(Test)] type T = S; - //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions + //~^ ERROR attribute cannot be used on #[proc_macro_derive(Test)] impl S { } - //~^ ERROR the `#[proc_macro_derive]` attribute may only be used on bare functions + //~^ ERROR attribute cannot be used on } fn main() {} diff --git a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr index 537032d777f54..753e3e2f21da5 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-proc_macro_derive.stderr @@ -1,38 +1,56 @@ -error: the `#[proc_macro_derive]` attribute may only be used on bare functions - --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:10:1 +error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type + --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:16:5 + | +LL | #[proc_macro_derive(Test)] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[proc_macro_derive]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:5:1 | LL | #[proc_macro_derive(Test)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[proc_macro_derive]` can only be applied to functions -error: the `#[proc_macro_derive]` attribute may only be used on bare functions - --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:18:17 +error: `#[proc_macro_derive]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:8:17 | LL | mod inner { #![proc_macro_derive(Test)] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[proc_macro_derive]` can only be applied to functions -error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type - --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:21:5 +error: `#[proc_macro_derive]` attribute cannot be used on modules + --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:13:17 | -LL | #[proc_macro_derive(Test)] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | mod inner { #![proc_macro_derive(Test)] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[proc_macro_derive]` can only be applied to functions -error: the `#[proc_macro_derive]` attribute may only be used on bare functions - --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:24:5 +error: `#[proc_macro_derive]` attribute cannot be used on structs + --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:19:5 | LL | #[proc_macro_derive(Test)] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[proc_macro_derive]` can only be applied to functions -error: the `#[proc_macro_derive]` attribute may only be used on bare functions - --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:27:5 +error: `#[proc_macro_derive]` attribute cannot be used on type aliases + --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:22:5 | LL | #[proc_macro_derive(Test)] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[proc_macro_derive]` can only be applied to functions -error: the `#[proc_macro_derive]` attribute may only be used on bare functions - --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:30:5 +error: `#[proc_macro_derive]` attribute cannot be used on inherent impl blocks + --> $DIR/issue-43106-gating-of-proc_macro_derive.rs:25:5 | LL | #[proc_macro_derive(Test)] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[proc_macro_derive]` can only be applied to functions -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/ffi-attrs/ffi_const.rs b/tests/ui/ffi-attrs/ffi_const.rs index dddc862b0fa60..caeaf8a25a9c5 100644 --- a/tests/ui/ffi-attrs/ffi_const.rs +++ b/tests/ui/ffi-attrs/ffi_const.rs @@ -1,16 +1,16 @@ #![feature(ffi_const)] #![crate_type = "lib"] -#[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions +#[unsafe(ffi_const)] //~ ERROR attribute cannot be used on pub fn foo() {} -#[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions +#[unsafe(ffi_const)] //~ ERROR attribute cannot be used on macro_rules! bar { () => {}; } extern "C" { - #[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions + #[unsafe(ffi_const)] //~ ERROR attribute cannot be used on static INT: i32; #[ffi_const] //~ ERROR unsafe attribute used without unsafe diff --git a/tests/ui/ffi-attrs/ffi_const.stderr b/tests/ui/ffi-attrs/ffi_const.stderr index 7f31237539d11..f3be925431836 100644 --- a/tests/ui/ffi-attrs/ffi_const.stderr +++ b/tests/ui/ffi-attrs/ffi_const.stderr @@ -9,24 +9,29 @@ help: wrap the attribute in `unsafe(...)` LL | #[unsafe(ffi_const)] | +++++++ + -error[E0756]: `#[ffi_const]` may only be used on foreign functions +error: `#[ffi_const]` attribute cannot be used on functions --> $DIR/ffi_const.rs:4:1 | LL | #[unsafe(ffi_const)] | ^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[ffi_const]` can only be applied to foreign functions -error[E0756]: `#[ffi_const]` may only be used on foreign functions +error: `#[ffi_const]` attribute cannot be used on macro defs --> $DIR/ffi_const.rs:7:1 | LL | #[unsafe(ffi_const)] | ^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[ffi_const]` can only be applied to foreign functions -error[E0756]: `#[ffi_const]` may only be used on foreign functions +error: `#[ffi_const]` attribute cannot be used on foreign statics --> $DIR/ffi_const.rs:13:5 | LL | #[unsafe(ffi_const)] | ^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[ffi_const]` can only be applied to foreign functions error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0756`. diff --git a/tests/ui/ffi-attrs/ffi_pure.rs b/tests/ui/ffi-attrs/ffi_pure.rs index 1f4812f55cf1b..c56be79391965 100644 --- a/tests/ui/ffi-attrs/ffi_pure.rs +++ b/tests/ui/ffi-attrs/ffi_pure.rs @@ -1,16 +1,16 @@ #![feature(ffi_pure)] #![crate_type = "lib"] -#[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions +#[unsafe(ffi_pure)] //~ ERROR attribute cannot be used on pub fn foo() {} -#[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions +#[unsafe(ffi_pure)] //~ ERROR attribute cannot be used on macro_rules! bar { () => {}; } extern "C" { - #[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions + #[unsafe(ffi_pure)] //~ ERROR attribute cannot be used on static INT: i32; #[ffi_pure] //~ ERROR unsafe attribute used without unsafe diff --git a/tests/ui/ffi-attrs/ffi_pure.stderr b/tests/ui/ffi-attrs/ffi_pure.stderr index bd1177c01e2b0..da1eae975ac2d 100644 --- a/tests/ui/ffi-attrs/ffi_pure.stderr +++ b/tests/ui/ffi-attrs/ffi_pure.stderr @@ -9,24 +9,29 @@ help: wrap the attribute in `unsafe(...)` LL | #[unsafe(ffi_pure)] | +++++++ + -error[E0755]: `#[ffi_pure]` may only be used on foreign functions +error: `#[ffi_pure]` attribute cannot be used on functions --> $DIR/ffi_pure.rs:4:1 | LL | #[unsafe(ffi_pure)] | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[ffi_pure]` can only be applied to foreign functions -error[E0755]: `#[ffi_pure]` may only be used on foreign functions +error: `#[ffi_pure]` attribute cannot be used on macro defs --> $DIR/ffi_pure.rs:7:1 | LL | #[unsafe(ffi_pure)] | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[ffi_pure]` can only be applied to foreign functions -error[E0755]: `#[ffi_pure]` may only be used on foreign functions +error: `#[ffi_pure]` attribute cannot be used on foreign statics --> $DIR/ffi_pure.rs:13:5 | LL | #[unsafe(ffi_pure)] | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[ffi_pure]` can only be applied to foreign functions error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0755`. diff --git a/tests/ui/force-inlining/invalid.rs b/tests/ui/force-inlining/invalid.rs index e9f5712413e80..6047739992f1a 100644 --- a/tests/ui/force-inlining/invalid.rs +++ b/tests/ui/force-inlining/invalid.rs @@ -28,110 +28,110 @@ pub fn forced4() { } #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on extern crate std as other_std; #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on use std::collections::HashMap; #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on static _FOO: &'static str = "FOO"; #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on const _BAR: u32 = 3; #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on mod foo { } #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on unsafe extern "C" { #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on static X: &'static u32; #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on type Y; #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on fn foo(); } #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on type Foo = u32; #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on enum Bar<#[rustc_force_inline] T> { -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on Baz(std::marker::PhantomData), } #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on struct Qux { #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on field: u32, } #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on union FooBar { x: u32, y: u32, } #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on trait FooBaz { #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on type Foo; #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on const Bar: i32; #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on fn foo() {} } #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on trait FooQux = FooBaz; #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on impl Bar { #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on fn foo() {} } #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on impl FooBaz for Bar { type Foo = u32; const Bar: i32 = 3; } #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on macro_rules! barqux { ($foo:tt) => { $foo }; } fn barqux(#[rustc_force_inline] _x: u32) {} //~^ ERROR allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters -//~^^ ERROR attribute should be applied to a function +//~^^ ERROR attribute cannot be used on #[rustc_force_inline] //~^ ERROR attribute cannot be applied to a `async`, `gen` or `async gen` function @@ -147,16 +147,16 @@ async gen fn async_gen_foo() {} fn main() { let _x = #[rustc_force_inline] || { }; -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on let _y = #[rustc_force_inline] 3 + 4; -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on let _z = 3; match _z { #[rustc_force_inline] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on 1 => (), _ => (), } diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr index 3b3da00ae88c7..299a3ed4a462d 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -64,322 +64,272 @@ LL - #[rustc_force_inline = 2] LL + #[rustc_force_inline] | -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on extern crates --> $DIR/invalid.rs:30:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | extern crate std as other_std; - | ------------------------------ not a function definition + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on use statements --> $DIR/invalid.rs:34:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | use std::collections::HashMap; - | ------------------------------ not a function definition + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on statics --> $DIR/invalid.rs:38:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | static _FOO: &'static str = "FOO"; - | ---------------------------------- not a function definition + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on constants --> $DIR/invalid.rs:42:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | const _BAR: u32 = 3; - | -------------------- not a function definition + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on modules --> $DIR/invalid.rs:46:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | mod foo { } - | ----------- not a function definition + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on foreign modules --> $DIR/invalid.rs:50:1 | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / unsafe extern "C" { -LL | | #[rustc_force_inline] -LL | | -LL | | static X: &'static u32; -... | -LL | | fn foo(); -LL | | } - | |_- not a function definition - -error: attribute should be applied to a function +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions + +error: `#[rustc_force_inline]` attribute cannot be used on foreign statics + --> $DIR/invalid.rs:53:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions + +error: `#[rustc_force_inline]` attribute cannot be used on foreign types + --> $DIR/invalid.rs:57:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions + +error: `#[rustc_force_inline]` attribute cannot be used on foreign functions + --> $DIR/invalid.rs:61:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions + +error: `#[rustc_force_inline]` attribute cannot be used on type aliases --> $DIR/invalid.rs:66:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | type Foo = u32; - | --------------- not a function definition + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on enums --> $DIR/invalid.rs:70:1 | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / enum Bar<#[rustc_force_inline] T> { -LL | | -LL | | #[rustc_force_inline] -... | -LL | | } - | |_- not a function definition - -error: attribute should be applied to a function +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions + +error: `#[rustc_force_inline]` attribute cannot be used on function params --> $DIR/invalid.rs:72:10 | LL | enum Bar<#[rustc_force_inline] T> { - | ^^^^^^^^^^^^^^^^^^^^^ - not a function definition + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on enum variants --> $DIR/invalid.rs:74:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | Baz(std::marker::PhantomData), - | -------------------------------- not a function definition + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on structs --> $DIR/invalid.rs:79:1 | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / struct Qux { -LL | | #[rustc_force_inline] -LL | | -LL | | field: u32, -LL | | } - | |_- not a function definition - -error: attribute should be applied to a function +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions + +error: `#[rustc_force_inline]` attribute cannot be used on struct fields --> $DIR/invalid.rs:82:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | field: u32, - | ---------- not a function definition + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on unions --> $DIR/invalid.rs:87:1 | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / union FooBar { -LL | | x: u32, -LL | | y: u32, -LL | | } - | |_- not a function definition +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on traits --> $DIR/invalid.rs:94:1 | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / trait FooBaz { -LL | | #[rustc_force_inline] -LL | | -LL | | type Foo; -... | -LL | | fn foo() {} -LL | | } - | |_- not a function definition - -error: attribute should be applied to a function - --> $DIR/invalid.rs:109:1 - | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | trait FooQux = FooBaz; - | ---------------------- not a function definition + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function - --> $DIR/invalid.rs:113:1 +error: `#[rustc_force_inline]` attribute cannot be used on associated types + --> $DIR/invalid.rs:97:5 | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / impl Bar { -LL | | #[rustc_force_inline] -LL | | -LL | | fn foo() {} -LL | | } - | |_- not a function definition - -error: attribute should be applied to a function - --> $DIR/invalid.rs:121:1 +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / impl FooBaz for Bar { -LL | | type Foo = u32; -LL | | const Bar: i32 = 3; -LL | | } - | |_- not a function definition + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function - --> $DIR/invalid.rs:128:1 +error: `#[rustc_force_inline]` attribute cannot be used on associated consts + --> $DIR/invalid.rs:100:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions + +error: `#[rustc_force_inline]` attribute cannot be used on provided trait methods + --> $DIR/invalid.rs:104:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions + +error: `#[rustc_force_inline]` attribute cannot be used on trait aliases + --> $DIR/invalid.rs:109:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | macro_rules! barqux { ($foo:tt) => { $foo }; } - | ---------------------------------------------- not a function definition - -error: attribute should be applied to a function - --> $DIR/invalid.rs:132:11 | -LL | fn barqux(#[rustc_force_inline] _x: u32) {} - | ^^^^^^^^^^^^^^^^^^^^^-------- - | | - | not a function definition + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:136:1 +error: `#[rustc_force_inline]` attribute cannot be used on inherent impl blocks + --> $DIR/invalid.rs:113:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | async fn async_foo() {} - | -------------------- `async`, `gen` or `async gen` function + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:140:1 +error: `#[rustc_force_inline]` attribute cannot be used on inherent methods + --> $DIR/invalid.rs:116:5 + | +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions + +error: `#[rustc_force_inline]` attribute cannot be used on trait impl blocks + --> $DIR/invalid.rs:121:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | gen fn gen_foo() {} - | ---------------- `async`, `gen` or `async gen` function + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:144:1 +error: `#[rustc_force_inline]` attribute cannot be used on macro defs + --> $DIR/invalid.rs:128:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | async gen fn async_gen_foo() {} - | ---------------------------- `async`, `gen` or `async gen` function + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on function params + --> $DIR/invalid.rs:132:11 + | +LL | fn barqux(#[rustc_force_inline] _x: u32) {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions + +error: `#[rustc_force_inline]` attribute cannot be used on closures --> $DIR/invalid.rs:149:14 | LL | let _x = #[rustc_force_inline] || { }; - | ^^^^^^^^^^^^^^^^^^^^^ ------ not a function definition + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on expressions --> $DIR/invalid.rs:151:14 | LL | let _y = #[rustc_force_inline] 3 + 4; - | ^^^^^^^^^^^^^^^^^^^^^ - not a function definition + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on statements --> $DIR/invalid.rs:153:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | let _z = 3; - | ----------- not a function definition + | + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function +error: `#[rustc_force_inline]` attribute cannot be used on match arms --> $DIR/invalid.rs:158:9 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | 1 => (), - | ------- not a function definition - -error: attribute should be applied to a function - --> $DIR/invalid.rs:97:5 - | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | type Foo; - | --------- not a function definition - -error: attribute should be applied to a function - --> $DIR/invalid.rs:100:5 - | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | const Bar: i32; - | --------------- not a function definition - -error: attribute should be applied to a function - --> $DIR/invalid.rs:104:5 - | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn foo() {} - | ----------- not a function definition - -error: attribute should be applied to a function - --> $DIR/invalid.rs:116:5 | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn foo() {} - | ----------- not a function definition + = help: `#[rustc_force_inline]` can only be applied to functions -error: attribute should be applied to a function - --> $DIR/invalid.rs:53:5 +error: attribute cannot be applied to a `async`, `gen` or `async gen` function + --> $DIR/invalid.rs:136:1 | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ LL | -LL | static X: &'static u32; - | ----------------------- not a function definition +LL | async fn async_foo() {} + | -------------------- `async`, `gen` or `async gen` function -error: attribute should be applied to a function - --> $DIR/invalid.rs:57:5 +error: attribute cannot be applied to a `async`, `gen` or `async gen` function + --> $DIR/invalid.rs:140:1 | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ LL | -LL | type Y; - | ------- not a function definition +LL | gen fn gen_foo() {} + | ---------------- `async`, `gen` or `async gen` function -error: attribute should be applied to a function - --> $DIR/invalid.rs:61:5 +error: attribute cannot be applied to a `async`, `gen` or `async gen` function + --> $DIR/invalid.rs:144:1 | -LL | #[rustc_force_inline] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_force_inline] + | ^^^^^^^^^^^^^^^^^^^^^ LL | -LL | fn foo(); - | --------- not a function definition +LL | async gen fn async_gen_foo() {} + | ---------------------------- `async`, `gen` or `async gen` function error: aborting due to 37 previous errors diff --git a/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr b/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr index 8b9ad78db3743..6d5a22e4cedb1 100644 --- a/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr +++ b/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr @@ -25,6 +25,14 @@ LL | #[rustc_layout_scalar_valid_range_end(a = "a")] | | expected an integer literal here | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` +error: `#[rustc_layout_scalar_valid_range_end]` attribute cannot be used on enums + --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:12:1 + | +LL | #[rustc_layout_scalar_valid_range_end(1)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_layout_scalar_valid_range_end]` can only be applied to structs + error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:18:1 | @@ -34,17 +42,6 @@ LL | #[rustc_layout_scalar_valid_range_start(rustc_layout_scalar_valid_range_sta | | expected an integer literal here | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` -error: attribute should be applied to a struct - --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:12:1 - | -LL | #[rustc_layout_scalar_valid_range_end(1)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | / enum E { -LL | | X = 1, -LL | | Y = 14, -LL | | } - | |_- not a struct - error: aborting due to 5 previous errors Some errors have detailed explanations: E0539, E0805. diff --git a/tests/ui/issues/issue-31769.rs b/tests/ui/issues/issue-31769.rs index f56c6ea565685..354c1be9ed554 100644 --- a/tests/ui/issues/issue-31769.rs +++ b/tests/ui/issues/issue-31769.rs @@ -1,4 +1,4 @@ fn main() { - #[inline] struct Foo; //~ ERROR attribute should be applied to function or closure + #[inline] struct Foo; //~ ERROR attribute cannot be used on #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to a struct, enum, or union } diff --git a/tests/ui/issues/issue-31769.stderr b/tests/ui/issues/issue-31769.stderr index 03e2f931c847b..0f75e84f2a704 100644 --- a/tests/ui/issues/issue-31769.stderr +++ b/tests/ui/issues/issue-31769.stderr @@ -1,8 +1,10 @@ -error[E0518]: attribute should be applied to function or closure +error: `#[inline]` attribute cannot be used on structs --> $DIR/issue-31769.rs:2:5 | LL | #[inline] struct Foo; - | ^^^^^^^^^ ----------- not a function or closure + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/issue-31769.rs:3:12 @@ -12,5 +14,4 @@ LL | #[repr(C)] fn foo() {} error: aborting due to 2 previous errors -Some errors have detailed explanations: E0517, E0518. -For more information about an error, try `rustc --explain E0517`. +For more information about this error, try `rustc --explain E0517`. diff --git a/tests/ui/issues/issue-43988.rs b/tests/ui/issues/issue-43988.rs index 5fea5576b7f03..bd23e0e2457df 100644 --- a/tests/ui/issues/issue-43988.rs +++ b/tests/ui/issues/issue-43988.rs @@ -4,12 +4,13 @@ fn main() { #[inline] let _a = 4; - //~^^ ERROR attribute should be applied to function or closure + //~^^ ERROR attribute cannot be used on #[inline(XYZ)] let _b = 4; //~^^ ERROR malformed `inline` attribute + //~| ERROR attribute cannot be used on #[repr(nothing)] let _x = 0; @@ -30,6 +31,7 @@ fn main() { #[inline(ABC)] foo(); //~^^ ERROR malformed `inline` attribute + //~| ERROR attribute cannot be used on let _z = #[repr] 1; //~^ ERROR malformed `repr` attribute diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index b50d691e68576..0219eeb693e73 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -1,3 +1,11 @@ +error: `#[inline]` attribute cannot be used on statements + --> $DIR/issue-43988.rs:5:5 + | +LL | #[inline] + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + error[E0539]: malformed `inline` attribute input --> $DIR/issue-43988.rs:10:5 | @@ -19,8 +27,16 @@ LL - #[inline(XYZ)] LL + #[inline] | +error: `#[inline]` attribute cannot be used on statements + --> $DIR/issue-43988.rs:10:5 + | +LL | #[inline(XYZ)] + | ^^^^^^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + error[E0552]: unrecognized representation hint - --> $DIR/issue-43988.rs:14:12 + --> $DIR/issue-43988.rs:15:12 | LL | #[repr(nothing)] | ^^^^^^^ @@ -29,7 +45,7 @@ LL | #[repr(nothing)] = note: for more information, visit error[E0552]: unrecognized representation hint - --> $DIR/issue-43988.rs:18:12 + --> $DIR/issue-43988.rs:19:12 | LL | #[repr(something_not_real)] | ^^^^^^^^^^^^^^^^^^ @@ -38,7 +54,7 @@ LL | #[repr(something_not_real)] = note: for more information, visit error[E0539]: malformed `repr` attribute input - --> $DIR/issue-43988.rs:24:5 + --> $DIR/issue-43988.rs:25:5 | LL | #[repr] | ^^^^^^^ expected this to be a list @@ -57,7 +73,7 @@ LL | #[repr(align(...))] = and 2 other candidates error[E0539]: malformed `inline` attribute input - --> $DIR/issue-43988.rs:30:5 + --> $DIR/issue-43988.rs:31:5 | LL | #[inline(ABC)] | ^^^^^^^^^---^^ @@ -77,8 +93,16 @@ LL - #[inline(ABC)] LL + #[inline] | +error: `#[inline]` attribute cannot be used on expressions + --> $DIR/issue-43988.rs:31:5 + | +LL | #[inline(ABC)] + | ^^^^^^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions + error[E0539]: malformed `repr` attribute input - --> $DIR/issue-43988.rs:34:14 + --> $DIR/issue-43988.rs:36:14 | LL | let _z = #[repr] 1; | ^^^^^^^ expected this to be a list @@ -96,15 +120,7 @@ LL | let _z = #[repr(align(...))] 1; | ++++++++++++ = and 2 other candidates -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43988.rs:5:5 - | -LL | #[inline] - | ^^^^^^^^^ -LL | let _a = 4; - | ----------- not a function or closure - -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0518, E0539, E0552. -For more information about an error, try `rustc --explain E0518`. +Some errors have detailed explanations: E0539, E0552. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/issues/issue-78957.rs b/tests/ui/issues/issue-78957.rs index 567c59fd560d9..2ff92612e1852 100644 --- a/tests/ui/issues/issue-78957.rs +++ b/tests/ui/issues/issue-78957.rs @@ -3,26 +3,26 @@ use std::marker::PhantomData; pub struct Foo<#[inline] const N: usize>; -//~^ ERROR attribute should be applied to function or closure +//~^ ERROR attribute cannot be used on pub struct Bar<#[cold] const N: usize>; -//~^ ERROR attribute should be applied to a function -//~| WARN this was previously accepted +//~^ ERROR attribute cannot be used on +//~| WARN previously accepted pub struct Baz<#[repr(C)] const N: usize>; //~^ ERROR attribute should be applied to a struct, enum, or union // pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); -//~^ ERROR attribute should be applied to function or closure +//~^ ERROR attribute cannot be used on pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); -//~^ ERROR attribute should be applied to a function -//~| WARN this was previously accepted +//~^ ERROR attribute cannot be used on +//~| WARN previously accepted pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>); //~^ ERROR attribute should be applied to a struct, enum, or union // pub struct Foo3<#[inline] T>(PhantomData); -//~^ ERROR attribute should be applied to function or closure +//~^ ERROR attribute cannot be used on pub struct Bar3<#[cold] T>(PhantomData); -//~^ ERROR attribute should be applied to a function -//~| WARN this was previously accepted +//~^ ERROR attribute cannot be used on +//~| WARN previously accepted pub struct Baz3<#[repr(C)] T>(PhantomData); //~^ ERROR attribute should be applied to a struct, enum, or union diff --git a/tests/ui/issues/issue-78957.stderr b/tests/ui/issues/issue-78957.stderr index 6de22d6bf79fc..d271b1840fb5a 100644 --- a/tests/ui/issues/issue-78957.stderr +++ b/tests/ui/issues/issue-78957.stderr @@ -1,21 +1,26 @@ -error[E0518]: attribute should be applied to function or closure +error: `#[inline]` attribute cannot be used on function params --> $DIR/issue-78957.rs:5:16 | LL | pub struct Foo<#[inline] const N: usize>; - | ^^^^^^^^^ -------------- not a function or closure + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/issue-78957.rs:7:16 +error: `#[inline]` attribute cannot be used on function params + --> $DIR/issue-78957.rs:13:17 | -LL | pub struct Bar<#[cold] const N: usize>; - | ^^^^^^^ -------------- not a function definition +LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); + | ^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -note: the lint level is defined here - --> $DIR/issue-78957.rs:1:9 + = help: `#[inline]` can only be applied to functions + +error: `#[inline]` attribute cannot be used on function params + --> $DIR/issue-78957.rs:21:17 | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ +LL | pub struct Foo3<#[inline] T>(PhantomData); + | ^^^^^^^^^ + | + = help: `#[inline]` can only be applied to functions error[E0517]: attribute should be applied to a struct, enum, or union --> $DIR/issue-78957.rs:10:23 @@ -23,47 +28,50 @@ error[E0517]: attribute should be applied to a struct, enum, or union LL | pub struct Baz<#[repr(C)] const N: usize>; | ^ -------------- not a struct, enum, or union -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-78957.rs:13:17 +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-78957.rs:18:24 | -LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>); - | ^^^^^^^^^ -- not a function or closure +LL | pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>); + | ^ -- not a struct, enum, or union -error: attribute should be applied to a function definition - --> $DIR/issue-78957.rs:15:17 +error[E0517]: attribute should be applied to a struct, enum, or union + --> $DIR/issue-78957.rs:26:24 | -LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); - | ^^^^^^^ -- not a function definition +LL | pub struct Baz3<#[repr(C)] T>(PhantomData); + | ^ - not a struct, enum, or union + +error: `#[cold]` attribute cannot be used on function params + --> $DIR/issue-78957.rs:7:16 + | +LL | pub struct Bar<#[cold] const N: usize>; + | ^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-78957.rs:18:24 + = help: `#[cold]` can only be applied to functions +note: the lint level is defined here + --> $DIR/issue-78957.rs:1:9 | -LL | pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>); - | ^ -- not a struct, enum, or union +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-78957.rs:21:17 +error: `#[cold]` attribute cannot be used on function params + --> $DIR/issue-78957.rs:15:17 | -LL | pub struct Foo3<#[inline] T>(PhantomData); - | ^^^^^^^^^ - not a function or closure +LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>); + | ^^^^^^^ + | + = 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 only be applied to functions -error: attribute should be applied to a function definition +error: `#[cold]` attribute cannot be used on function params --> $DIR/issue-78957.rs:23:17 | LL | pub struct Bar3<#[cold] T>(PhantomData); - | ^^^^^^^ - not a function definition + | ^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-78957.rs:26:24 - | -LL | pub struct Baz3<#[repr(C)] T>(PhantomData); - | ^ - not a struct, enum, or union + = help: `#[cold]` can only be applied to functions error: aborting due to 9 previous errors -Some errors have detailed explanations: E0517, E0518. -For more information about an error, try `rustc --explain E0517`. +For more information about this error, try `rustc --explain E0517`. diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.rs index 5982c771033d0..301e690be388b 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.rs @@ -1,13 +1,13 @@ #[link_ordinal(123)] -//~^ ERROR attribute should be applied to a foreign function or static +//~^ ERROR attribute cannot be used on struct Foo {} #[link_ordinal(123)] -//~^ ERROR attribute should be applied to a foreign function or static +//~^ ERROR attribute cannot be used on fn test() {} #[link_ordinal(42)] -//~^ ERROR attribute should be applied to a foreign function or static +//~^ ERROR attribute cannot be used on static mut imported_val: i32 = 123; #[link(name = "exporter", kind = "raw-dylib")] diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.stderr index 8f279508720ce..c561373db77f6 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.stderr @@ -1,20 +1,26 @@ -error: attribute should be applied to a foreign function or static +error: `#[link_ordinal]` attribute cannot be used on structs --> $DIR/link-ordinal-not-foreign-fn.rs:1:1 | LL | #[link_ordinal(123)] | ^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link_ordinal]` can be applied to foreign functions, foreign statics -error: attribute should be applied to a foreign function or static +error: `#[link_ordinal]` attribute cannot be used on functions --> $DIR/link-ordinal-not-foreign-fn.rs:5:1 | LL | #[link_ordinal(123)] | ^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link_ordinal]` can be applied to foreign functions, foreign statics -error: attribute should be applied to a foreign function or static +error: `#[link_ordinal]` attribute cannot be used on statics --> $DIR/link-ordinal-not-foreign-fn.rs:9:1 | LL | #[link_ordinal(42)] | ^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link_ordinal]` can be applied to foreign functions, foreign statics error: aborting due to 3 previous errors diff --git a/tests/ui/lint/inline-trait-and-foreign-items.rs b/tests/ui/lint/inline-trait-and-foreign-items.rs index 39bc01f71b5a0..d41a09dee96f1 100644 --- a/tests/ui/lint/inline-trait-and-foreign-items.rs +++ b/tests/ui/lint/inline-trait-and-foreign-items.rs @@ -4,33 +4,33 @@ #![warn(unused_attributes)] trait Trait { - #[inline] //~ WARN `#[inline]` is ignored on constants - //~^ WARN this was previously accepted + #[inline] //~ WARN attribute cannot be used on +//~| WARN previously accepted const X: u32; - #[inline] //~ ERROR attribute should be applied to function or closure + #[inline] //~ ERROR attribute cannot be used on type T; type U; } impl Trait for () { - #[inline] //~ WARN `#[inline]` is ignored on constants - //~^ WARN this was previously accepted + #[inline] //~ WARN attribute cannot be used on +//~| WARN previously accepted const X: u32 = 0; - #[inline] //~ ERROR attribute should be applied to function or closure + #[inline] //~ ERROR attribute cannot be used on type T = Self; - #[inline] //~ ERROR attribute should be applied to function or closure + #[inline] //~ ERROR attribute cannot be used on type U = impl Trait; //~ ERROR unconstrained opaque type } extern "C" { - #[inline] //~ ERROR attribute should be applied to function or closure + #[inline] //~ ERROR attribute cannot be used on static X: u32; - #[inline] //~ ERROR attribute should be applied to function or closure + #[inline] //~ ERROR attribute cannot be used on type T; } diff --git a/tests/ui/lint/inline-trait-and-foreign-items.stderr b/tests/ui/lint/inline-trait-and-foreign-items.stderr index 2f1fb4c46c08b..4bde4bc590aa8 100644 --- a/tests/ui/lint/inline-trait-and-foreign-items.stderr +++ b/tests/ui/lint/inline-trait-and-foreign-items.stderr @@ -1,65 +1,42 @@ -warning: `#[inline]` is ignored on constants - --> $DIR/inline-trait-and-foreign-items.rs:7:5 - | -LL | #[inline] - | ^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: see issue #65833 for more information -note: the lint level is defined here - --> $DIR/inline-trait-and-foreign-items.rs:4:9 - | -LL | #![warn(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ - -error[E0518]: attribute should be applied to function or closure +error: `#[inline]` attribute cannot be used on associated types --> $DIR/inline-trait-and-foreign-items.rs:11:5 | -LL | #[inline] - | ^^^^^^^^^ -LL | type T; - | ------- not a function or closure - -warning: `#[inline]` is ignored on constants - --> $DIR/inline-trait-and-foreign-items.rs:18:5 - | LL | #[inline] | ^^^^^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: see issue #65833 for more information + = help: `#[inline]` can only be applied to functions -error[E0518]: attribute should be applied to function or closure +error: `#[inline]` attribute cannot be used on associated types --> $DIR/inline-trait-and-foreign-items.rs:22:5 | LL | #[inline] | ^^^^^^^^^ -LL | type T = Self; - | -------------- not a function or closure + | + = help: `#[inline]` can only be applied to functions -error[E0518]: attribute should be applied to function or closure +error: `#[inline]` attribute cannot be used on associated types --> $DIR/inline-trait-and-foreign-items.rs:25:5 | LL | #[inline] | ^^^^^^^^^ -LL | type U = impl Trait; - | -------------------- not a function or closure + | + = help: `#[inline]` can only be applied to functions -error[E0518]: attribute should be applied to function or closure +error: `#[inline]` attribute cannot be used on foreign statics --> $DIR/inline-trait-and-foreign-items.rs:30:5 | LL | #[inline] | ^^^^^^^^^ -LL | static X: u32; - | -------------- not a function or closure + | + = help: `#[inline]` can only be applied to functions -error[E0518]: attribute should be applied to function or closure +error: `#[inline]` attribute cannot be used on foreign types --> $DIR/inline-trait-and-foreign-items.rs:33:5 | LL | #[inline] | ^^^^^^^^^ -LL | type T; - | ------- not a function or closure + | + = help: `#[inline]` can only be applied to functions error: unconstrained opaque type --> $DIR/inline-trait-and-foreign-items.rs:26:14 @@ -69,6 +46,28 @@ LL | type U = impl Trait; | = note: `U` must be used in combination with a concrete type within the same impl +warning: `#[inline]` attribute cannot be used on associated consts + --> $DIR/inline-trait-and-foreign-items.rs:7:5 + | +LL | #[inline] + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[inline]` can only be applied to functions +note: the lint level is defined here + --> $DIR/inline-trait-and-foreign-items.rs:4:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +warning: `#[inline]` attribute cannot be used on associated consts + --> $DIR/inline-trait-and-foreign-items.rs:18:5 + | +LL | #[inline] + | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[inline]` can only be applied to functions + error: aborting due to 6 previous errors; 2 warnings emitted -For more information about this error, try `rustc --explain E0518`. diff --git a/tests/ui/lint/unused/unused-attr-macro-rules.rs b/tests/ui/lint/unused/unused-attr-macro-rules.rs index 7a8a1bb1ae523..96f2834a2963a 100644 --- a/tests/ui/lint/unused/unused-attr-macro-rules.rs +++ b/tests/ui/lint/unused/unused-attr-macro-rules.rs @@ -4,8 +4,10 @@ // A sample of various built-in attributes. #[macro_export] -#[macro_use] //~ ERROR `#[macro_use]` only has an effect -#[path="foo"] //~ ERROR #[path]` only has an effect +#[macro_use] //~ ERROR attribute cannot be used on +//~| WARN previously accepted +#[path="foo"] //~ ERROR attribute cannot be used on +//~| WARN previously accepted #[recursion_limit="1"] //~ ERROR crate-level attribute should be an inner attribute macro_rules! foo { () => {}; diff --git a/tests/ui/lint/unused/unused-attr-macro-rules.stderr b/tests/ui/lint/unused/unused-attr-macro-rules.stderr index 1e1211af5e296..0c55ae678e993 100644 --- a/tests/ui/lint/unused/unused-attr-macro-rules.stderr +++ b/tests/ui/lint/unused/unused-attr-macro-rules.stderr @@ -1,5 +1,5 @@ error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/unused-attr-macro-rules.rs:9:1 + --> $DIR/unused-attr-macro-rules.rs:11:1 | LL | #[recursion_limit="1"] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -10,17 +10,23 @@ note: the lint level is defined here LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -error: `#[macro_use]` only has an effect on `extern crate` and modules +error: `#[macro_use]` attribute cannot be used on macro defs --> $DIR/unused-attr-macro-rules.rs:7:1 | LL | #[macro_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: `#[macro_use]` can be applied to modules, extern crates, crates -error: `#[path]` only has an effect on modules - --> $DIR/unused-attr-macro-rules.rs:8:1 +error: `#[path]` attribute cannot be used on macro defs + --> $DIR/unused-attr-macro-rules.rs:9:1 | LL | #[path="foo"] | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[path]` can only be applied to modules error: aborting due to 3 previous errors diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 27927cf37e92a..9e37f6504cc25 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -15,127 +15,127 @@ note: the lint level is defined here LL | #![deny(unused_attributes, unused_must_use)] | ^^^^^^^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to an extern crate +error: `#[must_use]` has no effect when applied to extern crates --> $DIR/unused_attributes-must_use.rs:7:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a module +error: `#[must_use]` has no effect when applied to modules --> $DIR/unused_attributes-must_use.rs:10:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a use +error: `#[must_use]` has no effect when applied to use statements --> $DIR/unused_attributes-must_use.rs:13:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a constant item +error: `#[must_use]` has no effect when applied to constants --> $DIR/unused_attributes-must_use.rs:16:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a static item +error: `#[must_use]` has no effect when applied to statics --> $DIR/unused_attributes-must_use.rs:18:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to an inherent implementation block +error: `#[must_use]` has no effect when applied to inherent impl blocks --> $DIR/unused_attributes-must_use.rs:35:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a foreign module +error: `#[must_use]` has no effect when applied to foreign modules --> $DIR/unused_attributes-must_use.rs:49:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a type alias +error: `#[must_use]` has no effect when applied to type aliases --> $DIR/unused_attributes-must_use.rs:63:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a type parameter +error: `#[must_use]` has no effect when applied to type parameters --> $DIR/unused_attributes-must_use.rs:66:8 | LL | fn qux<#[must_use] T>(_: T) {} | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to an trait implementation block +error: `#[must_use]` has no effect when applied to trait impl blocks --> $DIR/unused_attributes-must_use.rs:81:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a trait alias +error: `#[must_use]` has no effect when applied to trait aliases --> $DIR/unused_attributes-must_use.rs:91:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a macro def +error: `#[must_use]` has no effect when applied to macro defs --> $DIR/unused_attributes-must_use.rs:94:1 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a statement +error: `#[must_use]` has no effect when applied to statements --> $DIR/unused_attributes-must_use.rs:102:5 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a closure +error: `#[must_use]` has no effect when applied to closures --> $DIR/unused_attributes-must_use.rs:106:13 | LL | let x = #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to an match arm +error: `#[must_use]` has no effect when applied to match arms --> $DIR/unused_attributes-must_use.rs:128:9 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a struct field +error: `#[must_use]` has no effect when applied to struct fields --> $DIR/unused_attributes-must_use.rs:136:28 | LL | let s = PatternField { #[must_use] foo: 123 }; | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a pattern field +error: `#[must_use]` has no effect when applied to pattern fields --> $DIR/unused_attributes-must_use.rs:137:24 | LL | let PatternField { #[must_use] foo } = s; | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to an associated const +error: `#[must_use]` has no effect when applied to associated consts --> $DIR/unused_attributes-must_use.rs:70:5 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to an associated type +error: `#[must_use]` has no effect when applied to associated types --> $DIR/unused_attributes-must_use.rs:72:5 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a provided trait method +error: `#[must_use]` has no effect when applied to provided trait methods --> $DIR/unused_attributes-must_use.rs:85:5 | LL | #[must_use] | ^^^^^^^^^^^ -error: `#[must_use]` has no effect when applied to a foreign static item +error: `#[must_use]` has no effect when applied to foreign statics --> $DIR/unused_attributes-must_use.rs:52:5 | LL | #[must_use] diff --git a/tests/ui/lint/warn-unused-inline-on-fn-prototypes.rs b/tests/ui/lint/warn-unused-inline-on-fn-prototypes.rs index 4684fe145774d..bef607a4ec5c4 100644 --- a/tests/ui/lint/warn-unused-inline-on-fn-prototypes.rs +++ b/tests/ui/lint/warn-unused-inline-on-fn-prototypes.rs @@ -1,12 +1,14 @@ #![deny(unused_attributes)] trait Trait { - #[inline] //~ ERROR `#[inline]` is ignored on function prototypes + #[inline] //~ ERROR attribute cannot be used on + //~^ WARN previously accepted fn foo(); } extern "C" { - #[inline] //~ ERROR `#[inline]` is ignored on function prototypes + #[inline] //~ ERROR attribute cannot be used on + //~^ WARN previously accepted fn foo(); } diff --git a/tests/ui/lint/warn-unused-inline-on-fn-prototypes.stderr b/tests/ui/lint/warn-unused-inline-on-fn-prototypes.stderr index ab19d80e7327c..336366042f927 100644 --- a/tests/ui/lint/warn-unused-inline-on-fn-prototypes.stderr +++ b/tests/ui/lint/warn-unused-inline-on-fn-prototypes.stderr @@ -1,20 +1,25 @@ -error: `#[inline]` is ignored on function prototypes +error: `#[inline]` attribute cannot be used on required trait methods --> $DIR/warn-unused-inline-on-fn-prototypes.rs:4:5 | LL | #[inline] | ^^^^^^^^^ | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[inline]` can be applied to functions, inherent methods, provided trait methods, trait methods in impl blocks, closures note: the lint level is defined here --> $DIR/warn-unused-inline-on-fn-prototypes.rs:1:9 | LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ -error: `#[inline]` is ignored on function prototypes - --> $DIR/warn-unused-inline-on-fn-prototypes.rs:9:5 +error: `#[inline]` attribute cannot be used on foreign functions + --> $DIR/warn-unused-inline-on-fn-prototypes.rs:10:5 | LL | #[inline] | ^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = help: `#[inline]` can be applied to methods, functions, closures error: aborting due to 2 previous errors diff --git a/tests/ui/loop-match/invalid-attribute.rs b/tests/ui/loop-match/invalid-attribute.rs index d8d2f605eb496..a5d7daac58357 100644 --- a/tests/ui/loop-match/invalid-attribute.rs +++ b/tests/ui/loop-match/invalid-attribute.rs @@ -3,17 +3,17 @@ #![allow(incomplete_features)] #![feature(loop_match)] -#![loop_match] //~ ERROR should be applied to a loop -#![const_continue] //~ ERROR should be applied to a break expression +#![loop_match] //~ ERROR attribute cannot be used on +#![const_continue] //~ ERROR attribute cannot be used on extern "C" { - #[loop_match] //~ ERROR should be applied to a loop - #[const_continue] //~ ERROR should be applied to a break expression + #[loop_match] //~ ERROR attribute cannot be used on + #[const_continue] //~ ERROR attribute cannot be used on fn f(); } -#[loop_match] //~ ERROR should be applied to a loop -#[const_continue] //~ ERROR should be applied to a break expression +#[loop_match] //~ ERROR attribute cannot be used on +#[const_continue] //~ ERROR attribute cannot be used on #[repr(C)] struct S { a: u32, @@ -21,18 +21,18 @@ struct S { } trait Invoke { - #[loop_match] //~ ERROR should be applied to a loop - #[const_continue] //~ ERROR should be applied to a break expression + #[loop_match] //~ ERROR attribute cannot be used on + #[const_continue] //~ ERROR attribute cannot be used on extern "C" fn invoke(&self); } -#[loop_match] //~ ERROR should be applied to a loop -#[const_continue] //~ ERROR should be applied to a break expression +#[loop_match] //~ ERROR attribute cannot be used on +#[const_continue] //~ ERROR attribute cannot be used on extern "C" fn ok() {} fn main() { - #[loop_match] //~ ERROR should be applied to a loop - #[const_continue] //~ ERROR should be applied to a break expression + #[loop_match] //~ ERROR attribute cannot be used on + #[const_continue] //~ ERROR attribute cannot be used on || {}; { diff --git a/tests/ui/loop-match/invalid-attribute.stderr b/tests/ui/loop-match/invalid-attribute.stderr index 07015311f9c3c..ddb68aea31b69 100644 --- a/tests/ui/loop-match/invalid-attribute.stderr +++ b/tests/ui/loop-match/invalid-attribute.stderr @@ -1,54 +1,98 @@ -error: `#[const_continue]` should be applied to a break expression - --> $DIR/invalid-attribute.rs:16:1 +error: `#[loop_match]` attribute cannot be used on crates + --> $DIR/invalid-attribute.rs:6:1 | -LL | #[const_continue] - | ^^^^^^^^^^^^^^^^^ -LL | #[repr(C)] -LL | struct S { - | -------- not a break expression +LL | #![loop_match] + | ^^^^^^^^^^^^^^ + | + = help: `#[loop_match]` can be applied to -error: `#[loop_match]` should be applied to a loop +error: `#[const_continue]` attribute cannot be used on crates + --> $DIR/invalid-attribute.rs:7:1 + | +LL | #![const_continue] + | ^^^^^^^^^^^^^^^^^^ + | + = help: `#[const_continue]` can be applied to + +error: `#[loop_match]` attribute cannot be used on foreign functions + --> $DIR/invalid-attribute.rs:10:5 + | +LL | #[loop_match] + | ^^^^^^^^^^^^^ + | + = help: `#[loop_match]` can be applied to + +error: `#[const_continue]` attribute cannot be used on foreign functions + --> $DIR/invalid-attribute.rs:11:5 + | +LL | #[const_continue] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[const_continue]` can be applied to + +error: `#[loop_match]` attribute cannot be used on structs --> $DIR/invalid-attribute.rs:15:1 | LL | #[loop_match] | ^^^^^^^^^^^^^ -... -LL | struct S { - | -------- not a loop + | + = help: `#[loop_match]` can be applied to -error: `#[const_continue]` should be applied to a break expression - --> $DIR/invalid-attribute.rs:30:1 +error: `#[const_continue]` attribute cannot be used on structs + --> $DIR/invalid-attribute.rs:16:1 | LL | #[const_continue] | ^^^^^^^^^^^^^^^^^ -LL | extern "C" fn ok() {} - | ------------------ not a break expression + | + = help: `#[const_continue]` can be applied to -error: `#[loop_match]` should be applied to a loop +error: `#[loop_match]` attribute cannot be used on required trait methods + --> $DIR/invalid-attribute.rs:24:5 + | +LL | #[loop_match] + | ^^^^^^^^^^^^^ + | + = help: `#[loop_match]` can be applied to + +error: `#[const_continue]` attribute cannot be used on required trait methods + --> $DIR/invalid-attribute.rs:25:5 + | +LL | #[const_continue] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[const_continue]` can be applied to + +error: `#[loop_match]` attribute cannot be used on functions --> $DIR/invalid-attribute.rs:29:1 | LL | #[loop_match] | ^^^^^^^^^^^^^ -LL | #[const_continue] -LL | extern "C" fn ok() {} - | ------------------ not a loop + | + = help: `#[loop_match]` can be applied to -error: `#[const_continue]` should be applied to a break expression - --> $DIR/invalid-attribute.rs:35:5 +error: `#[const_continue]` attribute cannot be used on functions + --> $DIR/invalid-attribute.rs:30:1 | -LL | #[const_continue] - | ^^^^^^^^^^^^^^^^^ -LL | || {}; - | -- not a break expression +LL | #[const_continue] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[const_continue]` can be applied to -error: `#[loop_match]` should be applied to a loop +error: `#[loop_match]` attribute cannot be used on closures --> $DIR/invalid-attribute.rs:34:5 | LL | #[loop_match] | ^^^^^^^^^^^^^ + | + = help: `#[loop_match]` can be applied to + +error: `#[const_continue]` attribute cannot be used on closures + --> $DIR/invalid-attribute.rs:35:5 + | LL | #[const_continue] -LL | || {}; - | -- not a loop + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[const_continue]` can be applied to error: `#[const_continue]` should be applied to a break expression --> $DIR/invalid-attribute.rs:40:9 @@ -67,65 +111,5 @@ LL | #[const_continue] LL | 5 | - not a loop -error: `#[const_continue]` should be applied to a break expression - --> $DIR/invalid-attribute.rs:25:5 - | -LL | #[const_continue] - | ^^^^^^^^^^^^^^^^^ -LL | extern "C" fn invoke(&self); - | ---------------------------- not a break expression - -error: `#[loop_match]` should be applied to a loop - --> $DIR/invalid-attribute.rs:24:5 - | -LL | #[loop_match] - | ^^^^^^^^^^^^^ -LL | #[const_continue] -LL | extern "C" fn invoke(&self); - | ---------------------------- not a loop - -error: `#[const_continue]` should be applied to a break expression - --> $DIR/invalid-attribute.rs:11:5 - | -LL | #[const_continue] - | ^^^^^^^^^^^^^^^^^ -LL | fn f(); - | ------- not a break expression - -error: `#[loop_match]` should be applied to a loop - --> $DIR/invalid-attribute.rs:10:5 - | -LL | #[loop_match] - | ^^^^^^^^^^^^^ -LL | #[const_continue] -LL | fn f(); - | ------- not a loop - -error: `#[const_continue]` should be applied to a break expression - --> $DIR/invalid-attribute.rs:7:1 - | -LL | / #![allow(incomplete_features)] -LL | | #![feature(loop_match)] -LL | | #![loop_match] -LL | | #![const_continue] - | | ^^^^^^^^^^^^^^^^^^ -... | -LL | | }; -LL | | } - | |_- not a break expression - -error: `#[loop_match]` should be applied to a loop - --> $DIR/invalid-attribute.rs:6:1 - | -LL | / #![allow(incomplete_features)] -LL | | #![feature(loop_match)] -LL | | #![loop_match] - | | ^^^^^^^^^^^^^^ -LL | | #![const_continue] -... | -LL | | }; -LL | | } - | |_- not a loop - error: aborting due to 14 previous errors diff --git a/tests/ui/macros/issue-68060.rs b/tests/ui/macros/issue-68060.rs index 4eddb96848cd0..2edf986174325 100644 --- a/tests/ui/macros/issue-68060.rs +++ b/tests/ui/macros/issue-68060.rs @@ -2,13 +2,12 @@ fn main() { (0..) .map( #[target_feature(enable = "")] - //~^ ERROR: attribute should be applied to a function + //~^ ERROR: attribute cannot be used on #[track_caller] //~^ ERROR: `#[track_caller]` on closures is currently unstable //~| NOTE: see issue #87417 //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date |_| (), - //~^ NOTE: not a function ) .next(); } diff --git a/tests/ui/macros/issue-68060.stderr b/tests/ui/macros/issue-68060.stderr index ef2246d5bd6bb..c701e50f054c1 100644 --- a/tests/ui/macros/issue-68060.stderr +++ b/tests/ui/macros/issue-68060.stderr @@ -1,11 +1,10 @@ -error: attribute should be applied to a function definition +error: `#[target_feature]` attribute cannot be used on closures --> $DIR/issue-68060.rs:4:13 | LL | #[target_feature(enable = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | |_| (), - | ------ not a function definition + | + = help: `#[target_feature]` can be applied to methods, functions error[E0658]: `#[track_caller]` on closures is currently unstable --> $DIR/issue-68060.rs:6:13 diff --git a/tests/ui/marker_trait_attr/marker-attribute-on-non-trait.rs b/tests/ui/marker_trait_attr/marker-attribute-on-non-trait.rs index 0bf620934ec7b..1fb206d628f30 100644 --- a/tests/ui/marker_trait_attr/marker-attribute-on-non-trait.rs +++ b/tests/ui/marker_trait_attr/marker-attribute-on-non-trait.rs @@ -1,23 +1,23 @@ #![feature(marker_trait_attr)] -#[marker] //~ ERROR attribute should be applied to a trait +#[marker] //~ ERROR attribute cannot be used on struct Struct {} -#[marker] //~ ERROR attribute should be applied to a trait +#[marker] //~ ERROR attribute cannot be used on impl Struct {} -#[marker] //~ ERROR attribute should be applied to a trait +#[marker] //~ ERROR attribute cannot be used on union Union { x: i32, } -#[marker] //~ ERROR attribute should be applied to a trait +#[marker] //~ ERROR attribute cannot be used on const CONST: usize = 10; -#[marker] //~ ERROR attribute should be applied to a trait +#[marker] //~ ERROR attribute cannot be used on fn function() {} -#[marker] //~ ERROR attribute should be applied to a trait +#[marker] //~ ERROR attribute cannot be used on type Type = (); fn main() {} diff --git a/tests/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr b/tests/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr index 19a5290dd7eb6..71abe7f39df03 100644 --- a/tests/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr +++ b/tests/ui/marker_trait_attr/marker-attribute-on-non-trait.stderr @@ -1,52 +1,50 @@ -error: attribute should be applied to a trait +error: `#[marker]` attribute cannot be used on structs --> $DIR/marker-attribute-on-non-trait.rs:3:1 | LL | #[marker] | ^^^^^^^^^ -LL | struct Struct {} - | ---------------- not a trait + | + = help: `#[marker]` can only be applied to traits -error: attribute should be applied to a trait +error: `#[marker]` attribute cannot be used on inherent impl blocks --> $DIR/marker-attribute-on-non-trait.rs:6:1 | LL | #[marker] | ^^^^^^^^^ -LL | impl Struct {} - | -------------- not a trait + | + = help: `#[marker]` can only be applied to traits -error: attribute should be applied to a trait +error: `#[marker]` attribute cannot be used on unions --> $DIR/marker-attribute-on-non-trait.rs:9:1 | -LL | #[marker] - | ^^^^^^^^^ -LL | / union Union { -LL | | x: i32, -LL | | } - | |_- not a trait +LL | #[marker] + | ^^^^^^^^^ + | + = help: `#[marker]` can only be applied to traits -error: attribute should be applied to a trait +error: `#[marker]` attribute cannot be used on constants --> $DIR/marker-attribute-on-non-trait.rs:14:1 | LL | #[marker] | ^^^^^^^^^ -LL | const CONST: usize = 10; - | ------------------------ not a trait + | + = help: `#[marker]` can only be applied to traits -error: attribute should be applied to a trait +error: `#[marker]` attribute cannot be used on functions --> $DIR/marker-attribute-on-non-trait.rs:17:1 | LL | #[marker] | ^^^^^^^^^ -LL | fn function() {} - | ---------------- not a trait + | + = help: `#[marker]` can only be applied to traits -error: attribute should be applied to a trait +error: `#[marker]` attribute cannot be used on type aliases --> $DIR/marker-attribute-on-non-trait.rs:20:1 | LL | #[marker] | ^^^^^^^^^ -LL | type Type = (); - | --------------- not a trait + | + = help: `#[marker]` can only be applied to traits error: aborting due to 6 previous errors diff --git a/tests/ui/panic-handler/panic-handler-wrong-location.stderr b/tests/ui/panic-handler/panic-handler-wrong-location.stderr index 66ee91aa4c199..9b361bf8d603f 100644 --- a/tests/ui/panic-handler/panic-handler-wrong-location.stderr +++ b/tests/ui/panic-handler/panic-handler-wrong-location.stderr @@ -2,7 +2,7 @@ error[E0718]: `panic_impl` lang item must be applied to a function --> $DIR/panic-handler-wrong-location.rs:6:1 | LL | #[panic_handler] - | ^^^^^^^^^^^^^^^^ attribute should be applied to a function, not a static item + | ^^^^^^^^^^^^^^^^ attribute should be applied to a function, not a static error: `#[panic_handler]` function required, but not found diff --git a/tests/ui/proc-macro/illegal-proc-macro-derive-use.rs b/tests/ui/proc-macro/illegal-proc-macro-derive-use.rs index 4efd9e952fc14..19473fb2cafc3 100644 --- a/tests/ui/proc-macro/illegal-proc-macro-derive-use.rs +++ b/tests/ui/proc-macro/illegal-proc-macro-derive-use.rs @@ -8,7 +8,7 @@ pub fn foo(a: proc_macro::TokenStream) -> proc_macro::TokenStream { // Issue #37590 #[proc_macro_derive(Foo)] -//~^ ERROR: the `#[proc_macro_derive]` attribute may only be used on bare functions +//~^ ERROR: attribute cannot be used on pub struct Foo { } diff --git a/tests/ui/proc-macro/illegal-proc-macro-derive-use.stderr b/tests/ui/proc-macro/illegal-proc-macro-derive-use.stderr index c0930ab710246..f01619b919564 100644 --- a/tests/ui/proc-macro/illegal-proc-macro-derive-use.stderr +++ b/tests/ui/proc-macro/illegal-proc-macro-derive-use.stderr @@ -4,11 +4,13 @@ error: the `#[proc_macro_derive]` attribute is only usable with crates of the `p LL | #[proc_macro_derive(Foo)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: the `#[proc_macro_derive]` attribute may only be used on bare functions +error: `#[proc_macro_derive]` attribute cannot be used on structs --> $DIR/illegal-proc-macro-derive-use.rs:10:1 | LL | #[proc_macro_derive(Foo)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[proc_macro_derive]` can only be applied to functions error: aborting due to 2 previous errors diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.rs index 143f9a3009b61..b538a97280d5c 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.rs @@ -3,11 +3,11 @@ struct Foo; #[non_exhaustive] -//~^ ERROR attribute should be applied to a struct or enum [E0701] +//~^ ERROR attribute cannot be used on trait Bar { } #[non_exhaustive] -//~^ ERROR attribute should be applied to a struct or enum [E0701] +//~^ ERROR attribute cannot be used on union Baz { f1: u16, f2: u16 diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr index 1ac017aa08b9d..3522c4599770b 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr @@ -7,28 +7,22 @@ LL | #[non_exhaustive(anything)] | | didn't expect any arguments here | help: must be of the form: `#[non_exhaustive]` -error[E0701]: attribute should be applied to a struct or enum +error: `#[non_exhaustive]` attribute cannot be used on traits --> $DIR/invalid-attribute.rs:5:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ -LL | -LL | trait Bar { } - | ------------- not a struct or enum + | + = help: `#[non_exhaustive]` can be applied to data types, enum variants -error[E0701]: attribute should be applied to a struct or enum +error: `#[non_exhaustive]` attribute cannot be used on unions --> $DIR/invalid-attribute.rs:9:1 | -LL | #[non_exhaustive] - | ^^^^^^^^^^^^^^^^^ -LL | -LL | / union Baz { -LL | | f1: u16, -LL | | f2: u16 -LL | | } - | |_- not a struct or enum +LL | #[non_exhaustive] + | ^^^^^^^^^^^^^^^^^ + | + = help: `#[non_exhaustive]` can be applied to data types, enum variants error: aborting due to 3 previous errors -Some errors have detailed explanations: E0565, E0701. -For more information about an error, try `rustc --explain E0565`. +For more information about this error, try `rustc --explain E0565`. diff --git a/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.rs b/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.rs index 2d2b01b6f947a..53a856e0df301 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.rs @@ -1,5 +1,5 @@ #[track_caller] struct S; -//~^^ ERROR attribute should be applied to a function definition +//~^^ ERROR attribute cannot be used on fn main() {} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.stderr b/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.stderr index f976b7f5210b8..6ff66be4e5cea 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.stderr +++ b/tests/ui/rfcs/rfc-2091-track-caller/only-for-fns.stderr @@ -1,11 +1,10 @@ -error[E0739]: attribute should be applied to a function definition +error: `#[track_caller]` attribute cannot be used on structs --> $DIR/only-for-fns.rs:1:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ -LL | struct S; - | --------- not a function definition + | + = help: `#[track_caller]` can only be applied to functions error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0739`. diff --git a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr index 4244c11eb3eb4..23c93a4ed8bdb 100644 --- a/tests/ui/rustdoc/check-doc-alias-attr-location.stderr +++ b/tests/ui/rustdoc/check-doc-alias-attr-location.stderr @@ -10,13 +10,13 @@ error: `#[doc(alias = "...")]` isn't allowed on foreign module LL | #[doc(alias = "foo")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on inherent implementation block +error: `#[doc(alias = "...")]` isn't allowed on implementation block --> $DIR/check-doc-alias-attr-location.rs:12:7 | LL | #[doc(alias = "bar")] | ^^^^^^^^^^^^^ -error: `#[doc(alias = "...")]` isn't allowed on trait implementation block +error: `#[doc(alias = "...")]` isn't allowed on implementation block --> $DIR/check-doc-alias-attr-location.rs:18:7 | LL | #[doc(alias = "foobar")] diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs index d13098c3a6acb..b34a48aba2619 100644 --- a/tests/ui/target-feature/invalid-attribute.rs +++ b/tests/ui/target-feature/invalid-attribute.rs @@ -3,19 +3,16 @@ #![warn(unused_attributes)] #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on extern crate alloc; -//~^ NOTE not a function #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on use alloc::alloc::alloc; -//~^ NOTE not a function #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on extern "Rust" {} -//~^ NOTE not a function #[target_feature = "+sse2"] //~^ ERROR malformed `target_feature` attribute @@ -32,42 +29,35 @@ extern "Rust" {} unsafe fn foo() {} #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on mod another {} -//~^ NOTE not a function #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on const FOO: usize = 7; -//~^ NOTE not a function #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on struct Foo; -//~^ NOTE not a function #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on enum Bar {} -//~^ NOTE not a function #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on union Qux { - //~^ NOTE not a function - f1: u16, + f1: u16, f2: u16, } #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on type Uwu = (); -//~^ NOTE not a function #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on trait Baz {} -//~^ NOTE not a function #[inline(always)] //~^ ERROR: cannot use `#[inline(always)]` @@ -75,21 +65,18 @@ trait Baz {} unsafe fn test() {} #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on static A: () = (); -//~^ NOTE not a function #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on impl Quux for u8 {} -//~^ NOTE not a function -//~| NOTE missing `foo` in implementation +//~^ NOTE missing `foo` in implementation //~| ERROR missing: `foo` #[target_feature(enable = "sse2")] -//~^ ERROR attribute should be applied to a function +//~^ ERROR attribute cannot be used on impl Foo {} -//~^ NOTE not a function trait Quux { fn foo(); //~ NOTE `foo` from trait @@ -109,17 +96,15 @@ impl Quux for Foo { fn main() { #[target_feature(enable = "sse2")] - //~^ ERROR attribute should be applied to a function + //~^ ERROR attribute cannot be used on unsafe { foo(); } - //~^^^ NOTE not a function #[target_feature(enable = "sse2")] - //~^ ERROR attribute should be applied to a function + //~^ ERROR attribute cannot be used on || {}; - //~^ NOTE not a function -} + } #[target_feature(enable = "+sse2")] //~^ ERROR `+sse2` is not valid for this target diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index 113c0c3695a66..a0117649a5735 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -1,5 +1,29 @@ +error: `#[target_feature]` attribute cannot be used on extern crates + --> $DIR/invalid-attribute.rs:5:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[target_feature]` can only be applied to functions + +error: `#[target_feature]` attribute cannot be used on use statements + --> $DIR/invalid-attribute.rs:9:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[target_feature]` can only be applied to functions + +error: `#[target_feature]` attribute cannot be used on foreign modules + --> $DIR/invalid-attribute.rs:13:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[target_feature]` can only be applied to functions + error[E0539]: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:20:1 + --> $DIR/invalid-attribute.rs:17:1 | LL | #[target_feature = "+sse2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +32,7 @@ LL | #[target_feature = "+sse2"] | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]` error[E0539]: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:26:1 + --> $DIR/invalid-attribute.rs:23:1 | LL | #[target_feature(bar)] | ^^^^^^^^^^^^^^^^^---^^ @@ -17,7 +41,7 @@ LL | #[target_feature(bar)] | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]` error[E0539]: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:29:1 + --> $DIR/invalid-attribute.rs:26:1 | LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^^^-------^^^^^^^^^^ @@ -25,161 +49,116 @@ LL | #[target_feature(disable = "baz")] | | expected this to be of the form `enable = "..."` | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]` -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:5:1 +error: `#[target_feature]` attribute cannot be used on modules + --> $DIR/invalid-attribute.rs:31:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | extern crate alloc; - | ------------------- not a function definition - -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:10:1 | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | use alloc::alloc::alloc; - | ------------------------ not a function definition + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:15:1 +error: `#[target_feature]` attribute cannot be used on constants + --> $DIR/invalid-attribute.rs:35:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | extern "Rust" {} - | ---------------- not a function definition - -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:34:1 | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | mod another {} - | -------------- not a function definition + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition +error: `#[target_feature]` attribute cannot be used on structs --> $DIR/invalid-attribute.rs:39:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | const FOO: usize = 7; - | --------------------- not a function definition + | + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:44:1 +error: `#[target_feature]` attribute cannot be used on enums + --> $DIR/invalid-attribute.rs:43:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | struct Foo; - | ----------- not a function definition + | + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:49:1 +error: `#[target_feature]` attribute cannot be used on unions + --> $DIR/invalid-attribute.rs:47:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | enum Bar {} - | ----------- not a function definition + | + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition +error: `#[target_feature]` attribute cannot be used on type aliases --> $DIR/invalid-attribute.rs:54:1 | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / union Qux { -LL | | -LL | | f1: u16, -LL | | f2: u16, -LL | | } - | |_- not a function definition - -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:62:1 - | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | type Uwu = (); - | -------------- not a function definition + | + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:67:1 +error: `#[target_feature]` attribute cannot be used on traits + --> $DIR/invalid-attribute.rs:58:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | trait Baz {} - | ------------ not a function definition - -error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/invalid-attribute.rs:72:1 | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:77:1 +error: `#[target_feature]` attribute cannot be used on statics + --> $DIR/invalid-attribute.rs:67:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | static A: () = (); - | ------------------ not a function definition + | + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:82:1 +error: `#[target_feature]` attribute cannot be used on trait impl blocks + --> $DIR/invalid-attribute.rs:71:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | impl Quux for u8 {} - | ------------------- not a function definition + | + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:89:1 +error: `#[target_feature]` attribute cannot be used on inherent impl blocks + --> $DIR/invalid-attribute.rs:77:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | impl Foo {} - | ----------- not a function definition + | + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:111:5 +error: `#[target_feature]` attribute cannot be used on expressions + --> $DIR/invalid-attribute.rs:98:5 | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | / unsafe { -LL | | foo(); -LL | | } - | |_____- not a function definition +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[target_feature]` can only be applied to functions -error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:118:5 +error: `#[target_feature]` attribute cannot be used on closures + --> $DIR/invalid-attribute.rs:104:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | || {}; - | ----- not a function definition + | + = help: `#[target_feature]` can be applied to methods, functions + +error: cannot use `#[inline(always)]` with `#[target_feature]` + --> $DIR/invalid-attribute.rs:62:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ error: the feature named `foo` is not valid for this target - --> $DIR/invalid-attribute.rs:23:18 + --> $DIR/invalid-attribute.rs:20:18 | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ `foo` is not valid for this target error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/invalid-attribute.rs:84:1 + --> $DIR/invalid-attribute.rs:73:1 | LL | impl Quux for u8 {} | ^^^^^^^^^^^^^^^^ missing `foo` in implementation @@ -188,7 +167,7 @@ LL | fn foo(); | --------- `foo` from trait error: `#[target_feature(..)]` cannot be applied to safe trait method - --> $DIR/invalid-attribute.rs:100:5 + --> $DIR/invalid-attribute.rs:87:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method @@ -197,13 +176,13 @@ LL | fn foo() {} | -------- not an `unsafe` function error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/invalid-attribute.rs:103:5 + --> $DIR/invalid-attribute.rs:90:5 | LL | fn foo() {} | ^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait - --> $DIR/invalid-attribute.rs:95:5 + --> $DIR/invalid-attribute.rs:82:5 | LL | fn foo(); | ^^^^^^^^^ @@ -211,7 +190,7 @@ LL | fn foo(); found signature `#[target_features] fn()` error: the feature named `+sse2` is not valid for this target - --> $DIR/invalid-attribute.rs:124:18 + --> $DIR/invalid-attribute.rs:109:18 | LL | #[target_feature(enable = "+sse2")] | ^^^^^^^^^^^^^^^^ `+sse2` is not valid for this target diff --git a/tests/ui/traits/alias/not-a-marker.rs b/tests/ui/traits/alias/not-a-marker.rs index b004b9ff9ae3f..633cc60554da7 100644 --- a/tests/ui/traits/alias/not-a-marker.rs +++ b/tests/ui/traits/alias/not-a-marker.rs @@ -1,7 +1,7 @@ #![feature(trait_alias, marker_trait_attr)] #[marker] -//~^ ERROR attribute should be applied to a trait +//~^ ERROR attribute cannot be used on trait Foo = Send; fn main() {} diff --git a/tests/ui/traits/alias/not-a-marker.stderr b/tests/ui/traits/alias/not-a-marker.stderr index 2f3f6fea30f6a..8b0eba65b956b 100644 --- a/tests/ui/traits/alias/not-a-marker.stderr +++ b/tests/ui/traits/alias/not-a-marker.stderr @@ -1,11 +1,10 @@ -error: attribute should be applied to a trait +error: `#[marker]` attribute cannot be used on trait aliases --> $DIR/not-a-marker.rs:3:1 | LL | #[marker] | ^^^^^^^^^ -LL | -LL | trait Foo = Send; - | ----------------- not a trait + | + = help: `#[marker]` can only be applied to traits error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/attr-misuse.rs b/tests/ui/traits/const-traits/attr-misuse.rs index 01ac74feff74d..70dfcbf47d289 100644 --- a/tests/ui/traits/const-traits/attr-misuse.rs +++ b/tests/ui/traits/const-traits/attr-misuse.rs @@ -2,9 +2,9 @@ #[const_trait] trait A { - #[const_trait] //~ ERROR attribute should be applied + #[const_trait] //~ ERROR attribute cannot be used on fn foo(self); } -#[const_trait] //~ ERROR attribute should be applied +#[const_trait] //~ ERROR attribute cannot be used on fn main() {} diff --git a/tests/ui/traits/const-traits/attr-misuse.stderr b/tests/ui/traits/const-traits/attr-misuse.stderr index 998958cedf748..2f86efac4c921 100644 --- a/tests/ui/traits/const-traits/attr-misuse.stderr +++ b/tests/ui/traits/const-traits/attr-misuse.stderr @@ -1,18 +1,18 @@ -error: attribute should be applied to a trait +error: `#[const_trait]` attribute cannot be used on required trait methods + --> $DIR/attr-misuse.rs:5:5 + | +LL | #[const_trait] + | ^^^^^^^^^^^^^^ + | + = help: `#[const_trait]` can only be applied to traits + +error: `#[const_trait]` attribute cannot be used on functions --> $DIR/attr-misuse.rs:9:1 | LL | #[const_trait] | ^^^^^^^^^^^^^^ -LL | fn main() {} - | ------------ not a trait - -error: attribute should be applied to a trait - --> $DIR/attr-misuse.rs:5:5 | -LL | #[const_trait] - | ^^^^^^^^^^^^^^ -LL | fn foo(self); - | ------------- not a trait + = help: `#[const_trait]` can only be applied to traits error: aborting due to 2 previous errors diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.rs b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs index 0d6e4ebb4085f..cdd4178fc87a8 100644 --- a/tests/ui/unstable-feature-bound/unstable_inherent_method.rs +++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs @@ -9,14 +9,14 @@ pub trait Trait { #[unstable(feature = "feat", issue = "none" )] #[unstable_feature_bound(foo)] - //~^ ERROR: attribute should be applied to `impl`, trait or free function + //~^ ERROR: attribute cannot be used on fn foo(); } #[stable(feature = "a", since = "1.1.1" )] impl Trait for u8 { #[unstable_feature_bound(foo)] - //~^ ERROR: attribute should be applied to `impl`, trait or free function + //~^ ERROR: attribute cannot be used on fn foo() {} } diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr index 90cbb32df7c2f..2a1ae936cfeea 100644 --- a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr +++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr @@ -1,20 +1,18 @@ -error: attribute should be applied to `impl`, trait or free function +error: `#[unstable_feature_bound]` attribute cannot be used on required trait methods --> $DIR/unstable_inherent_method.rs:11:5 | LL | #[unstable_feature_bound(foo)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn foo(); - | --------- not an `impl`, trait or free function + | + = help: `#[unstable_feature_bound]` can be applied to functions, trait impl blocks, traits -error: attribute should be applied to `impl`, trait or free function +error: `#[unstable_feature_bound]` attribute cannot be used on trait methods in impl blocks --> $DIR/unstable_inherent_method.rs:18:5 | LL | #[unstable_feature_bound(foo)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn foo() {} - | ----------- not an `impl`, trait or free function + | + = help: `#[unstable_feature_bound]` can be applied to functions, trait impl blocks, traits error: aborting due to 2 previous errors diff --git a/tests/ui/where-clauses/unsupported_attribute.rs b/tests/ui/where-clauses/unsupported_attribute.rs index 33128b383b991..75213e176610e 100644 --- a/tests/ui/where-clauses/unsupported_attribute.rs +++ b/tests/ui/where-clauses/unsupported_attribute.rs @@ -13,18 +13,18 @@ fn foo<'a, T>() where #[doc = "doc"] T: Trait, //~ ERROR most attributes are not supported in `where` clauses #[doc = "doc"] 'a: 'static, //~ ERROR most attributes are not supported in `where` clauses - #[ignore] T: Trait, //~ ERROR most attributes are not supported in `where` clauses - #[ignore] 'a: 'static, //~ ERROR most attributes are not supported in `where` clauses - #[should_panic] T: Trait, //~ ERROR most attributes are not supported in `where` clauses - #[should_panic] 'a: 'static, //~ ERROR most attributes are not supported in `where` clauses - #[macro_use] T: Trait, //~ ERROR most attributes are not supported in `where` clauses - #[macro_use] 'a: 'static, //~ ERROR most attributes are not supported in `where` clauses + #[ignore] T: Trait, //~ ERROR attribute cannot be used on + #[ignore] 'a: 'static, //~ ERROR attribute cannot be used on + #[should_panic] T: Trait, //~ ERROR attribute cannot be used on + #[should_panic] 'a: 'static, //~ ERROR attribute cannot be used on + #[macro_use] T: Trait, //~ ERROR attribute cannot be used on + #[macro_use] 'a: 'static, //~ ERROR attribute cannot be used on #[allow(unused)] T: Trait, //~ ERROR most attributes are not supported in `where` clauses #[allow(unused)] 'a: 'static, //~ ERROR most attributes are not supported in `where` clauses - #[deprecated] T: Trait, //~ ERROR most attributes are not supported in `where` clauses - #[deprecated] 'a: 'static, //~ ERROR most attributes are not supported in `where` clauses - #[automatically_derived] T: Trait, //~ ERROR most attributes are not supported in `where` clauses - #[automatically_derived] 'a: 'static, //~ ERROR most attributes are not supported in `where` clauses + #[deprecated] T: Trait, //~ ERROR attribute cannot be used on + #[deprecated] 'a: 'static, //~ ERROR attribute cannot be used on + #[automatically_derived] T: Trait, //~ ERROR attribute cannot be used on + #[automatically_derived] 'a: 'static, //~ ERROR attribute cannot be used on #[derive(Clone)] T: Trait, //~^ ERROR most attributes are not supported in `where` clauses //~| ERROR expected non-macro attribute, found attribute macro `derive` diff --git a/tests/ui/where-clauses/unsupported_attribute.stderr b/tests/ui/where-clauses/unsupported_attribute.stderr index ecb28039f8851..411c895ed8736 100644 --- a/tests/ui/where-clauses/unsupported_attribute.stderr +++ b/tests/ui/where-clauses/unsupported_attribute.stderr @@ -10,115 +10,115 @@ error: expected non-macro attribute, found attribute macro `derive` LL | #[derive(Clone)] 'a: 'static, | ^^^^^^ not a non-macro attribute -error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:14:5 - | -LL | #[doc = "doc"] T: Trait, - | ^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:15:5 - | -LL | #[doc = "doc"] 'a: 'static, - | ^^^^^^^^^^^^^^ - | - = help: only `#[cfg]` and `#[cfg_attr]` are supported - -error: most attributes are not supported in `where` clauses +error: `#[ignore]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:16:5 | LL | #[ignore] T: Trait, | ^^^^^^^^^ | - = help: only `#[cfg]` and `#[cfg_attr]` are supported + = help: `#[ignore]` can only be applied to functions -error: most attributes are not supported in `where` clauses +error: `#[ignore]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:17:5 | LL | #[ignore] 'a: 'static, | ^^^^^^^^^ | - = help: only `#[cfg]` and `#[cfg_attr]` are supported + = help: `#[ignore]` can only be applied to functions -error: most attributes are not supported in `where` clauses +error: `#[should_panic]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:18:5 | LL | #[should_panic] T: Trait, | ^^^^^^^^^^^^^^^ | - = help: only `#[cfg]` and `#[cfg_attr]` are supported + = help: `#[should_panic]` can only be applied to functions -error: most attributes are not supported in `where` clauses +error: `#[should_panic]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:19:5 | LL | #[should_panic] 'a: 'static, | ^^^^^^^^^^^^^^^ | - = help: only `#[cfg]` and `#[cfg_attr]` are supported + = help: `#[should_panic]` can only be applied to functions -error: most attributes are not supported in `where` clauses +error: `#[macro_use]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:20:5 | LL | #[macro_use] T: Trait, | ^^^^^^^^^^^^ | - = help: only `#[cfg]` and `#[cfg_attr]` are supported + = help: `#[macro_use]` can be applied to modules, extern crates, crates -error: most attributes are not supported in `where` clauses +error: `#[macro_use]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:21:5 | LL | #[macro_use] 'a: 'static, | ^^^^^^^^^^^^ | - = help: only `#[cfg]` and `#[cfg_attr]` are supported + = help: `#[macro_use]` can be applied to modules, extern crates, crates -error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:22:5 +error: `#[deprecated]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:24:5 | -LL | #[allow(unused)] T: Trait, - | ^^^^^^^^^^^^^^^^ +LL | #[deprecated] T: Trait, + | ^^^^^^^^^^^^^ | - = help: only `#[cfg]` and `#[cfg_attr]` are supported + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates -error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:23:5 +error: `#[deprecated]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:25:5 | -LL | #[allow(unused)] 'a: 'static, - | ^^^^^^^^^^^^^^^^ +LL | #[deprecated] 'a: 'static, + | ^^^^^^^^^^^^^ | - = help: only `#[cfg]` and `#[cfg_attr]` are supported + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates + +error: `#[automatically_derived]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:26:5 + | +LL | #[automatically_derived] T: Trait, + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[automatically_derived]` can only be applied to trait impl blocks + +error: `#[automatically_derived]` attribute cannot be used on where predicates + --> $DIR/unsupported_attribute.rs:27:5 + | +LL | #[automatically_derived] 'a: 'static, + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[automatically_derived]` can only be applied to trait impl blocks error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:24:5 + --> $DIR/unsupported_attribute.rs:14:5 | -LL | #[deprecated] T: Trait, - | ^^^^^^^^^^^^^ +LL | #[doc = "doc"] T: Trait, + | ^^^^^^^^^^^^^^ | = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:25:5 + --> $DIR/unsupported_attribute.rs:15:5 | -LL | #[deprecated] 'a: 'static, - | ^^^^^^^^^^^^^ +LL | #[doc = "doc"] 'a: 'static, + | ^^^^^^^^^^^^^^ | = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:26:5 + --> $DIR/unsupported_attribute.rs:22:5 | -LL | #[automatically_derived] T: Trait, - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[allow(unused)] T: Trait, + | ^^^^^^^^^^^^^^^^ | = help: only `#[cfg]` and `#[cfg_attr]` are supported error: most attributes are not supported in `where` clauses - --> $DIR/unsupported_attribute.rs:27:5 + --> $DIR/unsupported_attribute.rs:23:5 | -LL | #[automatically_derived] 'a: 'static, - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[allow(unused)] 'a: 'static, + | ^^^^^^^^^^^^^^^^ | = help: only `#[cfg]` and `#[cfg_attr]` are supported From b67cd4c6cf4abc47056b1f45957a8ab8f3e7a559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Aug 2025 16:28:56 +0000 Subject: [PATCH 208/252] cleanup: Remove useless `[T].iter().last()` --- compiler/rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_macros/src/diagnostics/utils.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dc2eb17589c66..f62b8d1d57620 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1741,7 +1741,7 @@ fn deny_equality_constraints( .map(|segment| segment.ident.name) .zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name)) .all(|(a, b)| a == b) - && let Some(potential_assoc) = full_path.segments.iter().last() + && let Some(potential_assoc) = full_path.segments.last() { suggest(poly, potential_assoc, predicate); } diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 060799e981d46..c310b99d53513 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -146,7 +146,7 @@ impl<'ty> FieldInnerTy<'ty> { }; let path = &ty_path.path; - let ty = path.segments.iter().last().unwrap(); + let ty = path.segments.last().unwrap(); let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments else { panic!("expected bracketed generic arguments"); }; From 5c631041aa0b0ad9e161b966b78e6dfdb8011023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Thu, 14 Aug 2025 15:22:45 +0000 Subject: [PATCH 209/252] Basic implementation of `autodiff` intrinsic --- compiler/rustc_builtin_macros/src/autodiff.rs | 139 +++++++- .../src/builder/autodiff.rs | 302 ++++-------------- compiler/rustc_codegen_llvm/src/context.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 76 ++++- .../rustc_hir_analysis/src/check/intrinsic.rs | 5 +- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/mod.rs | 4 + 7 files changed, 284 insertions(+), 245 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index a662840eda5fa..3f8585d35bca6 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -329,17 +329,22 @@ mod llvm_enzyme { .filter(|a| **a == DiffActivity::Active || **a == DiffActivity::ActiveOnly) .count() as u32; let (d_sig, new_args, idents, errored) = gen_enzyme_decl(ecx, &sig, &x, span); - let d_body = gen_enzyme_body( + + // TODO(Sa4dUs): Remove this and all the related logic + let _d_body = gen_enzyme_body( ecx, &x, n_active, &sig, &d_sig, primal, &new_args, span, sig_span, idents, errored, &generics, ); + let d_body = + call_autodiff(ecx, primal, first_ident(&meta_item_vec[0]), span, &d_sig); + // The first element of it is the name of the function to be generated let asdf = Box::new(ast::Fn { defaultness: ast::Defaultness::Final, sig: d_sig, ident: first_ident(&meta_item_vec[0]), - generics, + generics: generics.clone(), contract: None, body: Some(d_body), define_opaque: None, @@ -428,12 +433,15 @@ mod llvm_enzyme { tokens: ts, }); + let vis_clone = vis.clone(); + + let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span); let d_annotatable = match &item { Annotatable::AssocItem(_, _) => { let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf); let d_fn = Box::new(ast::AssocItem { - attrs: thin_vec![d_attr, inline_never], + attrs: thin_vec![d_attr], id: ast::DUMMY_NODE_ID, span, vis, @@ -443,13 +451,13 @@ mod llvm_enzyme { Annotatable::AssocItem(d_fn, Impl { of_trait: false }) } Annotatable::Item(_) => { - let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); + let mut d_fn = ecx.item(span, thin_vec![d_attr], ItemKind::Fn(asdf)); d_fn.vis = vis; Annotatable::Item(d_fn) } Annotatable::Stmt(_) => { - let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); + let mut d_fn = ecx.item(span, thin_vec![d_attr], ItemKind::Fn(asdf)); d_fn.vis = vis; Annotatable::Stmt(Box::new(ast::Stmt { @@ -463,7 +471,9 @@ mod llvm_enzyme { } }; - return vec![orig_annotatable, d_annotatable]; + let dummy_const_annotatable = gen_dummy_const(ecx, span, primal, sig, generics, vis_clone); + + return vec![orig_annotatable, dummy_const_annotatable, d_annotatable]; } // shadow arguments (the extra ones which were not in the original (primal) function), in reverse mode must be @@ -484,6 +494,123 @@ mod llvm_enzyme { ty } + // Generate `autodiff` intrinsic call + // ``` + // std::intrinsics::autodiff(source, diff, (args)) + // ``` + fn call_autodiff( + ecx: &ExtCtxt<'_>, + primal: Ident, + diff: Ident, + span: Span, + d_sig: &FnSig, + ) -> P { + let primal_path_expr = ecx.expr_path(ecx.path_ident(span, primal)); + let diff_path_expr = ecx.expr_path(ecx.path_ident(span, diff)); + + let tuple_expr = ecx.expr_tuple( + span, + d_sig + .decl + .inputs + .iter() + .map(|arg| match arg.pat.kind { + PatKind::Ident(_, ident, _) => ecx.expr_path(ecx.path_ident(span, ident)), + _ => todo!(), + }) + .collect::>() + .into(), + ); + + let enzyme_path = ecx.path( + span, + vec![ + Ident::from_str("std"), + Ident::from_str("intrinsics"), + Ident::from_str("autodiff"), + ], + ); + let call_expr = ecx.expr_call( + span, + ecx.expr_path(enzyme_path), + vec![primal_path_expr, diff_path_expr, tuple_expr].into(), + ); + + let block = ecx.block_expr(call_expr); + + block + } + + // Generate dummy const to prevent primal function + // from being optimized away before applying enzyme + // ``` + // const _: () = + // { + // #[used] + // pub static DUMMY_PTR: fn_type = primal_fn; + // }; + // ``` + fn gen_dummy_const( + ecx: &ExtCtxt<'_>, + span: Span, + primal: Ident, + sig: FnSig, + generics: Generics, + vis: Visibility, + ) -> Annotatable { + // #[used] + let used_attr = P(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::used))); + let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); + let used_attr = outer_normal_attr(&used_attr, new_id, span); + + // static DUMMY_PTR: = + let static_ident = Ident::from_str_and_span("DUMMY_PTR", span); + let fn_ptr_ty = ast::TyKind::BareFn(Box::new(ast::BareFnTy { + safety: sig.header.safety, + ext: sig.header.ext, + generic_params: generics.params, + decl: sig.decl, + decl_span: sig.span, + })); + let static_ty = ecx.ty(span, fn_ptr_ty); + + let static_expr = ecx.expr_path(ecx.path(span, vec![primal])); + let static_item_kind = ast::ItemKind::Static(Box::new(ast::StaticItem { + ident: static_ident, + ty: static_ty, + safety: ast::Safety::Default, + mutability: ast::Mutability::Not, + expr: Some(static_expr), + define_opaque: None, + })); + + let static_item = ast::Item { + attrs: thin_vec![used_attr], + id: ast::DUMMY_NODE_ID, + span, + vis, + kind: static_item_kind, + tokens: None, + }; + + let block_expr = ecx.expr_block(Box::new(ast::Block { + stmts: thin_vec![ecx.stmt_item(span, P(static_item))], + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span, + tokens: None, + })); + + let const_item = ecx.item_const( + span, + Ident::from_str_and_span("_", span), + ecx.ty(span, ast::TyKind::Tup(thin_vec![])), + block_expr, + ); + + Annotatable::Item(const_item) + } + // Will generate a body of the type: // ``` // { diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 829b3c513c258..66c34fbcfb181 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -3,22 +3,22 @@ use std::ptr; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode}; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::common::TypeKind; -use rustc_codegen_ssa::traits::BaseTypeCodegenMethods; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; use rustc_errors::FatalError; use rustc_middle::bug; use tracing::{debug, trace}; use crate::back::write::llvm_err; -use crate::builder::{SBuilder, UNNAMED}; +use crate::builder::{Builder, PlaceRef, UNNAMED}; use crate::context::SimpleCx; use crate::declare::declare_simple_fn; use crate::errors::{AutoDiffWithoutEnable, LlvmError}; use crate::llvm::AttributePlace::Function; -use crate::llvm::{Metadata, True}; +use crate::llvm::{Metadata, True, Type}; use crate::value::Value; use crate::{CodegenContext, LlvmCodegenBackend, ModuleLlvm, attributes, llvm}; -fn get_params(fnc: &Value) -> Vec<&Value> { +fn _get_params(fnc: &Value) -> Vec<&Value> { let param_num = llvm::LLVMCountParams(fnc) as usize; let mut fnc_args: Vec<&Value> = vec![]; fnc_args.reserve(param_num); @@ -29,7 +29,7 @@ fn get_params(fnc: &Value) -> Vec<&Value> { fnc_args } -fn has_sret(fnc: &Value) -> bool { +fn _has_sret(fnc: &Value) -> bool { let num_args = llvm::LLVMCountParams(fnc) as usize; if num_args == 0 { false @@ -48,14 +48,13 @@ fn has_sret(fnc: &Value) -> bool { // need to match those. // FIXME(ZuseZ4): This logic is a bit more complicated than it should be, can we simplify it // using iterators and peek()? -fn match_args_from_caller_to_enzyme<'ll>( +fn match_args_from_caller_to_enzyme<'ll, 'tcx>( cx: &SimpleCx<'ll>, - builder: &SBuilder<'ll, 'll>, + builder: &mut Builder<'_, 'll, 'tcx>, width: u32, args: &mut Vec<&'ll llvm::Value>, inputs: &[DiffActivity], outer_args: &[&'ll llvm::Value], - has_sret: bool, ) { debug!("matching autodiff arguments"); // We now handle the issue that Rust level arguments not always match the llvm-ir level @@ -67,20 +66,12 @@ fn match_args_from_caller_to_enzyme<'ll>( let mut outer_pos: usize = 0; let mut activity_pos = 0; - if has_sret { - // Then the first outer arg is the sret pointer. Enzyme doesn't know about sret, so the - // inner function will still return something. We increase our outer_pos by one, - // and once we're done with all other args we will take the return of the inner call and - // update the sret pointer with it - outer_pos = 1; - } - - let enzyme_const = cx.create_metadata(b"enzyme_const"); - let enzyme_out = cx.create_metadata(b"enzyme_out"); - let enzyme_dup = cx.create_metadata(b"enzyme_dup"); - let enzyme_dupv = cx.create_metadata(b"enzyme_dupv"); - let enzyme_dupnoneed = cx.create_metadata(b"enzyme_dupnoneed"); - let enzyme_dupnoneedv = cx.create_metadata(b"enzyme_dupnoneedv"); + let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap(); + let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap(); + let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap(); + let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap(); + let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap(); + let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap(); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -193,92 +184,6 @@ fn match_args_from_caller_to_enzyme<'ll>( } } -// On LLVM-IR, we can luckily declare __enzyme_ functions without specifying the input -// arguments. We do however need to declare them with their correct return type. -// We already figured the correct return type out in our frontend, when generating the outer_fn, -// so we can now just go ahead and use that. This is not always trivial, e.g. because sret. -// Beyond sret, this article describes our challenges nicely: -// -// I.e. (i32, f32) will get merged into i64, but we don't handle that yet. -fn compute_enzyme_fn_ty<'ll>( - cx: &SimpleCx<'ll>, - attrs: &AutoDiffAttrs, - fn_to_diff: &'ll Value, - outer_fn: &'ll Value, -) -> &'ll llvm::Type { - let fn_ty = cx.get_type_of_global(outer_fn); - let mut ret_ty = cx.get_return_type(fn_ty); - - let has_sret = has_sret(outer_fn); - - if has_sret { - // Now we don't just forward the return type, so we have to figure it out based on the - // primal return type, in combination with the autodiff settings. - let fn_ty = cx.get_type_of_global(fn_to_diff); - let inner_ret_ty = cx.get_return_type(fn_ty); - - let void_ty = unsafe { llvm::LLVMVoidTypeInContext(cx.llcx) }; - if inner_ret_ty == void_ty { - // This indicates that even the inner function has an sret. - // Right now I only look for an sret in the outer function. - // This *probably* needs some extra handling, but I never ran - // into such a case. So I'll wait for user reports to have a test case. - bug!("sret in inner function"); - } - - if attrs.width == 1 { - // Enzyme returns a struct of style: - // `{ original_ret(if requested), float, float, ... }` - let mut struct_elements = vec![]; - if attrs.has_primal_ret() { - struct_elements.push(inner_ret_ty); - } - // Next, we push the list of active floats, since they will be lowered to `enzyme_out`, - // and therefore part of the return struct. - let param_tys = cx.func_params_types(fn_ty); - for (act, param_ty) in attrs.input_activity.iter().zip(param_tys) { - if matches!(act, DiffActivity::Active) { - // Now find the float type at position i based on the fn_ty, - // to know what (f16/f32/f64/...) to add to the struct. - struct_elements.push(param_ty); - } - } - ret_ty = cx.type_struct(&struct_elements, false); - } else { - // First we check if we also have to deal with the primal return. - match attrs.mode { - DiffMode::Forward => match attrs.ret_activity { - DiffActivity::Dual => { - let arr_ty = - unsafe { llvm::LLVMArrayType2(inner_ret_ty, attrs.width as u64 + 1) }; - ret_ty = arr_ty; - } - DiffActivity::DualOnly => { - let arr_ty = - unsafe { llvm::LLVMArrayType2(inner_ret_ty, attrs.width as u64) }; - ret_ty = arr_ty; - } - DiffActivity::Const => { - todo!("Not sure, do we need to do something here?"); - } - _ => { - bug!("unreachable"); - } - }, - DiffMode::Reverse => { - todo!("Handle sret for reverse mode"); - } - _ => { - bug!("unreachable"); - } - } - } - } - - // LLVM can figure out the input types on it's own, so we take a shortcut here. - unsafe { llvm::LLVMFunctionType(ret_ty, ptr::null(), 0, True) } -} - /// When differentiating `fn_to_diff`, take a `outer_fn` and generate another /// function with expected naming and calling conventions[^1] which will be /// discovered by the enzyme LLVM pass and its body populated with the differentiated @@ -288,11 +193,15 @@ fn compute_enzyme_fn_ty<'ll>( /// [^1]: // FIXME(ZuseZ4): `outer_fn` should include upstream safety checks to // cover some assumptions of enzyme/autodiff, which could lead to UB otherwise. -fn generate_enzyme_call<'ll>( +pub(crate) fn generate_enzyme_call<'ll, 'tcx>( + builder: &mut Builder<'_, 'll, 'tcx>, cx: &SimpleCx<'ll>, fn_to_diff: &'ll Value, - outer_fn: &'ll Value, + outer_name: &str, + ret_ty: &'ll Type, + fn_args: &[&'ll Value], attrs: AutoDiffAttrs, + dest: PlaceRef<'tcx, &'ll Value>, ) { // We have to pick the name depending on whether we want forward or reverse mode autodiff. let mut ad_name: String = match attrs.mode { @@ -302,11 +211,9 @@ fn generate_enzyme_call<'ll>( } .to_string(); - // add outer_fn name to ad_name to make it unique, in case users apply autodiff to multiple + // add outer_name to ad_name to make it unique, in case users apply autodiff to multiple // functions. Unwrap will only panic, if LLVM gave us an invalid string. - let name = llvm::get_value_name(outer_fn); - let outer_fn_name = std::str::from_utf8(&name).unwrap(); - ad_name.push_str(outer_fn_name); + ad_name.push_str(outer_name); // Let us assume the user wrote the following function square: // @@ -317,13 +224,7 @@ fn generate_enzyme_call<'ll>( // ret double %0 // } // ``` - // - // The user now applies autodiff to the function square, in which case fn_to_diff will be `square`. - // Our macro generates the following placeholder code (slightly simplified): - // - // ```llvm // define double @dsquare(double %x) { - // ; placeholder code // return 0.0; // } // ``` @@ -340,120 +241,52 @@ fn generate_enzyme_call<'ll>( // ret double %0 // } // ``` - unsafe { - let enzyme_ty = compute_enzyme_fn_ty(cx, &attrs, fn_to_diff, outer_fn); - - // FIXME(ZuseZ4): the CC/Addr/Vis values are best effort guesses, we should look at tests and - // think a bit more about what should go here. - let cc = llvm::LLVMGetFunctionCallConv(outer_fn); - let ad_fn = declare_simple_fn( - cx, - &ad_name, - llvm::CallConv::try_from(cc).expect("invalid callconv"), - llvm::UnnamedAddr::No, - llvm::Visibility::Default, - enzyme_ty, - ); - - // Otherwise LLVM might inline our temporary code before the enzyme pass has a chance to - // do it's work. - let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx); - attributes::apply_to_llfn(ad_fn, Function, &[attr]); - - // We add a made-up attribute just such that we can recognize it after AD to update - // (no)-inline attributes. We'll then also remove this attribute. - let enzyme_marker_attr = llvm::CreateAttrString(cx.llcx, "enzyme_marker"); - attributes::apply_to_llfn(outer_fn, Function, &[enzyme_marker_attr]); - - // first, remove all calls from fnc - let entry = llvm::LLVMGetFirstBasicBlock(outer_fn); - let br = llvm::LLVMRustGetTerminator(entry); - llvm::LLVMRustEraseInstFromParent(br); - - let last_inst = llvm::LLVMRustGetLastInstruction(entry).unwrap(); - let mut builder = SBuilder::build(cx, entry); - - let num_args = llvm::LLVMCountParams(&fn_to_diff); - let mut args = Vec::with_capacity(num_args as usize + 1); - args.push(fn_to_diff); - - let enzyme_primal_ret = cx.create_metadata(b"enzyme_primal_return"); - if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { - args.push(cx.get_metadata_value(enzyme_primal_ret)); - } - if attrs.width > 1 { - let enzyme_width = cx.create_metadata(b"enzyme_width"); - args.push(cx.get_metadata_value(enzyme_width)); - args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); - } - - let has_sret = has_sret(outer_fn); - let outer_args: Vec<&llvm::Value> = get_params(outer_fn); - match_args_from_caller_to_enzyme( - &cx, - &builder, - attrs.width, - &mut args, - &attrs.input_activity, - &outer_args, - has_sret, - ); - - let call = builder.call(enzyme_ty, ad_fn, &args, None); - - // This part is a bit iffy. LLVM requires that a call to an inlineable function has some - // metadata attached to it, but we just created this code oota. Given that the - // differentiated function already has partly confusing metadata, and given that this - // affects nothing but the auttodiff IR, we take a shortcut and just steal metadata from the - // dummy code which we inserted at a higher level. - // FIXME(ZuseZ4): Work with Enzyme core devs to clarify what debug metadata issues we have, - // and how to best improve it for enzyme core and rust-enzyme. - let md_ty = cx.get_md_kind_id("dbg"); - if llvm::LLVMRustHasMetadata(last_inst, md_ty) { - let md = llvm::LLVMRustDIGetInstMetadata(last_inst) - .expect("failed to get instruction metadata"); - let md_todiff = cx.get_metadata_value(md); - llvm::LLVMSetMetadata(call, md_ty, md_todiff); - } else { - // We don't panic, since depending on whether we are in debug or release mode, we might - // have no debug info to copy, which would then be ok. - trace!("no dbg info"); - } - - // Now that we copied the metadata, get rid of dummy code. - llvm::LLVMRustEraseInstUntilInclusive(entry, last_inst); + let enzyme_ty = unsafe { llvm::LLVMFunctionType(ret_ty, ptr::null(), 0, True) }; + + // FIXME(ZuseZ4): the CC/Addr/Vis values are best effort guesses, we should look at tests and + // think a bit more about what should go here. + // FIXME(Sa4dUs): have to find a way to get the cc, using `FastCallConv` for now + let cc = 8; + let ad_fn = declare_simple_fn( + cx, + &ad_name, + llvm::CallConv::try_from(cc).expect("invalid callconv"), + llvm::UnnamedAddr::No, + llvm::Visibility::Default, + enzyme_ty, + ); + + // Otherwise LLVM might inline our temporary code before the enzyme pass has a chance to + // do it's work. + let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx); + attributes::apply_to_llfn(ad_fn, Function, &[attr]); + + let num_args = llvm::LLVMCountParams(&fn_to_diff); + let mut args = Vec::with_capacity(num_args as usize + 1); + args.push(fn_to_diff); + + let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap(); + if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { + args.push(cx.get_metadata_value(enzyme_primal_ret)); + } + if attrs.width > 1 { + let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap(); + args.push(cx.get_metadata_value(enzyme_width)); + args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); + } - if cx.val_ty(call) == cx.type_void() || has_sret { - if has_sret { - // This is what we already have in our outer_fn (shortened): - // define void @_foo(ptr <..> sret([32 x i8]) initializes((0, 32)) %0, <...>) { - // %7 = call [4 x double] (...) @__enzyme_fwddiff_foo(ptr @square, metadata !"enzyme_width", i64 4, <...>) - // - // store [4 x double] %7, ptr %0, align 8 - // ret void - // } + match_args_from_caller_to_enzyme( + &cx, + builder, + attrs.width, + &mut args, + &attrs.input_activity, + fn_args, + ); - // now store the result of the enzyme call into the sret pointer. - let sret_ptr = outer_args[0]; - let call_ty = cx.val_ty(call); - if attrs.width == 1 { - assert_eq!(cx.type_kind(call_ty), TypeKind::Struct); - } else { - assert_eq!(cx.type_kind(call_ty), TypeKind::Array); - } - llvm::LLVMBuildStore(&builder.llbuilder, call, sret_ptr); - } - builder.ret_void(); - } else { - builder.ret(call); - } + let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None); - // Let's crash in case that we messed something up above and generated invalid IR. - llvm::LLVMRustVerifyFunction( - outer_fn, - llvm::LLVMRustVerifierFailureAction::LLVMAbortProcessAction, - ); - } + builder.store_to_place(call, dest.val); } pub(crate) fn differentiate<'ll>( @@ -461,6 +294,7 @@ pub(crate) fn differentiate<'ll>( cgcx: &CodegenContext, diff_items: Vec, ) -> Result<(), FatalError> { + // TODO(Sa4dUs): delete all this logic for item in &diff_items { trace!("{}", item); } @@ -480,7 +314,7 @@ pub(crate) fn differentiate<'ll>( for item in diff_items.iter() { let name = item.source.clone(); let fn_def: Option<&llvm::Value> = cx.get_function(&name); - let Some(fn_def) = fn_def else { + let Some(_fn_def) = fn_def else { return Err(llvm_err( diag_handler.handle(), LlvmError::PrepareAutoDiff { @@ -492,7 +326,7 @@ pub(crate) fn differentiate<'ll>( }; debug!(?item.target); let fn_target: Option<&llvm::Value> = cx.get_function(&item.target); - let Some(fn_target) = fn_target else { + let Some(_fn_target) = fn_target else { return Err(llvm_err( diag_handler.handle(), LlvmError::PrepareAutoDiff { @@ -503,7 +337,7 @@ pub(crate) fn differentiate<'ll>( )); }; - generate_enzyme_call(&cx, fn_def, fn_target, item.attrs.clone()); + // generate_enzyme_call(&cx, fn_def, fn_target, item.attrs.clone()); } // FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 27ae729a53110..8eb15571e8242 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -660,7 +660,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } } impl<'ll> SimpleCx<'ll> { - pub(crate) fn get_return_type(&self, ty: &'ll Type) -> &'ll Type { + pub(crate) fn _get_return_type(&self, ty: &'ll Type) -> &'ll Type { assert_eq!(self.type_kind(ty), TypeKind::Function); unsafe { llvm::LLVMGetReturnType(ty) } } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 7b27e496986ae..1102fc1d0c8c8 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -3,23 +3,26 @@ use std::cmp::Ordering; use rustc_abi::{Align, BackendRepr, ExternAbi, Float, HasDataLayout, Primitive, Size}; use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh}; +use rustc_codegen_ssa::codegen_attrs::autodiff_attrs; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; use rustc_hir as hir; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::BinOp; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; -use rustc_middle::ty::{self, GenericArgsRef, Ty}; +use rustc_middle::ty::{self, GenericArgsRef, Instance, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; -use rustc_symbol_mangling::mangle_internal_symbol; +use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate}; use rustc_target::spec::PanicStrategy; use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; +use crate::builder::autodiff::generate_enzyme_call; use crate::context::CodegenCx; use crate::llvm::{self, Metadata}; use crate::type_::Type; @@ -174,10 +177,17 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { span: Span, ) -> Result<(), ty::Instance<'tcx>> { let tcx = self.tcx; + let callee_ty = instance.ty(tcx, self.typing_env()); - let name = tcx.item_name(instance.def_id()); let fn_args = instance.args; + let sig = callee_ty.fn_sig(tcx); + let sig = tcx.normalize_erasing_late_bound_regions(self.typing_env(), sig); + let ret_ty = sig.output(); + let name = tcx.item_name(instance.def_id()); + + let llret_ty = self.layout_of(ret_ty).llvm_type(self); + let simple = call_simple_intrinsic(self, name, args); let llval = match name { _ if simple.is_some() => simple.unwrap(), @@ -189,6 +199,66 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { &[ptr, args[1].immediate()], ) } + sym::autodiff => { + let val_arr: Vec<&'ll Value> = match args[2].val { + crate::intrinsic::OperandValue::Ref(ref place_value) => { + let mut ret_arr = vec![]; + let tuple_place = PlaceRef { val: *place_value, layout: args[2].layout }; + + for i in 0..tuple_place.layout.layout.0.fields.count() { + let field_place = tuple_place.project_field(self, i); + let field_layout = tuple_place.layout.field(self, i); + let llvm_ty = field_layout.llvm_type(self.cx); + + let field_val = + self.load(llvm_ty, field_place.val.llval, field_place.val.align); + + ret_arr.push(field_val) + } + + ret_arr + } + crate::intrinsic::OperandValue::Pair(v1, v2) => vec![v1, v2], + OperandValue::Immediate(v) => vec![v], + OperandValue::ZeroSized => bug!("unexpected `ZeroSized` arg"), + }; + + // Get source, diff, and attrs + let source_id = match fn_args.into_type_list(tcx)[0].kind() { + ty::FnDef(def_id, _) => def_id, + _ => bug!("invalid args"), + }; + let fn_source = Instance::mono(tcx, *source_id); + let source_symbol = + symbol_name_for_instance_in_crate(tcx, fn_source.clone(), LOCAL_CRATE); + let fn_to_diff: Option<&'ll llvm::Value> = self.cx.get_function(&source_symbol); + let Some(fn_to_diff) = fn_to_diff else { bug!("could not find source function") }; + + let diff_id = match fn_args.into_type_list(tcx)[1].kind() { + ty::FnDef(def_id, _) => def_id, + _ => bug!("invalid args"), + }; + let fn_diff = Instance::mono(tcx, *diff_id); + let diff_symbol = + symbol_name_for_instance_in_crate(tcx, fn_diff.clone(), LOCAL_CRATE); + + let diff_attrs = autodiff_attrs(tcx, *diff_id); + let Some(diff_attrs) = diff_attrs else { bug!("could not find autodiff attrs") }; + + // Build body + generate_enzyme_call( + self, + self.cx, + fn_to_diff, + &diff_symbol, + llret_ty, + &val_arr, + diff_attrs.clone(), + result, + ); + + return Ok(()); + } sym::is_val_statically_known => { if let OperandValue::Immediate(imm) = args[0].val { self.call_intrinsic( diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 4441dd6ebd66a..46371cfe591b4 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -135,6 +135,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::round_ties_even_f32 | sym::round_ties_even_f64 | sym::round_ties_even_f128 + | sym::autodiff | sym::const_eval_select => hir::Safety::Safe, _ => hir::Safety::Unsafe, }; @@ -171,6 +172,8 @@ pub(crate) fn check_intrinsic_type( } }; + let has_autodiff = tcx.has_attr(intrinsic_id, sym::rustc_autodiff); + let bound_vars = tcx.mk_bound_variable_kinds(&[ ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon), ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon), @@ -195,9 +198,9 @@ pub(crate) fn check_intrinsic_type( (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty) }; - let safety = intrinsic_operation_unsafety(tcx, intrinsic_id); let n_lts = 0; let (n_tps, n_cts, inputs, output) = match intrinsic_name { + sym::autodiff => (4, 0, vec![param(0), param(1), param(2)], param(3)), sym::abort => (0, 0, vec![], tcx.types.never), sym::unreachable => (0, 0, vec![], tcx.types.never), sym::breakpoint => (0, 0, vec![], tcx.types.unit), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 416ce27367e5e..f7a8258a9d86d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -542,6 +542,7 @@ symbols! { audit_that, augmented_assignments, auto_traits, + autodiff, autodiff_forward, autodiff_reverse, automatically_derived, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 7228ad0ed6d08..6c389c55a5f3a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3157,6 +3157,10 @@ pub const unsafe fn copysignf64(x: f64, y: f64) -> f64; #[rustc_intrinsic] pub const unsafe fn copysignf128(x: f128, y: f128) -> f128; +#[rustc_nounwind] +#[rustc_intrinsic] +pub const fn autodiff(f: F, df: G, args: T) -> R; + /// Inform Miri that a given pointer definitely has a certain alignment. #[cfg(miri)] #[rustc_allow_const_fn_unstable(const_eval_select)] From 250d77e5d72fde69a6406050a3b037635f685378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Thu, 14 Aug 2025 15:27:57 +0000 Subject: [PATCH 210/252] Complete functionality and general cleanup --- Cargo.lock | 2 - compiler/rustc_builtin_macros/src/autodiff.rs | 492 ++++-------------- compiler/rustc_codegen_gcc/src/lib.rs | 6 - .../src/builder/autodiff.rs | 178 +++---- compiler/rustc_codegen_llvm/src/context.rs | 5 - compiler/rustc_codegen_llvm/src/intrinsic.rs | 212 +++++--- compiler/rustc_codegen_llvm/src/lib.rs | 6 - compiler/rustc_codegen_ssa/src/back/write.rs | 18 +- compiler/rustc_codegen_ssa/src/base.rs | 7 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 10 +- .../rustc_codegen_ssa/src/traits/write.rs | 2 - .../rustc_hir_analysis/src/check/intrinsic.rs | 3 +- .../src/middle/codegen_fn_attrs.rs | 4 - compiler/rustc_middle/src/mir/mono.rs | 2 - compiler/rustc_monomorphize/Cargo.toml | 2 - compiler/rustc_monomorphize/src/collector.rs | 5 + .../src/collector/autodiff.rs | 48 ++ .../rustc_monomorphize/src/partitioning.rs | 34 +- .../src/partitioning/autodiff.rs | 143 ----- library/core/src/intrinsics/mod.rs | 34 ++ library/core/src/macros/mod.rs | 2 + src/doc/rustc-dev-guide/src/SUMMARY.md | 1 - .../src/autodiff/limitations.md | 27 - triagebot.toml | 3 - 24 files changed, 419 insertions(+), 827 deletions(-) create mode 100644 compiler/rustc_monomorphize/src/collector/autodiff.rs delete mode 100644 compiler/rustc_monomorphize/src/partitioning/autodiff.rs delete mode 100644 src/doc/rustc-dev-guide/src/autodiff/limitations.md diff --git a/Cargo.lock b/Cargo.lock index 8a878faecbc7f..e8590fa484bf2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4308,7 +4308,6 @@ name = "rustc_monomorphize" version = "0.0.0" dependencies = [ "rustc_abi", - "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -4317,7 +4316,6 @@ dependencies = [ "rustc_middle", "rustc_session", "rustc_span", - "rustc_symbol_mangling", "rustc_target", "serde", "serde_json", diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 3f8585d35bca6..c260dca87c036 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -15,11 +15,12 @@ mod llvm_enzyme { use rustc_ast::tokenstream::*; use rustc_ast::visit::AssocCtxt::*; use rustc_ast::{ - self as ast, AssocItemKind, BindingMode, ExprKind, FnRetTy, FnSig, Generics, ItemKind, - MetaItemInner, PatKind, QSelf, TyKind, Visibility, + self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemKind, BindingMode, + FnRetTy, FnSig, GenericArg, GenericArgs, GenericParamKind, Generics, ItemKind, + MetaItemInner, PatKind, Path, PathSegment, TyKind, Visibility, }; use rustc_expand::base::{Annotatable, ExtCtxt}; - use rustc_span::{Ident, Span, Symbol, kw, sym}; + use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, trace}; @@ -179,11 +180,8 @@ mod llvm_enzyme { } /// We expand the autodiff macro to generate a new placeholder function which passes - /// type-checking and can be called by users. The function body of the placeholder function will - /// later be replaced on LLVM-IR level, so the design of the body is less important and for now - /// should just prevent early inlining and optimizations which alter the function signature. - /// The exact signature of the generated function depends on the configuration provided by the - /// user, but here is an example: + /// type-checking and can be called by users. The exact signature of the generated function + /// depends on the configuration provided by the user, but here is an example: /// /// ``` /// #[autodiff(cos_box, Reverse, Duplicated, Active)] @@ -199,14 +197,8 @@ mod llvm_enzyme { /// f32::sin(**x) /// } /// #[rustc_autodiff(Reverse, Duplicated, Active)] - /// #[inline(never)] /// fn cos_box(x: &Box, dx: &mut Box, dret: f32) -> f32 { - /// unsafe { - /// asm!("NOP"); - /// }; - /// ::core::hint::black_box(sin(x)); - /// ::core::hint::black_box((dx, dret)); - /// ::core::hint::black_box(sin(x)) + /// std::intrinsics::autodiff(sin::<>, cos_box::<>, (x, dx, dret)) /// } /// ``` /// FIXME(ZuseZ4): Once autodiff is enabled by default, make this a doc comment which is checked @@ -227,16 +219,24 @@ mod llvm_enzyme { // first get information about the annotable item: visibility, signature, name and generic // parameters. // these will be used to generate the differentiated version of the function - let Some((vis, sig, primal, generics)) = (match &item { - Annotatable::Item(iitem) => extract_item_info(iitem), + let Some((vis, sig, primal, generics, impl_of_trait)) = (match &item { + Annotatable::Item(iitem) => { + extract_item_info(iitem).map(|(v, s, p, g)| (v, s, p, g, false)) + } Annotatable::Stmt(stmt) => match &stmt.kind { - ast::StmtKind::Item(iitem) => extract_item_info(iitem), + ast::StmtKind::Item(iitem) => { + extract_item_info(iitem).map(|(v, s, p, g)| (v, s, p, g, false)) + } _ => None, }, - Annotatable::AssocItem(assoc_item, Impl { .. }) => match &assoc_item.kind { - ast::AssocItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => { - Some((assoc_item.vis.clone(), sig.clone(), ident.clone(), generics.clone())) - } + Annotatable::AssocItem(assoc_item, Impl { of_trait }) => match &assoc_item.kind { + ast::AssocItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => Some(( + assoc_item.vis.clone(), + sig.clone(), + ident.clone(), + generics.clone(), + *of_trait, + )), _ => None, }, _ => None, @@ -254,7 +254,6 @@ mod llvm_enzyme { }; let has_ret = has_ret(&sig.decl.output); - let sig_span = ecx.with_call_site_ctxt(sig.span); // create TokenStream from vec elemtents: // meta_item doesn't have a .tokens field @@ -323,28 +322,27 @@ mod llvm_enzyme { } let span = ecx.with_def_site_ctxt(expand_span); - let n_active: u32 = x - .input_activity - .iter() - .filter(|a| **a == DiffActivity::Active || **a == DiffActivity::ActiveOnly) - .count() as u32; - let (d_sig, new_args, idents, errored) = gen_enzyme_decl(ecx, &sig, &x, span); - - // TODO(Sa4dUs): Remove this and all the related logic - let _d_body = gen_enzyme_body( - ecx, &x, n_active, &sig, &d_sig, primal, &new_args, span, sig_span, idents, errored, - &generics, - ); + let d_sig = gen_enzyme_decl(ecx, &sig, &x, span); - let d_body = - call_autodiff(ecx, primal, first_ident(&meta_item_vec[0]), span, &d_sig); + let d_body = ecx.block( + span, + thin_vec![call_autodiff( + ecx, + primal, + first_ident(&meta_item_vec[0]), + span, + &d_sig, + &generics, + impl_of_trait, + )], + ); // The first element of it is the name of the function to be generated - let asdf = Box::new(ast::Fn { + let d_fn = Box::new(ast::Fn { defaultness: ast::Defaultness::Final, sig: d_sig, ident: first_ident(&meta_item_vec[0]), - generics: generics.clone(), + generics, contract: None, body: Some(d_body), define_opaque: None, @@ -433,13 +431,11 @@ mod llvm_enzyme { tokens: ts, }); - let vis_clone = vis.clone(); - let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span); let d_annotatable = match &item { Annotatable::AssocItem(_, _) => { - let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf); + let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(d_fn); let d_fn = Box::new(ast::AssocItem { attrs: thin_vec![d_attr], id: ast::DUMMY_NODE_ID, @@ -451,13 +447,13 @@ mod llvm_enzyme { Annotatable::AssocItem(d_fn, Impl { of_trait: false }) } Annotatable::Item(_) => { - let mut d_fn = ecx.item(span, thin_vec![d_attr], ItemKind::Fn(asdf)); + let mut d_fn = ecx.item(span, thin_vec![d_attr], ItemKind::Fn(d_fn)); d_fn.vis = vis; Annotatable::Item(d_fn) } Annotatable::Stmt(_) => { - let mut d_fn = ecx.item(span, thin_vec![d_attr], ItemKind::Fn(asdf)); + let mut d_fn = ecx.item(span, thin_vec![d_attr], ItemKind::Fn(d_fn)); d_fn.vis = vis; Annotatable::Stmt(Box::new(ast::Stmt { @@ -471,9 +467,7 @@ mod llvm_enzyme { } }; - let dummy_const_annotatable = gen_dummy_const(ecx, span, primal, sig, generics, vis_clone); - - return vec![orig_annotatable, dummy_const_annotatable, d_annotatable]; + return vec![orig_annotatable, d_annotatable]; } // shadow arguments (the extra ones which were not in the original (primal) function), in reverse mode must be @@ -504,9 +498,11 @@ mod llvm_enzyme { diff: Ident, span: Span, d_sig: &FnSig, - ) -> P { - let primal_path_expr = ecx.expr_path(ecx.path_ident(span, primal)); - let diff_path_expr = ecx.expr_path(ecx.path_ident(span, diff)); + generics: &Generics, + is_impl: bool, + ) -> rustc_ast::Stmt { + let primal_path_expr = gen_turbofish_expr(ecx, primal, generics, span, is_impl); + let diff_path_expr = gen_turbofish_expr(ecx, diff, generics, span, is_impl); let tuple_expr = ecx.expr_tuple( span, @@ -522,371 +518,65 @@ mod llvm_enzyme { .into(), ); - let enzyme_path = ecx.path( - span, - vec![ - Ident::from_str("std"), - Ident::from_str("intrinsics"), - Ident::from_str("autodiff"), - ], - ); + let enzyme_path_idents = ecx.std_path(&[sym::intrinsics, sym::autodiff]); + let enzyme_path = ecx.path(span, enzyme_path_idents); let call_expr = ecx.expr_call( span, ecx.expr_path(enzyme_path), vec![primal_path_expr, diff_path_expr, tuple_expr].into(), ); - let block = ecx.block_expr(call_expr); - - block - } - - // Generate dummy const to prevent primal function - // from being optimized away before applying enzyme - // ``` - // const _: () = - // { - // #[used] - // pub static DUMMY_PTR: fn_type = primal_fn; - // }; - // ``` - fn gen_dummy_const( - ecx: &ExtCtxt<'_>, - span: Span, - primal: Ident, - sig: FnSig, - generics: Generics, - vis: Visibility, - ) -> Annotatable { - // #[used] - let used_attr = P(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::used))); - let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); - let used_attr = outer_normal_attr(&used_attr, new_id, span); - - // static DUMMY_PTR: = - let static_ident = Ident::from_str_and_span("DUMMY_PTR", span); - let fn_ptr_ty = ast::TyKind::BareFn(Box::new(ast::BareFnTy { - safety: sig.header.safety, - ext: sig.header.ext, - generic_params: generics.params, - decl: sig.decl, - decl_span: sig.span, - })); - let static_ty = ecx.ty(span, fn_ptr_ty); - - let static_expr = ecx.expr_path(ecx.path(span, vec![primal])); - let static_item_kind = ast::ItemKind::Static(Box::new(ast::StaticItem { - ident: static_ident, - ty: static_ty, - safety: ast::Safety::Default, - mutability: ast::Mutability::Not, - expr: Some(static_expr), - define_opaque: None, - })); - - let static_item = ast::Item { - attrs: thin_vec![used_attr], - id: ast::DUMMY_NODE_ID, - span, - vis, - kind: static_item_kind, - tokens: None, - }; - - let block_expr = ecx.expr_block(Box::new(ast::Block { - stmts: thin_vec![ecx.stmt_item(span, P(static_item))], - id: ast::DUMMY_NODE_ID, - rules: ast::BlockCheckMode::Default, - span, - tokens: None, - })); - - let const_item = ecx.item_const( - span, - Ident::from_str_and_span("_", span), - ecx.ty(span, ast::TyKind::Tup(thin_vec![])), - block_expr, - ); - - Annotatable::Item(const_item) + ecx.stmt_expr(call_expr) } - // Will generate a body of the type: - // ``` - // { - // unsafe { - // asm!("NOP"); - // } - // ::core::hint::black_box(primal(args)); - // ::core::hint::black_box((args, ret)); - // - // } - // ``` - fn init_body_helper( + // Generate turbofish expression from fn name and generics + // Given `foo` and `` params, gen `foo::` + // We use this expression when passing primal and diff function to the autodiff intrinsic + fn gen_turbofish_expr( ecx: &ExtCtxt<'_>, - span: Span, - primal: Ident, - new_names: &[String], - sig_span: Span, - new_decl_span: Span, - idents: &[Ident], - errored: bool, + ident: Ident, generics: &Generics, - ) -> (Box, Box, Box, Box) { - let blackbox_path = ecx.std_path(&[sym::hint, sym::black_box]); - let noop = ast::InlineAsm { - asm_macro: ast::AsmMacro::Asm, - template: vec![ast::InlineAsmTemplatePiece::String("NOP".into())], - template_strs: Box::new([]), - operands: vec![], - clobber_abis: vec![], - options: ast::InlineAsmOptions::PURE | ast::InlineAsmOptions::NOMEM, - line_spans: vec![], - }; - let noop_expr = ecx.expr_asm(span, Box::new(noop)); - let unsf = ast::BlockCheckMode::Unsafe(ast::UnsafeSource::CompilerGenerated); - let unsf_block = ast::Block { - stmts: thin_vec![ecx.stmt_semi(noop_expr)], - id: ast::DUMMY_NODE_ID, - tokens: None, - rules: unsf, - span, - }; - let unsf_expr = ecx.expr_block(Box::new(unsf_block)); - let blackbox_call_expr = ecx.expr_path(ecx.path(span, blackbox_path)); - let primal_call = gen_primal_call(ecx, span, primal, idents, generics); - let black_box_primal_call = ecx.expr_call( - new_decl_span, - blackbox_call_expr.clone(), - thin_vec![primal_call.clone()], - ); - let tup_args = new_names - .iter() - .map(|arg| ecx.expr_path(ecx.path_ident(span, Ident::from_str(arg)))) - .collect(); - - let black_box_remaining_args = ecx.expr_call( - sig_span, - blackbox_call_expr.clone(), - thin_vec![ecx.expr_tuple(sig_span, tup_args)], - ); - - let mut body = ecx.block(span, ThinVec::new()); - body.stmts.push(ecx.stmt_semi(unsf_expr)); - - // This uses primal args which won't be available if we errored before - if !errored { - body.stmts.push(ecx.stmt_semi(black_box_primal_call.clone())); - } - body.stmts.push(ecx.stmt_semi(black_box_remaining_args)); - - (body, primal_call, black_box_primal_call, blackbox_call_expr) - } - - /// We only want this function to type-check, since we will replace the body - /// later on llvm level. Using `loop {}` does not cover all return types anymore, - /// so instead we manually build something that should pass the type checker. - /// We also add a inline_asm line, as one more barrier for rustc to prevent inlining - /// or const propagation. inline_asm will also triggers an Enzyme crash if due to another - /// bug would ever try to accidentally differentiate this placeholder function body. - /// Finally, we also add back_box usages of all input arguments, to prevent rustc - /// from optimizing any arguments away. - fn gen_enzyme_body( - ecx: &ExtCtxt<'_>, - x: &AutoDiffAttrs, - n_active: u32, - sig: &ast::FnSig, - d_sig: &ast::FnSig, - primal: Ident, - new_names: &[String], span: Span, - sig_span: Span, - idents: Vec, - errored: bool, - generics: &Generics, - ) -> Box { - let new_decl_span = d_sig.span; - - // Just adding some default inline-asm and black_box usages to prevent early inlining - // and optimizations which alter the function signature. - // - // The bb_primal_call is the black_box call of the primal function. We keep it around, - // since it has the convenient property of returning the type of the primal function, - // Remember, we only care to match types here. - // No matter which return we pick, we always wrap it into a std::hint::black_box call, - // to prevent rustc from propagating it into the caller. - let (mut body, primal_call, bb_primal_call, bb_call_expr) = init_body_helper( - ecx, - span, - primal, - new_names, - sig_span, - new_decl_span, - &idents, - errored, - generics, - ); - - if !has_ret(&d_sig.decl.output) { - // there is no return type that we have to match, () works fine. - return body; - } - - // Everything from here onwards just tries to fulfil the return type. Fun! - - // having an active-only return means we'll drop the original return type. - // So that can be treated identical to not having one in the first place. - let primal_ret = has_ret(&sig.decl.output) && !x.has_active_only_ret(); - - if primal_ret && n_active == 0 && x.mode.is_rev() { - // We only have the primal ret. - body.stmts.push(ecx.stmt_expr(bb_primal_call)); - return body; - } - - if !primal_ret && n_active == 1 { - // Again no tuple return, so return default float val. - let ty = match d_sig.decl.output { - FnRetTy::Ty(ref ty) => ty.clone(), - FnRetTy::Default(span) => { - panic!("Did not expect Default ret ty: {:?}", span); + is_impl: bool, + ) -> Box { + let generic_args = generics + .params + .iter() + .filter_map(|p| match &p.kind { + GenericParamKind::Type { .. } => { + let path = ast::Path::from_ident(p.ident); + let ty = ecx.ty_path(path); + Some(AngleBracketedArg::Arg(GenericArg::Type(ty))) } - }; - let arg = ty.kind.is_simple_path().unwrap(); - let tmp = ecx.def_site_path(&[arg, kw::Default]); - let default_call_expr = ecx.expr_path(ecx.path(span, tmp)); - let default_call_expr = ecx.expr_call(new_decl_span, default_call_expr, thin_vec![]); - body.stmts.push(ecx.stmt_expr(default_call_expr)); - return body; - } - - let mut exprs: Box = primal_call; - let d_ret_ty = match d_sig.decl.output { - FnRetTy::Ty(ref ty) => ty.clone(), - FnRetTy::Default(span) => { - panic!("Did not expect Default ret ty: {:?}", span); - } - }; - if x.mode.is_fwd() { - // Fwd mode is easy. If the return activity is Const, we support arbitrary types. - // Otherwise, we only support a scalar, a pair of scalars, or an array of scalars. - // We checked that (on a best-effort base) in the preceding gen_enzyme_decl function. - // In all three cases, we can return `std::hint::black_box(::default())`. - if x.ret_activity == DiffActivity::Const { - // Here we call the primal function, since our dummy function has the same return - // type due to the Const return activity. - exprs = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![exprs]); - } else { - let q = QSelf { ty: d_ret_ty, path_span: span, position: 0 }; - let y = ExprKind::Path( - Some(Box::new(q)), - ecx.path_ident(span, Ident::with_dummy_span(kw::Default)), - ); - let default_call_expr = ecx.expr(span, y); - let default_call_expr = - ecx.expr_call(new_decl_span, default_call_expr, thin_vec![]); - exprs = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![default_call_expr]); - } - } else if x.mode.is_rev() { - if x.width == 1 { - // We either have `-> ArbitraryType` or `-> (ArbitraryType, repeated_float_scalars)`. - match d_ret_ty.kind { - TyKind::Tup(ref args) => { - // We have a tuple return type. We need to create a tuple of the same size - // and fill it with default values. - let mut exprs2 = thin_vec![exprs]; - for arg in args.iter().skip(1) { - let arg = arg.kind.is_simple_path().unwrap(); - let tmp = ecx.def_site_path(&[arg, kw::Default]); - let default_call_expr = ecx.expr_path(ecx.path(span, tmp)); - let default_call_expr = - ecx.expr_call(new_decl_span, default_call_expr, thin_vec![]); - exprs2.push(default_call_expr); - } - exprs = ecx.expr_tuple(new_decl_span, exprs2); - } - _ => { - // Interestingly, even the `-> ArbitraryType` case - // ends up getting matched and handled correctly above, - // so we don't have to handle any other case for now. - panic!("Unsupported return type: {:?}", d_ret_ty); - } + GenericParamKind::Const { .. } => { + let expr = ecx.expr_path(ast::Path::from_ident(p.ident)); + let anon_const = AnonConst { id: ast::DUMMY_NODE_ID, value: expr }; + Some(AngleBracketedArg::Arg(GenericArg::Const(anon_const))) } - } - exprs = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![exprs]); - } else { - unreachable!("Unsupported mode: {:?}", x.mode); - } - - body.stmts.push(ecx.stmt_expr(exprs)); + GenericParamKind::Lifetime { .. } => None, + }) + .collect::>(); - body - } + let args: AngleBracketedArgs = AngleBracketedArgs { span, args: generic_args }; - fn gen_primal_call( - ecx: &ExtCtxt<'_>, - span: Span, - primal: Ident, - idents: &[Ident], - generics: &Generics, - ) -> Box { - let has_self = idents.len() > 0 && idents[0].name == kw::SelfLower; + let segment = PathSegment { + ident, + id: ast::DUMMY_NODE_ID, + args: Some(Box::new(GenericArgs::AngleBracketed(args))), + }; - if has_self { - let args: ThinVec<_> = - idents[1..].iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect(); - let self_expr = ecx.expr_self(span); - ecx.expr_method_call(span, self_expr, primal, args) + let segments = if is_impl { + thin_vec![ + PathSegment { ident: Ident::from_str("Self"), id: ast::DUMMY_NODE_ID, args: None }, + segment, + ] } else { - let args: ThinVec<_> = - idents.iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect(); - let mut primal_path = ecx.path_ident(span, primal); - - let is_generic = !generics.params.is_empty(); - - match (is_generic, primal_path.segments.last_mut()) { - (true, Some(function_path)) => { - let primal_generic_types = generics - .params - .iter() - .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })); - - let generated_generic_types = primal_generic_types - .map(|type_param| { - let generic_param = TyKind::Path( - None, - ast::Path { - span, - segments: thin_vec![ast::PathSegment { - ident: type_param.ident, - args: None, - id: ast::DUMMY_NODE_ID, - }], - tokens: None, - }, - ); - - ast::AngleBracketedArg::Arg(ast::GenericArg::Type(Box::new(ast::Ty { - id: type_param.id, - span, - kind: generic_param, - tokens: None, - }))) - }) - .collect(); - - function_path.args = - Some(Box::new(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { - span, - args: generated_generic_types, - }))); - } - _ => {} - } + thin_vec![segment] + }; - let primal_call_expr = ecx.expr_path(primal_path); - ecx.expr_call(span, primal_call_expr, args) - } + let path = Path { span, segments, tokens: None }; + + ecx.expr_path(path) } // Generate the new function declaration. Const arguments are kept as is. Duplicated arguments must @@ -905,7 +595,7 @@ mod llvm_enzyme { sig: &ast::FnSig, x: &AutoDiffAttrs, span: Span, - ) -> (ast::FnSig, Vec, Vec, bool) { + ) -> ast::FnSig { let dcx = ecx.sess.dcx(); let has_ret = has_ret(&sig.decl.output); let sig_args = sig.decl.inputs.len() + if has_ret { 1 } else { 0 }; @@ -917,7 +607,7 @@ mod llvm_enzyme { found: num_activities, }); // This is not the right signature, but we can continue parsing. - return (sig.clone(), vec![], vec![], true); + return sig.clone(); } assert!(sig.decl.inputs.len() == x.input_activity.len()); assert!(has_ret == x.has_ret_activity()); @@ -960,7 +650,7 @@ mod llvm_enzyme { if errors { // This is not the right signature, but we can continue parsing. - return (sig.clone(), new_inputs, idents, true); + return sig.clone(); } let unsafe_activities = x @@ -1174,7 +864,7 @@ mod llvm_enzyme { } let d_sig = FnSig { header: d_header, decl: d_decl, span }; trace!("Generated signature: {:?}", d_sig); - (d_sig, new_inputs, idents, false) + d_sig } } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index b11f11d38e3ae..4025aba82da32 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -93,7 +93,6 @@ use gccjit::{CType, Context, OptimizationLevel}; #[cfg(feature = "master")] use gccjit::{TargetInfo, Version}; use rustc_ast::expand::allocator::AllocatorKind; -use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn, @@ -363,12 +362,7 @@ impl WriteBackendMethods for GccCodegenBackend { _exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, - diff_functions: Vec, ) -> Result, FatalError> { - if !diff_functions.is_empty() { - unimplemented!(); - } - back::lto::run_fat(cgcx, each_linked_rlib_for_lto, modules) } diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 66c34fbcfb181..56116959a6223 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -1,40 +1,93 @@ use std::ptr; -use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode}; -use rustc_codegen_ssa::ModuleCodegen; +use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; -use rustc_errors::FatalError; -use rustc_middle::bug; -use tracing::{debug, trace}; +use rustc_middle::ty::{PseudoCanonicalInput, Ty, TyCtxt, TypingEnv}; +use rustc_middle::{bug, ty}; +use tracing::debug; -use crate::back::write::llvm_err; use crate::builder::{Builder, PlaceRef, UNNAMED}; use crate::context::SimpleCx; use crate::declare::declare_simple_fn; -use crate::errors::{AutoDiffWithoutEnable, LlvmError}; use crate::llvm::AttributePlace::Function; use crate::llvm::{Metadata, True, Type}; use crate::value::Value; -use crate::{CodegenContext, LlvmCodegenBackend, ModuleLlvm, attributes, llvm}; +use crate::{attributes, llvm}; -fn _get_params(fnc: &Value) -> Vec<&Value> { - let param_num = llvm::LLVMCountParams(fnc) as usize; - let mut fnc_args: Vec<&Value> = vec![]; - fnc_args.reserve(param_num); - unsafe { - llvm::LLVMGetParams(fnc, fnc_args.as_mut_ptr()); - fnc_args.set_len(param_num); +pub(crate) fn adjust_activity_to_abi<'tcx>( + tcx: TyCtxt<'tcx>, + fn_ty: Ty<'tcx>, + da: &mut Vec, +) { + if !matches!(fn_ty.kind(), ty::FnDef(..)) { + bug!("expected fn def for autodiff, got {:?}", fn_ty); } - fnc_args -} -fn _has_sret(fnc: &Value) -> bool { - let num_args = llvm::LLVMCountParams(fnc) as usize; - if num_args == 0 { - false - } else { - unsafe { llvm::LLVMRustHasAttributeAtIndex(fnc, 0, llvm::AttributeKind::StructRet) } + // We don't actually pass the types back into the type system. + // All we do is decide how to handle the arguments. + let sig = fn_ty.fn_sig(tcx).skip_binder(); + + let mut new_activities = vec![]; + let mut new_positions = vec![]; + for (i, ty) in sig.inputs().iter().enumerate() { + if let Some(inner_ty) = ty.builtin_deref(true) { + if inner_ty.is_slice() { + // Now we need to figure out the size of each slice element in memory to allow + // safety checks and usability improvements in the backend. + let sty = match inner_ty.builtin_index() { + Some(sty) => sty, + None => { + panic!("slice element type unknown"); + } + }; + let pci = PseudoCanonicalInput { + typing_env: TypingEnv::fully_monomorphized(), + value: sty, + }; + + let layout = tcx.layout_of(pci); + let elem_size = match layout { + Ok(layout) => layout.size, + Err(_) => { + bug!("autodiff failed to compute slice element size"); + } + }; + let elem_size: u32 = elem_size.bytes() as u32; + + // We know that the length will be passed as extra arg. + if !da.is_empty() { + // We are looking at a slice. The length of that slice will become an + // extra integer on llvm level. Integers are always const. + // However, if the slice get's duplicated, we want to know to later check the + // size. So we mark the new size argument as FakeActivitySize. + // There is one FakeActivitySize per slice, so for convenience we store the + // slice element size in bytes in it. We will use the size in the backend. + let activity = match da[i] { + DiffActivity::DualOnly + | DiffActivity::Dual + | DiffActivity::Dualv + | DiffActivity::DuplicatedOnly + | DiffActivity::Duplicated => { + DiffActivity::FakeActivitySize(Some(elem_size)) + } + DiffActivity::Const => DiffActivity::Const, + _ => bug!("unexpected activity for ptr/ref"), + }; + new_activities.push(activity); + new_positions.push(i + 1); + } + + continue; + } + } + } + // now add the extra activities coming from slices + // Reverse order to not invalidate the indices + for _ in 0..new_activities.len() { + let pos = new_positions.pop().unwrap(); + let activity = new_activities.pop().unwrap(); + da.insert(pos, activity); } } @@ -66,12 +119,12 @@ fn match_args_from_caller_to_enzyme<'ll, 'tcx>( let mut outer_pos: usize = 0; let mut activity_pos = 0; - let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap(); - let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap(); - let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap(); - let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap(); - let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap(); - let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap(); + let enzyme_const = cx.create_metadata(b"enzyme_const"); + let enzyme_out = cx.create_metadata(b"enzyme_out"); + let enzyme_dup = cx.create_metadata(b"enzyme_dup"); + let enzyme_dupv = cx.create_metadata(b"enzyme_dupv"); + let enzyme_dupnoneed = cx.create_metadata(b"enzyme_dupnoneed"); + let enzyme_dupnoneedv = cx.create_metadata(b"enzyme_dupnoneedv"); while activity_pos < inputs.len() { let diff_activity = inputs[activity_pos as usize]; @@ -223,7 +276,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( // %0 = fmul double %x, %x // ret double %0 // } - // ``` + // // define double @dsquare(double %x) { // return 0.0; // } @@ -245,8 +298,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( // FIXME(ZuseZ4): the CC/Addr/Vis values are best effort guesses, we should look at tests and // think a bit more about what should go here. - // FIXME(Sa4dUs): have to find a way to get the cc, using `FastCallConv` for now - let cc = 8; + let cc = unsafe { llvm::LLVMGetFunctionCallConv(fn_to_diff) }; let ad_fn = declare_simple_fn( cx, &ad_name, @@ -265,12 +317,12 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); - let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap(); + let enzyme_primal_ret = cx.create_metadata(b"enzyme_primal_return"); if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) { args.push(cx.get_metadata_value(enzyme_primal_ret)); } if attrs.width > 1 { - let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap(); + let enzyme_width = cx.create_metadata(b"enzyme_width"); args.push(cx.get_metadata_value(enzyme_width)); args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64)); } @@ -288,61 +340,3 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( builder.store_to_place(call, dest.val); } - -pub(crate) fn differentiate<'ll>( - module: &'ll ModuleCodegen, - cgcx: &CodegenContext, - diff_items: Vec, -) -> Result<(), FatalError> { - // TODO(Sa4dUs): delete all this logic - for item in &diff_items { - trace!("{}", item); - } - - let diag_handler = cgcx.create_dcx(); - - let cx = SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx, cgcx.pointer_size); - - // First of all, did the user try to use autodiff without using the -Zautodiff=Enable flag? - if !diff_items.is_empty() - && !cgcx.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::Enable) - { - return Err(diag_handler.handle().emit_almost_fatal(AutoDiffWithoutEnable)); - } - - // Here we replace the placeholder code with the actual autodiff code, which calls Enzyme. - for item in diff_items.iter() { - let name = item.source.clone(); - let fn_def: Option<&llvm::Value> = cx.get_function(&name); - let Some(_fn_def) = fn_def else { - return Err(llvm_err( - diag_handler.handle(), - LlvmError::PrepareAutoDiff { - src: item.source.clone(), - target: item.target.clone(), - error: "could not find source function".to_owned(), - }, - )); - }; - debug!(?item.target); - let fn_target: Option<&llvm::Value> = cx.get_function(&item.target); - let Some(_fn_target) = fn_target else { - return Err(llvm_err( - diag_handler.handle(), - LlvmError::PrepareAutoDiff { - src: item.source.clone(), - target: item.target.clone(), - error: "could not find target function".to_owned(), - }, - )); - }; - - // generate_enzyme_call(&cx, fn_def, fn_target, item.attrs.clone()); - } - - // FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts - - trace!("done with differentiate()"); - - Ok(()) -} diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8eb15571e8242..da8c1e5f47b10 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -8,7 +8,6 @@ use std::str; use rustc_abi::{HasDataLayout, Size, TargetDataLayout, VariantIdx}; use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh}; -use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::errors as ssa_errors; use rustc_codegen_ssa::traits::*; use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN}; @@ -660,10 +659,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } } impl<'ll> SimpleCx<'ll> { - pub(crate) fn _get_return_type(&self, ty: &'ll Type) -> &'ll Type { - assert_eq!(self.type_kind(ty), TypeKind::Function); - unsafe { llvm::LLVMGetReturnType(ty) } - } pub(crate) fn get_type_of_global(&self, val: &'ll Value) -> &'ll Type { unsafe { llvm::LLVMGlobalGetValueType(val) } } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 1102fc1d0c8c8..4935f8d7dffd8 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -9,21 +9,23 @@ use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphizati use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; -use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::{self as hir}; use rustc_middle::mir::BinOp; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; -use rustc_middle::ty::{self, GenericArgsRef, Instance, Ty}; +use rustc_middle::ty::{self, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv}; use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate}; +use rustc_target::callconv::PassMode; use rustc_target::spec::PanicStrategy; use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; -use crate::builder::autodiff::generate_enzyme_call; +use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call}; use crate::context::CodegenCx; +use crate::errors::AutoDiffWithoutEnable; use crate::llvm::{self, Metadata}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; @@ -177,16 +179,9 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { span: Span, ) -> Result<(), ty::Instance<'tcx>> { let tcx = self.tcx; - let callee_ty = instance.ty(tcx, self.typing_env()); - let fn_args = instance.args; - - let sig = callee_ty.fn_sig(tcx); - let sig = tcx.normalize_erasing_late_bound_regions(self.typing_env(), sig); - let ret_ty = sig.output(); let name = tcx.item_name(instance.def_id()); - - let llret_ty = self.layout_of(ret_ty).llvm_type(self); + let fn_args = instance.args; let simple = call_simple_intrinsic(self, name, args); let llval = match name { @@ -200,63 +195,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { ) } sym::autodiff => { - let val_arr: Vec<&'ll Value> = match args[2].val { - crate::intrinsic::OperandValue::Ref(ref place_value) => { - let mut ret_arr = vec![]; - let tuple_place = PlaceRef { val: *place_value, layout: args[2].layout }; - - for i in 0..tuple_place.layout.layout.0.fields.count() { - let field_place = tuple_place.project_field(self, i); - let field_layout = tuple_place.layout.field(self, i); - let llvm_ty = field_layout.llvm_type(self.cx); - - let field_val = - self.load(llvm_ty, field_place.val.llval, field_place.val.align); - - ret_arr.push(field_val) - } - - ret_arr - } - crate::intrinsic::OperandValue::Pair(v1, v2) => vec![v1, v2], - OperandValue::Immediate(v) => vec![v], - OperandValue::ZeroSized => bug!("unexpected `ZeroSized` arg"), - }; - - // Get source, diff, and attrs - let source_id = match fn_args.into_type_list(tcx)[0].kind() { - ty::FnDef(def_id, _) => def_id, - _ => bug!("invalid args"), - }; - let fn_source = Instance::mono(tcx, *source_id); - let source_symbol = - symbol_name_for_instance_in_crate(tcx, fn_source.clone(), LOCAL_CRATE); - let fn_to_diff: Option<&'ll llvm::Value> = self.cx.get_function(&source_symbol); - let Some(fn_to_diff) = fn_to_diff else { bug!("could not find source function") }; - - let diff_id = match fn_args.into_type_list(tcx)[1].kind() { - ty::FnDef(def_id, _) => def_id, - _ => bug!("invalid args"), - }; - let fn_diff = Instance::mono(tcx, *diff_id); - let diff_symbol = - symbol_name_for_instance_in_crate(tcx, fn_diff.clone(), LOCAL_CRATE); - - let diff_attrs = autodiff_attrs(tcx, *diff_id); - let Some(diff_attrs) = diff_attrs else { bug!("could not find autodiff attrs") }; - - // Build body - generate_enzyme_call( - self, - self.cx, - fn_to_diff, - &diff_symbol, - llret_ty, - &val_arr, - diff_attrs.clone(), - result, - ); - + codegen_autodiff(self, tcx, instance, args, result); return Ok(()); } sym::is_val_statically_known => { @@ -1183,6 +1122,143 @@ fn get_rust_try_fn<'a, 'll, 'tcx>( rust_try } +fn codegen_autodiff<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, + args: &[OperandRef<'tcx, &'ll Value>], + result: PlaceRef<'tcx, &'ll Value>, +) { + if !tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::Enable) { + let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutEnable); + } + + let fn_args = instance.args; + let callee_ty = instance.ty(tcx, bx.typing_env()); + + let sig = callee_ty.fn_sig(tcx).skip_binder(); + + let ret_ty = sig.output(); + let llret_ty = bx.layout_of(ret_ty).llvm_type(bx); + + // Get source, diff, and attrs + let (source_id, source_args) = match fn_args.into_type_list(tcx)[0].kind() { + ty::FnDef(def_id, source_params) => (def_id, source_params), + _ => bug!("invalid autodiff intrinsic args"), + }; + + let fn_source = match Instance::try_resolve(tcx, bx.cx.typing_env(), *source_id, source_args) { + Ok(Some(instance)) => instance, + Ok(None) => bug!( + "could not resolve ({:?}, {:?}) to a specific autodiff instance", + source_id, + source_args + ), + Err(_) => { + // An error has already been emitted + return; + } + }; + + let source_symbol = symbol_name_for_instance_in_crate(tcx, fn_source.clone(), LOCAL_CRATE); + let Some(fn_to_diff) = bx.cx.get_function(&source_symbol) else { + bug!("could not find source function") + }; + + let (diff_id, diff_args) = match fn_args.into_type_list(tcx)[1].kind() { + ty::FnDef(def_id, diff_args) => (def_id, diff_args), + _ => bug!("invalid args"), + }; + + let fn_diff = match Instance::try_resolve(tcx, bx.cx.typing_env(), *diff_id, diff_args) { + Ok(Some(instance)) => instance, + Ok(None) => bug!( + "could not resolve ({:?}, {:?}) to a specific autodiff instance", + diff_id, + diff_args + ), + Err(_) => { + // An error has already been emitted + return; + } + }; + + let val_arr = get_args_from_tuple(bx, args[2], fn_diff); + let diff_symbol = symbol_name_for_instance_in_crate(tcx, fn_diff.clone(), LOCAL_CRATE); + + let Some(mut diff_attrs) = autodiff_attrs(tcx, fn_diff.def_id()) else { + bug!("could not find autodiff attrs") + }; + + adjust_activity_to_abi( + tcx, + fn_source.ty(tcx, TypingEnv::fully_monomorphized()), + &mut diff_attrs.input_activity, + ); + + // Build body + generate_enzyme_call( + bx, + bx.cx, + fn_to_diff, + &diff_symbol, + llret_ty, + &val_arr, + diff_attrs.clone(), + result, + ); +} + +fn get_args_from_tuple<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, + tuple_op: OperandRef<'tcx, &'ll Value>, + fn_instance: Instance<'tcx>, +) -> Vec<&'ll Value> { + let cx = bx.cx; + let fn_abi = cx.fn_abi_of_instance(fn_instance, ty::List::empty()); + + match tuple_op.val { + OperandValue::Immediate(val) => vec![val], + OperandValue::Pair(v1, v2) => vec![v1, v2], + OperandValue::Ref(ptr) => { + let tuple_place = PlaceRef { val: ptr, layout: tuple_op.layout }; + + let mut result = Vec::with_capacity(fn_abi.args.len()); + let mut tuple_index = 0; + + for arg in &fn_abi.args { + match arg.mode { + PassMode::Ignore => {} + PassMode::Direct(_) | PassMode::Cast { .. } => { + let field = tuple_place.project_field(bx, tuple_index); + let llvm_ty = field.layout.llvm_type(bx.cx); + let val = bx.load(llvm_ty, field.val.llval, field.val.align); + result.push(val); + tuple_index += 1; + } + PassMode::Pair(_, _) => { + let field = tuple_place.project_field(bx, tuple_index); + let llvm_ty = field.layout.llvm_type(bx.cx); + let pair_val = bx.load(llvm_ty, field.val.llval, field.val.align); + result.push(bx.extract_value(pair_val, 0)); + result.push(bx.extract_value(pair_val, 1)); + tuple_index += 1; + } + PassMode::Indirect { .. } => { + let field = tuple_place.project_field(bx, tuple_index); + result.push(field.val.llval); + tuple_index += 1; + } + } + } + + result + } + + OperandValue::ZeroSized => vec![], + } +} + fn generic_simd_intrinsic<'ll, 'tcx>( bx: &mut Builder<'_, 'll, 'tcx>, name: Symbol, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index ca84b6de8b11a..79e80db6f5554 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -30,7 +30,6 @@ use context::SimpleCx; use errors::ParseTargetMachineConfig; use llvm_util::target_config; use rustc_ast::expand::allocator::AllocatorKind; -use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, @@ -173,15 +172,10 @@ impl WriteBackendMethods for LlvmCodegenBackend { exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, - diff_fncs: Vec, ) -> Result, FatalError> { let mut module = back::lto::run_fat(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, modules)?; - if !diff_fncs.is_empty() { - builder::autodiff::differentiate(&module, cgcx, diff_fncs)?; - } - let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); back::lto::run_pass_manager(cgcx, dcx, &mut module, false)?; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index aa29afb7f5b11..2e8122798d169 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -7,7 +7,6 @@ use std::{fs, io, mem, str, thread}; use rustc_abi::Size; use rustc_ast::attr; -use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::jobserver::{self, Acquired}; use rustc_data_structures::memmap::Mmap; @@ -38,7 +37,7 @@ use tracing::debug; use super::link::{self, ensure_removed}; use super::lto::{self, SerializedModule}; use crate::back::lto::check_lto_allowed; -use crate::errors::{AutodiffWithoutLto, ErrorCreatingRemarkDir}; +use crate::errors::ErrorCreatingRemarkDir; use crate::traits::*; use crate::{ CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, @@ -454,7 +453,6 @@ pub(crate) fn start_async_codegen( backend: B, tcx: TyCtxt<'_>, target_cpu: String, - autodiff_items: &[AutoDiffItem], ) -> OngoingCodegen { let (coordinator_send, coordinator_receive) = channel(); @@ -473,7 +471,6 @@ pub(crate) fn start_async_codegen( backend.clone(), tcx, &crate_info, - autodiff_items, shared_emitter, codegen_worker_send, coordinator_receive, @@ -728,7 +725,6 @@ pub(crate) enum WorkItem { each_linked_rlib_for_lto: Vec, needs_fat_lto: Vec>, import_only_modules: Vec<(SerializedModule, WorkProduct)>, - autodiff: Vec, }, /// Performs thin-LTO on the given module. ThinLto(lto::ThinModule), @@ -1001,7 +997,6 @@ fn execute_fat_lto_work_item( each_linked_rlib_for_lto: &[PathBuf], mut needs_fat_lto: Vec>, import_only_modules: Vec<(SerializedModule, WorkProduct)>, - autodiff: Vec, module_config: &ModuleConfig, ) -> Result, FatalError> { for (module, wp) in import_only_modules { @@ -1013,7 +1008,6 @@ fn execute_fat_lto_work_item( exported_symbols_for_lto, each_linked_rlib_for_lto, needs_fat_lto, - autodiff, )?; let module = B::codegen(cgcx, module, module_config)?; Ok(WorkItemResult::Finished(module)) @@ -1105,7 +1099,6 @@ fn start_executing_work( backend: B, tcx: TyCtxt<'_>, crate_info: &CrateInfo, - autodiff_items: &[AutoDiffItem], shared_emitter: SharedEmitter, codegen_worker_send: Sender, coordinator_receive: Receiver>, @@ -1115,7 +1108,6 @@ fn start_executing_work( ) -> thread::JoinHandle> { let coordinator_send = tx_to_llvm_workers; let sess = tcx.sess; - let autodiff_items = autodiff_items.to_vec(); let mut each_linked_rlib_for_lto = Vec::new(); let mut each_linked_rlib_file_for_lto = Vec::new(); @@ -1448,7 +1440,6 @@ fn start_executing_work( each_linked_rlib_for_lto: each_linked_rlib_file_for_lto, needs_fat_lto, import_only_modules, - autodiff: autodiff_items.clone(), }, 0, )); @@ -1456,11 +1447,6 @@ fn start_executing_work( helper.request_token(); } } else { - if !autodiff_items.is_empty() { - let dcx = cgcx.create_dcx(); - dcx.handle().emit_fatal(AutodiffWithoutLto {}); - } - for (work, cost) in generate_thin_lto_work( &cgcx, &exported_symbols_for_lto, @@ -1795,7 +1781,6 @@ fn spawn_work<'a, B: ExtraBackendMethods>( each_linked_rlib_for_lto, needs_fat_lto, import_only_modules, - autodiff, } => { let _timer = cgcx .prof @@ -1806,7 +1791,6 @@ fn spawn_work<'a, B: ExtraBackendMethods>( &each_linked_rlib_for_lto, needs_fat_lto, import_only_modules, - autodiff, module_config, ) } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index b4556ced0b3fb..b483c01da59e5 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -647,7 +647,7 @@ pub fn codegen_crate( ) -> OngoingCodegen { // Skip crate items and just output metadata in -Z no-codegen mode. if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() { - let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, &[]); + let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu); ongoing_codegen.codegen_finished(tcx); @@ -665,8 +665,7 @@ pub fn codegen_crate( // Run the monomorphization collector and partition the collected items into // codegen units. - let MonoItemPartitions { codegen_units, autodiff_items, .. } = - tcx.collect_and_partition_mono_items(()); + let MonoItemPartitions { codegen_units, .. } = tcx.collect_and_partition_mono_items(()); // Force all codegen_unit queries so they are already either red or green // when compile_codegen_unit accesses them. We are not able to re-execute @@ -679,7 +678,7 @@ pub fn codegen_crate( } } - let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu, autodiff_items); + let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu); // Codegen an allocator shim, if necessary. if let Some(kind) = allocator_kind_for_codegen(tcx) { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a36a772bc9719..af70f0deb0706 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -177,14 +177,6 @@ fn process_builtin_attrs( let mut interesting_spans = InterestingAttributeDiagnosticSpans::default(); let rust_target_features = tcx.rust_target_features(LOCAL_CRATE); - // If our rustc version supports autodiff/enzyme, then we call our handler - // to check for any `#[rustc_autodiff(...)]` attributes. - // FIXME(jdonszelmann): merge with loop below - if cfg!(llvm_enzyme) { - let ad = autodiff_attrs(tcx, did.into()); - codegen_fn_attrs.autodiff_item = ad; - } - for attr in attrs.iter() { if let hir::Attribute::Parsed(p) = attr { match p { @@ -612,7 +604,7 @@ fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option { /// placeholder functions. We wrote the rustc_autodiff attributes ourself, so this should never /// panic, unless we introduced a bug when parsing the autodiff macro. //FIXME(jdonszelmann): put in the main loop. No need to have two..... :/ Let's do that when we make autodiff parsed. -fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { +pub fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { let attrs = tcx.get_attrs(id, sym::rustc_autodiff); let attrs = attrs.filter(|attr| attr.has_name(sym::rustc_autodiff)).collect::>(); diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index f391c198e1a10..c29ad90735b7b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -1,6 +1,5 @@ use std::path::PathBuf; -use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_middle::dep_graph::WorkProduct; @@ -23,7 +22,6 @@ pub trait WriteBackendMethods: Clone + 'static { exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, - diff_fncs: Vec, ) -> Result, FatalError>; /// Performs thin LTO by performing necessary global analysis and returning two /// lists, one of the modules that need optimization and another for modules that diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 46371cfe591b4..f50aed0b3c23c 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -172,8 +172,6 @@ pub(crate) fn check_intrinsic_type( } }; - let has_autodiff = tcx.has_attr(intrinsic_id, sym::rustc_autodiff); - let bound_vars = tcx.mk_bound_variable_kinds(&[ ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon), ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon), @@ -198,6 +196,7 @@ pub(crate) fn check_intrinsic_type( (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty) }; + let safety = intrinsic_operation_unsafety(tcx, intrinsic_id); let n_lts = 0; let (n_tps, n_cts, inputs, output) = match intrinsic_name { sym::autodiff => (4, 0, vec![param(0), param(1), param(2)], param(3)), diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 2852c4cbd34c7..7d2fc0995aa0b 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use rustc_abi::Align; -use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, Linkage, OptimizeAttr}; use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; @@ -75,8 +74,6 @@ pub struct CodegenFnAttrs { /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around /// the function entry. pub patchable_function_entry: Option, - /// For the `#[autodiff]` macros. - pub autodiff_item: Option, } #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] @@ -182,7 +179,6 @@ impl CodegenFnAttrs { instruction_set: None, alignment: None, patchable_function_entry: None, - autodiff_item: None, } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 440771b3d68a0..0e6f797b1e4f9 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -2,7 +2,6 @@ use std::borrow::Cow; use std::fmt; use std::hash::Hash; -use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxIndexMap; @@ -336,7 +335,6 @@ impl ToStableHashKey> for MonoItem<'_> { pub struct MonoItemPartitions<'tcx> { pub codegen_units: &'tcx [CodegenUnit<'tcx>], pub all_mono_items: &'tcx DefIdSet, - pub autodiff_items: &'tcx [AutoDiffItem], } #[derive(Debug, HashStable)] diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 0ed5b4fc0d09c..09a55f0b5f8da 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -6,7 +6,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } -rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } @@ -15,7 +14,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } serde = "1" serde_json = "1" diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 26ca8518434b3..af2c317706752 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -205,6 +205,8 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. +mod autodiff; + use std::cell::OnceCell; use rustc_data_structures::fx::FxIndexMap; @@ -235,6 +237,7 @@ use rustc_span::source_map::{Spanned, dummy_spanned, respan}; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, trace}; +use crate::collector::autodiff::collect_autodiff_fn; use crate::errors::{ self, EncounteredErrorWhileInstantiating, EncounteredErrorWhileInstantiatingGlobalAsm, NoOptimizedMir, RecursionLimit, @@ -911,6 +914,8 @@ fn visit_instance_use<'tcx>( return; } if let Some(intrinsic) = tcx.intrinsic(instance.def_id()) { + collect_autodiff_fn(tcx, instance, intrinsic, output); + if let Some(_requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) { // The intrinsics assert_inhabited, assert_zero_valid, and assert_mem_uninitialized_valid will // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any diff --git a/compiler/rustc_monomorphize/src/collector/autodiff.rs b/compiler/rustc_monomorphize/src/collector/autodiff.rs new file mode 100644 index 0000000000000..13868cca944a2 --- /dev/null +++ b/compiler/rustc_monomorphize/src/collector/autodiff.rs @@ -0,0 +1,48 @@ +use rustc_middle::bug; +use rustc_middle::ty::{self, GenericArg, IntrinsicDef, TyCtxt}; + +use crate::collector::{MonoItems, create_fn_mono_item}; + +// Here, we force both primal and diff function to be collected in +// mono so this does not interfere in `autodiff` intrinsics +// codegen process. If they are unused, LLVM will remove them when +// compiling with O3. +pub(crate) fn collect_autodiff_fn<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, + intrinsic: IntrinsicDef, + output: &mut MonoItems<'tcx>, +) { + if intrinsic.name != rustc_span::sym::autodiff { + return; + }; + + collect_autodiff_fn_from_arg(instance.args[0], tcx, output); +} + +fn collect_autodiff_fn_from_arg<'tcx>( + arg: GenericArg<'tcx>, + tcx: TyCtxt<'tcx>, + output: &mut MonoItems<'tcx>, +) { + let (instance, span) = match arg.kind() { + ty::GenericArgKind::Type(ty) => match ty.kind() { + ty::FnDef(def_id, substs) => { + let span = tcx.def_span(def_id); + let instance = ty::Instance::expect_resolve( + tcx, + ty::TypingEnv::non_body_analysis(tcx, def_id), + *def_id, + substs, + span, + ); + + (instance, span) + } + _ => bug!("expected autodiff function"), + }, + _ => bug!("expected type when matching autodiff arg"), + }; + + output.push(create_fn_mono_item(tcx, instance, span)); +} diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 628ea2b63de6b..d784d3540c410 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -92,8 +92,6 @@ //! source-level module, functions from the same module will be available for //! inlining, even when they are not marked `#[inline]`. -mod autodiff; - use std::cmp; use std::collections::hash_map::Entry; use std::fs::{self, File}; @@ -251,17 +249,7 @@ where always_export_generics, ); - // We can't differentiate a function that got inlined. - let autodiff_active = cfg!(llvm_enzyme) - && matches!(mono_item, MonoItem::Fn(_)) - && cx - .tcx - .codegen_fn_attrs(mono_item.def_id()) - .autodiff_item - .as_ref() - .is_some_and(|ad| ad.is_active()); - - if !autodiff_active && visibility == Visibility::Hidden && can_be_internalized { + if visibility == Visibility::Hidden && can_be_internalized { internalization_candidates.insert(mono_item); } let size_estimate = mono_item.size_estimate(cx.tcx); @@ -1157,27 +1145,15 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio } } - #[cfg(not(llvm_enzyme))] - let autodiff_mono_items: Vec<_> = vec![]; - #[cfg(llvm_enzyme)] - let mut autodiff_mono_items: Vec<_> = vec![]; let mono_items: DefIdSet = items .iter() .filter_map(|mono_item| match *mono_item { - MonoItem::Fn(ref instance) => { - #[cfg(llvm_enzyme)] - autodiff_mono_items.push((mono_item, instance)); - Some(instance.def_id()) - } + MonoItem::Fn(ref instance) => Some(instance.def_id()), MonoItem::Static(def_id) => Some(def_id), _ => None, }) .collect(); - let autodiff_items = - autodiff::find_autodiff_source_functions(tcx, &usage_map, autodiff_mono_items); - let autodiff_items = tcx.arena.alloc_from_iter(autodiff_items); - // Output monomorphization stats per def_id if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats && let Err(err) = @@ -1235,11 +1211,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio } } - MonoItemPartitions { - all_mono_items: tcx.arena.alloc(mono_items), - codegen_units, - autodiff_items, - } + MonoItemPartitions { all_mono_items: tcx.arena.alloc(mono_items), codegen_units } } /// Outputs stats about instantiation counts and estimated size, per `MonoItem`'s diff --git a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs deleted file mode 100644 index 22d593b80b895..0000000000000 --- a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs +++ /dev/null @@ -1,143 +0,0 @@ -use rustc_ast::expand::autodiff_attrs::{AutoDiffItem, DiffActivity}; -use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::bug; -use rustc_middle::mir::mono::MonoItem; -use rustc_middle::ty::{self, Instance, PseudoCanonicalInput, Ty, TyCtxt, TypingEnv}; -use rustc_symbol_mangling::symbol_name_for_instance_in_crate; -use tracing::{debug, trace}; - -use crate::partitioning::UsageMap; - -fn adjust_activity_to_abi<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>, da: &mut Vec) { - if !matches!(fn_ty.kind(), ty::FnDef(..)) { - bug!("expected fn def for autodiff, got {:?}", fn_ty); - } - - // We don't actually pass the types back into the type system. - // All we do is decide how to handle the arguments. - let sig = fn_ty.fn_sig(tcx).skip_binder(); - - let mut new_activities = vec![]; - let mut new_positions = vec![]; - for (i, ty) in sig.inputs().iter().enumerate() { - if let Some(inner_ty) = ty.builtin_deref(true) { - if inner_ty.is_slice() { - // Now we need to figure out the size of each slice element in memory to allow - // safety checks and usability improvements in the backend. - let sty = match inner_ty.builtin_index() { - Some(sty) => sty, - None => { - panic!("slice element type unknown"); - } - }; - let pci = PseudoCanonicalInput { - typing_env: TypingEnv::fully_monomorphized(), - value: sty, - }; - - let layout = tcx.layout_of(pci); - let elem_size = match layout { - Ok(layout) => layout.size, - Err(_) => { - bug!("autodiff failed to compute slice element size"); - } - }; - let elem_size: u32 = elem_size.bytes() as u32; - - // We know that the length will be passed as extra arg. - if !da.is_empty() { - // We are looking at a slice. The length of that slice will become an - // extra integer on llvm level. Integers are always const. - // However, if the slice get's duplicated, we want to know to later check the - // size. So we mark the new size argument as FakeActivitySize. - // There is one FakeActivitySize per slice, so for convenience we store the - // slice element size in bytes in it. We will use the size in the backend. - let activity = match da[i] { - DiffActivity::DualOnly - | DiffActivity::Dual - | DiffActivity::Dualv - | DiffActivity::DuplicatedOnly - | DiffActivity::Duplicated => { - DiffActivity::FakeActivitySize(Some(elem_size)) - } - DiffActivity::Const => DiffActivity::Const, - _ => bug!("unexpected activity for ptr/ref"), - }; - new_activities.push(activity); - new_positions.push(i + 1); - } - - continue; - } - } - } - // now add the extra activities coming from slices - // Reverse order to not invalidate the indices - for _ in 0..new_activities.len() { - let pos = new_positions.pop().unwrap(); - let activity = new_activities.pop().unwrap(); - da.insert(pos, activity); - } -} - -pub(crate) fn find_autodiff_source_functions<'tcx>( - tcx: TyCtxt<'tcx>, - usage_map: &UsageMap<'tcx>, - autodiff_mono_items: Vec<(&MonoItem<'tcx>, &Instance<'tcx>)>, -) -> Vec { - let mut autodiff_items: Vec = vec![]; - for (item, instance) in autodiff_mono_items { - let target_id = instance.def_id(); - let cg_fn_attr = &tcx.codegen_fn_attrs(target_id).autodiff_item; - let Some(target_attrs) = cg_fn_attr else { - continue; - }; - let mut input_activities: Vec = target_attrs.input_activity.clone(); - if target_attrs.is_source() { - trace!("source found: {:?}", target_id); - } - if !target_attrs.apply_autodiff() { - continue; - } - - let target_symbol = symbol_name_for_instance_in_crate(tcx, instance.clone(), LOCAL_CRATE); - - let source = - usage_map.used_map.get(&item).unwrap().into_iter().find_map(|item| match *item { - MonoItem::Fn(ref instance_s) => { - let source_id = instance_s.def_id(); - if let Some(ad) = &tcx.codegen_fn_attrs(source_id).autodiff_item - && ad.is_active() - { - return Some(instance_s); - } - None - } - _ => None, - }); - let inst = match source { - Some(source) => source, - None => continue, - }; - - debug!("source_id: {:?}", inst.def_id()); - let fn_ty = inst.ty(tcx, ty::TypingEnv::fully_monomorphized()); - assert!(fn_ty.is_fn()); - adjust_activity_to_abi(tcx, fn_ty, &mut input_activities); - let symb = symbol_name_for_instance_in_crate(tcx, inst.clone(), LOCAL_CRATE); - - let mut new_target_attrs = target_attrs.clone(); - new_target_attrs.input_activity = input_activities; - let itm = new_target_attrs.into_item(symb, target_symbol); - autodiff_items.push(itm); - } - - if !autodiff_items.is_empty() { - trace!("AUTODIFF ITEMS EXIST"); - for item in &mut *autodiff_items { - trace!("{}", &item); - } - } - - autodiff_items -} diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 6c389c55a5f3a..dd838d494bc7d 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3157,6 +3157,40 @@ pub const unsafe fn copysignf64(x: f64, y: f64) -> f64; #[rustc_intrinsic] pub const unsafe fn copysignf128(x: f128, y: f128) -> f128; +/// Generates the LLVM body for the automatic differentiation of `f` using Enzyme, +/// with `df` as the derivative function and `args` as its arguments. +/// +/// Used internally as the body of `df` when expanding the `#[autodiff_forward]` +/// and `#[autodiff_reverse]` attribute macros. +/// +/// Type Parameters: +/// - `F`: The original function to differentiate. Must be a function item. +/// - `G`: The derivative function. Must be a function item. +/// - `T`: A tuple of arguments passed to `df`. +/// - `R`: The return type of the derivative function. +/// +/// This shows where the `autodiff` intrinsic is used during macro expansion: +/// +/// ```rust,ignore (macro example) +/// #[autodiff_forward(df1, Dual, Const, Dual)] +/// pub fn f1(x: &[f64], y: f64) -> f64 { +/// unimplemented!() +/// } +/// ``` +/// +/// expands to: +/// +/// ```rust,ignore (macro example) +/// #[rustc_autodiff] +/// #[inline(never)] +/// pub fn f1(x: &[f64], y: f64) -> f64 { +/// ::core::panicking::panic("not implemented") +/// } +/// #[rustc_autodiff(Forward, 1, Dual, Const, Dual)] +/// pub fn df1(x: &[f64], bx_0: &[f64], y: f64) -> (f64, f64) { +/// ::core::intrinsics::autodiff(f1::<>, df1::<>, (x, bx_0, y)) +/// } +/// ``` #[rustc_nounwind] #[rustc_intrinsic] pub const fn autodiff(f: F, df: G, args: T) -> R; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index c59290a757b67..888369d73f4ac 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1494,6 +1494,7 @@ pub(crate) mod builtin { /// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities. #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] + #[allow_internal_unstable(core_intrinsics)] #[rustc_builtin_macro] pub macro autodiff_forward($item:item) { /* compiler built-in */ @@ -1512,6 +1513,7 @@ pub(crate) mod builtin { /// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities. #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] + #[allow_internal_unstable(core_intrinsics)] #[rustc_builtin_macro] pub macro autodiff_reverse($item:item) { /* compiler built-in */ diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 9ded467d5cd75..025a078ae5b09 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -107,7 +107,6 @@ - [Installation](./autodiff/installation.md) - [How to debug](./autodiff/debugging.md) - [Autodiff flags](./autodiff/flags.md) - - [Current limitations](./autodiff/limitations.md) # Source Code Representation diff --git a/src/doc/rustc-dev-guide/src/autodiff/limitations.md b/src/doc/rustc-dev-guide/src/autodiff/limitations.md deleted file mode 100644 index 90afbd51f3fd9..0000000000000 --- a/src/doc/rustc-dev-guide/src/autodiff/limitations.md +++ /dev/null @@ -1,27 +0,0 @@ -# Current limitations - -## Safety and Soundness - -Enzyme currently assumes that the user passes shadow arguments (`dx`, `dy`, ...) of appropriate size. Under Reverse Mode, we additionally assume that shadow arguments are mutable. In Reverse Mode we adjust the outermost pointer or reference to be mutable. Therefore `&f32` will receive the shadow type `&mut f32`. However, we do not check length for other types than slices (e.g. enums, Vec). We also do not enforce mutability of inner references, but will warn if we recognize them. We do intend to add additional checks over time. - -## ABI adjustments - -In some cases, a function parameter might get lowered in a way that we currently don't handle correctly, leading to a compile time type mismatch in the `rustc_codegen_llvm` backend. Here are some [examples](https://github.com/EnzymeAD/rust/issues/105). - -## Compile Times - -Enzyme will often achieve excellent runtime performance, but might increase your compile time by a large factor. For Rust, we already have made significant improvements and have a list of further improvements planed - please reach out if you have time to help here. - -### Type Analysis - -Most of the times, Type Analysis (TA) is the reason of large (>5x) compile time increases when using Enzyme. This poster explains why we need to run Type Analysis in the bottom left part: [Poster Link](https://c.wsmoses.com/posters/Enzyme-llvmdev.pdf). - -We intend to increase the number of locations where we pass down Type information based on Rust types, which in turn will reduce the number of locations where Enzyme has to run Type Analysis, which will help compile times. - -### Duplicated Optimizations - -The key reason for Enzyme offering often excellent performance is that Enzyme differentiates already optimized LLVM-IR. However, we also (have to) run LLVM's optimization pipeline after differentiating, to make sure that the code which Enzyme generates is optimized properly. As a result you should have excellent runtime performance (please fill an issue if not), but at a compile time cost for running optimizations twice. - -### Fat-LTO - -The usage of `#[autodiff(...)]` currently requires compiling your project with Fat-LTO. We technically only need LTO if the function being differentiated calls functions in other compilation units. Therefore, other solutions are possible, but this is the most simple one to get started. diff --git a/triagebot.toml b/triagebot.toml index 6f6e95c5b50e9..df81bb7116072 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -283,7 +283,6 @@ trigger_files = [ "src/tools/enzyme", "src/doc/unstable-book/src/compiler-flags/autodiff.md", "compiler/rustc_ast/src/expand/autodiff_attrs.rs", - "compiler/rustc_monomorphize/src/partitioning/autodiff.rs", "compiler/rustc_codegen_llvm/src/builder/autodiff.rs", "compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs", ] @@ -1285,8 +1284,6 @@ cc = ["@ZuseZ4"] cc = ["@ZuseZ4"] [mentions."compiler/rustc_builtin_macros/src/autodiff.rs"] cc = ["@ZuseZ4"] -[mentions."compiler/rustc_monomorphize/src/partitioning/autodiff.rs"] -cc = ["@ZuseZ4"] [mentions."compiler/rustc_codegen_llvm/src/builder/autodiff.rs"] cc = ["@ZuseZ4"] [mentions."compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs"] From c9c1c171289aa575040678f3d0c005342b1e29e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Thu, 14 Aug 2025 15:29:37 +0000 Subject: [PATCH 211/252] Remove inlining for autodiff handling --- compiler/rustc_builtin_macros/src/autodiff.rs | 32 ++++++++++++------- .../src/builder/autodiff.rs | 8 +---- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index c260dca87c036..48d0795af5ee2 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -192,7 +192,6 @@ mod llvm_enzyme { /// which becomes expanded to: /// ``` /// #[rustc_autodiff] - /// #[inline(never)] /// fn sin(x: &Box) -> f32 { /// f32::sin(**x) /// } @@ -371,7 +370,7 @@ mod llvm_enzyme { let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); let inline_never = outer_normal_attr(&inline_never_attr, new_id, span); - // We're avoid duplicating the attributes `#[rustc_autodiff]` and `#[inline(never)]`. + // We're avoid duplicating the attribute `#[rustc_autodiff]`. fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool { match (attr, item) { (ast::AttrKind::Normal(a), ast::AttrKind::Normal(b)) => { @@ -384,14 +383,16 @@ mod llvm_enzyme { } } + let mut has_inline_never = false; + // Don't add it multiple times: let orig_annotatable: Annotatable = match item { Annotatable::Item(ref mut iitem) => { if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) { iitem.attrs.push(attr); } - if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) { - iitem.attrs.push(inline_never.clone()); + if iitem.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) { + has_inline_never = true; } Annotatable::Item(iitem.clone()) } @@ -399,8 +400,8 @@ mod llvm_enzyme { if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) { assoc_item.attrs.push(attr); } - if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) { - assoc_item.attrs.push(inline_never.clone()); + if assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) { + has_inline_never = true; } Annotatable::AssocItem(assoc_item.clone(), i) } @@ -410,9 +411,8 @@ mod llvm_enzyme { if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) { iitem.attrs.push(attr); } - if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) - { - iitem.attrs.push(inline_never.clone()); + if iitem.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) { + has_inline_never = true; } } _ => unreachable!("stmt kind checked previously"), @@ -433,11 +433,19 @@ mod llvm_enzyme { let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id(); let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span); + + // If the source function has the `#[inline(never)]` attribute, we'll also add it to the diff function + let mut d_attrs = thin_vec![d_attr]; + + if has_inline_never { + d_attrs.push(inline_never); + } + let d_annotatable = match &item { Annotatable::AssocItem(_, _) => { let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(d_fn); let d_fn = Box::new(ast::AssocItem { - attrs: thin_vec![d_attr], + attrs: d_attrs, id: ast::DUMMY_NODE_ID, span, vis, @@ -447,13 +455,13 @@ mod llvm_enzyme { Annotatable::AssocItem(d_fn, Impl { of_trait: false }) } Annotatable::Item(_) => { - let mut d_fn = ecx.item(span, thin_vec![d_attr], ItemKind::Fn(d_fn)); + let mut d_fn = ecx.item(span, d_attrs, ItemKind::Fn(d_fn)); d_fn.vis = vis; Annotatable::Item(d_fn) } Annotatable::Stmt(_) => { - let mut d_fn = ecx.item(span, thin_vec![d_attr], ItemKind::Fn(d_fn)); + let mut d_fn = ecx.item(span, d_attrs, ItemKind::Fn(d_fn)); d_fn.vis = vis; Annotatable::Stmt(Box::new(ast::Stmt { diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 56116959a6223..e2df3265f6f7d 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -10,10 +10,9 @@ use tracing::debug; use crate::builder::{Builder, PlaceRef, UNNAMED}; use crate::context::SimpleCx; use crate::declare::declare_simple_fn; -use crate::llvm::AttributePlace::Function; +use crate::llvm; use crate::llvm::{Metadata, True, Type}; use crate::value::Value; -use crate::{attributes, llvm}; pub(crate) fn adjust_activity_to_abi<'tcx>( tcx: TyCtxt<'tcx>, @@ -308,11 +307,6 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( enzyme_ty, ); - // Otherwise LLVM might inline our temporary code before the enzyme pass has a chance to - // do it's work. - let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx); - attributes::apply_to_llfn(ad_fn, Function, &[attr]); - let num_args = llvm::LLVMCountParams(&fn_to_diff); let mut args = Vec::with_capacity(num_args as usize + 1); args.push(fn_to_diff); From e1d79b9aad9cfcfcf23c68ec8625411819d4e3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Thu, 14 Aug 2025 08:21:15 +0000 Subject: [PATCH 212/252] Remove lto inline logic --- compiler/rustc_codegen_llvm/src/attributes.rs | 16 ----------- compiler/rustc_codegen_llvm/src/back/lto.rs | 28 +------------------ compiler/rustc_codegen_llvm/src/context.rs | 10 ------- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 26 ----------------- 4 files changed, 1 insertion(+), 79 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index c548f4675834f..a6daacd95ef80 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -28,22 +28,6 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[ } } -pub(crate) fn has_attr(llfn: &Value, idx: AttributePlace, attr: AttributeKind) -> bool { - llvm::HasAttributeAtIndex(llfn, idx, attr) -} - -pub(crate) fn has_string_attr(llfn: &Value, name: &str) -> bool { - llvm::HasStringAttribute(llfn, name) -} - -pub(crate) fn remove_from_llfn(llfn: &Value, place: AttributePlace, kind: AttributeKind) { - llvm::RemoveRustEnumAttributeAtIndex(llfn, place, kind); -} - -pub(crate) fn remove_string_attr_from_llfn(llfn: &Value, name: &str) { - llvm::RemoveStringAttrFromFn(llfn, name); -} - /// Get LLVM attribute for the provided inline heuristic. #[inline] fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index c269f11e931bf..853d0295238e6 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -24,9 +24,8 @@ use crate::back::write::{ self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, save_temp_bitcode, }; use crate::errors::{LlvmError, LtoBitcodeFromRlib}; -use crate::llvm::AttributePlace::Function; use crate::llvm::{self, build_string}; -use crate::{LlvmCodegenBackend, ModuleLlvm, SimpleCx, attributes}; +use crate::{LlvmCodegenBackend, ModuleLlvm, SimpleCx}; /// We keep track of the computed LTO cache keys from the previous /// session to determine which CGUs we can reuse. @@ -593,31 +592,6 @@ pub(crate) fn run_pass_manager( } if cfg!(llvm_enzyme) && enable_ad && !thin { - let cx = - SimpleCx::new(module.module_llvm.llmod(), &module.module_llvm.llcx, cgcx.pointer_size); - - for function in cx.get_functions() { - let enzyme_marker = "enzyme_marker"; - if attributes::has_string_attr(function, enzyme_marker) { - // Sanity check: Ensure 'noinline' is present before replacing it. - assert!( - attributes::has_attr(function, Function, llvm::AttributeKind::NoInline), - "Expected __enzyme function to have 'noinline' before adding 'alwaysinline'" - ); - - attributes::remove_from_llfn(function, Function, llvm::AttributeKind::NoInline); - attributes::remove_string_attr_from_llfn(function, enzyme_marker); - - assert!( - !attributes::has_string_attr(function, enzyme_marker), - "Expected function to not have 'enzyme_marker'" - ); - - let always_inline = llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx); - attributes::apply_to_llfn(function, Function, &[always_inline]); - } - } - let opt_stage = llvm::OptStage::FatLTO; let stage = write::AutodiffStage::PostAD; if !config.autodiff.contains(&config::AutoDiff::NoPostopt) { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index da8c1e5f47b10..b0f3494ea68c0 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -722,16 +722,6 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) } } - - pub(crate) fn get_functions(&self) -> Vec<&'ll Value> { - let mut functions = vec![]; - let mut func = unsafe { llvm::LLVMGetFirstFunction(self.llmod()) }; - while let Some(f) = func { - functions.push(f); - func = unsafe { llvm::LLVMGetNextFunction(f) } - } - functions - } } impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 154ba4fd69018..0ea0af0c9afbf 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -42,32 +42,6 @@ pub(crate) fn AddFunctionAttributes<'ll>( } } -pub(crate) fn HasAttributeAtIndex<'ll>( - llfn: &'ll Value, - idx: AttributePlace, - kind: AttributeKind, -) -> bool { - unsafe { LLVMRustHasAttributeAtIndex(llfn, idx.as_uint(), kind) } -} - -pub(crate) fn HasStringAttribute<'ll>(llfn: &'ll Value, name: &str) -> bool { - unsafe { LLVMRustHasFnAttribute(llfn, name.as_c_char_ptr(), name.len()) } -} - -pub(crate) fn RemoveStringAttrFromFn<'ll>(llfn: &'ll Value, name: &str) { - unsafe { LLVMRustRemoveFnAttribute(llfn, name.as_c_char_ptr(), name.len()) } -} - -pub(crate) fn RemoveRustEnumAttributeAtIndex( - llfn: &Value, - place: AttributePlace, - kind: AttributeKind, -) { - unsafe { - LLVMRustRemoveEnumAttributeAtIndex(llfn, place.as_uint(), kind); - } -} - pub(crate) fn AddCallSiteAttributes<'ll>( callsite: &'ll Value, idx: AttributePlace, From 65d329d189651f5f4612e87132ca6c041cf61ab4 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Thu, 14 Aug 2025 12:50:07 -0400 Subject: [PATCH 213/252] Adjust error message grammar to be less awkward --- .../src/diagnostics/move_errors.rs | 2 +- tests/ui/borrowck/borrowck-in-static.stderr | 2 +- .../borrowck/borrowck-move-by-capture.stderr | 2 +- tests/ui/borrowck/issue-103624.stderr | 2 +- .../issue-87456-point-to-closure.stderr | 2 +- ...ove-upvar-from-non-once-ref-closure.stderr | 2 +- tests/ui/issues/issue-4335.stderr | 2 +- ...-move-out-of-closure-env-issue-1965.stderr | 2 +- ...e-52663-span-decl-captured-variable.stderr | 2 +- ...borrowck-call-is-borrow-issue-12224.stderr | 2 +- .../dont-suggest-ref/move-into-closure.stderr | 82 +++++++++---------- .../suggestions/option-content-move2.stderr | 4 +- .../suggestions/option-content-move3.stderr | 8 +- .../unboxed-closure-illegal-move.stderr | 8 +- 14 files changed, 61 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index af71db6948329..0b3151fd8b82d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -518,7 +518,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { .with_span_help( self.get_closure_bound_clause_span(*def_id), "`Fn` and `FnMut` closures require captured values to be able to be \ - consumed multiple times, but an `FnOnce` consume them only once", + consumed multiple times, but `FnOnce` closures may consume them only once", ) } _ => { diff --git a/tests/ui/borrowck/borrowck-in-static.stderr b/tests/ui/borrowck/borrowck-in-static.stderr index d85f6f5fdd5c7..32419da0ce233 100644 --- a/tests/ui/borrowck/borrowck-in-static.stderr +++ b/tests/ui/borrowck/borrowck-in-static.stderr @@ -10,7 +10,7 @@ LL | Box::new(|| x) | | | captured by this `Fn` closure | - = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once + = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once help: consider cloning the value if the performance cost is acceptable | LL | Box::new(|| x.clone()) diff --git a/tests/ui/borrowck/borrowck-move-by-capture.stderr b/tests/ui/borrowck/borrowck-move-by-capture.stderr index e9e054407662f..0ace615628177 100644 --- a/tests/ui/borrowck/borrowck-move-by-capture.stderr +++ b/tests/ui/borrowck/borrowck-move-by-capture.stderr @@ -12,7 +12,7 @@ LL | let _h = to_fn_once(move || -> isize { *bar }); | | | `bar` is moved here | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/borrowck-move-by-capture.rs:3:37 | LL | fn to_fn_mut>(f: F) -> F { f } diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr index ef02280888671..bd6c1c44bfb36 100644 --- a/tests/ui/borrowck/issue-103624.stderr +++ b/tests/ui/borrowck/issue-103624.stderr @@ -13,7 +13,7 @@ LL | LL | self.b; | ^^^^^^ `self.b` is moved here | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/issue-103624.rs:7:36 | LL | async fn spawn_blocking(f: impl (Fn() -> T) + Send + Sync + 'static) -> T { diff --git a/tests/ui/borrowck/issue-87456-point-to-closure.stderr b/tests/ui/borrowck/issue-87456-point-to-closure.stderr index 043e336cd86df..c31d096109ce0 100644 --- a/tests/ui/borrowck/issue-87456-point-to-closure.stderr +++ b/tests/ui/borrowck/issue-87456-point-to-closure.stderr @@ -10,7 +10,7 @@ LL | LL | let _foo: String = val; | ^^^ move occurs because `val` has type `String`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/issue-87456-point-to-closure.rs:3:24 | LL | fn take_mut(_val: impl FnMut()) {} diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr index d33330413103f..69c3667491633 100644 --- a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr +++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -10,7 +10,7 @@ LL | y.into_iter(); | | | move occurs because `y` has type `Vec`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:5:28 | LL | fn call(f: F) where F : Fn() { diff --git a/tests/ui/issues/issue-4335.stderr b/tests/ui/issues/issue-4335.stderr index b6d8f08616383..d1a64e3dd4620 100644 --- a/tests/ui/issues/issue-4335.stderr +++ b/tests/ui/issues/issue-4335.stderr @@ -10,7 +10,7 @@ LL | id(Box::new(|| *v)) | | | captured by this `FnMut` closure | - = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once + = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once help: if `T` implemented `Clone`, you could clone the value --> $DIR/issue-4335.rs:5:10 | diff --git a/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr index dfc983bf48744..e2aa5718cb650 100644 --- a/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr +++ b/tests/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr @@ -10,7 +10,7 @@ LL | let _f = to_fn(|| test(i)); | | | captured by this `Fn` closure | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:3:33 | LL | fn to_fn>(f: F) -> F { f } diff --git a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr index 7f9a8e50dae66..4749e3b8e453d 100644 --- a/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr +++ b/tests/ui/nll/issue-52663-span-decl-captured-variable.stderr @@ -10,7 +10,7 @@ LL | expect_fn(|| drop(x.0)); | | | captured by this `Fn` closure | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/issue-52663-span-decl-captured-variable.rs:1:33 | LL | fn expect_fn(f: F) where F : Fn() { diff --git a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 8081f7b3a8b0f..f7750884b4a65 100644 --- a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -44,7 +44,7 @@ LL | LL | foo(f); | ^ move occurs because `f` has type `{closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 52:58}`, which does not implement the `Copy` trait | - = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once + = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once help: consider cloning the value if the performance cost is acceptable | LL | foo(f.clone()); diff --git a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr index 132a31c8f7ceb..39c2fabf9eb14 100644 --- a/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr +++ b/tests/ui/suggestions/dont-suggest-ref/move-into-closure.stderr @@ -12,7 +12,7 @@ LL | let X(_t) = x; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:13:18 | LL | fn consume_fn(_f: F) { } @@ -37,7 +37,7 @@ LL | if let Either::One(_t) = e { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:13:18 | LL | fn consume_fn(_f: F) { } @@ -62,7 +62,7 @@ LL | while let Either::One(_t) = e { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:13:18 | LL | fn consume_fn(_f: F) { } @@ -90,7 +90,7 @@ LL | Either::One(_t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:13:18 | LL | fn consume_fn(_f: F) { } @@ -118,7 +118,7 @@ LL | Either::One(_t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:13:18 | LL | fn consume_fn(_f: F) { } @@ -143,7 +143,7 @@ LL | let X(mut _t) = x; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:13:18 | LL | fn consume_fn(_f: F) { } @@ -168,7 +168,7 @@ LL | if let Either::One(mut _t) = em { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:13:18 | LL | fn consume_fn(_f: F) { } @@ -193,7 +193,7 @@ LL | while let Either::One(mut _t) = em { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:13:18 | LL | fn consume_fn(_f: F) { } @@ -221,7 +221,7 @@ LL | Either::One(mut _t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:13:18 | LL | fn consume_fn(_f: F) { } @@ -249,7 +249,7 @@ LL | Either::One(mut _t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:13:18 | LL | fn consume_fn(_f: F) { } @@ -273,7 +273,7 @@ LL | let X(_t) = x; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:39:22 | LL | fn consume_fn(_f: F) { } @@ -298,7 +298,7 @@ LL | if let Either::One(_t) = e { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:39:22 | LL | fn consume_fn(_f: F) { } @@ -323,7 +323,7 @@ LL | while let Either::One(_t) = e { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:39:22 | LL | fn consume_fn(_f: F) { } @@ -351,7 +351,7 @@ LL | Either::One(_t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:39:22 | LL | fn consume_fn(_f: F) { } @@ -379,7 +379,7 @@ LL | Either::One(_t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:39:22 | LL | fn consume_fn(_f: F) { } @@ -404,7 +404,7 @@ LL | let X(mut _t) = x; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:39:22 | LL | fn consume_fn(_f: F) { } @@ -429,7 +429,7 @@ LL | if let Either::One(mut _t) = em { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:39:22 | LL | fn consume_fn(_f: F) { } @@ -454,7 +454,7 @@ LL | while let Either::One(mut _t) = em { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:39:22 | LL | fn consume_fn(_f: F) { } @@ -482,7 +482,7 @@ LL | Either::One(mut _t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:39:22 | LL | fn consume_fn(_f: F) { } @@ -510,7 +510,7 @@ LL | Either::One(mut _t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:39:22 | LL | fn consume_fn(_f: F) { } @@ -534,7 +534,7 @@ LL | let X(_t) = x; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:50:29 | LL | fn method_consume_fn(&self, _f: F) { } @@ -559,7 +559,7 @@ LL | if let Either::One(_t) = e { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:50:29 | LL | fn method_consume_fn(&self, _f: F) { } @@ -584,7 +584,7 @@ LL | while let Either::One(_t) = e { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:50:29 | LL | fn method_consume_fn(&self, _f: F) { } @@ -612,7 +612,7 @@ LL | Either::One(_t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:50:29 | LL | fn method_consume_fn(&self, _f: F) { } @@ -640,7 +640,7 @@ LL | Either::One(_t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:50:29 | LL | fn method_consume_fn(&self, _f: F) { } @@ -665,7 +665,7 @@ LL | let X(mut _t) = x; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:50:29 | LL | fn method_consume_fn(&self, _f: F) { } @@ -690,7 +690,7 @@ LL | if let Either::One(mut _t) = em { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:50:29 | LL | fn method_consume_fn(&self, _f: F) { } @@ -715,7 +715,7 @@ LL | while let Either::One(mut _t) = em { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:50:29 | LL | fn method_consume_fn(&self, _f: F) { } @@ -743,7 +743,7 @@ LL | Either::One(mut _t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:50:29 | LL | fn method_consume_fn(&self, _f: F) { } @@ -771,7 +771,7 @@ LL | Either::One(mut _t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:50:29 | LL | fn method_consume_fn(&self, _f: F) { } @@ -795,7 +795,7 @@ LL | let X(_t) = x; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } @@ -820,7 +820,7 @@ LL | if let Either::One(_t) = e { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } @@ -845,7 +845,7 @@ LL | while let Either::One(_t) = e { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } @@ -873,7 +873,7 @@ LL | Either::One(_t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } @@ -901,7 +901,7 @@ LL | Either::One(_t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } @@ -926,7 +926,7 @@ LL | let X(mut _t) = x; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } @@ -951,7 +951,7 @@ LL | if let Either::One(mut _t) = em { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } @@ -976,7 +976,7 @@ LL | while let Either::One(mut _t) = em { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } @@ -1004,7 +1004,7 @@ LL | Either::One(mut _t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } @@ -1032,7 +1032,7 @@ LL | Either::One(mut _t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } @@ -1060,7 +1060,7 @@ LL | Either::One(mut _t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/move-into-closure.rs:25:21 | LL | fn consume_fnmut(_f: F) { } diff --git a/tests/ui/suggestions/option-content-move2.stderr b/tests/ui/suggestions/option-content-move2.stderr index c8aa6667b583f..5bcbdd711ae77 100644 --- a/tests/ui/suggestions/option-content-move2.stderr +++ b/tests/ui/suggestions/option-content-move2.stderr @@ -14,7 +14,7 @@ LL | LL | var = Some(NotCopyable); | --- variable moved due to use in closure | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/option-content-move2.rs:5:12 | LL | fn func H, H: FnMut()>(_: F) {} @@ -44,7 +44,7 @@ LL | LL | var = Some(NotCopyableButCloneable); | --- variable moved due to use in closure | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/option-content-move2.rs:5:12 | LL | fn func H, H: FnMut()>(_: F) {} diff --git a/tests/ui/suggestions/option-content-move3.stderr b/tests/ui/suggestions/option-content-move3.stderr index 2c9a86c036be4..f78d3cf678629 100644 --- a/tests/ui/suggestions/option-content-move3.stderr +++ b/tests/ui/suggestions/option-content-move3.stderr @@ -9,7 +9,7 @@ LL | move || { LL | let x = var; | ^^^ move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait | - = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once + = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once note: if `NotCopyable` implemented `Clone`, you could clone the value --> $DIR/option-content-move3.rs:2:1 | @@ -38,7 +38,7 @@ LL | move || { LL | let x = var; | --- variable moved due to use in closure | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/option-content-move3.rs:6:12 | LL | fn func H, H: FnMut()>(_: F) {} @@ -63,7 +63,7 @@ LL | move || { LL | let x = var; | ^^^ move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait | - = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once + = help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once help: consider borrowing here | LL | let x = &var; @@ -84,7 +84,7 @@ LL | move || { LL | let x = var; | --- variable moved due to use in closure | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/option-content-move3.rs:6:12 | LL | fn func H, H: FnMut()>(_: F) {} diff --git a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr index 9d87402a15bff..266da54941df2 100644 --- a/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr +++ b/tests/ui/unboxed-closures/unboxed-closure-illegal-move.stderr @@ -10,7 +10,7 @@ LL | let f = to_fn(|| drop(x)); | | | captured by this `Fn` closure | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/unboxed-closure-illegal-move.rs:7:33 | LL | fn to_fn>(f: F) -> F { f } @@ -32,7 +32,7 @@ LL | let f = to_fn_mut(|| drop(x)); | | | captured by this `FnMut` closure | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/unboxed-closure-illegal-move.rs:8:37 | LL | fn to_fn_mut>(f: F) -> F { f } @@ -54,7 +54,7 @@ LL | let f = to_fn(move || drop(x)); | | | captured by this `Fn` closure | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/unboxed-closure-illegal-move.rs:7:33 | LL | fn to_fn>(f: F) -> F { f } @@ -72,7 +72,7 @@ LL | let f = to_fn_mut(move || drop(x)); | | | captured by this `FnMut` closure | -help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once +help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once --> $DIR/unboxed-closure-illegal-move.rs:8:37 | LL | fn to_fn_mut>(f: F) -> F { f } From 51df1dad6c7465395a8ac3e6c31b04468ba347b4 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Wed, 6 Aug 2025 21:49:07 +0500 Subject: [PATCH 214/252] fixed diagnostic --- .../rustc_mir_build/src/check_tail_calls.rs | 11 +++- .../caller-lifetime-presence.rs | 51 +++++++++++++++++++ .../caller-lifetime-presence.stderr | 32 ++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 tests/ui/explicit-tail-calls/caller-lifetime-presence.rs create mode 100644 tests/ui/explicit-tail-calls/caller-lifetime-presence.stderr diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index b4c8b20e50f9c..2b2c2cbc37290 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -3,6 +3,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::Applicability; use rustc_hir::LangItem; use rustc_hir::def::DefKind; +use rustc_hir::def_id::CRATE_DEF_ID; use rustc_middle::span_bug; use rustc_middle::thir::visit::{self, Visitor}; use rustc_middle::thir::{BodyTy, Expr, ExprId, ExprKind, Thir}; @@ -132,7 +133,15 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { if caller_sig.inputs_and_output != callee_sig.inputs_and_output { if caller_sig.inputs() != callee_sig.inputs() { - self.report_arguments_mismatch(expr.span, caller_sig, callee_sig); + self.report_arguments_mismatch( + expr.span, + self.tcx.liberate_late_bound_regions( + CRATE_DEF_ID.to_def_id(), + self.caller_ty.fn_sig(self.tcx), + ), + self.tcx + .liberate_late_bound_regions(CRATE_DEF_ID.to_def_id(), ty.fn_sig(self.tcx)), + ); } // FIXME(explicit_tail_calls): this currently fails for cases where opaques are used. diff --git a/tests/ui/explicit-tail-calls/caller-lifetime-presence.rs b/tests/ui/explicit-tail-calls/caller-lifetime-presence.rs new file mode 100644 index 0000000000000..2382bc9dd1e05 --- /dev/null +++ b/tests/ui/explicit-tail-calls/caller-lifetime-presence.rs @@ -0,0 +1,51 @@ +//! Regression test for: https://github.com/rust-lang/rust/issues/144957 +//! +//! This test ensures that lifetime information is included in diagnostics. +//! +//! Specifically, it checks that the `become` call produces an error with lifetimes shown +//! in both caller and callee signatures. +//! +//! If the test fails: +//! - Lifetimes may be missing (fix the diagnostic), or +//! - The message format changed (update the test). + +#![feature(explicit_tail_calls)] +#![allow(incomplete_features)] + +fn foo<'a>(_: fn(&'a ())) { + become bar(dummy); + //~^ ERROR mismatched signatures + //~| NOTE `become` requires caller and callee to have matching signatures + //~| NOTE caller signature: `fn(fn(&'a ()))` + //~| NOTE callee signature: `fn(for<'a> fn(&'a ()))` +} + +fn bar(_: fn(&())) {} + +fn dummy(_: &()) {} + +fn foo_(_: fn(&())) { + become bar1(dummy2); + //~^ ERROR mismatched signatures + //~| NOTE `become` requires caller and callee to have matching signatures + //~| NOTE caller signature: `fn(for<'a> fn(&'a ()))` + //~| NOTE callee signature: `fn(fn(&'a ()))` +} + +fn bar1<'a>(_: fn(&'a ())) {} + +fn dummy2(_: &()) {} + +fn foo__(_: fn(&'static ())) { + become bar(dummy3); + //~^ ERROR mismatched signatures + //~| NOTE `become` requires caller and callee to have matching signatures + //~| NOTE caller signature: `fn(fn(&'static ()))` + //~| NOTE callee signature: `fn(for<'a> fn(&'a ()))` +} + +fn bar2(_: fn(&())) {} + +fn dummy3(_: &()) {} + +fn main() {} diff --git a/tests/ui/explicit-tail-calls/caller-lifetime-presence.stderr b/tests/ui/explicit-tail-calls/caller-lifetime-presence.stderr new file mode 100644 index 0000000000000..2fb981d968206 --- /dev/null +++ b/tests/ui/explicit-tail-calls/caller-lifetime-presence.stderr @@ -0,0 +1,32 @@ +error: mismatched signatures + --> $DIR/caller-lifetime-presence.rs:16:5 + | +LL | become bar(dummy); + | ^^^^^^^^^^^^^^^^^ + | + = note: `become` requires caller and callee to have matching signatures + = note: caller signature: `fn(fn(&'a ()))` + = note: callee signature: `fn(for<'a> fn(&'a ()))` + +error: mismatched signatures + --> $DIR/caller-lifetime-presence.rs:28:5 + | +LL | become bar1(dummy2); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `become` requires caller and callee to have matching signatures + = note: caller signature: `fn(for<'a> fn(&'a ()))` + = note: callee signature: `fn(fn(&'a ()))` + +error: mismatched signatures + --> $DIR/caller-lifetime-presence.rs:40:5 + | +LL | become bar(dummy3); + | ^^^^^^^^^^^^^^^^^^ + | + = note: `become` requires caller and callee to have matching signatures + = note: caller signature: `fn(fn(&'static ()))` + = note: callee signature: `fn(for<'a> fn(&'a ()))` + +error: aborting due to 3 previous errors + From cdd4118204e48227fae6a09321b77c7c4a39a186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Thu, 14 Aug 2025 15:42:14 +0000 Subject: [PATCH 215/252] Update autodiff tests for the new intrinsics impl --- .../codegen-llvm/{ => autodiff}/autodiffv2.rs | 7 +- tests/codegen-llvm/autodiff/batched.rs | 71 ++++++------ tests/codegen-llvm/autodiff/generic.rs | 17 +-- tests/codegen-llvm/autodiff/identical_fnc.rs | 10 +- tests/codegen-llvm/autodiff/inline.rs | 23 ---- tests/codegen-llvm/autodiff/scalar.rs | 3 +- tests/codegen-llvm/autodiff/sret.rs | 28 ++--- tests/codegen-llvm/autodiff/trait.rs | 30 +++++ tests/pretty/autodiff/autodiff_forward.pp | 106 ++++-------------- tests/pretty/autodiff/autodiff_reverse.pp | 40 ++----- tests/pretty/autodiff/autodiff_reverse.rs | 4 +- tests/pretty/autodiff/inherent_impl.pp | 12 +- tests/ui/autodiff/macro_hygiene.rs | 22 ++++ 13 files changed, 152 insertions(+), 221 deletions(-) rename tests/codegen-llvm/{ => autodiff}/autodiffv2.rs (96%) delete mode 100644 tests/codegen-llvm/autodiff/inline.rs create mode 100644 tests/codegen-llvm/autodiff/trait.rs create mode 100644 tests/ui/autodiff/macro_hygiene.rs diff --git a/tests/codegen-llvm/autodiffv2.rs b/tests/codegen-llvm/autodiff/autodiffv2.rs similarity index 96% rename from tests/codegen-llvm/autodiffv2.rs rename to tests/codegen-llvm/autodiff/autodiffv2.rs index a40d19d3be3a8..85aed6a183b63 100644 --- a/tests/codegen-llvm/autodiffv2.rs +++ b/tests/codegen-llvm/autodiff/autodiffv2.rs @@ -26,12 +26,13 @@ #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_forward; +// CHECK: ; #[no_mangle] //#[autodiff(d_square1, Forward, Dual, Dual)] -#[autodiff(d_square2, Forward, 4, Dualv, Dualv)] -#[autodiff(d_square3, Forward, 4, Dual, Dual)] +#[autodiff_forward(d_square2, 4, Dualv, Dualv)] +#[autodiff_forward(d_square3, 4, Dual, Dual)] fn square(x: &[f32], y: &mut [f32]) { assert!(x.len() >= 4); assert!(y.len() >= 5); diff --git a/tests/codegen-llvm/autodiff/batched.rs b/tests/codegen-llvm/autodiff/batched.rs index d27aed50e6cc4..306a6ed9d1f4f 100644 --- a/tests/codegen-llvm/autodiff/batched.rs +++ b/tests/codegen-llvm/autodiff/batched.rs @@ -17,11 +17,12 @@ use std::autodiff::autodiff_forward; #[autodiff_forward(d_square2, 4, Dual, DualOnly)] #[autodiff_forward(d_square1, 4, Dual, Dual)] #[no_mangle] +#[inline(never)] fn square(x: &f32) -> f32 { x * x } -// d_sqaure2 +// d_square2 // CHECK: define internal fastcc [4 x float] @fwddiffe4square(float %x.0.val, [4 x ptr] %"x'") // CHECK-NEXT: start: // CHECK-NEXT: %0 = extractvalue [4 x ptr] %"x'", 0 @@ -32,24 +33,20 @@ fn square(x: &f32) -> f32 { // CHECK-NEXT: %"_2'ipl2" = load float, ptr %2, align 4 // CHECK-NEXT: %3 = extractvalue [4 x ptr] %"x'", 3 // CHECK-NEXT: %"_2'ipl3" = load float, ptr %3, align 4 -// CHECK-NEXT: %4 = insertelement <4 x float> poison, float %"_2'ipl", i64 0 -// CHECK-NEXT: %5 = insertelement <4 x float> %4, float %"_2'ipl1", i64 1 -// CHECK-NEXT: %6 = insertelement <4 x float> %5, float %"_2'ipl2", i64 2 -// CHECK-NEXT: %7 = insertelement <4 x float> %6, float %"_2'ipl3", i64 3 -// CHECK-NEXT: %8 = fadd fast <4 x float> %7, %7 -// CHECK-NEXT: %9 = insertelement <4 x float> poison, float %x.0.val, i64 0 -// CHECK-NEXT: %10 = shufflevector <4 x float> %9, <4 x float> poison, <4 x i32> zeroinitializer -// CHECK-NEXT: %11 = fmul fast <4 x float> %8, %10 -// CHECK-NEXT: %12 = extractelement <4 x float> %11, i64 0 -// CHECK-NEXT: %13 = insertvalue [4 x float] undef, float %12, 0 -// CHECK-NEXT: %14 = extractelement <4 x float> %11, i64 1 -// CHECK-NEXT: %15 = insertvalue [4 x float] %13, float %14, 1 -// CHECK-NEXT: %16 = extractelement <4 x float> %11, i64 2 -// CHECK-NEXT: %17 = insertvalue [4 x float] %15, float %16, 2 -// CHECK-NEXT: %18 = extractelement <4 x float> %11, i64 3 -// CHECK-NEXT: %19 = insertvalue [4 x float] %17, float %18, 3 -// CHECK-NEXT: ret [4 x float] %19 -// CHECK-NEXT: } +// CHECK-NEXT: %4 = fmul float %"_2'ipl", 2.000000e+00 +// CHECK-NEXT: %5 = fmul fast float %4, %x.0.val +// CHECK-NEXT: %6 = insertvalue [4 x float] undef, float %5, 0 +// CHECK-NEXT: %7 = fmul float %"_2'ipl1", 2.000000e+00 +// CHECK-NEXT: %8 = fmul fast float %7, %x.0.val +// CHECK-NEXT: %9 = insertvalue [4 x float] %6, float %8, 1 +// CHECK-NEXT: %10 = fmul float %"_2'ipl2", 2.000000e+00 +// CHECK-NEXT: %11 = fmul fast float %10, %x.0.val +// CHECK-NEXT: %12 = insertvalue [4 x float] %9, float %11, 2 +// CHECK-NEXT: %13 = fmul float %"_2'ipl3", 2.000000e+00 +// CHECK-NEXT: %14 = fmul fast float %13, %x.0.val +// CHECK-NEXT: %15 = insertvalue [4 x float] %12, float %14, 3 +// CHECK-NEXT: ret [4 x float] %15 +// CHECK-NEXT: } // d_square3, the extra float is the original return value (x * x) // CHECK: define internal fastcc { float, [4 x float] } @fwddiffe4square.1(float %x.0.val, [4 x ptr] %"x'") @@ -63,26 +60,22 @@ fn square(x: &f32) -> f32 { // CHECK-NEXT: %3 = extractvalue [4 x ptr] %"x'", 3 // CHECK-NEXT: %"_2'ipl3" = load float, ptr %3, align 4 // CHECK-NEXT: %_0 = fmul float %x.0.val, %x.0.val -// CHECK-NEXT: %4 = insertelement <4 x float> poison, float %"_2'ipl", i64 0 -// CHECK-NEXT: %5 = insertelement <4 x float> %4, float %"_2'ipl1", i64 1 -// CHECK-NEXT: %6 = insertelement <4 x float> %5, float %"_2'ipl2", i64 2 -// CHECK-NEXT: %7 = insertelement <4 x float> %6, float %"_2'ipl3", i64 3 -// CHECK-NEXT: %8 = fadd fast <4 x float> %7, %7 -// CHECK-NEXT: %9 = insertelement <4 x float> poison, float %x.0.val, i64 0 -// CHECK-NEXT: %10 = shufflevector <4 x float> %9, <4 x float> poison, <4 x i32> zeroinitializer -// CHECK-NEXT: %11 = fmul fast <4 x float> %8, %10 -// CHECK-NEXT: %12 = extractelement <4 x float> %11, i64 0 -// CHECK-NEXT: %13 = insertvalue [4 x float] undef, float %12, 0 -// CHECK-NEXT: %14 = extractelement <4 x float> %11, i64 1 -// CHECK-NEXT: %15 = insertvalue [4 x float] %13, float %14, 1 -// CHECK-NEXT: %16 = extractelement <4 x float> %11, i64 2 -// CHECK-NEXT: %17 = insertvalue [4 x float] %15, float %16, 2 -// CHECK-NEXT: %18 = extractelement <4 x float> %11, i64 3 -// CHECK-NEXT: %19 = insertvalue [4 x float] %17, float %18, 3 -// CHECK-NEXT: %20 = insertvalue { float, [4 x float] } undef, float %_0, 0 -// CHECK-NEXT: %21 = insertvalue { float, [4 x float] } %20, [4 x float] %19, 1 -// CHECK-NEXT: ret { float, [4 x float] } %21 -// CHECK-NEXT: } +// CHECK-NEXT: %4 = fmul float %"_2'ipl", 2.000000e+00 +// CHECK-NEXT: %5 = fmul fast float %4, %x.0.val +// CHECK-NEXT: %6 = insertvalue [4 x float] undef, float %5, 0 +// CHECK-NEXT: %7 = fmul float %"_2'ipl1", 2.000000e+00 +// CHECK-NEXT: %8 = fmul fast float %7, %x.0.val +// CHECK-NEXT: %9 = insertvalue [4 x float] %6, float %8, 1 +// CHECK-NEXT: %10 = fmul float %"_2'ipl2", 2.000000e+00 +// CHECK-NEXT: %11 = fmul fast float %10, %x.0.val +// CHECK-NEXT: %12 = insertvalue [4 x float] %9, float %11, 2 +// CHECK-NEXT: %13 = fmul float %"_2'ipl3", 2.000000e+00 +// CHECK-NEXT: %14 = fmul fast float %13, %x.0.val +// CHECK-NEXT: %15 = insertvalue [4 x float] %12, float %14, 3 +// CHECK-NEXT: %16 = insertvalue { float, [4 x float] } undef, float %_0, 0 +// CHECK-NEXT: %17 = insertvalue { float, [4 x float] } %16, [4 x float] %15, 1 +// CHECK-NEXT: ret { float, [4 x float] } %17 +// CHECK-NEXT: } fn main() { let x = std::hint::black_box(3.0); diff --git a/tests/codegen-llvm/autodiff/generic.rs b/tests/codegen-llvm/autodiff/generic.rs index 2f674079be021..6f56460a2b6d1 100644 --- a/tests/codegen-llvm/autodiff/generic.rs +++ b/tests/codegen-llvm/autodiff/generic.rs @@ -6,27 +6,28 @@ use std::autodiff::autodiff_reverse; #[autodiff_reverse(d_square, Duplicated, Active)] +#[inline(never)] fn square + Copy>(x: &T) -> T { *x * *x } -// Ensure that `d_square::` code is generated even if `square::` was never called +// Ensure that `d_square::` code is generated // // CHECK: ; generic::square -// CHECK-NEXT: ; Function Attrs: -// CHECK-NEXT: define internal {{.*}} double +// CHECK-NEXT: ; Function Attrs: {{.*}} +// CHECK-NEXT: define internal {{.*}} float // CHECK-NEXT: start: // CHECK-NOT: ret -// CHECK: fmul double +// CHECK: fmul float -// Ensure that `d_square::` code is generated +// Ensure that `d_square::` code is generated even if `square::` was never called // // CHECK: ; generic::square -// CHECK-NEXT: ; Function Attrs: {{.*}} -// CHECK-NEXT: define internal {{.*}} float +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define internal {{.*}} double // CHECK-NEXT: start: // CHECK-NOT: ret -// CHECK: fmul float +// CHECK: fmul double fn main() { let xf32: f32 = std::hint::black_box(3.0); diff --git a/tests/codegen-llvm/autodiff/identical_fnc.rs b/tests/codegen-llvm/autodiff/identical_fnc.rs index 1c25b3d09ab0d..6066f8cb34fb9 100644 --- a/tests/codegen-llvm/autodiff/identical_fnc.rs +++ b/tests/codegen-llvm/autodiff/identical_fnc.rs @@ -14,25 +14,27 @@ use std::autodiff::autodiff_reverse; #[autodiff_reverse(d_square, Duplicated, Active)] +#[inline(never)] fn square(x: &f64) -> f64 { x * x } #[autodiff_reverse(d_square2, Duplicated, Active)] +#[inline(never)] fn square2(x: &f64) -> f64 { x * x } // CHECK:; identical_fnc::main // CHECK-NEXT:; Function Attrs: -// CHECK-NEXT:define internal void @_ZN13identical_fnc4main17hf4dbc69c8d2f9130E() +// CHECK-NEXT:define internal void @_ZN13identical_fnc4main17h6009e4f751bf9407E() // CHECK-NEXT:start: // CHECK-NOT:br // CHECK-NOT:ret // CHECK:; call identical_fnc::d_square -// CHECK-NEXT: call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx1) -// CHECK-NEXT:; call identical_fnc::d_square -// CHECK-NEXT: call fastcc void @_ZN13identical_fnc8d_square17h4c364207a2f8e06dE(double %x.val, ptr noalias noundef nonnull align 8 dereferenceable(8) %dx2) +// CHECK-NEXT:call fastcc void @_ZN13identical_fnc8d_square17hcb5768e95528c35fE(double %x.val, ptr noalias noundef align 8 dereferenceable(8) %dx1) +// CHECK:; call identical_fnc::d_square +// CHECK-NEXT:call fastcc void @_ZN13identical_fnc8d_square17hcb5768e95528c35fE(double %x.val, ptr noalias noundef align 8 dereferenceable(8) %dx2) fn main() { let x = std::hint::black_box(3.0); diff --git a/tests/codegen-llvm/autodiff/inline.rs b/tests/codegen-llvm/autodiff/inline.rs deleted file mode 100644 index 65bed170207cc..0000000000000 --- a/tests/codegen-llvm/autodiff/inline.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat -Zautodiff=NoPostopt -//@ no-prefer-dynamic -//@ needs-enzyme - -#![feature(autodiff)] - -use std::autodiff::autodiff_reverse; - -#[autodiff_reverse(d_square, Duplicated, Active)] -fn square(x: &f64) -> f64 { - x * x -} - -// CHECK: ; inline::d_square -// CHECK-NEXT: ; Function Attrs: alwaysinline -// CHECK-NOT: noinline -// CHECK-NEXT: define internal fastcc void @_ZN6inline8d_square17h021c74e92c259cdeE -fn main() { - let x = std::hint::black_box(3.0); - let mut dx1 = std::hint::black_box(1.0); - let _ = d_square(&x, &mut dx1, 1.0); - assert_eq!(dx1, 6.0); -} diff --git a/tests/codegen-llvm/autodiff/scalar.rs b/tests/codegen-llvm/autodiff/scalar.rs index 096b4209e84ad..55b989f920da3 100644 --- a/tests/codegen-llvm/autodiff/scalar.rs +++ b/tests/codegen-llvm/autodiff/scalar.rs @@ -7,11 +7,12 @@ use std::autodiff::autodiff_reverse; #[autodiff_reverse(d_square, Duplicated, Active)] #[no_mangle] +#[inline(never)] fn square(x: &f64) -> f64 { x * x } -// CHECK:define internal fastcc double @diffesquare(double %x.0.val, ptr nocapture nonnull align 8 %"x'" +// CHECK:define internal fastcc double @diffesquare(double %x.0.val, ptr nonnull align 8 captures(none) %"x'") // CHECK-NEXT:invertstart: // CHECK-NEXT: %_0 = fmul double %x.0.val, %x.0.val // CHECK-NEXT: %0 = fadd fast double %x.0.val, %x.0.val diff --git a/tests/codegen-llvm/autodiff/sret.rs b/tests/codegen-llvm/autodiff/sret.rs index d2fa85e3e3787..dbc253ce89434 100644 --- a/tests/codegen-llvm/autodiff/sret.rs +++ b/tests/codegen-llvm/autodiff/sret.rs @@ -13,30 +13,30 @@ use std::autodiff::autodiff_reverse; #[no_mangle] #[autodiff_reverse(df, Active, Active, Active)] +#[inline(never)] fn primal(x: f32, y: f32) -> f64 { (x * x * y) as f64 } -// CHECK:define internal fastcc void @_ZN4sret2df17h93be4316dd8ea006E(ptr dead_on_unwind noalias nocapture noundef nonnull writable writeonly align 8 dereferenceable(16) initializes((0, 16)) %_0, float noundef %x, float noundef %y) -// CHECK-NEXT:start: -// CHECK-NEXT: %0 = tail call fastcc { double, float, float } @diffeprimal(float %x, float %y) -// CHECK-NEXT: %.elt = extractvalue { double, float, float } %0, 0 -// CHECK-NEXT: store double %.elt, ptr %_0, align 8 -// CHECK-NEXT: %_0.repack1 = getelementptr inbounds nuw i8, ptr %_0, i64 8 -// CHECK-NEXT: %.elt2 = extractvalue { double, float, float } %0, 1 -// CHECK-NEXT: store float %.elt2, ptr %_0.repack1, align 8 -// CHECK-NEXT: %_0.repack3 = getelementptr inbounds nuw i8, ptr %_0, i64 12 -// CHECK-NEXT: %.elt4 = extractvalue { double, float, float } %0, 2 -// CHECK-NEXT: store float %.elt4, ptr %_0.repack3, align 4 -// CHECK-NEXT: ret void -// CHECK-NEXT:} +// CHECK: define internal fastcc { double, float, float } @diffeprimal(float noundef %x, float noundef %y) +// CHECK-NEXT: invertstart: +// CHECK-NEXT: %_4 = fmul float %x, %x +// CHECK-NEXT: %_3 = fmul float %_4, %y +// CHECK-NEXT: %_0 = fpext float %_3 to double +// CHECK-NEXT: %0 = fadd fast float %y, %y +// CHECK-NEXT: %1 = fmul fast float %0, %x +// CHECK-NEXT: %2 = insertvalue { double, float, float } undef, double %_0, 0 +// CHECK-NEXT: %3 = insertvalue { double, float, float } %2, float %1, 1 +// CHECK-NEXT: %4 = insertvalue { double, float, float } %3, float %_4, 2 +// CHECK-NEXT: ret { double, float, float } %4 +// CHECK-NEXT: } fn main() { let x = std::hint::black_box(3.0); let y = std::hint::black_box(2.5); let scalar = std::hint::black_box(1.0); let (r1, r2, r3) = df(x, y, scalar); - // 3*3*1.5 = 22.5 + // 3*3*2.5 = 22.5 assert_eq!(r1, 22.5); // 2*x*y = 2*3*2.5 = 15.0 assert_eq!(r2, 15.0); diff --git a/tests/codegen-llvm/autodiff/trait.rs b/tests/codegen-llvm/autodiff/trait.rs new file mode 100644 index 0000000000000..701f3a9e843bd --- /dev/null +++ b/tests/codegen-llvm/autodiff/trait.rs @@ -0,0 +1,30 @@ +//@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme + +// Just check it does not crash for now +// CHECK: ; +#![feature(autodiff)] + +use std::autodiff::autodiff_reverse; + +struct Foo { + a: f64, +} + +trait MyTrait { + fn f(&self, x: f64) -> f64; + fn df(&self, x: f64, seed: f64) -> (f64, f64); +} + +impl MyTrait for Foo { + #[autodiff_reverse(df, Const, Active, Active)] + fn f(&self, x: f64) -> f64 { + self.a * 0.25 * (x * x - 1.0 - 2.0 * x.ln()) + } +} + +fn main() { + let foo = Foo { a: 3.0f64 }; + dbg!(foo.df(1.0, 1.0)); +} diff --git a/tests/pretty/autodiff/autodiff_forward.pp b/tests/pretty/autodiff/autodiff_forward.pp index a2525abc83207..6eddb5669c7ab 100644 --- a/tests/pretty/autodiff/autodiff_forward.pp +++ b/tests/pretty/autodiff/autodiff_forward.pp @@ -3,10 +3,10 @@ //@ needs-enzyme #![feature(autodiff)] -#[prelude_import] -use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; //@ pretty-mode:expanded //@ pretty-compare-only //@ pp-exact:autodiff_forward.pp @@ -16,7 +16,6 @@ use std::autodiff::{autodiff_forward, autodiff_reverse}; #[rustc_autodiff] -#[inline(never)] pub fn f1(x: &[f64], y: f64) -> f64 { @@ -36,163 +35,96 @@ ::core::panicking::panic("not implemented") } #[rustc_autodiff(Forward, 1, Dual, Const, Dual)] -#[inline(never)] pub fn df1(x: &[f64], bx_0: &[f64], y: f64) -> (f64, f64) { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f1(x, y)); - ::core::hint::black_box((bx_0,)); - ::core::hint::black_box(<(f64, f64)>::default()) + ::core::intrinsics::autodiff(f1::<>, df1::<>, (x, bx_0, y)) } #[rustc_autodiff] -#[inline(never)] pub fn f2(x: &[f64], y: f64) -> f64 { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Forward, 1, Dual, Const, Const)] -#[inline(never)] pub fn df2(x: &[f64], bx_0: &[f64], y: f64) -> f64 { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f2(x, y)); - ::core::hint::black_box((bx_0,)); - ::core::hint::black_box(f2(x, y)) + ::core::intrinsics::autodiff(f2::<>, df2::<>, (x, bx_0, y)) } #[rustc_autodiff] -#[inline(never)] pub fn f3(x: &[f64], y: f64) -> f64 { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Forward, 1, Dual, Const, Const)] -#[inline(never)] pub fn df3(x: &[f64], bx_0: &[f64], y: f64) -> f64 { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f3(x, y)); - ::core::hint::black_box((bx_0,)); - ::core::hint::black_box(f3(x, y)) + ::core::intrinsics::autodiff(f3::<>, df3::<>, (x, bx_0, y)) } #[rustc_autodiff] -#[inline(never)] pub fn f4() {} #[rustc_autodiff(Forward, 1, None)] -#[inline(never)] -pub fn df4() -> () { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f4()); - ::core::hint::black_box(()); -} +pub fn df4() -> () { ::core::intrinsics::autodiff(f4::<>, df4::<>, ()) } #[rustc_autodiff] -#[inline(never)] pub fn f5(x: &[f64], y: f64) -> f64 { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Forward, 1, Const, Dual, Const)] -#[inline(never)] pub fn df5_y(x: &[f64], y: f64, by_0: f64) -> f64 { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f5(x, y)); - ::core::hint::black_box((by_0,)); - ::core::hint::black_box(f5(x, y)) + ::core::intrinsics::autodiff(f5::<>, df5_y::<>, (x, y, by_0)) } #[rustc_autodiff(Forward, 1, Dual, Const, Const)] -#[inline(never)] pub fn df5_x(x: &[f64], bx_0: &[f64], y: f64) -> f64 { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f5(x, y)); - ::core::hint::black_box((bx_0,)); - ::core::hint::black_box(f5(x, y)) + ::core::intrinsics::autodiff(f5::<>, df5_x::<>, (x, bx_0, y)) } #[rustc_autodiff(Reverse, 1, Duplicated, Const, Active)] -#[inline(never)] pub fn df5_rev(x: &[f64], dx_0: &mut [f64], y: f64, dret: f64) -> f64 { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f5(x, y)); - ::core::hint::black_box((dx_0, dret)); - ::core::hint::black_box(f5(x, y)) + ::core::intrinsics::autodiff(f5::<>, df5_rev::<>, (x, dx_0, y, dret)) } struct DoesNotImplDefault; #[rustc_autodiff] -#[inline(never)] pub fn f6() -> DoesNotImplDefault { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Forward, 1, Const)] -#[inline(never)] pub fn df6() -> DoesNotImplDefault { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f6()); - ::core::hint::black_box(()); - ::core::hint::black_box(f6()) + ::core::intrinsics::autodiff(f6::<>, df6::<>, ()) } #[rustc_autodiff] -#[inline(never)] pub fn f7(x: f32) -> () {} #[rustc_autodiff(Forward, 1, Const, None)] -#[inline(never)] pub fn df7(x: f32) -> () { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f7(x)); - ::core::hint::black_box(()); + ::core::intrinsics::autodiff(f7::<>, df7::<>, (x,)) } #[no_mangle] #[rustc_autodiff] -#[inline(never)] fn f8(x: &f32) -> f32 { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Forward, 4, Dual, Dual)] -#[inline(never)] fn f8_3(x: &f32, bx_0: &f32, bx_1: &f32, bx_2: &f32, bx_3: &f32) -> [f32; 5usize] { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f8(x)); - ::core::hint::black_box((bx_0, bx_1, bx_2, bx_3)); - ::core::hint::black_box(<[f32; 5usize]>::default()) + ::core::intrinsics::autodiff(f8::<>, f8_3::<>, + (x, bx_0, bx_1, bx_2, bx_3)) } #[rustc_autodiff(Forward, 4, Dual, DualOnly)] -#[inline(never)] fn f8_2(x: &f32, bx_0: &f32, bx_1: &f32, bx_2: &f32, bx_3: &f32) -> [f32; 4usize] { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f8(x)); - ::core::hint::black_box((bx_0, bx_1, bx_2, bx_3)); - ::core::hint::black_box(<[f32; 4usize]>::default()) + ::core::intrinsics::autodiff(f8::<>, f8_2::<>, + (x, bx_0, bx_1, bx_2, bx_3)) } #[rustc_autodiff(Forward, 1, Dual, DualOnly)] -#[inline(never)] fn f8_1(x: &f32, bx_0: &f32) -> f32 { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f8(x)); - ::core::hint::black_box((bx_0,)); - ::core::hint::black_box(::default()) + ::core::intrinsics::autodiff(f8::<>, f8_1::<>, (x, bx_0)) } pub fn f9() { #[rustc_autodiff] - #[inline(never)] fn inner(x: f32) -> f32 { x * x } #[rustc_autodiff(Forward, 1, Dual, Dual)] - #[inline(never)] fn d_inner_2(x: f32, bx_0: f32) -> (f32, f32) { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(inner(x)); - ::core::hint::black_box((bx_0,)); - ::core::hint::black_box(<(f32, f32)>::default()) + ::core::intrinsics::autodiff(inner::<>, d_inner_2::<>, (x, bx_0)) } #[rustc_autodiff(Forward, 1, Dual, DualOnly)] - #[inline(never)] fn d_inner_1(x: f32, bx_0: f32) -> f32 { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(inner(x)); - ::core::hint::black_box((bx_0,)); - ::core::hint::black_box(::default()) + ::core::intrinsics::autodiff(inner::<>, d_inner_1::<>, (x, bx_0)) } } #[rustc_autodiff] -#[inline(never)] pub fn f10 + Copy>(x: &T) -> T { *x * *x } #[rustc_autodiff(Reverse, 1, Duplicated, Active)] -#[inline(never)] pub fn d_square + Copy>(x: &T, dx_0: &mut T, dret: T) -> T { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f10::(x)); - ::core::hint::black_box((dx_0, dret)); - ::core::hint::black_box(f10::(x)) + ::core::intrinsics::autodiff(f10::, d_square::, (x, dx_0, dret)) } fn main() {} diff --git a/tests/pretty/autodiff/autodiff_reverse.pp b/tests/pretty/autodiff/autodiff_reverse.pp index e67c3443ddef1..8f598b865c7b2 100644 --- a/tests/pretty/autodiff/autodiff_reverse.pp +++ b/tests/pretty/autodiff/autodiff_reverse.pp @@ -3,10 +3,10 @@ //@ needs-enzyme #![feature(autodiff)] -#[prelude_import] -use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; //@ pretty-mode:expanded //@ pretty-compare-only //@ pp-exact:autodiff_reverse.pp @@ -16,7 +16,6 @@ use std::autodiff::autodiff_reverse; #[rustc_autodiff] -#[inline(never)] pub fn f1(x: &[f64], y: f64) -> f64 { // Not the most interesting derivative, but who are we to judge @@ -29,58 +28,33 @@ ::core::panicking::panic("not implemented") } #[rustc_autodiff(Reverse, 1, Duplicated, Const, Active)] -#[inline(never)] pub fn df1(x: &[f64], dx_0: &mut [f64], y: f64, dret: f64) -> f64 { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f1(x, y)); - ::core::hint::black_box((dx_0, dret)); - ::core::hint::black_box(f1(x, y)) + ::core::intrinsics::autodiff(f1::<>, df1::<>, (x, dx_0, y, dret)) } #[rustc_autodiff] -#[inline(never)] pub fn f2() {} #[rustc_autodiff(Reverse, 1, None)] -#[inline(never)] -pub fn df2() { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f2()); - ::core::hint::black_box(()); -} +pub fn df2() { ::core::intrinsics::autodiff(f2::<>, df2::<>, ()) } #[rustc_autodiff] -#[inline(never)] pub fn f3(x: &[f64], y: f64) -> f64 { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Reverse, 1, Duplicated, Const, Active)] -#[inline(never)] pub fn df3(x: &[f64], dx_0: &mut [f64], y: f64, dret: f64) -> f64 { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f3(x, y)); - ::core::hint::black_box((dx_0, dret)); - ::core::hint::black_box(f3(x, y)) + ::core::intrinsics::autodiff(f3::<>, df3::<>, (x, dx_0, y, dret)) } enum Foo { Reverse, } use Foo::Reverse; #[rustc_autodiff] -#[inline(never)] pub fn f4(x: f32) { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Reverse, 1, Const, None)] -#[inline(never)] -pub fn df4(x: f32) { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f4(x)); - ::core::hint::black_box(()); -} +pub fn df4(x: f32) { ::core::intrinsics::autodiff(f4::<>, df4::<>, (x,)) } #[rustc_autodiff] -#[inline(never)] pub fn f5(x: *const f32, y: &f32) { ::core::panicking::panic("not implemented") } #[rustc_autodiff(Reverse, 1, DuplicatedOnly, Duplicated, None)] -#[inline(never)] pub unsafe fn df5(x: *const f32, dx_0: *mut f32, y: &f32, dy_0: &mut f32) { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(f5(x, y)); - ::core::hint::black_box((dx_0, dy_0)); + ::core::intrinsics::autodiff(f5::<>, df5::<>, (x, dx_0, y, dy_0)) } fn main() {} diff --git a/tests/pretty/autodiff/autodiff_reverse.rs b/tests/pretty/autodiff/autodiff_reverse.rs index d37e5e3eb4cec..c50b81d7780d0 100644 --- a/tests/pretty/autodiff/autodiff_reverse.rs +++ b/tests/pretty/autodiff/autodiff_reverse.rs @@ -23,7 +23,9 @@ pub fn f3(x: &[f64], y: f64) -> f64 { unimplemented!() } -enum Foo { Reverse } +enum Foo { + Reverse, +} use Foo::Reverse; // What happens if we already have Reverse in type (enum variant decl) and value (enum variant // constructor) namespace? > It's expected to work normally. diff --git a/tests/pretty/autodiff/inherent_impl.pp b/tests/pretty/autodiff/inherent_impl.pp index d18061b2dbdef..36a9222640ae5 100644 --- a/tests/pretty/autodiff/inherent_impl.pp +++ b/tests/pretty/autodiff/inherent_impl.pp @@ -3,10 +3,10 @@ //@ needs-enzyme #![feature(autodiff)] -#[prelude_import] -use ::std::prelude::rust_2015::*; #[macro_use] extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; //@ pretty-mode:expanded //@ pretty-compare-only //@ pp-exact:inherent_impl.pp @@ -26,16 +26,12 @@ impl MyTrait for Foo { #[rustc_autodiff] - #[inline(never)] fn f(&self, x: f64) -> f64 { self.a * 0.25 * (x * x - 1.0 - 2.0 * x.ln()) } #[rustc_autodiff(Reverse, 1, Const, Active, Active)] - #[inline(never)] fn df(&self, x: f64, dret: f64) -> (f64, f64) { - unsafe { asm!("NOP", options(pure, nomem)); }; - ::core::hint::black_box(self.f(x)); - ::core::hint::black_box((dret,)); - ::core::hint::black_box((self.f(x), f64::default())) + ::core::intrinsics::autodiff(Self::f::<>, Self::df::<>, + (self, x, dret)) } } diff --git a/tests/ui/autodiff/macro_hygiene.rs b/tests/ui/autodiff/macro_hygiene.rs new file mode 100644 index 0000000000000..dec58254b9953 --- /dev/null +++ b/tests/ui/autodiff/macro_hygiene.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat +//@ no-prefer-dynamic +//@ needs-enzyme +//@ check-pass + +// In the past, we just checked for correct macro hygiene information. + +#![feature(autodiff)] + +macro_rules! demo { + () => { + #[std::autodiff::autodiff_reverse(fd, Active, Active)] + fn f(x: f64) -> f64 { + x * x + } + }; +} +demo!(); + +fn main() { + dbg!(f(2.0f64)); +} From 5d01d90ad617349109db79cb9980267fd294d735 Mon Sep 17 00:00:00 2001 From: Jens Reidel Date: Sun, 20 Jul 2025 07:04:58 +0200 Subject: [PATCH 216/252] std: thread: Return error if setting thread stack size fails Currently, when setting the thread stack size fails, it would be rounded up to the nearest multiple of the page size and the code asserts that the next call to pthread_attr_setstacksize succeeds. This may be true for glibc, but it isn't true for musl, which not only enforces a minimum stack size, but also a maximum stack size of usize::MAX / 4 - PTHREAD_STACK_MIN [1], triggering the assert rather than erroring gracefully. There isn't any way to handle this properly other than bailing out and letting the user know it didn't succeed. [1]: https://git.musl-libc.org/cgit/musl/tree/src/thread/pthread_attr_setstacksize.c#n5 Signed-off-by: Jens Reidel --- library/std/src/sys/pal/unix/thread.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 36e53e7cadca3..24b65c11fd2ab 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -77,7 +77,18 @@ impl Thread { let page_size = os::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(libc::pthread_attr_setstacksize(attr.as_mut_ptr(), stack_size), 0); + + // Some libc implementations, e.g. musl, place an upper bound + // on the stack size, in which case we can only gracefully return + // an error here. + if libc::pthread_attr_setstacksize(attr.as_mut_ptr(), stack_size) != 0 { + assert_eq!(libc::pthread_attr_destroy(attr.as_mut_ptr()), 0); + drop(Box::from_raw(data)); + return Err(io::const_error!( + io::ErrorKind::InvalidInput, + "invalid stack size" + )); + } } }; } From fa18b3ebe29154440f6e8d9ad83021802b3aaa29 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 14 Aug 2025 21:23:24 +0200 Subject: [PATCH 217/252] drive-by: fix typo --- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index f151e24947e11..c3dc3e42b83d8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -36,7 +36,7 @@ enum MergingSucc { True, } -/// Indicates to the call terminator codegen whether a cal +/// Indicates to the call terminator codegen whether a call /// is a normal call or an explicit tail call. #[derive(Debug, PartialEq)] enum CallKind { From 8b387d84fe6ba00561ca00f6553c46598e3f2d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 14 Aug 2025 22:24:37 +0200 Subject: [PATCH 218/252] Deduplicate `-L` paths passed to rustc --- compiler/rustc_session/src/config.rs | 31 +++++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c665c85d1fea4..a0b214d4a2536 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2828,16 +2828,27 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M // This is the location used by the `rustc-dev` `rustup` component. real_source_base_dir("lib/rustlib/rustc-src/rust", "compiler/rustc/src/main.rs"); - let mut search_paths = vec![]; - for s in &matches.opt_strs("L") { - search_paths.push(SearchPath::from_cli_opt( - sysroot.path(), - &target_triple, - early_dcx, - s, - unstable_opts.unstable_options, - )); - } + // We eagerly scan all files in each passed -L path. If the same directory is passed multiple + // times, and the directory contains a lot of files, this can take a lot of time. + // So we remove -L paths that were passed multiple times, and keep only the first occurrence. + // We still have to keep the original order of the -L arguments. + let search_paths: Vec = { + let mut seen_search_paths = FxHashSet::default(); + let search_path_matches: Vec = matches.opt_strs("L"); + search_path_matches + .iter() + .filter(|p| seen_search_paths.insert(*p)) + .map(|path| { + SearchPath::from_cli_opt( + sysroot.path(), + &target_triple, + early_dcx, + &path, + unstable_opts.unstable_options, + ) + }) + .collect() + }; let working_dir = std::env::current_dir().unwrap_or_else(|e| { early_dcx.early_fatal(format!("Current directory is invalid: {e}")); From fd5b7373db2093be7e1c906d8f92627689cc1eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 14 Aug 2025 22:30:10 +0200 Subject: [PATCH 219/252] Do not pass duplicated `-L` arguments to merged doctests --- src/librustdoc/doctest.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 73ce62cdcde6a..95bd31729de18 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -16,7 +16,7 @@ use std::{fmt, panic, str}; pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder}; pub(crate) use markdown::test as test_markdown; -use rustc_data_structures::fx::{FxHashMap, FxHasher, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxHasher, FxIndexMap, FxIndexSet}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagCtxtHandle}; use rustc_hir as hir; @@ -689,6 +689,10 @@ fn run_test( "--extern=doctest_bundle_{edition}=", edition = doctest.edition )); + + // Deduplicate passed -L directory paths, since usually all dependencies will be in the + // same directory (e.g. target/debug/deps from Cargo). + let mut seen_search_dirs = FxHashSet::default(); for extern_str in &rustdoc_options.extern_strs { if let Some((_cratename, path)) = extern_str.split_once('=') { // Direct dependencies of the tests themselves are @@ -698,7 +702,9 @@ fn run_test( .parent() .filter(|x| x.components().count() > 0) .unwrap_or(Path::new(".")); - runner_compiler.arg("-L").arg(dir); + if seen_search_dirs.insert(dir) { + runner_compiler.arg("-L").arg(dir); + } } } let output_bundle_file = doctest From 2355563e0ad51e2285b57ddb1d3d00b90a7cef02 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 14 Aug 2025 19:40:07 -0500 Subject: [PATCH 220/252] Windows: Replace `GetThreadId`+`GetCurrentThread` with `GetCurrentThreadId` Reference: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadid --- library/std/src/sys/pal/windows/c/bindings.txt | 2 +- library/std/src/sys/pal/windows/c/windows_sys.rs | 2 +- library/std/src/sys/pal/windows/thread.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index c8e4dca478162..abc1c19827fe7 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2158,6 +2158,7 @@ GetCurrentDirectoryW GetCurrentProcess GetCurrentProcessId GetCurrentThread +GetCurrentThreadId GetEnvironmentStringsW GetEnvironmentVariableW GetExitCodeProcess @@ -2185,7 +2186,6 @@ GetSystemInfo GetSystemTimeAsFileTime GetSystemTimePreciseAsFileTime GetTempPathW -GetThreadId GetUserProfileDirectoryW GetWindowsDirectoryW HANDLE diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index 45a273d241a98..989a1246650cd 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -38,6 +38,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetCurrentDirectoryW(nbufferle windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcess() -> HANDLE); windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcessId() -> u32); windows_targets::link!("kernel32.dll" "system" fn GetCurrentThread() -> HANDLE); +windows_targets::link!("kernel32.dll" "system" fn GetCurrentThreadId() -> u32); windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentStringsW() -> PWSTR); windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentVariableW(lpname : PCWSTR, lpbuffer : PWSTR, nsize : u32) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess : HANDLE, lpexitcode : *mut u32) -> BOOL); @@ -61,7 +62,6 @@ windows_targets::link!("kernel32.dll" "system" fn GetSystemInfo(lpsysteminfo : * windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME)); windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME)); windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32); -windows_targets::link!("kernel32.dll" "system" fn GetThreadId(thread : HANDLE) -> u32); windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32); windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL); diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index c708da5af12ac..b0e38220a2d3b 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -129,7 +129,7 @@ impl Thread { pub(crate) fn current_os_id() -> Option { // SAFETY: FFI call with no preconditions. - let id: u32 = unsafe { c::GetThreadId(c::GetCurrentThread()) }; + let id: u32 = unsafe { c::GetCurrentThreadId() }; // A return value of 0 indicates failed lookup. if id == 0 { None } else { Some(id.into()) } From ffdc40f30ab3ed1b4b1b7e5b2c877f21fe4e38ef Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 14 Aug 2025 17:51:48 -0700 Subject: [PATCH 221/252] bootstrap: Switch from fd-lock to native locking in std In the process, fix a race condition, by never truncating or writing to the file unless we currently hold the lock. --- src/bootstrap/Cargo.lock | 12 --------- src/bootstrap/Cargo.toml | 1 - src/bootstrap/src/bin/main.rs | 46 ++++++++++++++++------------------- 3 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 537f4b6184f1b..e5f95b8727317 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -48,7 +48,6 @@ dependencies = [ "clap", "clap_complete", "cmake", - "fd-lock", "home", "ignore", "insta", @@ -268,17 +267,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "fd-lock" -version = "4.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" -dependencies = [ - "cfg-if", - "rustix", - "windows-sys 0.59.0", -] - [[package]] name = "filetime" version = "0.2.25" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index bdf0b42255ee5..60c3548e16de4 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -38,7 +38,6 @@ cmake = "=0.1.54" build_helper = { path = "../build_helper" } clap = { version = "4.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } clap_complete = "4.4" -fd-lock = "4.0" home = "0.5" ignore = "0.4" libc = "0.2" diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 8b2d67266a77b..93c7faf4f0159 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -5,8 +5,8 @@ //! parent directory, and otherwise documentation can be found throughout the `build` //! directory in each respective module. -use std::fs::{self, OpenOptions}; -use std::io::{self, BufRead, BufReader, IsTerminal, Write}; +use std::fs::{self, OpenOptions, TryLockError}; +use std::io::{self, BufRead, BufReader, IsTerminal, Read, Write}; use std::path::Path; use std::str::FromStr; use std::time::Instant; @@ -39,38 +39,34 @@ fn main() { let config = Config::parse(flags); let mut build_lock; - let _build_lock_guard; if !config.bypass_bootstrap_lock { // Display PID of process holding the lock // PID will be stored in a lock file let lock_path = config.out.join("lock"); - let pid = fs::read_to_string(&lock_path); - - build_lock = fd_lock::RwLock::new(t!(fs::OpenOptions::new() + build_lock = t!(fs::OpenOptions::new() + .read(true) .write(true) - .truncate(true) .create(true) - .open(&lock_path))); - _build_lock_guard = match build_lock.try_write() { - Ok(mut lock) => { - t!(lock.write(process::id().to_string().as_ref())); - lock + .truncate(false) + .open(&lock_path)); + t!(build_lock.try_lock().or_else(|e| { + if let TryLockError::Error(e) = e { + return Err(e); } - err => { - drop(err); - // #135972: We can reach this point when the lock has been taken, - // but the locker has not yet written its PID to the file - if let Some(pid) = pid.ok().filter(|pid| !pid.is_empty()) { - println!("WARNING: build directory locked by process {pid}, waiting for lock"); - } else { - println!("WARNING: build directory locked, waiting for lock"); - } - let mut lock = t!(build_lock.write()); - t!(lock.write(process::id().to_string().as_ref())); - lock + let mut pid = String::new(); + t!(build_lock.read_to_string(&mut pid)); + // #135972: We can reach this point when the lock has been taken, + // but the locker has not yet written its PID to the file + if !pid.is_empty() { + println!("WARNING: build directory locked by process {pid}, waiting for lock"); + } else { + println!("WARNING: build directory locked, waiting for lock"); } - }; + build_lock.lock() + })); + t!(build_lock.set_len(0)); + t!(build_lock.write_all(process::id().to_string().as_bytes())); } // check_version warnings are not printed during setup, or during CI From 56b33cd5fa0eb2814f94f5fc636775ac70d10b0e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 14 Aug 2025 18:02:39 -0700 Subject: [PATCH 222/252] bootstrap: Remove dependency on xattr Extracting the Rust tarballs doesn't require this. --- src/bootstrap/Cargo.lock | 15 ++------------- src/bootstrap/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index e5f95b8727317..be29e77e572af 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -747,13 +747,12 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.43" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" dependencies = [ "filetime", "libc", - "xattr", ] [[package]] @@ -1135,16 +1134,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "xattr" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" -dependencies = [ - "libc", - "rustix", -] - [[package]] name = "xz2" version = "0.1.7" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 60c3548e16de4..cd5a60187e51b 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -50,7 +50,7 @@ serde = "1.0" serde_derive = "1.0" serde_json = "1.0" sha2 = "0.10" -tar = "0.4" +tar = { version = "0.4.44", default-features = false } termcolor = "1.4" toml = "0.5" walkdir = "2.4" From 2a2903c49eeb63211abf1ad50d01ddd710582efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 13 Aug 2025 09:55:01 +0200 Subject: [PATCH 223/252] Split codegen backend check step into two and don't run it with `x check compiler` --- src/bootstrap/src/core/build_steps/check.rs | 109 +++++++++++--- src/bootstrap/src/core/builder/mod.rs | 3 +- src/bootstrap/src/core/builder/tests.rs | 149 +------------------- 3 files changed, 91 insertions(+), 170 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 1e08e8547dc72..4a110b733e14d 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -314,41 +314,31 @@ pub fn prepare_compiler_for_check( } } -/// Checks a single codegen backend. +/// Check the Cranelift codegen backend. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct CodegenBackend { - pub build_compiler: Compiler, - pub target: TargetSelection, - pub backend: CodegenBackendKind, +pub struct CraneliftCodegenBackend { + build_compiler: Compiler, + target: TargetSelection, } -impl Step for CodegenBackend { +impl Step for CraneliftCodegenBackend { type Output = (); + const IS_HOST: bool = true; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.paths(&["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"]) + run.alias("rustc_codegen_cranelift").alias("cg_clif") } fn make_run(run: RunConfig<'_>) { - // FIXME: only check the backend(s) that were actually selected in run.paths let build_compiler = prepare_compiler_for_check(run.builder, run.target, Mode::Codegen); - for backend in [CodegenBackendKind::Cranelift, CodegenBackendKind::Gcc] { - run.builder.ensure(CodegenBackend { build_compiler, target: run.target, backend }); - } + run.builder.ensure(CraneliftCodegenBackend { build_compiler, target: run.target }); } fn run(self, builder: &Builder<'_>) { - // FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved - if builder.build.config.vendor && self.backend.is_gcc() { - println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled."); - return; - } - let build_compiler = self.build_compiler; let target = self.target; - let backend = self.backend; let mut cargo = builder::Cargo::new( builder, @@ -361,31 +351,104 @@ impl Step for CodegenBackend { cargo .arg("--manifest-path") - .arg(builder.src.join(format!("compiler/{}/Cargo.toml", backend.crate_name()))); + .arg(builder.src.join("compiler/rustc_codegen_cranelift/Cargo.toml")); rustc_cargo_env(builder, &mut cargo, target); let _guard = builder.msg( Kind::Check, - backend.crate_name(), + "rustc_codegen_cranelift", Mode::Codegen, self.build_compiler, target, ); - let stamp = build_stamp::codegen_backend_stamp(builder, build_compiler, target, &backend) - .with_prefix("check"); + let stamp = build_stamp::codegen_backend_stamp( + builder, + build_compiler, + target, + &CodegenBackendKind::Cranelift, + ) + .with_prefix("check"); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } fn metadata(&self) -> Option { Some( - StepMetadata::check(&self.backend.crate_name(), self.target) + StepMetadata::check("rustc_codegen_cranelift", self.target) .built_by(self.build_compiler), ) } } +/// Check the GCC codegen backend. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GccCodegenBackend { + build_compiler: Compiler, + target: TargetSelection, +} + +impl Step for GccCodegenBackend { + type Output = (); + + const IS_HOST: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("rustc_codegen_gcc").alias("cg_gcc") + } + + fn make_run(run: RunConfig<'_>) { + let build_compiler = prepare_compiler_for_check(run.builder, run.target, Mode::Codegen); + run.builder.ensure(GccCodegenBackend { build_compiler, target: run.target }); + } + + fn run(self, builder: &Builder<'_>) { + // FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved + if builder.build.config.vendor { + println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled."); + return; + } + + let build_compiler = self.build_compiler; + let target = self.target; + + let mut cargo = builder::Cargo::new( + builder, + build_compiler, + Mode::Codegen, + SourceType::InTree, + target, + builder.kind, + ); + + cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml")); + rustc_cargo_env(builder, &mut cargo, target); + + let _guard = builder.msg( + Kind::Check, + "rustc_codegen_gcc", + Mode::Codegen, + self.build_compiler, + target, + ); + + let stamp = build_stamp::codegen_backend_stamp( + builder, + build_compiler, + target, + &CodegenBackendKind::Gcc, + ) + .with_prefix("check"); + + run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + } + + fn metadata(&self) -> Option { + Some(StepMetadata::check("rustc_codegen_gcc", self.target).built_by(self.build_compiler)) + } +} + macro_rules! tool_check_step { ( $name:ident { diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 6226c81a3fdb7..2b521debd84d1 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1042,7 +1042,8 @@ impl<'a> Builder<'a> { Kind::Check | Kind::Fix => describe!( check::Rustc, check::Rustdoc, - check::CodegenBackend, + check::CraneliftCodegenBackend, + check::GccCodegenBackend, check::Clippy, check::Miri, check::CargoMiri, diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 9ba57542549b5..a9398a654e956 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1514,12 +1514,7 @@ mod snapshot { insta::assert_snapshot!( ctx.config("check") .path("compiler") - .render_steps(), @r" - [check] rustc 0 -> rustc 1 (73 crates) - [check] rustc 0 -> rustc 1 - [check] rustc 0 -> rustc_codegen_cranelift 1 - [check] rustc 0 -> rustc_codegen_gcc 1 - "); + .render_steps(), @"[check] rustc 0 -> rustc 1 (73 crates)"); } #[test] @@ -1545,12 +1540,7 @@ mod snapshot { ctx.config("check") .path("compiler") .stage(1) - .render_steps(), @r" - [check] rustc 0 -> rustc 1 (73 crates) - [check] rustc 0 -> rustc 1 - [check] rustc 0 -> rustc_codegen_cranelift 1 - [check] rustc 0 -> rustc_codegen_gcc 1 - "); + .render_steps(), @"[check] rustc 0 -> rustc 1 (73 crates)"); } #[test] @@ -1565,9 +1555,6 @@ mod snapshot { [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 [check] rustc 1 -> rustc 2 (73 crates) - [check] rustc 1 -> rustc 2 - [check] rustc 1 -> rustc_codegen_cranelift 2 - [check] rustc 1 -> rustc_codegen_gcc 2 "); } @@ -1679,12 +1666,7 @@ mod snapshot { ctx.config("check") .paths(&["library", "compiler"]) .args(&args) - .render_steps(), @r" - [check] rustc 0 -> rustc 1 (73 crates) - [check] rustc 0 -> rustc 1 - [check] rustc 0 -> rustc_codegen_cranelift 1 - [check] rustc 0 -> rustc_codegen_gcc 1 - "); + .render_steps(), @"[check] rustc 0 -> rustc 1 (73 crates)"); } #[test] @@ -1768,7 +1750,6 @@ mod snapshot { .render_steps(), @r" [check] rustc 0 -> rustc 1 [check] rustc 0 -> rustc_codegen_cranelift 1 - [check] rustc 0 -> rustc_codegen_gcc 1 "); } @@ -2068,130 +2049,6 @@ mod snapshot { [doc] rustc 1 -> reference (book) 2 "); } - - #[test] - fn clippy_ci() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("ci") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 - [clippy] rustc 1 -> bootstrap 2 - [clippy] rustc 1 -> std 1 - [clippy] rustc 1 -> rustc 2 - [check] rustc 1 -> rustc 2 - [clippy] rustc 1 -> rustc_codegen_gcc 2 - "); - } - - #[test] - fn clippy_compiler_stage1() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("compiler") - .render_steps(), @r" - [build] llvm - [clippy] rustc 0 -> rustc 1 - "); - } - - #[test] - fn clippy_compiler_stage2() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("compiler") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 - [clippy] rustc 1 -> rustc 2 - "); - } - - #[test] - fn clippy_std_stage1() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("std") - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 - [clippy] rustc 1 -> std 1 - "); - } - - #[test] - fn clippy_std_stage2() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("std") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 1 -> rustc 2 - [build] rustc 1 -> clippy-driver 2 - [build] rustc 1 -> cargo-clippy 2 - [clippy] rustc 2 -> std 2 - "); - } - - #[test] - fn clippy_miri_stage1() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("miri") - .stage(1) - .render_steps(), @r" - [build] llvm - [check] rustc 0 -> rustc 1 - [clippy] rustc 0 -> miri 1 - "); - } - - #[test] - fn clippy_miri_stage2() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("miri") - .stage(2) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [check] rustc 1 -> rustc 2 - [build] rustc 0 -> clippy-driver 1 - [build] rustc 0 -> cargo-clippy 1 - [clippy] rustc 1 -> miri 2 - "); - } - - #[test] - fn clippy_bootstrap() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("clippy") - .path("bootstrap") - .render_steps(), @"[clippy] rustc 0 -> bootstrap 1 "); - } } struct ExecutedSteps { From 8a7be4ab5e2f31e3ad571e00ed0800369a88124c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 16:45:35 +0200 Subject: [PATCH 224/252] Rename `compiler` to `build_compiler` in the `compile::Std` step --- src/bootstrap/src/core/build_steps/compile.rs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d860cafa1c0fd..5a44abc6c603e 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -37,11 +37,12 @@ use crate::{ debug, trace, }; -/// Build a standard library for the given `target` using the given `compiler`. +/// Build a standard library for the given `target` using the given `build_compiler`. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Std { pub target: TargetSelection, - pub compiler: Compiler, + /// Compiler that builds the standard library. + pub build_compiler: Compiler, /// Whether to build only a subset of crates in the standard library. /// /// This shouldn't be used from other steps; see the comment on [`Rustc`]. @@ -54,10 +55,10 @@ pub struct Std { } impl Std { - pub fn new(compiler: Compiler, target: TargetSelection) -> Self { + pub fn new(build_compiler: Compiler, target: TargetSelection) -> Self { Self { target, - compiler, + build_compiler, crates: Default::default(), force_recompile: false, extra_rust_args: &[], @@ -120,7 +121,7 @@ impl Step for Std { trace!(force_recompile); run.builder.ensure(Std { - compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + build_compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, crates, force_recompile, @@ -138,8 +139,8 @@ impl Step for Std { let target = self.target; // We already have std ready to be used for stage 0. - if self.compiler.stage == 0 { - let compiler = self.compiler; + if self.build_compiler.stage == 0 { + let compiler = self.build_compiler; builder.ensure(StdLink::from_std(self, compiler)); return; @@ -148,9 +149,10 @@ impl Step for Std { let build_compiler = if builder.download_rustc() && self.force_recompile { // When there are changes in the library tree with CI-rustc, we want to build // the stageN library and that requires using stageN-1 compiler. - builder.compiler(self.compiler.stage.saturating_sub(1), builder.config.host_target) + builder + .compiler(self.build_compiler.stage.saturating_sub(1), builder.config.host_target) } else { - self.compiler + self.build_compiler }; // When using `download-rustc`, we already have artifacts for the host available. Don't @@ -299,7 +301,7 @@ impl Step for Std { } fn metadata(&self) -> Option { - Some(StepMetadata::build("std", self.target).built_by(self.compiler)) + Some(StepMetadata::build("std", self.target).built_by(self.build_compiler)) } } @@ -680,7 +682,7 @@ impl StdLink { pub fn from_std(std: Std, host_compiler: Compiler) -> Self { Self { compiler: host_compiler, - target_compiler: std.compiler, + target_compiler: std.build_compiler, target: std.target, crates: std.crates, force_recompile: std.force_recompile, From d8a51f58b3677437a574265e73a9363ac3f3d396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 13 Aug 2025 07:31:41 +0200 Subject: [PATCH 225/252] Remove usage of `compiler_for` from the `compile::Std` step --- src/bootstrap/src/core/build_steps/compile.rs | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 5a44abc6c603e..ba9f006e715cc 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -189,51 +189,50 @@ impl Step for Std { let mut target_deps = builder.ensure(StartupObjects { compiler: build_compiler, target }); - let compiler_to_use = - builder.compiler_for(build_compiler.stage, build_compiler.host, target); - trace!(?compiler_to_use); - - if compiler_to_use != build_compiler - // Never uplift std unless we have compiled stage 1; if stage 1 is compiled, - // uplift it from there. - // - // FIXME: improve `fn compiler_for` to avoid adding stage condition here. - && build_compiler.stage > 1 + // Stage of the stdlib that we're building + let stage = build_compiler.stage; + + // If we're building a stage2+ libstd, full bootstrap is + // disabled and we have a stage1 libstd already compiled for the given target, + // then simply uplift a previously built stage1 library. + if build_compiler.stage > 1 + && !builder.config.full_bootstrap + // This estimates if a stage1 libstd exists for the given target. If we're not + // cross-compiling, it should definitely exist by the time we're building a stage2 + // libstd. + // Or if we are cross-compiling, and we are building a cross-compiled rustc, then that + // rustc needs to link to a cross-compiled libstd, so again we should have a stage1 + // libstd for the given target prepared. + // Even if we guess wrong in the cross-compiled case, the worst that should happen is + // that we build a fresh stage1 libstd below, and then we immediately uplift it, so we + // don't pay the libstd build cost twice. + && (target == builder.host_target || builder.config.hosts.contains(&target)) { - trace!( - ?compiler_to_use, - ?build_compiler, - "build_compiler != compiler_to_use, uplifting library" - ); + let build_compiler_for_std_to_uplift = builder.compiler(1, builder.host_target); + builder.std(build_compiler_for_std_to_uplift, target); - builder.std(compiler_to_use, target); - let msg = if compiler_to_use.host == target { + let msg = if build_compiler_for_std_to_uplift.host == target { format!( - "Uplifting library (stage{} -> stage{})", - compiler_to_use.stage, build_compiler.stage + "Uplifting library (stage{} -> stage{stage})", + build_compiler_for_std_to_uplift.stage ) } else { format!( - "Uplifting library (stage{}:{} -> stage{}:{})", - compiler_to_use.stage, compiler_to_use.host, build_compiler.stage, target + "Uplifting library (stage{}:{} -> stage{stage}:{target})", + build_compiler_for_std_to_uplift.stage, build_compiler_for_std_to_uplift.host, ) }; + builder.info(&msg); // Even if we're not building std this stage, the new sysroot must // still contain the third party objects needed by various targets. self.copy_extra_objects(builder, &build_compiler, target); - builder.ensure(StdLink::from_std(self, compiler_to_use)); + builder.ensure(StdLink::from_std(self, build_compiler_for_std_to_uplift)); return; } - trace!( - ?compiler_to_use, - ?build_compiler, - "compiler == compiler_to_use, handling not-cross-compile scenario" - ); - target_deps.extend(self.copy_extra_objects(builder, &build_compiler, target)); // We build a sysroot for mir-opt tests using the same trick that Miri does: A check build From 36dfed6435a48841e1befff580bbc26a796df79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 13 Aug 2025 07:34:59 +0200 Subject: [PATCH 226/252] Remove usage of `compiler_for` from the `compile::Rustc` step --- src/bootstrap/src/core/build_steps/compile.rs | 94 +++++++++---------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index ba9f006e715cc..da828937861b8 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -666,6 +666,14 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, cargo: &mut Car cargo.rustdocflag("-Zcrate-attr=warn(rust_2018_idioms)"); } +/// Link all libstd rlibs/dylibs into a sysroot of `target_compiler`. +/// +/// Links those artifacts generated by `compiler` to the `stage` compiler's +/// sysroot for the specified `host` and `target`. +/// +/// Note that this assumes that `compiler` has already generated the libstd +/// libraries for `target`, and this method will find them in the relevant +/// output directory. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct StdLink { pub compiler: Compiler, @@ -952,14 +960,8 @@ impl Rustc { } impl Step for Rustc { - /// We return the stage of the "actual" compiler (not the uplifted one). - /// - /// By "actual" we refer to the uplifting logic where we may not compile the requested stage; - /// instead, we uplift it from the previous stages. Which can lead to bootstrap failures in - /// specific situations where we request stage X from other steps. However we may end up - /// uplifting it from stage Y, causing the other stage to fail when attempting to link with - /// stage X which was never actually built. - type Output = u32; + type Output = (); + const IS_HOST: bool = true; const DEFAULT: bool = false; @@ -998,7 +1000,7 @@ impl Step for Rustc { /// This will build the compiler for a particular stage of the build using /// the `build_compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. - fn run(self, builder: &Builder<'_>) -> u32 { + fn run(self, builder: &Builder<'_>) { let build_compiler = self.build_compiler; let target = self.target; @@ -1014,7 +1016,7 @@ impl Step for Rustc { &sysroot, builder.config.ci_rustc_dev_contents(), ); - return build_compiler.stage; + return; } // Build a standard library for `target` using the `build_compiler`. @@ -1028,31 +1030,33 @@ impl Step for Rustc { builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes"); builder.ensure(RustcLink::from_rustc(self, build_compiler)); - return build_compiler.stage; + return; } - let compiler_to_use = - builder.compiler_for(build_compiler.stage, build_compiler.host, target); - if compiler_to_use != build_compiler { - builder.ensure(Rustc::new(compiler_to_use, target)); - let msg = if compiler_to_use.host == target { - format!( - "Uplifting rustc (stage{} -> stage{})", - compiler_to_use.stage, - build_compiler.stage + 1 - ) + // The stage of the compiler that we're building + let stage = build_compiler.stage + 1; + + // If we are building a stage3+ compiler, and full bootstrap is disabled, and we have a + // previous rustc available, we will uplift a compiler from a previous stage. + if build_compiler.stage >= 2 + && !builder.config.full_bootstrap + && (target == builder.host_target || builder.hosts.contains(&target)) + { + // If we're cross-compiling, the earliest rustc that we could have is stage 2. + // If we're not cross-compiling, then we should have rustc stage 1. + let stage_to_uplift = if target == builder.host_target { 1 } else { 2 }; + let rustc_to_uplift = builder.compiler(stage_to_uplift, target); + let msg = if rustc_to_uplift.host == target { + format!("Uplifting rustc (stage{} -> stage{stage})", rustc_to_uplift.stage,) } else { format!( - "Uplifting rustc (stage{}:{} -> stage{}:{})", - compiler_to_use.stage, - compiler_to_use.host, - build_compiler.stage + 1, - target + "Uplifting rustc (stage{}:{} -> stage{stage}:{target})", + rustc_to_uplift.stage, rustc_to_uplift.host, ) }; builder.info(&msg); - builder.ensure(RustcLink::from_rustc(self, compiler_to_use)); - return compiler_to_use.stage; + builder.ensure(RustcLink::from_rustc(self, rustc_to_uplift)); + return; } // Build a standard library for the current host target using the `build_compiler`. @@ -1129,8 +1133,6 @@ impl Step for Rustc { self, builder.compiler(build_compiler.stage, builder.config.host_target), )); - - build_compiler.stage } fn metadata(&self) -> Option { @@ -1910,12 +1912,18 @@ impl Step for Sysroot { } } +/// Prepare a compiler sysroot. +/// +/// The sysroot may contain various things useful for running the compiler, like linkers and +/// linker wrappers (LLD, LLVM bitcode linker, etc.). +/// +/// This will assemble a compiler in `build/$target/stage$stage`. #[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)] pub struct Assemble { /// The compiler which we will produce in this step. Assemble itself will /// take care of ensuring that the necessary prerequisites to do so exist, - /// that is, this target can be a stage2 compiler and Assemble will build - /// previous stages for you. + /// that is, this can be e.g. a stage2 compiler and Assemble will build + /// the previous stages for you. pub target_compiler: Compiler, } @@ -1933,11 +1941,6 @@ impl Step for Assemble { }); } - /// Prepare a new compiler from the artifacts in `stage` - /// - /// This will assemble a compiler in `build/$host/stage$stage`. The compiler - /// must have been previously produced by the `stage - 1` builder.build - /// compiler. fn run(self, builder: &Builder<'_>) -> Compiler { let target_compiler = self.target_compiler; @@ -2066,7 +2069,7 @@ impl Step for Assemble { target_compiler.stage - 1, builder.config.host_target, ); - let mut build_compiler = + let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.host_target); // Build enzyme @@ -2090,24 +2093,13 @@ impl Step for Assemble { } // Build the libraries for this compiler to link to (i.e., the libraries - // it uses at runtime). NOTE: Crates the target compiler compiles don't - // link to these. (FIXME: Is that correct? It seems to be correct most - // of the time but I think we do link to these for stage2/bin compilers - // when not performing a full bootstrap). + // it uses at runtime). debug!( ?build_compiler, "target_compiler.host" = ?target_compiler.host, "building compiler libraries to link to" ); - let actual_stage = builder.ensure(Rustc::new(build_compiler, target_compiler.host)); - // Current build_compiler.stage might be uplifted instead of being built; so update it - // to not fail while linking the artifacts. - debug!( - "(old) build_compiler.stage" = build_compiler.stage, - "(adjusted) build_compiler.stage" = actual_stage, - "temporarily adjusting `build_compiler.stage` to account for uplifted libraries" - ); - build_compiler.stage = actual_stage; + builder.ensure(Rustc::new(build_compiler, target_compiler.host)); let stage = target_compiler.stage; let host = target_compiler.host; From f2c2d3ebc329865a1a5c2f41420711c2b1032c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 17:19:45 +0200 Subject: [PATCH 227/252] Clarify that `build.full-bootstrap` is only used to affect uplifting, not stage selection --- bootstrap.example.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 89da6eeb53153..41649fd796c1b 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -345,9 +345,9 @@ # want to use vendoring. See https://forge.rust-lang.org/infra/other-installation-methods.html#source-code. #build.vendor = if "is a tarball source" && "vendor" dir exists && ".cargo/config.toml" file exists { true } else { false } -# Typically the build system will build the Rust compiler twice. The second -# compiler, however, will simply use its own libraries to link against. If you -# would rather to perform a full bootstrap, compiling the compiler three times, +# If you build the compiler more than twice (stage3+) or the standard library more than once +# (stage 2+), the third compiler and second library will get uplifted from stage2 and stage1, +# respectively. If you would like to disable this uplifting, and rather perform a full bootstrap, # then you can set this option to true. # # This is only useful for verifying that rustc generates reproducible builds. From 2218ff1940bc8baafcc1acf2c861d48499e20d06 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 4 Aug 2025 23:59:28 +0900 Subject: [PATCH 228/252] fix: Reject async assoc fns of const traits/impls in ast_passes --- compiler/rustc_ast_passes/messages.ftl | 7 +++++++ .../rustc_ast_passes/src/ast_validation.rs | 16 ++++++++++++++++ compiler/rustc_ast_passes/src/errors.rs | 10 ++++++++++ tests/crashes/117629.rs | 10 ---------- .../const-traits/const-trait-async-assoc-fn.rs | 18 ++++++++++++++++++ .../const-trait-async-assoc-fn.stderr | 18 ++++++++++++++++++ 6 files changed, 69 insertions(+), 10 deletions(-) delete mode 100644 tests/crashes/117629.rs create mode 100644 tests/ui/traits/const-traits/const-trait-async-assoc-fn.rs create mode 100644 tests/ui/traits/const-traits/const-trait-async-assoc-fn.stderr diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 340a1a239c5b0..92ac04d183773 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -32,6 +32,13 @@ ast_passes_assoc_type_without_body = associated type in `impl` without body .suggestion = provide a definition for the type +ast_passes_async_fn_in_const_trait_or_trait_impl = + async functions are not allowed in `const` {$in_impl -> + [true] trait impls + *[false] traits + } + .label = associated functions of `const` cannot be declared `async` + ast_passes_at_least_one_trait = at least one trait must be specified ast_passes_auto_generic = auto traits cannot have generic parameters diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index f62b8d1d57620..de192aa1e5eb6 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -293,6 +293,21 @@ impl<'a> AstValidator<'a> { }); } + fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrTraitImpl) { + let Some(const_keyword) = parent.constness() else { return }; + + let Some(CoroutineKind::Async { span: async_keyword, .. }) = sig.header.coroutine_kind + else { + return; + }; + + self.dcx().emit_err(errors::AsyncFnInConstTraitOrTraitImpl { + async_keyword, + in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }), + const_keyword, + }); + } + fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { self.check_decl_num_args(fn_decl); self.check_decl_cvariadic_pos(fn_decl); @@ -1566,6 +1581,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl); if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { self.check_trait_fn_not_const(sig.header.constness, parent); + self.check_async_fn_in_const_trait_or_impl(sig, parent); } } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 1cb2493afe884..5ecc0d21411d1 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -62,6 +62,16 @@ pub(crate) struct TraitFnConst { pub make_trait_const_sugg: Option, } +#[derive(Diagnostic)] +#[diag(ast_passes_async_fn_in_const_trait_or_trait_impl)] +pub(crate) struct AsyncFnInConstTraitOrTraitImpl { + #[primary_span] + pub async_keyword: Span, + pub in_impl: bool, + #[label] + pub const_keyword: Span, +} + #[derive(Diagnostic)] #[diag(ast_passes_forbidden_bound)] pub(crate) struct ForbiddenBound { diff --git a/tests/crashes/117629.rs b/tests/crashes/117629.rs deleted file mode 100644 index f63365395c6b4..0000000000000 --- a/tests/crashes/117629.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #117629 -//@ edition:2021 - -#![feature(const_trait_impl)] - -const trait Tr { - async fn ft1() {} -} - -fn main() {} diff --git a/tests/ui/traits/const-traits/const-trait-async-assoc-fn.rs b/tests/ui/traits/const-traits/const-trait-async-assoc-fn.rs new file mode 100644 index 0000000000000..00fdccc2ac8e4 --- /dev/null +++ b/tests/ui/traits/const-traits/const-trait-async-assoc-fn.rs @@ -0,0 +1,18 @@ +//@ edition: 2021 +#![feature(const_trait_impl)] + +const trait Tr { + async fn ft1() {} +//~^ ERROR async functions are not allowed in `const` traits +} + +const trait Tr2 { + fn f() -> impl std::future::Future; +} + +impl const Tr2 for () { + async fn f() {} +//~^ ERROR async functions are not allowed in `const` trait impls +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/const-trait-async-assoc-fn.stderr b/tests/ui/traits/const-traits/const-trait-async-assoc-fn.stderr new file mode 100644 index 0000000000000..09ba0969dc994 --- /dev/null +++ b/tests/ui/traits/const-traits/const-trait-async-assoc-fn.stderr @@ -0,0 +1,18 @@ +error: async functions are not allowed in `const` traits + --> $DIR/const-trait-async-assoc-fn.rs:5:5 + | +LL | const trait Tr { + | ----- associated functions of `const` cannot be declared `async` +LL | async fn ft1() {} + | ^^^^^ + +error: async functions are not allowed in `const` trait impls + --> $DIR/const-trait-async-assoc-fn.rs:14:5 + | +LL | impl const Tr2 for () { + | ----- associated functions of `const` cannot be declared `async` +LL | async fn f() {} + | ^^^^^ + +error: aborting due to 2 previous errors + From cda2114c655a1eab26c8c8678eb23525733353dc Mon Sep 17 00:00:00 2001 From: AMS21 Date: Fri, 15 Aug 2025 09:57:24 +0200 Subject: [PATCH 229/252] Fix typos in bootstrap.example.toml equivelent -> equivalent recommeded -> recommended --- bootstrap.example.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 89da6eeb53153..2e448f5df92c2 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -9,7 +9,7 @@ # a custom configuration file can also be specified with `--config` to the build # system. # -# Note that the following are equivelent, for more details see . +# Note that the following are equivalent, for more details see . # # build.verbose = 1 # @@ -482,7 +482,7 @@ # Use `--extra-checks=''` to temporarily disable all extra checks. # # Automatically enabled in the "tools" profile. -# Set to the empty string to force disable (recommeded for hdd systems). +# Set to the empty string to force disable (recommended for hdd systems). #build.tidy-extra-checks = "" # Indicates whether ccache is used when building certain artifacts (e.g. LLVM). From ae4eeb9299b5938cca183ad7a90e70a1bb4b1174 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 15 Aug 2025 11:59:23 +0200 Subject: [PATCH 230/252] Fix wrong spans with external macros in the `dropping_copy_types` lint --- compiler/rustc_lint/src/drop_forget_useless.rs | 2 +- tests/ui/lint/dropping_copy_types-macros.fixed | 3 +++ tests/ui/lint/dropping_copy_types-macros.rs | 3 +++ tests/ui/lint/dropping_copy_types-macros.stderr | 16 +++++++++++++++- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 7f098893f7de5..c2d137986ce4d 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -151,7 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { && let Node::Stmt(stmt) = node && let StmtKind::Semi(e) = stmt.kind && e.hir_id == expr.hir_id - && let Some(arg_span) = arg.span.find_ancestor_inside(expr.span) + && let Some(arg_span) = arg.span.find_ancestor_inside_same_ctxt(expr.span) { UseLetUnderscoreIgnoreSuggestion::Suggestion { start_span: expr.span.shrink_to_lo().until(arg_span), diff --git a/tests/ui/lint/dropping_copy_types-macros.fixed b/tests/ui/lint/dropping_copy_types-macros.fixed index a8ceedadc8063..2a0c398815755 100644 --- a/tests/ui/lint/dropping_copy_types-macros.fixed +++ b/tests/ui/lint/dropping_copy_types-macros.fixed @@ -9,4 +9,7 @@ fn main() { let mut msg = String::new(); let _ = writeln!(&mut msg, "test"); //~^ ERROR calls to `std::mem::drop` + + let _ = format_args!("a"); + //~^ ERROR calls to `std::mem::drop` } diff --git a/tests/ui/lint/dropping_copy_types-macros.rs b/tests/ui/lint/dropping_copy_types-macros.rs index b249b0c868f37..2272e0e8560d1 100644 --- a/tests/ui/lint/dropping_copy_types-macros.rs +++ b/tests/ui/lint/dropping_copy_types-macros.rs @@ -9,4 +9,7 @@ fn main() { let mut msg = String::new(); drop(writeln!(&mut msg, "test")); //~^ ERROR calls to `std::mem::drop` + + drop(format_args!("a")); + //~^ ERROR calls to `std::mem::drop` } diff --git a/tests/ui/lint/dropping_copy_types-macros.stderr b/tests/ui/lint/dropping_copy_types-macros.stderr index 117e9f4fe099c..5048f6e3f18bf 100644 --- a/tests/ui/lint/dropping_copy_types-macros.stderr +++ b/tests/ui/lint/dropping_copy_types-macros.stderr @@ -17,5 +17,19 @@ LL - drop(writeln!(&mut msg, "test")); LL + let _ = writeln!(&mut msg, "test"); | -error: aborting due to 1 previous error +error: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types-macros.rs:13:5 + | +LL | drop(format_args!("a")); + | ^^^^^-----------------^ + | | + | argument has type `Arguments<'_>` + | +help: use `let _ = ...` to ignore the expression or result + | +LL - drop(format_args!("a")); +LL + let _ = format_args!("a"); + | + +error: aborting due to 2 previous errors From f39085bb372f00b5b6849001e947727c9dc77ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 4 Aug 2025 17:22:46 +0200 Subject: [PATCH 231/252] Add `derive_from` unstable feature --- compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 87ecc7b41e213..07f928b8c8824 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -470,6 +470,8 @@ declare_features! ( (unstable, deprecated_suggestion, "1.61.0", Some(94785)), /// Allows deref patterns. (incomplete, deref_patterns, "1.79.0", Some(87121)), + /// Allows deriving the From trait on single-field structs. + (unstable, derive_from, "CURRENT_RUSTC_VERSION", Some(144889)), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. (unstable, doc_auto_cfg, "1.58.0", Some(43781)), /// Allows `#[doc(cfg(...))]`. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 416ce27367e5e..16db57da86eeb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -846,6 +846,7 @@ symbols! { derive_const, derive_const_issue: "118304", derive_default_enum, + derive_from, derive_smart_pointer, destruct, destructuring_assignment, From e935a155c2078185f0705bb972a38953e770e393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 4 Aug 2025 17:24:18 +0200 Subject: [PATCH 232/252] Create unstable `From` builtin macro and register it --- compiler/rustc_builtin_macros/src/deriving/from.rs | 13 +++++++++++++ compiler/rustc_builtin_macros/src/deriving/mod.rs | 1 + compiler/rustc_builtin_macros/src/lib.rs | 1 + library/core/src/macros/mod.rs | 11 +++++++++++ library/core/src/prelude/v1.rs | 7 +++++++ 5 files changed, 33 insertions(+) create mode 100644 compiler/rustc_builtin_macros/src/deriving/from.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs new file mode 100644 index 0000000000000..79fd4caa4403a --- /dev/null +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -0,0 +1,13 @@ +use rustc_ast as ast; +use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_span::{Span, sym}; + +pub(crate) fn expand_deriving_from( + cx: &ExtCtxt<'_>, + span: Span, + mitem: &ast::MetaItem, + item: &Annotatable, + push: &mut dyn FnMut(Annotatable), + is_const: bool, +) { +} diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 1edc2965deffa..cee6952fa3460 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -23,6 +23,7 @@ pub(crate) mod clone; pub(crate) mod coerce_pointee; pub(crate) mod debug; pub(crate) mod default; +pub(crate) mod from; pub(crate) mod hash; #[path = "cmp/eq.rs"] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 7bc448a9acb8b..86a4927f3903f 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -139,6 +139,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { PartialEq: partial_eq::expand_deriving_partial_eq, PartialOrd: partial_ord::expand_deriving_partial_ord, CoercePointee: coerce_pointee::expand_deriving_coerce_pointee, + From: from::expand_deriving_from, } let client = rustc_proc_macro::bridge::client::Client::expand1(rustc_proc_macro::quote); diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index db8b527d59312..dea459e83bcef 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1768,4 +1768,15 @@ pub(crate) mod builtin { pub macro deref($pat:pat) { builtin # deref($pat) } + + /// Derive macro generating an impl of the trait `From`. + /// Currently, it can only be used on single-field structs. + // Note that the macro is in a different module than the `From` trait, + // to avoid triggering an unstable feature being used if someone imports + // `std::convert::From`. + #[rustc_builtin_macro] + #[unstable(feature = "derive_from", issue = "144889")] + pub macro From($item: item) { + /* compiler built-in */ + } } diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index a4be66b90cab3..d8d82afb0e625 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -117,3 +117,10 @@ pub use crate::macros::builtin::deref; reason = "`type_alias_impl_trait` has open design concerns" )] pub use crate::macros::builtin::define_opaque; + +#[unstable( + feature = "derive_from", + issue = "144889", + reason = "`derive(From)` is unstable" +)] +pub use crate::macros::builtin::From; From c0839ea7d242f077cec567af1e4489951efb6570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 4 Aug 2025 17:32:22 +0200 Subject: [PATCH 233/252] Add feature gate test --- tests/ui/feature-gates/feature-gate-derive-from.rs | 6 ++++++ .../feature-gates/feature-gate-derive-from.stderr | 13 +++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 tests/ui/feature-gates/feature-gate-derive-from.rs create mode 100644 tests/ui/feature-gates/feature-gate-derive-from.stderr diff --git a/tests/ui/feature-gates/feature-gate-derive-from.rs b/tests/ui/feature-gates/feature-gate-derive-from.rs new file mode 100644 index 0000000000000..12440356ddf25 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-derive-from.rs @@ -0,0 +1,6 @@ +//@ edition: 2021 + +#[derive(From)] //~ ERROR use of unstable library feature `derive_from` +struct Foo(u32); + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-derive-from.stderr b/tests/ui/feature-gates/feature-gate-derive-from.stderr new file mode 100644 index 0000000000000..d58dcdd754111 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-derive-from.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `derive_from` + --> $DIR/feature-gate-derive-from.rs:3:10 + | +LL | #[derive(From)] + | ^^^^ + | + = note: see issue #144889 for more information + = help: add `#![feature(derive_from)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 1f3a7471bfb05a5fd76309545de0412d265e28be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 12:07:15 +0200 Subject: [PATCH 234/252] Implement `#[derive(From)]` --- compiler/rustc_builtin_macros/messages.ftl | 9 ++ .../rustc_builtin_macros/src/deriving/from.rs | 125 ++++++++++++++- .../src/deriving/generic/ty.rs | 11 +- compiler/rustc_builtin_macros/src/errors.rs | 18 +++ compiler/rustc_span/src/symbol.rs | 3 + tests/ui/deriving/deriving-all-codegen.rs | 11 +- tests/ui/deriving/deriving-all-codegen.stdout | 148 ++++++++++++++++++ .../ui/deriving/deriving-from-wrong-target.rs | 38 +++++ .../deriving-from-wrong-target.stderr | 115 ++++++++++++++ tests/ui/deriving/deriving-from.rs | 58 +++++++ 10 files changed, 530 insertions(+), 6 deletions(-) create mode 100644 tests/ui/deriving/deriving-from-wrong-target.rs create mode 100644 tests/ui/deriving/deriving-from-wrong-target.stderr create mode 100644 tests/ui/deriving/deriving-from.rs diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index eb3c40cc593d3..358c0d3db460f 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -222,6 +222,15 @@ builtin_macros_format_unused_args = multiple unused formatting arguments builtin_macros_format_use_positional = consider using a positional formatting argument instead +builtin_macros_derive_from_wrong_target = `#[derive(From)]` used on {$kind} + +builtin_macros_derive_from_wrong_field_count = `#[derive(From)]` used on a struct with {$multiple_fields -> + [true] multiple fields + *[false] no fields +} + +builtin_macros_derive_from_usage_note = `#[derive(From)]` can only be used on structs with exactly one field + builtin_macros_multiple_default_attrs = multiple `#[default]` attributes .note = only one `#[default]` attribute is needed .label = `#[default]` used here diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index 79fd4caa4403a..ef0e6ca324a32 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -1,13 +1,132 @@ use rustc_ast as ast; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::{Span, sym}; +use rustc_ast::{ItemKind, VariantData}; +use rustc_errors::MultiSpan; +use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; +use rustc_span::{Ident, Span, kw, sym}; +use thin_vec::thin_vec; +use crate::deriving::generic::ty::{Bounds, Path, PathKind, Ty}; +use crate::deriving::generic::{ + BlockOrExpr, FieldlessVariantsStrategy, MethodDef, SubstructureFields, TraitDef, + combine_substructure, +}; +use crate::deriving::pathvec_std; +use crate::errors; + +/// Generate an implementation of the `From` trait, provided that `item` +/// is a struct or a tuple struct with exactly one field. pub(crate) fn expand_deriving_from( cx: &ExtCtxt<'_>, span: Span, mitem: &ast::MetaItem, - item: &Annotatable, + annotatable: &Annotatable, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { + let Annotatable::Item(item) = &annotatable else { + cx.dcx().bug("derive(From) used on something else than an item"); + }; + + // #[derive(From)] is currently usable only on structs with exactly one field. + let field = if let ItemKind::Struct(_, _, data) = &item.kind + && let [field] = data.fields() + { + Some(field.clone()) + } else { + None + }; + + let from_type = match &field { + Some(field) => Ty::AstTy(field.ty.clone()), + // We don't have a type to put into From<...> if we don't have a single field, so just put + // unit there. + None => Ty::Unit, + }; + let path = + Path::new_(pathvec_std!(convert::From), vec![Box::new(from_type.clone())], PathKind::Std); + + // Generate code like this: + // + // struct S(u32); + // #[automatically_derived] + // impl ::core::convert::From for S { + // #[inline] + // fn from(value: u32) -> S { + // Self(value) + // } + // } + let from_trait_def = TraitDef { + span, + path, + skip_path_as_bound: true, + needs_copy_as_bound_if_packed: false, + additional_bounds: Vec::new(), + supports_unions: false, + methods: vec![MethodDef { + name: sym::from, + generics: Bounds { bounds: vec![] }, + explicit_self: false, + nonself_args: vec![(from_type, sym::value)], + ret_ty: Ty::Self_, + attributes: thin_vec![cx.attr_word(sym::inline, span)], + fieldless_variants_strategy: FieldlessVariantsStrategy::Default, + combine_substructure: combine_substructure(Box::new(|cx, span, substructure| { + let Some(field) = &field else { + let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span); + let err_span = MultiSpan::from_spans(vec![span, item_span]); + let error = match &item.kind { + ItemKind::Struct(_, _, data) => { + cx.dcx().emit_err(errors::DeriveFromWrongFieldCount { + span: err_span, + multiple_fields: data.fields().len() > 1, + }) + } + ItemKind::Enum(_, _, _) | ItemKind::Union(_, _, _) => { + cx.dcx().emit_err(errors::DeriveFromWrongTarget { + span: err_span, + kind: &format!("{} {}", item.kind.article(), item.kind.descr()), + }) + } + _ => cx.dcx().bug("Invalid derive(From) ADT input"), + }; + + return BlockOrExpr::new_expr(DummyResult::raw_expr(span, Some(error))); + }; + + let self_kw = Ident::new(kw::SelfUpper, span); + let expr: Box = match substructure.fields { + SubstructureFields::StaticStruct(variant, _) => match variant { + // Self { + // field: value + // } + VariantData::Struct { .. } => cx.expr_struct_ident( + span, + self_kw, + thin_vec![cx.field_imm( + span, + field.ident.unwrap(), + cx.expr_ident(span, Ident::new(sym::value, span)) + )], + ), + // Self(value) + VariantData::Tuple(_, _) => cx.expr_call_ident( + span, + self_kw, + thin_vec![cx.expr_ident(span, Ident::new(sym::value, span))], + ), + variant => { + cx.dcx().bug(format!("Invalid derive(From) ADT variant: {variant:?}")); + } + }, + _ => cx.dcx().bug("Invalid derive(From) ADT input"), + }; + BlockOrExpr::new_expr(expr) + })), + }], + associated_types: Vec::new(), + is_const, + is_staged_api_crate: cx.ecfg.features.staged_api(), + }; + + from_trait_def.expand(cx, mitem, annotatable, push); } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index 00e70b21cf4f0..1458553d4925e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -2,7 +2,7 @@ //! when specifying impls to be derived. pub(crate) use Ty::*; -use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind}; +use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind, TyKind}; use rustc_expand::base::ExtCtxt; use rustc_span::source_map::respan; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw}; @@ -65,7 +65,7 @@ impl Path { } } -/// A type. Supports pointers, Self, and literals. +/// A type. Supports pointers, Self, literals, unit or an arbitrary AST path. #[derive(Clone)] pub(crate) enum Ty { Self_, @@ -76,6 +76,8 @@ pub(crate) enum Ty { Path(Path), /// For () return types. Unit, + /// An arbitrary type. + AstTy(Box), } pub(crate) fn self_ref() -> Ty { @@ -101,6 +103,7 @@ impl Ty { let ty = ast::TyKind::Tup(ThinVec::new()); cx.ty(span, ty) } + AstTy(ty) => ty.clone(), } } @@ -132,6 +135,10 @@ impl Ty { cx.path_all(span, false, vec![self_ty], params) } Path(p) => p.to_path(cx, span, self_ty, generics), + AstTy(ty) => match &ty.kind { + TyKind::Path(_, path) => path.clone(), + _ => cx.dcx().span_bug(span, "non-path in a path in generic `derive`"), + }, Ref(..) => cx.dcx().span_bug(span, "ref in a path in generic `derive`"), Unit => cx.dcx().span_bug(span, "unit in a path in generic `derive`"), } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index bb520db75b96c..54e8f7503377f 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -446,6 +446,24 @@ pub(crate) struct DefaultHasArg { pub(crate) span: Span, } +#[derive(Diagnostic)] +#[diag(builtin_macros_derive_from_wrong_target)] +#[note(builtin_macros_derive_from_usage_note)] +pub(crate) struct DeriveFromWrongTarget<'a> { + #[primary_span] + pub(crate) span: MultiSpan, + pub(crate) kind: &'a str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_derive_from_wrong_field_count)] +#[note(builtin_macros_derive_from_usage_note)] +pub(crate) struct DeriveFromWrongFieldCount { + #[primary_span] + pub(crate) span: MultiSpan, + pub(crate) multiple_fields: bool, +} + #[derive(Diagnostic)] #[diag(builtin_macros_derive_macro_call)] pub(crate) struct DeriveMacroCall { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 16db57da86eeb..153a5803bf3bc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -392,6 +392,7 @@ symbols! { __D, __H, __S, + __T, __awaitee, __try_var, _t, @@ -745,6 +746,7 @@ symbols! { contracts_ensures, contracts_internals, contracts_requires, + convert, convert_identity, copy, copy_closures, @@ -2331,6 +2333,7 @@ symbols! { va_start, val, validity, + value, values, var, variant_count, diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs index e2b6804fbd1d8..00a269ccb5cfa 100644 --- a/tests/ui/deriving/deriving-all-codegen.rs +++ b/tests/ui/deriving/deriving-all-codegen.rs @@ -16,6 +16,7 @@ #![crate_type = "lib"] #![allow(dead_code)] #![allow(deprecated)] +#![feature(derive_from)] // Empty struct. #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -38,6 +39,14 @@ struct PackedPoint { y: u32, } +#[derive(Clone, Copy, Debug, Default, From, Hash, PartialEq, Eq, PartialOrd, Ord)] +struct TupleSingleField(u32); + +#[derive(Clone, Copy, Debug, Default, From, Hash, PartialEq, Eq, PartialOrd, Ord)] +struct SingleField { + foo: bool, +} + // A large struct. Note: because this derives `Copy`, it gets the simple // `clone` implemention that just does `*self`. #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -86,7 +95,7 @@ struct PackedManualCopy(u32); impl Copy for PackedManualCopy {} // A struct with an unsized field. Some derives are not usable in this case. -#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, From, Hash, PartialEq, Eq, PartialOrd, Ord)] struct Unsized([u32]); trait Trait { diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 0e4bfa30257df..78b93f39b9ea1 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -17,6 +17,7 @@ #![crate_type = "lib"] #![allow(dead_code)] #![allow(deprecated)] +#![feature(derive_from)] #[macro_use] extern crate std; #[prelude_import] @@ -249,6 +250,148 @@ impl ::core::cmp::Ord for PackedPoint { } } +struct TupleSingleField(u32); +#[automatically_derived] +impl ::core::clone::Clone for TupleSingleField { + #[inline] + fn clone(&self) -> TupleSingleField { + let _: ::core::clone::AssertParamIsClone; + *self + } +} +#[automatically_derived] +impl ::core::marker::Copy for TupleSingleField { } +#[automatically_derived] +impl ::core::fmt::Debug for TupleSingleField { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_tuple_field1_finish(f, + "TupleSingleField", &&self.0) + } +} +#[automatically_derived] +impl ::core::default::Default for TupleSingleField { + #[inline] + fn default() -> TupleSingleField { + TupleSingleField(::core::default::Default::default()) + } +} +#[automatically_derived] +impl ::core::convert::From for TupleSingleField { + #[inline] + fn from(value: u32) -> TupleSingleField { Self(value) } +} +#[automatically_derived] +impl ::core::hash::Hash for TupleSingleField { + #[inline] + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&self.0, state) + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for TupleSingleField { } +#[automatically_derived] +impl ::core::cmp::PartialEq for TupleSingleField { + #[inline] + fn eq(&self, other: &TupleSingleField) -> bool { self.0 == other.0 } +} +#[automatically_derived] +impl ::core::cmp::Eq for TupleSingleField { + #[inline] + #[doc(hidden)] + #[coverage(off)] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq; + } +} +#[automatically_derived] +impl ::core::cmp::PartialOrd for TupleSingleField { + #[inline] + fn partial_cmp(&self, other: &TupleSingleField) + -> ::core::option::Option<::core::cmp::Ordering> { + ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) + } +} +#[automatically_derived] +impl ::core::cmp::Ord for TupleSingleField { + #[inline] + fn cmp(&self, other: &TupleSingleField) -> ::core::cmp::Ordering { + ::core::cmp::Ord::cmp(&self.0, &other.0) + } +} + +struct SingleField { + foo: bool, +} +#[automatically_derived] +impl ::core::clone::Clone for SingleField { + #[inline] + fn clone(&self) -> SingleField { + let _: ::core::clone::AssertParamIsClone; + *self + } +} +#[automatically_derived] +impl ::core::marker::Copy for SingleField { } +#[automatically_derived] +impl ::core::fmt::Debug for SingleField { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + ::core::fmt::Formatter::debug_struct_field1_finish(f, "SingleField", + "foo", &&self.foo) + } +} +#[automatically_derived] +impl ::core::default::Default for SingleField { + #[inline] + fn default() -> SingleField { + SingleField { foo: ::core::default::Default::default() } + } +} +#[automatically_derived] +impl ::core::convert::From for SingleField { + #[inline] + fn from(value: bool) -> SingleField { Self { foo: value } } +} +#[automatically_derived] +impl ::core::hash::Hash for SingleField { + #[inline] + fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { + ::core::hash::Hash::hash(&self.foo, state) + } +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for SingleField { } +#[automatically_derived] +impl ::core::cmp::PartialEq for SingleField { + #[inline] + fn eq(&self, other: &SingleField) -> bool { self.foo == other.foo } +} +#[automatically_derived] +impl ::core::cmp::Eq for SingleField { + #[inline] + #[doc(hidden)] + #[coverage(off)] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq; + } +} +#[automatically_derived] +impl ::core::cmp::PartialOrd for SingleField { + #[inline] + fn partial_cmp(&self, other: &SingleField) + -> ::core::option::Option<::core::cmp::Ordering> { + ::core::cmp::PartialOrd::partial_cmp(&self.foo, &other.foo) + } +} +#[automatically_derived] +impl ::core::cmp::Ord for SingleField { + #[inline] + fn cmp(&self, other: &SingleField) -> ::core::cmp::Ordering { + ::core::cmp::Ord::cmp(&self.foo, &other.foo) + } +} + // A large struct. Note: because this derives `Copy`, it gets the simple // `clone` implemention that just does `*self`. struct Big { @@ -572,6 +715,11 @@ impl ::core::fmt::Debug for Unsized { } } #[automatically_derived] +impl ::core::convert::From<[u32]> for Unsized { + #[inline] + fn from(value: [u32]) -> Unsized { Self(value) } +} +#[automatically_derived] impl ::core::hash::Hash for Unsized { #[inline] fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { diff --git a/tests/ui/deriving/deriving-from-wrong-target.rs b/tests/ui/deriving/deriving-from-wrong-target.rs new file mode 100644 index 0000000000000..57e009cae69eb --- /dev/null +++ b/tests/ui/deriving/deriving-from-wrong-target.rs @@ -0,0 +1,38 @@ +//@ edition: 2021 +//@ check-fail + +#![feature(derive_from)] +#![allow(dead_code)] + +#[derive(From)] +//~^ ERROR `#[derive(From)]` used on a struct with no fields +struct S1; + +#[derive(From)] +//~^ ERROR `#[derive(From)]` used on a struct with no fields +struct S2 {} + +#[derive(From)] +//~^ ERROR `#[derive(From)]` used on a struct with multiple fields +struct S3(u32, bool); + +#[derive(From)] +//~^ ERROR `#[derive(From)]` used on a struct with multiple fields +struct S4 { + a: u32, + b: bool, +} + +#[derive(From)] +//~^ ERROR `#[derive(From)]` used on an enum +enum E1 {} + +#[derive(From)] +//~^ ERROR the size for values of type `T` cannot be known at compilation time [E0277] +//~| ERROR the size for values of type `T` cannot be known at compilation time [E0277] +struct SUnsizedField { + last: T, + //~^ ERROR the size for values of type `T` cannot be known at compilation time [E0277] +} + +fn main() {} diff --git a/tests/ui/deriving/deriving-from-wrong-target.stderr b/tests/ui/deriving/deriving-from-wrong-target.stderr new file mode 100644 index 0000000000000..13593c95973e4 --- /dev/null +++ b/tests/ui/deriving/deriving-from-wrong-target.stderr @@ -0,0 +1,115 @@ +error: `#[derive(From)]` used on a struct with no fields + --> $DIR/deriving-from-wrong-target.rs:7:10 + | +LL | #[derive(From)] + | ^^^^ +LL | +LL | struct S1; + | ^^ + | + = note: `#[derive(From)]` can only be used on structs with exactly one field + +error: `#[derive(From)]` used on a struct with no fields + --> $DIR/deriving-from-wrong-target.rs:11:10 + | +LL | #[derive(From)] + | ^^^^ +LL | +LL | struct S2 {} + | ^^ + | + = note: `#[derive(From)]` can only be used on structs with exactly one field + +error: `#[derive(From)]` used on a struct with multiple fields + --> $DIR/deriving-from-wrong-target.rs:15:10 + | +LL | #[derive(From)] + | ^^^^ +LL | +LL | struct S3(u32, bool); + | ^^ + | + = note: `#[derive(From)]` can only be used on structs with exactly one field + +error: `#[derive(From)]` used on a struct with multiple fields + --> $DIR/deriving-from-wrong-target.rs:19:10 + | +LL | #[derive(From)] + | ^^^^ +LL | +LL | struct S4 { + | ^^ + | + = note: `#[derive(From)]` can only be used on structs with exactly one field + +error: `#[derive(From)]` used on an enum + --> $DIR/deriving-from-wrong-target.rs:26:10 + | +LL | #[derive(From)] + | ^^^^ +LL | +LL | enum E1 {} + | ^^ + | + = note: `#[derive(From)]` can only be used on structs with exactly one field + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/deriving-from-wrong-target.rs:30:10 + | +LL | #[derive(From)] + | ^^^^ doesn't have a size known at compile-time +... +LL | struct SUnsizedField { + | - this type parameter needs to be `Sized` + | +note: required by an implicit `Sized` bound in `From` + --> $SRC_DIR/core/src/convert/mod.rs:LL:COL +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - struct SUnsizedField { +LL + struct SUnsizedField { + | + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/deriving-from-wrong-target.rs:30:10 + | +LL | #[derive(From)] + | ^^^^ doesn't have a size known at compile-time +... +LL | struct SUnsizedField { + | - this type parameter needs to be `Sized` + | +note: required because it appears within the type `SUnsizedField` + --> $DIR/deriving-from-wrong-target.rs:33:8 + | +LL | struct SUnsizedField { + | ^^^^^^^^^^^^^ + = note: the return type of a function must have a statically known size +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - struct SUnsizedField { +LL + struct SUnsizedField { + | + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/deriving-from-wrong-target.rs:34:11 + | +LL | struct SUnsizedField { + | - this type parameter needs to be `Sized` +LL | last: T, + | ^ doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - struct SUnsizedField { +LL + struct SUnsizedField { + | +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | last: &T, + | + + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/deriving/deriving-from.rs b/tests/ui/deriving/deriving-from.rs new file mode 100644 index 0000000000000..ff4c5b4c426a6 --- /dev/null +++ b/tests/ui/deriving/deriving-from.rs @@ -0,0 +1,58 @@ +//@ edition: 2021 +//@ run-pass + +#![feature(derive_from)] + +#[derive(From)] +struct TupleSimple(u32); + +#[derive(From)] +struct TupleNonPathType([u32; 4]); + +#[derive(From)] +struct TupleWithRef<'a, T>(&'a T); + +#[derive(From)] +struct TupleSWithBound(T); + +#[derive(From)] +struct RawIdentifier { + r#use: u32, +} + +#[derive(From)] +struct Field { + foo: bool, +} + +#[derive(From)] +struct Const { + foo: [u32; C], +} + +fn main() { + let a = 42u32; + let b: [u32; 4] = [0, 1, 2, 3]; + let c = true; + + let s1: TupleSimple = a.into(); + assert_eq!(s1.0, a); + + let s2: TupleNonPathType = b.into(); + assert_eq!(s2.0, b); + + let s3: TupleWithRef = (&a).into(); + assert_eq!(s3.0, &a); + + let s4: TupleSWithBound = a.into(); + assert_eq!(s4.0, a); + + let s5: RawIdentifier = a.into(); + assert_eq!(s5.r#use, a); + + let s6: Field = c.into(); + assert_eq!(s6.foo, c); + + let s7: Const<4> = b.into(); + assert_eq!(s7.foo, b); +} From dbd5addf884158385782609405abb1161b827b15 Mon Sep 17 00:00:00 2001 From: AMS21 Date: Fri, 15 Aug 2025 11:32:22 +0200 Subject: [PATCH 235/252] Enhance UI test output handling for runtime errors When a UI test runs a compiled binary and an error/forbid pattern check fails, the failure message previously only showed compiler output, hiding the executed programs stdout/stderr. This makes it harder to see near-miss or unexpected runtime lines. --- src/tools/compiletest/src/runtest/ui.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index 0507c2600aed3..40b0ee0a399d4 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -10,6 +10,7 @@ use super::{ TestCx, TestOutput, Truncated, UI_FIXED, WillExecute, }; use crate::json; +use crate::runtest::ProcRes; impl TestCx<'_> { pub(super) fn run_ui_test(&self) { @@ -127,6 +128,9 @@ impl TestCx<'_> { ); } + // If the test is executed, capture its ProcRes separately so that + // pattern/forbid checks can report the *runtime* stdout/stderr when they fail. + let mut run_proc_res: Option = None; let output_to_check = if let WillExecute::Yes = should_run { let proc_res = self.exec_compiled_test(); let run_output_errors = if self.props.check_run_results { @@ -189,7 +193,10 @@ impl TestCx<'_> { unreachable!("run_ui_test() must not be called if the test should not run"); } - self.get_output(&proc_res) + let output = self.get_output(&proc_res); + // Move the proc_res into our option after we've extracted output. + run_proc_res = Some(proc_res); + output } else { self.get_output(&proc_res) }; @@ -200,9 +207,14 @@ impl TestCx<'_> { explicit, self.config.compare_mode, proc_res.status, self.props.error_patterns ); + // Compiler diagnostics (expected errors) are always tied to the compile-time ProcRes. self.check_expected_errors(&proc_res); - self.check_all_error_patterns(&output_to_check, &proc_res); - self.check_forbid_output(&output_to_check, &proc_res); + + // For runtime pattern/forbid checks prefer the executed program's ProcRes if available + // so that missing pattern failures include the program's stdout/stderr. + let pattern_proc_res = run_proc_res.as_ref().unwrap_or(&proc_res); + self.check_all_error_patterns(&output_to_check, pattern_proc_res); + self.check_forbid_output(&output_to_check, pattern_proc_res); if self.props.run_rustfix && self.config.compare_mode.is_none() { // And finally, compile the fixed code and make sure it both From f36ab498ceaf326b7b2ca0cd35a9131b94d5faba Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 15 Aug 2025 15:48:46 +0300 Subject: [PATCH 236/252] fix(tests/rmake/wasm-unexpected-features): change features from `WASM1` to `MVP` --- tests/run-make/wasm-unexpected-features/rmake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-make/wasm-unexpected-features/rmake.rs b/tests/run-make/wasm-unexpected-features/rmake.rs index 416b5ef4caa3d..01eff54e823c9 100644 --- a/tests/run-make/wasm-unexpected-features/rmake.rs +++ b/tests/run-make/wasm-unexpected-features/rmake.rs @@ -21,6 +21,6 @@ fn verify_features(path: &Path) { eprintln!("verify {path:?}"); let file = rfs::read(&path); - let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures::WASM1); + let mut validator = wasmparser::Validator::new_with_features(wasmparser::WasmFeatures::MVP); validator.validate_all(&file).unwrap(); } From 26817eec0520f30b8228990614ff2caa04811fcc Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 15 Aug 2025 21:34:58 +0800 Subject: [PATCH 237/252] Autolabel `src/tools/{rustfmt,rust-analyzer}` changes with `T-{rustfmt,rust-analyzer}` --- triagebot.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 6f6e95c5b50e9..497c4d020cd62 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -628,6 +628,16 @@ trigger_files = [ "src/ci", ] +[autolabel."T-rust-analyzer"] +trigger_files = [ + "src/tools/rust-analyzer", +] + +[autolabel."T-rustfmt"] +trigger_files = [ + "src/tools/rustfmt", +] + # ------------------------------------------------------------------------------ # Prioritization and team nominations # ------------------------------------------------------------------------------ From 33218a25c86e6acbb2db49105b63343097306d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 16:30:05 +0200 Subject: [PATCH 238/252] Remove duplicated tracing span in bootstrap --- src/bootstrap/src/core/build_steps/compile.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d860cafa1c0fd..0dff8c2bc323c 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2494,9 +2494,6 @@ pub fn stream_cargo( ) -> bool { let mut cmd = cargo.into_cmd(); - #[cfg(feature = "tracing")] - let _run_span = crate::utils::tracing::trace_cmd(&cmd); - // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. let mut message_format = if builder.config.json_output { From e9ce9ff498140ac257f35f163e9dfd52e96191cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 16:52:30 +0200 Subject: [PATCH 239/252] Fix tracing debug representation of steps without arguments in bootstrap --- src/bootstrap/src/core/builder/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 6226c81a3fdb7..ebbb19e9f87d2 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1839,9 +1839,14 @@ pub fn pretty_step_name() -> String { /// Renders `step` using its `Debug` implementation and extract the field arguments out of it. fn step_debug_args(step: &S) -> String { let step_dbg_repr = format!("{step:?}"); - let brace_start = step_dbg_repr.find('{').unwrap_or(0); - let brace_end = step_dbg_repr.rfind('}').unwrap_or(step_dbg_repr.len()); - step_dbg_repr[brace_start + 1..brace_end - 1].trim().to_string() + + // Some steps do not have any arguments, so they do not have the braces + match (step_dbg_repr.find('{'), step_dbg_repr.rfind('}')) { + (Some(brace_start), Some(brace_end)) => { + step_dbg_repr[brace_start + 1..brace_end - 1].trim().to_string() + } + _ => String::new(), + } } fn pretty_print_step(step: &S) -> String { From 24f5cc41c80a5ca22d5e6871aa71d1367bc15bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 16:58:20 +0200 Subject: [PATCH 240/252] Do not copy files in `copy_src_dirs` in dry run --- src/bootstrap/src/core/build_steps/dist.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 64c2cdd2ec795..414f4464d1edf 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -916,6 +916,12 @@ fn copy_src_dirs( exclude_dirs: &[&str], dst_dir: &Path, ) { + // Iterating, filtering and copying a large number of directories can be quite slow. + // Avoid doing it in dry run (and thus also tests). + if builder.config.dry_run() { + return; + } + fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool { let spath = match path.to_str() { Some(path) => path, From 5ee2224daa83c7d4337e50488f732808046ba0bc Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Fri, 15 Aug 2025 16:19:19 +0000 Subject: [PATCH 241/252] stabilize const exposed provenance --- library/core/src/ptr/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index b2607e453245a..be26e714e672c 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -974,7 +974,7 @@ pub const fn dangling_mut() -> *mut T { #[must_use] #[inline(always)] #[stable(feature = "exposed_provenance", since = "1.84.0")] -#[rustc_const_unstable(feature = "const_exposed_provenance", issue = "144538")] +#[rustc_const_stable(feature = "const_exposed_provenance", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead pub const fn with_exposed_provenance(addr: usize) -> *const T { @@ -1015,7 +1015,7 @@ pub const fn with_exposed_provenance(addr: usize) -> *const T { #[must_use] #[inline(always)] #[stable(feature = "exposed_provenance", since = "1.84.0")] -#[rustc_const_unstable(feature = "const_exposed_provenance", issue = "144538")] +#[rustc_const_stable(feature = "const_exposed_provenance", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead pub const fn with_exposed_provenance_mut(addr: usize) -> *mut T { From cd37ed50fadd0e932ac7c77c866683a546192f7a Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 15 Aug 2025 18:47:48 +0200 Subject: [PATCH 242/252] Enable new `[range-diff]` feature in triagebot --- triagebot.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 6f6e95c5b50e9..b1581f7400a26 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1589,3 +1589,8 @@ days-threshold = 28 # Documentation at: https://forge.rust-lang.org/triagebot/concern.html [concern] labels = ["S-waiting-on-concerns"] + +# Enable comments linking to triagebot range-diff when a PR is rebased +# onto a different base commit +# Documentation at: https://forge.rust-lang.org/triagebot/range-diff.html +[range-diff] From 77c3d6edfa30cf4c9dc010d96324f6f72579f36b Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 18 Aug 2025 09:37:50 +0530 Subject: [PATCH 243/252] remove default config --- src/bootstrap/src/core/config/config.rs | 1068 +++++++++++------------ src/bootstrap/src/core/config/mod.rs | 6 - src/bootstrap/src/core/download.rs | 71 +- 3 files changed, 563 insertions(+), 582 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 5eea54360238d..692c05456f69e 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -13,7 +13,6 @@ //! and the `bootstrap.toml` file—merging them, applying defaults, and performing //! cross-component validation. The main `parse_inner` function and its supporting //! helpers reside here, transforming raw `Toml` data into the structured `Config` type. - use std::cell::Cell; use std::collections::{BTreeSet, HashMap, HashSet}; use std::io::IsTerminal; @@ -48,7 +47,7 @@ use crate::core::config::toml::rust::{ use crate::core::config::toml::target::Target; use crate::core::config::{ DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo, - StringOrBool, set, threads_from_config, + StringOrBool, threads_from_config, }; use crate::core::download::{ DownloadContext, download_beta_toolchain, is_download_ci_available, maybe_download_rustfmt, @@ -463,35 +462,32 @@ impl Config { "flags.exclude" = ?flags_exclude ); - // First initialize the bare minimum that we need for further operation - source directory - // and execution context. - let mut config = Config::default_opts(); - let exec_ctx = ExecutionContext::new(flags_verbose, flags_cmd.fail_fast()); + // Set config values based on flags. - config.exec_ctx = exec_ctx; + let mut exec_ctx = ExecutionContext::new(flags_verbose, flags_cmd.fail_fast()); + exec_ctx.set_dry_run(if flags_dry_run { DryRun::UserSelected } else { DryRun::Disabled }); + let mut src = { + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + // Undo `src/bootstrap` + manifest_dir.parent().unwrap().parent().unwrap().to_owned() + }; - if let Some(src) = compute_src_directory(flags_src, &config.exec_ctx) { - config.src = src; + if let Some(src_) = compute_src_directory(flags_src, &exec_ctx) { + src = src_; } // Now load the TOML config, as soon as possible - let (mut toml, toml_path) = load_toml_config(&config.src, flags_config, &get_toml); - config.config = toml_path.clone(); - - postprocess_toml( - &mut toml, - &config.src, - toml_path, - config.exec_ctx(), - &flags_set, - &get_toml, - ); + let (mut toml, toml_path) = load_toml_config(&src, flags_config, &get_toml); + + let is_running_on_ci = flags_ci.unwrap_or(CiEnv::is_ci()); + + postprocess_toml(&mut toml, &src, toml_path.clone(), &exec_ctx, &flags_set, &get_toml); // Now override TOML values with flags, to make sure that we won't later override flags with // TOML values by accident instead, because flags have higher priority. let Build { description: build_description, - build: mut build_build, + build: build_build, host: build_host, target: build_target, build_dir: build_build_dir, @@ -538,7 +534,7 @@ impl Config { metrics: _, android_ndk: build_android_ndk, optimized_compiler_builtins: build_optimized_compiler_builtins, - jobs: mut build_jobs, + jobs: build_jobs, compiletest_diff_tool: build_compiletest_diff_tool, compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest, tidy_extra_checks: build_tidy_extra_checks, @@ -558,226 +554,179 @@ impl Config { } = toml.install.unwrap_or_default(); let Rust { - optimize: rust_optimize, + optimize: rust_optimize_, debug: rust_debug, - codegen_units: rust_codegen_units, - codegen_units_std: rust_codegen_units_std, + codegen_units: rust_codegen_units_, + codegen_units_std: rust_codegen_units_std_, rustc_debug_assertions: rust_rustc_debug_assertions, std_debug_assertions: rust_std_debug_assertions, tools_debug_assertions: rust_tools_debug_assertions, - overflow_checks: rust_overflow_checks, - overflow_checks_std: rust_overflow_checks_std, - debug_logging: rust_debug_logging, + overflow_checks: rust_overflow_checks_, + overflow_checks_std: rust_overflow_checks_std_, + debug_logging: rust_debug_logging_, debuginfo_level: rust_debuginfo_level, - debuginfo_level_rustc: rust_debuginfo_level_rustc, - debuginfo_level_std: rust_debuginfo_level_std, - debuginfo_level_tools: rust_debuginfo_level_tools, - debuginfo_level_tests: rust_debuginfo_level_tests, + debuginfo_level_rustc: rust_debuginfo_level_rustc_, + debuginfo_level_std: rust_debuginfo_level_std_, + debuginfo_level_tools: rust_debuginfo_level_tools_, + debuginfo_level_tests: rust_debuginfo_level_tests_, backtrace: rust_backtrace, incremental: rust_incremental, - randomize_layout: rust_randomize_layout, + randomize_layout: rust_randomize_layout_, default_linker: rust_default_linker, channel: rust_channel, musl_root: rust_musl_root, - rpath: rust_rpath, + rpath: rust_rpath_, verbose_tests: rust_verbose_tests, - optimize_tests: rust_optimize_tests, + optimize_tests: rust_optimize_tests_, codegen_tests: rust_codegen_tests, omit_git_hash: rust_omit_git_hash, - dist_src: rust_dist_src, + dist_src: rust_dist_src_, save_toolstates: rust_save_toolstates, - codegen_backends: rust_codegen_backends, + codegen_backends: rust_codegen_backends_, lld: rust_lld_enabled, llvm_tools: rust_llvm_tools, llvm_bitcode_linker: rust_llvm_bitcode_linker, deny_warnings: rust_deny_warnings, backtrace_on_ice: rust_backtrace_on_ice, - verify_llvm_ir: rust_verify_llvm_ir, - thin_lto_import_instr_limit: rust_thin_lto_import_instr_limit, - remap_debuginfo: rust_remap_debuginfo, + verify_llvm_ir: rust_verify_llvm_ir_, + thin_lto_import_instr_limit: rust_thin_lto_import_instr_limit_, + remap_debuginfo: rust_remap_debuginfo_, jemalloc: rust_jemalloc, test_compare_mode: rust_test_compare_mode, llvm_libunwind: rust_llvm_libunwind, control_flow_guard: rust_control_flow_guard, ehcont_guard: rust_ehcont_guard, - new_symbol_mangling: rust_new_symbol_mangling, - profile_generate: rust_profile_generate, - profile_use: rust_profile_use, + new_symbol_mangling: rust_new_symbol_mangling_, + profile_generate: rust_profile_generate_, + profile_use: rust_profile_use_, download_rustc: rust_download_rustc, - lto: rust_lto, - validate_mir_opts: rust_validate_mir_opts, - frame_pointers: rust_frame_pointers, - stack_protector: rust_stack_protector, - strip: rust_strip, + lto: rust_lto_, + validate_mir_opts: rust_validate_mir_opts_, + frame_pointers: rust_frame_pointers_, + stack_protector: rust_stack_protector_, + strip: rust_strip_, lld_mode: rust_lld_mode, - std_features: rust_std_features, + std_features: rust_std_features_, } = toml.rust.unwrap_or_default(); let Llvm { - optimize: llvm_optimize, - thin_lto: llvm_thin_lto, - release_debuginfo: llvm_release_debuginfo, - assertions: llvm_assertions, - tests: llvm_tests, - enzyme: llvm_enzyme, + optimize: llvm_optimize_, + thin_lto: llvm_thin_lto_, + release_debuginfo: llvm_release_debuginfo_, + assertions: llvm_assertions_, + tests: llvm_tests_, + enzyme: llvm_enzyme_, plugins: llvm_plugin, static_libstdcpp: llvm_static_libstdcpp, - libzstd: llvm_libzstd, + libzstd: llvm_libzstd_, ninja: llvm_ninja, - targets: llvm_targets, - experimental_targets: llvm_experimental_targets, - link_jobs: llvm_link_jobs, - link_shared: llvm_link_shared, - version_suffix: llvm_version_suffix, - clang_cl: llvm_clang_cl, - cflags: llvm_cflags, - cxxflags: llvm_cxxflags, - ldflags: llvm_ldflags, - use_libcxx: llvm_use_libcxx, - use_linker: llvm_use_linker, - allow_old_toolchain: llvm_allow_old_toolchain, - offload: llvm_offload, - polly: llvm_polly, - clang: llvm_clang, - enable_warnings: llvm_enable_warnings, + targets: llvm_targets_, + experimental_targets: llvm_experimental_targets_, + link_jobs: llvm_link_jobs_, + link_shared: llvm_link_shared_, + version_suffix: llvm_version_suffix_, + clang_cl: llvm_clang_cl_, + cflags: llvm_cflags_, + cxxflags: llvm_cxxflags_, + ldflags: llvm_ldflags_, + use_libcxx: llvm_use_libcxx_, + use_linker: llvm_use_linker_, + allow_old_toolchain: llvm_allow_old_toolchain_, + offload: llvm_offload_, + polly: llvm_polly_, + clang: llvm_clang_, + enable_warnings: llvm_enable_warnings_, download_ci_llvm: llvm_download_ci_llvm, - build_config: llvm_build_config, + build_config: llvm_build_config_, } = toml.llvm.unwrap_or_default(); let Dist { - sign_folder: dist_sign_folder, - upload_addr: dist_upload_addr, - src_tarball: dist_src_tarball, - compression_formats: dist_compression_formats, - compression_profile: dist_compression_profile, - include_mingw_linker: dist_include_mingw_linker, - vendor: dist_vendor, + sign_folder: dist_sign_folder_, + upload_addr: dist_upload_addr_, + src_tarball: dist_src_tarball_, + compression_formats: dist_compression_formats_, + compression_profile: dist_compression_profile_, + include_mingw_linker: dist_include_mingw_linker_, + vendor: dist_vendor_, } = toml.dist.unwrap_or_default(); let Gcc { download_ci_gcc: gcc_download_ci_gcc } = toml.gcc.unwrap_or_default(); - if cfg!(test) { - // When configuring bootstrap for tests, make sure to set the rustc and Cargo to the - // same ones used to call the tests (if custom ones are not defined in the toml). If we - // don't do that, bootstrap will use its own detection logic to find a suitable rustc - // and Cargo, which doesn't work when the caller is specìfying a custom local rustc or - // Cargo in their bootstrap.toml. - build_rustc = build_rustc.take().or(std::env::var_os("RUSTC").map(|p| p.into())); - build_cargo = build_cargo.take().or(std::env::var_os("CARGO").map(|p| p.into())); - } - - build_jobs = flags_jobs.or(build_jobs); - build_build = flags_build.or(build_build); - - let build_dir = flags_build_dir.or(build_build_dir.map(PathBuf::from)); - let host = if let Some(TargetSelectionList(hosts)) = flags_host { - Some(hosts) - } else { - build_host - .map(|file_host| file_host.iter().map(|h| TargetSelection::from_user(h)).collect()) - }; - let target = if let Some(TargetSelectionList(targets)) = flags_target { - Some(targets) - } else { - build_target.map(|file_target| { - file_target.iter().map(|h| TargetSelection::from_user(h)).collect() - }) - }; - - if let Some(rustc) = &build_rustc - && !flags_skip_stage0_validation - { - check_stage0_version(rustc, "rustc", &config.src, config.exec_ctx()); - } - if let Some(cargo) = &build_cargo - && !flags_skip_stage0_validation - { - check_stage0_version(cargo, "cargo", &config.src, config.exec_ctx()); + if rust_optimize_.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { + eprintln!( + "WARNING: setting `optimize` to `false` is known to cause errors and \ + should be considered unsupported. Refer to `bootstrap.example.toml` \ + for more details." + ); } // Prefer CLI verbosity flags if set (`flags_verbose` > 0), otherwise take the value from // TOML. - config - .exec_ctx - .set_verbosity(cmp::max(build_verbose.unwrap_or_default() as u8, flags_verbose)); + exec_ctx.set_verbosity(cmp::max(build_verbose.unwrap_or_default() as u8, flags_verbose)); + + let stage0_metadata = build_helper::stage0_parser::parse_stage0_file(); + let bootstrap_cache_path = build_bootstrap_cache_path; + let patch_binaries_for_nix = build_patch_binaries_for_nix; + + let path_modification_cache = Arc::new(Mutex::new(HashMap::new())); + + let host_target = flags_build + .or(build_build) + .map(|build| TargetSelection::from_user(&build)) + .unwrap_or_else(get_host_target); + let hosts = flags_host + .map(|TargetSelectionList(hosts)| hosts) + .or_else(|| { + build_host.map(|h| h.iter().map(|t| TargetSelection::from_user(t)).collect()) + }) + .unwrap_or_else(|| vec![host_target]); - let mut paths: Vec = flags_skip.into_iter().chain(flags_exclude).collect(); - if let Some(exclude) = build_exclude { - paths.extend(exclude); - } + let submodules = build_submodules; + let llvm_assertions = llvm_assertions_.unwrap_or(false); - // Set config values based on flags. - config.paths = flags_paths; - config.include_default_paths = flags_include_default_paths; - config.rustc_error_format = flags_rustc_error_format; - config.json_output = flags_json_output; - config.compile_time_deps = flags_compile_time_deps; - config.on_fail = flags_on_fail; - config.cmd = flags_cmd; - config.incremental = flags_incremental; - config.set_dry_run(if flags_dry_run { DryRun::UserSelected } else { DryRun::Disabled }); - config.dump_bootstrap_shims = flags_dump_bootstrap_shims; - config.keep_stage = flags_keep_stage; - config.keep_stage_std = flags_keep_stage_std; - config.color = flags_color; - config.free_args = flags_free_args; - config.llvm_profile_use = flags_llvm_profile_use; - config.llvm_profile_generate = flags_llvm_profile_generate; - config.enable_bolt_settings = flags_enable_bolt_settings; - config.bypass_bootstrap_lock = flags_bypass_bootstrap_lock; - config.is_running_on_ci = flags_ci.unwrap_or(CiEnv::is_ci()); - config.skip_std_check_if_no_download_rustc = flags_skip_std_check_if_no_download_rustc; - - // Infer the rest of the configuration. + let mut target_config = HashMap::new(); + let mut download_rustc_commit = None; + let llvm_link_shared = Cell::default(); + let mut llvm_from_ci = false; + let mut channel = "dev".to_string(); + let mut out = flags_build_dir + .or(build_build_dir.map(PathBuf::from)) + .unwrap_or_else(|| PathBuf::from("build")); + let mut rust_info = GitInfo::Absent; if cfg!(test) { // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly. - config.out = Path::new( - &env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"), - ) - .parent() - .unwrap() - .to_path_buf(); - } - - config.compiletest_allow_stage0 = build_compiletest_allow_stage0.unwrap_or(false); - config.stage0_metadata = build_helper::stage0_parser::parse_stage0_file(); - - config.change_id = toml.change_id.inner; - - config.skip = paths - .into_iter() - .map(|p| { - // Never return top-level path here as it would break `--skip` - // logic on rustc's internal test framework which is utilized - // by compiletest. - if cfg!(windows) { - PathBuf::from(p.to_str().unwrap().replace('/', "\\")) - } else { - p - } - }) - .collect(); - - #[cfg(feature = "tracing")] - span!( - target: "CONFIG_HANDLING", - tracing::Level::TRACE, - "normalizing and combining `flag.skip`/`flag.exclude` paths", - "config.skip" = ?config.skip, - ); - - config.jobs = Some(threads_from_config(build_jobs.unwrap_or(0))); - if let Some(build) = build_build { - config.host_target = TargetSelection::from_user(&build); + if out == PathBuf::from("build") { + out = Path::new( + &env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"), + ) + .parent() + .unwrap() + .to_path_buf(); + } + // When configuring bootstrap for tests, make sure to set the rustc and Cargo to the + // same ones used to call the tests (if custom ones are not defined in the toml). If we + // don't do that, bootstrap will use its own detection logic to find a suitable rustc + // and Cargo, which doesn't work when the caller is specìfying a custom local rustc or + // Cargo in their bootstrap.toml. + build_rustc = build_rustc.take().or(std::env::var_os("RUSTC").map(|p| p.into())); + build_cargo = build_cargo.take().or(std::env::var_os("CARGO").map(|p| p.into())); } - set(&mut config.out, build_dir); // NOTE: Bootstrap spawns various commands with different working directories. // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. - if !config.out.is_absolute() { + if !out.is_absolute() { // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead. - config.out = absolute(&config.out).expect("can't make empty path absolute"); + out = absolute(&out).expect("can't make empty path absolute"); + } + + if !flags_skip_stage0_validation { + if let Some(rustc) = &build_rustc { + check_stage0_version(rustc, "rustc", &src, &exec_ctx); + } + if let Some(cargo) = &build_cargo { + check_stage0_version(cargo, "cargo", &src, &exec_ctx); + } } if build_cargo_clippy.is_some() && build_rustc.is_none() { @@ -786,146 +735,74 @@ impl Config { ); } - config.initial_rustc = if let Some(rustc) = build_rustc { - rustc - } else { - let dwn_ctx = DownloadContext::from(&config); - download_beta_toolchain(dwn_ctx); - config - .out - .join(config.host_target) - .join("stage0") - .join("bin") - .join(exe("rustc", config.host_target)) - }; + let mut dwn_ctx = DownloadContext::new( + path_modification_cache.clone(), + &src, + rust_info.clone(), + &submodules, + download_rustc_commit.clone(), + host_target, + llvm_from_ci, + target_config.clone(), + out.clone(), + patch_binaries_for_nix, + &exec_ctx, + &stage0_metadata, + llvm_assertions, + &bootstrap_cache_path, + is_running_on_ci, + ); + + let initial_rustc = build_rustc.unwrap_or_else(|| { + download_beta_toolchain(&dwn_ctx); + out.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target)) + }); - config.initial_sysroot = t!(PathBuf::from_str( - command(&config.initial_rustc) + let initial_sysroot = t!(PathBuf::from_str( + command(&initial_rustc) .args(["--print", "sysroot"]) .run_in_dry_run() - .run_capture_stdout(&config) + .run_capture_stdout(&exec_ctx) .stdout() .trim() )); - config.initial_cargo_clippy = build_cargo_clippy; - - config.initial_cargo = if let Some(cargo) = build_cargo { - cargo - } else { - let dwn_ctx = DownloadContext::from(&config); - download_beta_toolchain(dwn_ctx); - config.initial_sysroot.join("bin").join(exe("cargo", config.host_target)) - }; + let initial_cargo = build_cargo.unwrap_or_else(|| { + download_beta_toolchain(&mut dwn_ctx); + initial_sysroot.join("bin").join(exe("cargo", host_target)) + }); // NOTE: it's important this comes *after* we set `initial_rustc` just above. - if config.dry_run() { - let dir = config.out.join("tmp-dry-run"); - t!(fs::create_dir_all(&dir)); - config.out = dir; + if exec_ctx.dry_run() { + out = out.join("tmp-dry-run"); + fs::create_dir_all(&out).expect("Failed to create dry-run directory"); + dwn_ctx.out = out.clone(); } - config.hosts = if let Some(hosts) = host { hosts } else { vec![config.host_target] }; - config.targets = if let Some(targets) = target { - targets - } else { - // If target is *not* configured, then default to the host - // toolchains. - config.hosts.clone() - }; - - config.nodejs = build_nodejs.map(PathBuf::from); - config.npm = build_npm.map(PathBuf::from); - config.gdb = build_gdb.map(PathBuf::from); - config.lldb = build_lldb.map(PathBuf::from); - config.python = build_python.map(PathBuf::from); - config.reuse = build_reuse.map(PathBuf::from); - config.submodules = build_submodules; - config.android_ndk = build_android_ndk; - config.bootstrap_cache_path = build_bootstrap_cache_path; - set(&mut config.low_priority, build_low_priority); - set(&mut config.compiler_docs, build_compiler_docs); - set(&mut config.library_docs_private_items, build_library_docs_private_items); - set(&mut config.docs_minification, build_docs_minification); - set(&mut config.docs, build_docs); - set(&mut config.locked_deps, build_locked_deps); - set(&mut config.full_bootstrap, build_full_bootstrap); - set(&mut config.extended, build_extended); - config.tools = build_tools; - set(&mut config.tool, build_tool); - set(&mut config.sanitizers, build_sanitizers); - set(&mut config.profiler, build_profiler); - set(&mut config.cargo_native_static, build_cargo_native_static); - set(&mut config.configure_args, build_configure_args); - set(&mut config.local_rebuild, build_local_rebuild); - set(&mut config.print_step_timings, build_print_step_timings); - set(&mut config.print_step_rusage, build_print_step_rusage); - config.patch_binaries_for_nix = build_patch_binaries_for_nix; - - // Verbose flag is a good default for `rust.verbose-tests`. - config.verbose_tests = config.is_verbose(); - - config.prefix = install_prefix.map(PathBuf::from); - config.sysconfdir = install_sysconfdir.map(PathBuf::from); - config.datadir = install_datadir.map(PathBuf::from); - config.docdir = install_docdir.map(PathBuf::from); - set(&mut config.bindir, install_bindir.map(PathBuf::from)); - config.libdir = install_libdir.map(PathBuf::from); - config.mandir = install_mandir.map(PathBuf::from); - - config.llvm_assertions = llvm_assertions.unwrap_or(false); - - let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel"))); + let file_content = t!(fs::read_to_string(src.join("src/ci/channel"))); let ci_channel = file_content.trim_end(); let is_user_configured_rust_channel = match rust_channel { - Some(channel) if channel == "auto-detect" => { - config.channel = ci_channel.into(); + Some(channel_) if channel_ == "auto-detect" => { + channel = ci_channel.into(); true } - Some(channel) => { - config.channel = channel; + Some(channel_) => { + channel = channel_; true } None => false, }; - let default = config.channel == "dev"; - config.omit_git_hash = rust_omit_git_hash.unwrap_or(default); + let omit_git_hash = rust_omit_git_hash.unwrap_or(channel == "dev"); - config.rust_info = git_info(&config.exec_ctx, config.omit_git_hash, &config.src); - config.cargo_info = - git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/cargo")); - config.rust_analyzer_info = git_info( - &config.exec_ctx, - config.omit_git_hash, - &config.src.join("src/tools/rust-analyzer"), - ); - config.clippy_info = - git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/clippy")); - config.miri_info = - git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/miri")); - config.rustfmt_info = - git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/rustfmt")); - config.enzyme_info = - git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/enzyme")); - config.in_tree_llvm_info = - git_info(&config.exec_ctx, false, &config.src.join("src/llvm-project")); - config.in_tree_gcc_info = git_info(&config.exec_ctx, false, &config.src.join("src/gcc")); - - config.vendor = build_vendor.unwrap_or( - config.rust_info.is_from_tarball() - && config.src.join("vendor").exists() - && config.src.join(".cargo/config.toml").exists(), - ); + rust_info = git_info(&exec_ctx, omit_git_hash, &src); + dwn_ctx.rust_info = rust_info.clone(); - if !is_user_configured_rust_channel && config.rust_info.is_from_tarball() { - config.channel = ci_channel.into(); + if !is_user_configured_rust_channel && rust_info.is_from_tarball() { + channel = ci_channel.into(); } - config.rust_profile_use = flags_rust_profile_use; - config.rust_profile_generate = flags_rust_profile_generate; - // FIXME(#133381): alt rustc builds currently do *not* have rustc debug assertions // enabled. We should not download a CI alt rustc if we need rustc to have debug // assertions (e.g. for crashes test suite). This can be changed once something like @@ -951,17 +828,35 @@ impl Config { ); } - let dwn_ctx = DownloadContext::from(&config); - config.download_rustc_commit = - download_ci_rustc_commit(dwn_ctx, rust_download_rustc, config.llvm_assertions); + download_rustc_commit = + download_ci_rustc_commit(&dwn_ctx, rust_download_rustc, llvm_assertions); + dwn_ctx.download_rustc_commit = download_rustc_commit.clone(); - if debug_assertions_requested && config.download_rustc_commit.is_some() { + if debug_assertions_requested && download_rustc_commit.is_some() { eprintln!( "WARN: `rust.debug-assertions = true` will prevent downloading CI rustc as alt CI \ rustc is not currently built with debug assertions." ); // We need to put this later down_ci_rustc_commit. - config.download_rustc_commit = None; + download_rustc_commit = None; + dwn_ctx.download_rustc_commit = None; + } + + // We need to override `rust.channel` if it's manually specified when using the CI rustc. + // This is because if the compiler uses a different channel than the one specified in bootstrap.toml, + // tests may fail due to using a different channel than the one used by the compiler during tests. + if let Some(commit) = &download_rustc_commit + && is_user_configured_rust_channel + { + println!( + "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel." + ); + + let channel_ = read_file_by_commit(&dwn_ctx, Path::new("src/ci/channel"), commit) + .trim() + .to_owned(); + + channel = channel_; } if let Some(t) = toml.target { @@ -969,24 +864,22 @@ impl Config { let mut target = Target::from_triple(&triple); if let Some(ref s) = cfg.llvm_config { - if config.download_rustc_commit.is_some() - && triple == *config.host_target.triple - { + if download_rustc_commit.is_some() && triple == *host_target.triple { panic!( "setting llvm_config for the host is incompatible with download-rustc" ); } - target.llvm_config = Some(config.src.join(s)); + target.llvm_config = Some(src.join(s)); } if let Some(patches) = cfg.llvm_has_rust_patches { assert!( - config.submodules == Some(false) || cfg.llvm_config.is_some(), + submodules == Some(false) || cfg.llvm_config.is_some(), "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided" ); target.llvm_has_rust_patches = Some(patches); } if let Some(ref s) = cfg.llvm_filecheck { - target.llvm_filecheck = Some(config.src.join(s)); + target.llvm_filecheck = Some(src.join(s)); } target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| { v.parse().unwrap_or_else(|_| { @@ -1023,82 +916,11 @@ impl Config { }) }); - config.target_config.insert(TargetSelection::from_user(&triple), target); + target_config.insert(TargetSelection::from_user(&triple), target); } + dwn_ctx.target_config = target_config.clone(); } - if rust_optimize.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { - eprintln!( - "WARNING: setting `optimize` to `false` is known to cause errors and \ - should be considered unsupported. Refer to `bootstrap.example.toml` \ - for more details." - ); - } - - config.rust_new_symbol_mangling = rust_new_symbol_mangling; - set(&mut config.rust_optimize_tests, rust_optimize_tests); - set(&mut config.codegen_tests, rust_codegen_tests); - set(&mut config.rust_rpath, rust_rpath); - set(&mut config.rust_strip, rust_strip); - set(&mut config.rust_frame_pointers, rust_frame_pointers); - config.rust_stack_protector = rust_stack_protector; - set(&mut config.jemalloc, rust_jemalloc); - set(&mut config.test_compare_mode, rust_test_compare_mode); - set(&mut config.backtrace, rust_backtrace); - set(&mut config.rust_dist_src, rust_dist_src); - set(&mut config.verbose_tests, rust_verbose_tests); - // in the case "false" is set explicitly, do not overwrite the command line args - if let Some(true) = rust_incremental { - config.incremental = true; - } - set(&mut config.lld_mode, rust_lld_mode); - set(&mut config.llvm_bitcode_linker_enabled, rust_llvm_bitcode_linker); - - config.rust_randomize_layout = rust_randomize_layout.unwrap_or_default(); - config.llvm_tools_enabled = rust_llvm_tools.unwrap_or(true); - - config.llvm_enzyme = config.channel == "dev" || config.channel == "nightly"; - config.rustc_default_linker = rust_default_linker; - config.musl_root = rust_musl_root.map(PathBuf::from); - config.save_toolstates = rust_save_toolstates.map(PathBuf::from); - set( - &mut config.deny_warnings, - match flags_warnings { - Warnings::Deny => Some(true), - Warnings::Warn => Some(false), - Warnings::Default => rust_deny_warnings, - }, - ); - set(&mut config.backtrace_on_ice, rust_backtrace_on_ice); - set(&mut config.rust_verify_llvm_ir, rust_verify_llvm_ir); - config.rust_thin_lto_import_instr_limit = rust_thin_lto_import_instr_limit; - set(&mut config.rust_remap_debuginfo, rust_remap_debuginfo); - set(&mut config.control_flow_guard, rust_control_flow_guard); - set(&mut config.ehcont_guard, rust_ehcont_guard); - config.llvm_libunwind_default = - rust_llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); - set( - &mut config.rust_codegen_backends, - rust_codegen_backends.map(|backends| parse_codegen_backends(backends, "rust")), - ); - - config.rust_codegen_units = rust_codegen_units.map(threads_from_config); - config.rust_codegen_units_std = rust_codegen_units_std.map(threads_from_config); - - if config.rust_profile_use.is_none() { - config.rust_profile_use = rust_profile_use; - } - - if config.rust_profile_generate.is_none() { - config.rust_profile_generate = rust_profile_generate; - } - - config.rust_lto = - rust_lto.as_deref().map(|value| RustcLto::from_str(value).unwrap()).unwrap_or_default(); - config.rust_validate_mir_opts = rust_validate_mir_opts; - - config.rust_optimize = rust_optimize.unwrap_or(RustOptimize::Bool(true)); - // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will // build our internal lld and use it as the default linker, by setting the `rust.lld` config // to true by default: @@ -1111,105 +933,24 @@ impl Config { // thus, disabled // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g. // when the config sets `rust.lld = false` - if default_lld_opt_in_targets().contains(&config.host_target.triple.to_string()) - && config.hosts == [config.host_target] + let lld_enabled = if default_lld_opt_in_targets().contains(&host_target.triple.to_string()) + && hosts == [host_target] { - let no_llvm_config = config - .target_config - .get(&config.host_target) - .is_none_or(|target_config| target_config.llvm_config.is_none()); - let enable_lld = config.llvm_from_ci || no_llvm_config; - // Prefer the config setting in case an explicit opt-out is needed. - config.lld_enabled = rust_lld_enabled.unwrap_or(enable_lld); + let no_llvm_config = + target_config.get(&host_target).map_or(true, |config| config.llvm_config.is_none()); + rust_lld_enabled.unwrap_or(llvm_from_ci || no_llvm_config) } else { - set(&mut config.lld_enabled, rust_lld_enabled); - } - - let default_std_features = BTreeSet::from([String::from("panic-unwind")]); - config.rust_std_features = rust_std_features.unwrap_or(default_std_features); - - let default = rust_debug == Some(true); - config.rustc_debug_assertions = rust_rustc_debug_assertions.unwrap_or(default); - config.std_debug_assertions = - rust_std_debug_assertions.unwrap_or(config.rustc_debug_assertions); - config.tools_debug_assertions = - rust_tools_debug_assertions.unwrap_or(config.rustc_debug_assertions); - config.rust_overflow_checks = rust_overflow_checks.unwrap_or(default); - config.rust_overflow_checks_std = - rust_overflow_checks_std.unwrap_or(config.rust_overflow_checks); - - config.rust_debug_logging = rust_debug_logging.unwrap_or(config.rustc_debug_assertions); - - let with_defaults = |debuginfo_level_specific: Option<_>| { - debuginfo_level_specific.or(rust_debuginfo_level).unwrap_or( - if rust_debug == Some(true) { - DebuginfoLevel::Limited - } else { - DebuginfoLevel::None - }, - ) + rust_lld_enabled.unwrap_or(false) }; - config.rust_debuginfo_level_rustc = with_defaults(rust_debuginfo_level_rustc); - config.rust_debuginfo_level_std = with_defaults(rust_debuginfo_level_std); - config.rust_debuginfo_level_tools = with_defaults(rust_debuginfo_level_tools); - config.rust_debuginfo_level_tests = - rust_debuginfo_level_tests.unwrap_or(DebuginfoLevel::None); - - config.reproducible_artifacts = flags_reproducible_artifact; - config.description = build_description; - - // We need to override `rust.channel` if it's manually specified when using the CI rustc. - // This is because if the compiler uses a different channel than the one specified in bootstrap.toml, - // tests may fail due to using a different channel than the one used by the compiler during tests. - if let Some(commit) = &config.download_rustc_commit - && is_user_configured_rust_channel - { - println!( - "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel." - ); - let dwn_ctx = DownloadContext::from(&config); - let channel = - read_file_by_commit(dwn_ctx, Path::new("src/ci/channel"), commit).trim().to_owned(); - - config.channel = channel; + if let Some(v) = llvm_link_shared_ { + llvm_link_shared.set(Some(v)); } - set(&mut config.ninja_in_file, llvm_ninja); - set(&mut config.llvm_optimize, llvm_optimize); - set(&mut config.llvm_thin_lto, llvm_thin_lto); - set(&mut config.llvm_release_debuginfo, llvm_release_debuginfo); - set(&mut config.llvm_static_stdcpp, llvm_static_libstdcpp); - set(&mut config.llvm_libzstd, llvm_libzstd); - if let Some(v) = llvm_link_shared { - config.llvm_link_shared.set(Some(v)); - } - config.llvm_targets.clone_from(&llvm_targets); - config.llvm_experimental_targets.clone_from(&llvm_experimental_targets); - config.llvm_link_jobs = llvm_link_jobs; - config.llvm_version_suffix.clone_from(&llvm_version_suffix); - config.llvm_clang_cl.clone_from(&llvm_clang_cl); - config.llvm_tests = llvm_tests.unwrap_or_default(); - config.llvm_enzyme = llvm_enzyme.unwrap_or_default(); - config.llvm_plugins = llvm_plugin.unwrap_or_default(); - - config.llvm_cflags.clone_from(&llvm_cflags); - config.llvm_cxxflags.clone_from(&llvm_cxxflags); - config.llvm_ldflags.clone_from(&llvm_ldflags); - set(&mut config.llvm_use_libcxx, llvm_use_libcxx); - config.llvm_use_linker.clone_from(&llvm_use_linker); - config.llvm_allow_old_toolchain = llvm_allow_old_toolchain.unwrap_or(false); - config.llvm_offload = llvm_offload.unwrap_or(false); - config.llvm_polly = llvm_polly.unwrap_or(false); - config.llvm_clang = llvm_clang.unwrap_or(false); - config.llvm_enable_warnings = llvm_enable_warnings.unwrap_or(false); - config.llvm_build_config = llvm_build_config.clone().unwrap_or(Default::default()); - - let dwn_ctx = DownloadContext::from(&config); - config.llvm_from_ci = - parse_download_ci_llvm(dwn_ctx, llvm_download_ci_llvm, config.llvm_assertions); - - if config.llvm_from_ci { + llvm_from_ci = parse_download_ci_llvm(&dwn_ctx, llvm_download_ci_llvm, llvm_assertions); + dwn_ctx.llvm_from_ci = llvm_from_ci; + + if llvm_from_ci { let warn = |option: &str| { println!( "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build." @@ -1223,7 +964,7 @@ impl Config { warn("static-libstdcpp"); } - if llvm_link_shared.is_some() { + if llvm_link_shared_.is_some() { warn("link-shared"); } @@ -1232,7 +973,7 @@ impl Config { // config to the ones used to build the LLVM artifacts on CI, and only notify users // if they've chosen a different value. - if llvm_libzstd.is_some() { + if llvm_libzstd_.is_some() { println!( "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \ like almost all `llvm.*` options, will be ignored and set by the LLVM CI \ @@ -1244,66 +985,30 @@ impl Config { } } - if !config.llvm_from_ci && config.llvm_thin_lto && llvm_link_shared.is_none() { + if !llvm_from_ci && llvm_thin_lto_.unwrap_or(false) && llvm_link_shared_.is_none() { // If we're building with ThinLTO on, by default we want to link // to LLVM shared, to avoid re-doing ThinLTO (which happens in // the link step) with each stage. - config.llvm_link_shared.set(Some(true)); - } - - config.gcc_ci_mode = match gcc_download_ci_gcc { - Some(value) => match value { - true => GccCiMode::DownloadFromCi, - false => GccCiMode::BuildLocally, - }, - None => GccCiMode::default(), - }; - - match build_ccache { - Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()), - Some(StringOrBool::Bool(true)) => { - config.ccache = Some("ccache".to_string()); - } - Some(StringOrBool::Bool(false)) | None => {} + llvm_link_shared.set(Some(true)); } - if config.llvm_from_ci { - let triple = &config.host_target.triple; - let dwn_ctx = DownloadContext::from(&config); - let ci_llvm_bin = ci_llvm_root(dwn_ctx).join("bin"); - let build_target = config - .target_config - .entry(config.host_target) - .or_insert_with(|| Target::from_triple(triple)); + if llvm_from_ci { + let triple = &host_target.triple; + let ci_llvm_bin = ci_llvm_root(&dwn_ctx).join("bin"); + let build_target = + target_config.entry(host_target).or_insert_with(|| Target::from_triple(triple)); + dwn_ctx.target_config.entry(host_target).or_insert_with(|| Target::from_triple(triple)); check_ci_llvm!(build_target.llvm_config); check_ci_llvm!(build_target.llvm_filecheck); - build_target.llvm_config = - Some(ci_llvm_bin.join(exe("llvm-config", config.host_target))); - build_target.llvm_filecheck = - Some(ci_llvm_bin.join(exe("FileCheck", config.host_target))); + build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", host_target))); + build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", host_target))); } - config.dist_sign_folder = dist_sign_folder.map(PathBuf::from); - config.dist_upload_addr = dist_upload_addr; - config.dist_compression_formats = dist_compression_formats; - set(&mut config.dist_compression_profile, dist_compression_profile); - set(&mut config.rust_dist_src, dist_src_tarball); - set(&mut config.dist_include_mingw_linker, dist_include_mingw_linker); - config.dist_vendor = dist_vendor.unwrap_or_else(|| { - // If we're building from git or tarball sources, enable it by default. - config.rust_info.is_managed_git_subrepository() || config.rust_info.is_from_tarball() - }); - - config.initial_rustfmt = if let Some(r) = build_rustfmt { - Some(r) - } else { - let dwn_ctx = DownloadContext::from(&config); - maybe_download_rustfmt(dwn_ctx) - }; + let initial_rustfmt = build_rustfmt.or_else(|| maybe_download_rustfmt(&dwn_ctx)); - if matches!(config.lld_mode, LldMode::SelfContained) - && !config.lld_enabled + if matches!(rust_lld_mode.unwrap_or_default(), LldMode::SelfContained) + && !lld_enabled && flags_stage.unwrap_or(0) > 0 { panic!( @@ -1311,29 +1016,13 @@ impl Config { ); } - let dwn_ctx = DownloadContext::from(&config); - if config.lld_enabled && is_system_llvm(dwn_ctx, config.host_target) { + if lld_enabled && is_system_llvm(&dwn_ctx, host_target) { panic!("Cannot enable LLD with `rust.lld = true` when using external llvm-config."); } - config.optimized_compiler_builtins = - build_optimized_compiler_builtins.unwrap_or(config.channel != "dev"); - config.compiletest_diff_tool = build_compiletest_diff_tool; - config.compiletest_use_stage0_libtest = - build_compiletest_use_stage0_libtest.unwrap_or(true); - config.tidy_extra_checks = build_tidy_extra_checks; - - let download_rustc = config.download_rustc_commit.is_some(); - config.explicit_stage_from_cli = flags_stage.is_some(); - config.explicit_stage_from_config = build_test_stage.is_some() - || build_build_stage.is_some() - || build_doc_stage.is_some() - || build_dist_stage.is_some() - || build_install_stage.is_some() - || build_check_stage.is_some() - || build_bench_stage.is_some(); - - config.stage = match config.cmd { + let download_rustc = download_rustc_commit.is_some(); + + let stage = match flags_cmd { Subcommand::Check { .. } => flags_stage.or(build_check_stage).unwrap_or(1), Subcommand::Clippy { .. } | Subcommand::Fix => { flags_stage.or(build_check_stage).unwrap_or(1) @@ -1362,7 +1051,7 @@ impl Config { }; // Now check that the selected stage makes sense, and if not, print a warning and end - match (config.stage, &config.cmd) { + match (stage, &flags_cmd) { (0, Subcommand::Build { .. }) => { eprintln!("ERROR: cannot build anything on stage 0. Use at least stage 1."); exit!(1); @@ -1382,7 +1071,7 @@ impl Config { _ => {} } - if config.compile_time_deps && !matches!(config.cmd, Subcommand::Check { .. }) { + if flags_compile_time_deps && !matches!(flags_cmd, Subcommand::Check { .. }) { eprintln!( "WARNING: Can't use --compile-time-deps with any subcommand other than check." ); @@ -1391,8 +1080,8 @@ impl Config { // CI should always run stage 2 builds, unless it specifically states otherwise #[cfg(not(test))] - if flags_stage.is_none() && config.is_running_on_ci { - match config.cmd { + if flags_stage.is_none() && is_running_on_ci { + match flags_cmd { Subcommand::Test { .. } | Subcommand::Miri { .. } | Subcommand::Doc { .. } @@ -1401,9 +1090,8 @@ impl Config { | Subcommand::Dist | Subcommand::Install => { assert_eq!( - config.stage, 2, - "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`", - config.stage, + stage, 2, + "x.py should be run with `--stage 2` on CI, but was run with `--stage {stage}`", ); } Subcommand::Clean { .. } @@ -1418,7 +1106,267 @@ impl Config { } } - config + let with_defaults = |debuginfo_level_specific: Option<_>| { + debuginfo_level_specific.or(rust_debuginfo_level).unwrap_or( + if rust_debug == Some(true) { + DebuginfoLevel::Limited + } else { + DebuginfoLevel::None + }, + ) + }; + + Config { + change_id: toml.change_id.inner, + bypass_bootstrap_lock: flags_bypass_bootstrap_lock, + ccache: match build_ccache { + Some(StringOrBool::String(s)) => Some(s), + Some(StringOrBool::Bool(true)) => Some("ccache".to_string()), + _ => None, + }, + ninja_in_file: llvm_ninja.unwrap_or(true), + compiler_docs: build_compiler_docs.unwrap_or(false), + library_docs_private_items: build_library_docs_private_items.unwrap_or(false), + docs_minification: build_docs_minification.unwrap_or(true), + docs: build_docs.unwrap_or(true), + locked_deps: build_locked_deps.unwrap_or(false), + full_bootstrap: build_full_bootstrap.unwrap_or(false), + bootstrap_cache_path, + extended: build_extended.unwrap_or(false), + tools: build_tools, + tool: build_tool.unwrap_or_default(), + sanitizers: build_sanitizers.unwrap_or(false), + profiler: build_profiler.unwrap_or(false), + include_default_paths: flags_include_default_paths, + rustc_error_format: flags_rustc_error_format, + json_output: flags_json_output, + compile_time_deps: flags_compile_time_deps, + test_compare_mode: rust_test_compare_mode.unwrap_or(false), + color: flags_color, + android_ndk: build_android_ndk, + optimized_compiler_builtins: build_optimized_compiler_builtins + .unwrap_or(channel != "dev"), + stdout_is_tty: std::io::stdout().is_terminal(), + stderr_is_tty: std::io::stderr().is_terminal(), + on_fail: flags_on_fail, + explicit_stage_from_cli: flags_stage.is_some(), + explicit_stage_from_config: build_test_stage.is_some() + || build_build_stage.is_some() + || build_doc_stage.is_some() + || build_dist_stage.is_some() + || build_install_stage.is_some() + || build_check_stage.is_some() + || build_bench_stage.is_some(), + + keep_stage: flags_keep_stage, + keep_stage_std: flags_keep_stage_std, + jobs: Some(threads_from_config(flags_jobs.or(build_jobs).unwrap_or(0))), + incremental: flags_incremental || rust_incremental == Some(true), + dump_bootstrap_shims: flags_dump_bootstrap_shims, + free_args: flags_free_args, + deny_warnings: match flags_warnings { + Warnings::Deny => true, + Warnings::Warn => false, + Warnings::Default => rust_deny_warnings.unwrap_or(true), + }, + backtrace_on_ice: rust_backtrace_on_ice.unwrap_or(false), + llvm_tests: llvm_tests_.unwrap_or_default(), + llvm_enzyme: llvm_enzyme_.unwrap_or_default(), + llvm_offload: llvm_offload_.unwrap_or(false), + llvm_plugins: llvm_plugin.unwrap_or_default(), + llvm_optimize: llvm_optimize_.unwrap_or(true), + llvm_release_debuginfo: llvm_release_debuginfo_.unwrap_or(false), + llvm_static_stdcpp: llvm_static_libstdcpp.unwrap_or(false), + llvm_libzstd: llvm_libzstd_.unwrap_or(false), + llvm_clang_cl: llvm_clang_cl_, + llvm_targets: llvm_targets_, + llvm_experimental_targets: llvm_experimental_targets_, + llvm_link_jobs: llvm_link_jobs_, + llvm_version_suffix: llvm_version_suffix_, + llvm_use_linker: llvm_use_linker_, + llvm_allow_old_toolchain: llvm_allow_old_toolchain_.unwrap_or(false), + llvm_polly: llvm_polly_.unwrap_or(false), + llvm_clang: llvm_clang_.unwrap_or(false), + llvm_enable_warnings: llvm_enable_warnings_.unwrap_or(false), + llvm_build_config: llvm_build_config_.clone().unwrap_or(Default::default()), + llvm_tools_enabled: rust_llvm_tools.unwrap_or(true), + llvm_bitcode_linker_enabled: rust_llvm_bitcode_linker.unwrap_or(false), + llvm_cflags: llvm_cflags_, + llvm_cxxflags: llvm_cxxflags_, + llvm_ldflags: llvm_ldflags_, + llvm_use_libcxx: llvm_use_libcxx_.unwrap_or(false), + gcc_ci_mode: match gcc_download_ci_gcc { + Some(value) => match value { + true => GccCiMode::DownloadFromCi, + false => GccCiMode::BuildLocally, + }, + None => GccCiMode::default(), + }, + rust_optimize: rust_optimize_.unwrap_or(RustOptimize::Bool(true)), + rust_codegen_units: rust_codegen_units_.map(threads_from_config), + rust_codegen_units_std: rust_codegen_units_std_.map(threads_from_config), + std_debug_assertions: rust_std_debug_assertions + .or(rust_rustc_debug_assertions) + .unwrap_or(rust_debug == Some(true)), + tools_debug_assertions: rust_tools_debug_assertions + .or(rust_rustc_debug_assertions) + .unwrap_or(rust_debug == Some(true)), + rust_overflow_checks_std: rust_overflow_checks_std_ + .or(rust_overflow_checks_) + .unwrap_or(rust_debug == Some(true)), + rust_overflow_checks: rust_overflow_checks_.unwrap_or(rust_debug == Some(true)), + rust_debug_logging: rust_debug_logging_ + .or(rust_rustc_debug_assertions) + .unwrap_or(rust_debug == Some(true)), + rust_debuginfo_level_rustc: with_defaults(rust_debuginfo_level_rustc_), + rust_debuginfo_level_std: with_defaults(rust_debuginfo_level_std_), + rust_debuginfo_level_tools: with_defaults(rust_debuginfo_level_tools_), + rust_debuginfo_level_tests: rust_debuginfo_level_tests_.unwrap_or(DebuginfoLevel::None), + rust_rpath: rust_rpath_.unwrap_or(true), + rust_strip: rust_strip_.unwrap_or(false), + rust_frame_pointers: rust_frame_pointers_.unwrap_or(false), + rust_stack_protector: rust_stack_protector_, + rustc_default_linker: rust_default_linker, + rust_optimize_tests: rust_optimize_tests_.unwrap_or(true), + rust_dist_src: dist_src_tarball_.unwrap_or_else(|| rust_dist_src_.unwrap_or(true)), + rust_codegen_backends: rust_codegen_backends_ + .map(|backends| parse_codegen_backends(backends, "rust")) + .unwrap_or(vec![CodegenBackendKind::Llvm]), + rust_verify_llvm_ir: rust_verify_llvm_ir_.unwrap_or(false), + rust_thin_lto_import_instr_limit: rust_thin_lto_import_instr_limit_, + rust_randomize_layout: rust_randomize_layout_.unwrap_or_default(), + rust_remap_debuginfo: rust_remap_debuginfo_.unwrap_or(false), + rust_new_symbol_mangling: rust_new_symbol_mangling_, + rust_profile_use: flags_rust_profile_use.or(rust_profile_use_), + rust_profile_generate: flags_rust_profile_generate.or(rust_profile_generate_), + rust_lto: rust_lto_ + .as_deref() + .map(|value| RustcLto::from_str(value).unwrap()) + .unwrap_or_default(), + rust_validate_mir_opts: rust_validate_mir_opts_, + rust_std_features: rust_std_features_ + .unwrap_or(BTreeSet::from([String::from("panic-unwind")])), + llvm_profile_use: flags_llvm_profile_use, + llvm_profile_generate: flags_llvm_profile_generate, + llvm_libunwind_default: rust_llvm_libunwind + .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")), + enable_bolt_settings: flags_enable_bolt_settings, + reproducible_artifacts: flags_reproducible_artifact, + local_rebuild: build_local_rebuild.unwrap_or(false), + jemalloc: rust_jemalloc.unwrap_or(false), + control_flow_guard: rust_control_flow_guard.unwrap_or(false), + ehcont_guard: rust_ehcont_guard.unwrap_or(false), + dist_sign_folder: dist_sign_folder_.map(PathBuf::from), + dist_upload_addr: dist_upload_addr_, + dist_compression_formats: dist_compression_formats_, + dist_compression_profile: dist_compression_profile_.unwrap_or("fast".into()), + dist_include_mingw_linker: dist_include_mingw_linker_.unwrap_or(true), + backtrace: rust_backtrace.unwrap_or(true), + low_priority: build_low_priority.unwrap_or(false), + description: build_description, + verbose_tests: rust_verbose_tests.unwrap_or(exec_ctx.is_verbose()), + save_toolstates: rust_save_toolstates.map(PathBuf::from), + print_step_timings: build_print_step_timings.unwrap_or(false), + print_step_rusage: build_print_step_rusage.unwrap_or(false), + musl_root: rust_musl_root.map(PathBuf::from), + prefix: install_prefix.map(PathBuf::from), + sysconfdir: install_sysconfdir.map(PathBuf::from), + datadir: install_datadir.map(PathBuf::from), + docdir: install_docdir.map(PathBuf::from), + bindir: install_bindir.map(PathBuf::from).unwrap_or("bin".into()), + libdir: install_libdir.map(PathBuf::from), + mandir: install_mandir.map(PathBuf::from), + codegen_tests: rust_codegen_tests.unwrap_or(true), + nodejs: build_nodejs.map(PathBuf::from), + npm: build_npm.map(PathBuf::from), + gdb: build_gdb.map(PathBuf::from), + lldb: build_lldb.map(PathBuf::from), + python: build_python.map(PathBuf::from), + reuse: build_reuse.map(PathBuf::from), + cargo_native_static: build_cargo_native_static.unwrap_or(false), + configure_args: build_configure_args.unwrap_or_default(), + compiletest_diff_tool: build_compiletest_diff_tool, + compiletest_allow_stage0: build_compiletest_allow_stage0.unwrap_or(false), + compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest.unwrap_or(true), + tidy_extra_checks: build_tidy_extra_checks, + skip_std_check_if_no_download_rustc: flags_skip_std_check_if_no_download_rustc, + cargo_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/cargo")), + rust_analyzer_info: git_info( + &exec_ctx, + omit_git_hash, + &src.join("src/tools/rust-analyzer"), + ), + clippy_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/clippy")), + miri_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/miri")), + rustfmt_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/rustfmt")), + enzyme_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/enzyme")), + in_tree_llvm_info: git_info(&exec_ctx, false, &src.join("src/llvm-project")), + in_tree_gcc_info: git_info(&exec_ctx, false, &src.join("src/gcc")), + dist_vendor: dist_vendor_.unwrap_or_else(|| { + // If we're building from git or tarball sources, enable it by default. + rust_info.is_managed_git_subrepository() || rust_info.is_from_tarball() + }), + targets: flags_target + .map(|TargetSelectionList(targets)| targets) + .or_else(|| { + build_target.map(|t| t.iter().map(|t| TargetSelection::from_user(t)).collect()) + }) + .unwrap_or_else(|| hosts.clone()), + #[allow(clippy::map_identity)] + skip: flags_skip + .into_iter() + .chain(flags_exclude) + .chain(build_exclude.unwrap_or_default()) + .map(|p| { + // Never return top-level path here as it would break `--skip` + // logic on rustc's internal test framework which is utilized by compiletest. + #[cfg(windows)] + { + PathBuf::from(p.to_string_lossy().replace('/', "\\")) + } + #[cfg(not(windows))] + { + p + } + }) + .collect(), + paths: flags_paths, + config: toml_path, + llvm_thin_lto: llvm_thin_lto_.unwrap_or(false), + rustc_debug_assertions: rust_rustc_debug_assertions.unwrap_or(rust_debug == Some(true)), + lld_mode: rust_lld_mode.unwrap_or_default(), + initial_cargo_clippy: build_cargo_clippy, + vendor: build_vendor.unwrap_or( + rust_info.is_from_tarball() + && src.join("vendor").exists() + && src.join(".cargo/config.toml").exists(), + ), + cmd: flags_cmd, + exec_ctx, + out, + rust_info, + initial_cargo, + initial_rustc, + initial_sysroot, + initial_rustfmt, + submodules, + target_config, + omit_git_hash, + stage, + src, + llvm_from_ci, + llvm_assertions, + lld_enabled, + host_target, + hosts, + channel, + is_running_on_ci, + path_modification_cache, + patch_binaries_for_nix, + stage0_metadata, + download_rustc_commit, + llvm_link_shared, + } } pub fn dry_run(&self) -> bool { @@ -2292,7 +2240,7 @@ pub fn has_changes_from_upstream<'a>( )] pub(crate) fn update_submodule<'a>(dwn_ctx: impl AsRef>, relative_path: &str) { let dwn_ctx = dwn_ctx.as_ref(); - if dwn_ctx.rust_info.is_from_tarball() || !submodules_(dwn_ctx.submodules, dwn_ctx.rust_info) { + if dwn_ctx.rust_info.is_from_tarball() || !submodules_(dwn_ctx.submodules, &dwn_ctx.rust_info) { return; } diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 285d20917e7da..02f44d41e9e15 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -402,12 +402,6 @@ pub enum GccCiMode { DownloadFromCi, } -pub fn set(field: &mut T, val: Option) { - if let Some(v) = val { - *field = v; - } -} - pub fn threads_from_config(v: u32) -> u32 { match v { 0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32, diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 5ded44cef1447..29a244a6c4087 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -403,13 +403,13 @@ impl Config { pub(crate) struct DownloadContext<'a> { pub path_modification_cache: Arc, PathFreshness>>>, pub src: &'a Path, - pub rust_info: &'a channel::GitInfo, + pub rust_info: channel::GitInfo, pub submodules: &'a Option, - pub download_rustc_commit: &'a Option, + pub download_rustc_commit: Option, pub host_target: TargetSelection, pub llvm_from_ci: bool, - pub target_config: &'a HashMap, - pub out: &'a Path, + pub target_config: HashMap, + pub out: PathBuf, pub patch_binaries_for_nix: Option, pub exec_ctx: &'a ExecutionContext, pub stage0_metadata: &'a build_helper::stage0_parser::Stage0, @@ -418,6 +418,45 @@ pub(crate) struct DownloadContext<'a> { pub is_running_on_ci: bool, } +impl<'a> DownloadContext<'a> { + #[allow(clippy::too_many_arguments)] + pub fn new( + path_modification_cache: Arc, PathFreshness>>>, + src: &'a Path, + rust_info: channel::GitInfo, + submodules: &'a Option, + download_rustc_commit: Option, + host_target: TargetSelection, + llvm_from_ci: bool, + target_config: HashMap, + out: PathBuf, + patch_binaries_for_nix: Option, + exec_ctx: &'a ExecutionContext, + stage0_metadata: &'a build_helper::stage0_parser::Stage0, + llvm_assertions: bool, + bootstrap_cache_path: &'a Option, + is_running_on_ci: bool, + ) -> Self { + Self { + path_modification_cache, + src, + rust_info, + submodules, + download_rustc_commit, + host_target, + llvm_from_ci, + target_config, + out, + patch_binaries_for_nix, + exec_ctx, + stage0_metadata, + llvm_assertions, + bootstrap_cache_path, + is_running_on_ci, + } + } +} + impl<'a> AsRef> for DownloadContext<'a> { fn as_ref(&self) -> &DownloadContext<'a> { self @@ -430,12 +469,12 @@ impl<'a> From<&'a Config> for DownloadContext<'a> { path_modification_cache: value.path_modification_cache.clone(), src: &value.src, host_target: value.host_target, - rust_info: &value.rust_info, - download_rustc_commit: &value.download_rustc_commit, + rust_info: value.rust_info.clone(), + download_rustc_commit: value.download_rustc_commit.clone(), submodules: &value.submodules, llvm_from_ci: value.llvm_from_ci, - target_config: &value.target_config, - out: &value.out, + target_config: value.target_config.clone(), + out: value.out.clone(), patch_binaries_for_nix: value.patch_binaries_for_nix, exec_ctx: &value.exec_ctx, stage0_metadata: &value.stage0_metadata, @@ -543,13 +582,13 @@ pub(crate) fn maybe_download_rustfmt<'a>( ); if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) { - fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("rustfmt"), dwn_ctx.exec_ctx); - fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("cargo-fmt"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("rustfmt"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("cargo-fmt"), dwn_ctx.exec_ctx); let lib_dir = bin_root.join("lib"); for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) { let lib = t!(lib); if path_is_dylib(&lib.path()) { - fix_bin_or_dylib(dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx); + fix_bin_or_dylib(&dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx); } } } @@ -615,10 +654,10 @@ fn download_toolchain<'a>( } if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) { - fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("rustc"), dwn_ctx.exec_ctx); - fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("rustdoc"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("rustc"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("rustdoc"), dwn_ctx.exec_ctx); fix_bin_or_dylib( - dwn_ctx.out, + &dwn_ctx.out, &bin_root.join("libexec").join("rust-analyzer-proc-macro-srv"), dwn_ctx.exec_ctx, ); @@ -626,7 +665,7 @@ fn download_toolchain<'a>( for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) { let lib = t!(lib); if path_is_dylib(&lib.path()) { - fix_bin_or_dylib(dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx); + fix_bin_or_dylib(&dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx); } } } @@ -963,7 +1002,7 @@ fn download_file<'a>( println!("download {url}"); }); // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/. - let tempfile = tempdir(dwn_ctx.out).join(dest_path.file_name().unwrap()); + let tempfile = tempdir(&dwn_ctx.out).join(dest_path.file_name().unwrap()); // While bootstrap itself only supports http and https downloads, downstream forks might // need to download components from other protocols. The match allows them adding more // protocols without worrying about merge conflicts if we change the HTTP implementation. From a0aaa1275a83b51089442127571f1eb62e993a23 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 18 Aug 2025 10:56:58 +0530 Subject: [PATCH 244/252] clippy'ed --- src/bootstrap/src/core/config/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 692c05456f69e..e6d5171eaf95c 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -937,7 +937,7 @@ impl Config { && hosts == [host_target] { let no_llvm_config = - target_config.get(&host_target).map_or(true, |config| config.llvm_config.is_none()); + target_config.get(&host_target).is_none_or(|config| config.llvm_config.is_none()); rust_lld_enabled.unwrap_or(llvm_from_ci || no_llvm_config) } else { rust_lld_enabled.unwrap_or(false) From f960e368a91714d38e3bd3c72c0eb530ee4784c8 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Mon, 18 Aug 2025 23:49:01 +0530 Subject: [PATCH 245/252] remove downstream new method --- src/bootstrap/src/core/config/config.rs | 24 +++++++-------- src/bootstrap/src/core/download.rs | 39 ------------------------- 2 files changed, 12 insertions(+), 51 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index e6d5171eaf95c..9028c7aec364d 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -735,23 +735,23 @@ impl Config { ); } - let mut dwn_ctx = DownloadContext::new( - path_modification_cache.clone(), - &src, - rust_info.clone(), - &submodules, - download_rustc_commit.clone(), + let mut dwn_ctx = DownloadContext { + path_modification_cache: path_modification_cache.clone(), + src: &src, + rust_info: rust_info.clone(), + submodules: &submodules, + download_rustc_commit: download_rustc_commit.clone(), host_target, llvm_from_ci, - target_config.clone(), - out.clone(), + target_config: target_config.clone(), + out: out.clone(), patch_binaries_for_nix, - &exec_ctx, - &stage0_metadata, + exec_ctx: &exec_ctx, + stage0_metadata: &stage0_metadata, llvm_assertions, - &bootstrap_cache_path, + bootstrap_cache_path: &bootstrap_cache_path, is_running_on_ci, - ); + }; let initial_rustc = build_rustc.unwrap_or_else(|| { download_beta_toolchain(&dwn_ctx); diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 29a244a6c4087..402d6019dabbb 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -418,45 +418,6 @@ pub(crate) struct DownloadContext<'a> { pub is_running_on_ci: bool, } -impl<'a> DownloadContext<'a> { - #[allow(clippy::too_many_arguments)] - pub fn new( - path_modification_cache: Arc, PathFreshness>>>, - src: &'a Path, - rust_info: channel::GitInfo, - submodules: &'a Option, - download_rustc_commit: Option, - host_target: TargetSelection, - llvm_from_ci: bool, - target_config: HashMap, - out: PathBuf, - patch_binaries_for_nix: Option, - exec_ctx: &'a ExecutionContext, - stage0_metadata: &'a build_helper::stage0_parser::Stage0, - llvm_assertions: bool, - bootstrap_cache_path: &'a Option, - is_running_on_ci: bool, - ) -> Self { - Self { - path_modification_cache, - src, - rust_info, - submodules, - download_rustc_commit, - host_target, - llvm_from_ci, - target_config, - out, - patch_binaries_for_nix, - exec_ctx, - stage0_metadata, - llvm_assertions, - bootstrap_cache_path, - is_running_on_ci, - } - } -} - impl<'a> AsRef> for DownloadContext<'a> { fn as_ref(&self) -> &DownloadContext<'a> { self From 46c4d5cf15dbe2955f0ad102ae89ec54a8e0a15e Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 20 Aug 2025 17:42:04 +0530 Subject: [PATCH 246/252] remove now not required _ --- src/bootstrap/src/core/config/config.rs | 230 ++++++++++++------------ 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 9028c7aec364d..b3fca61709e1c 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -554,105 +554,105 @@ impl Config { } = toml.install.unwrap_or_default(); let Rust { - optimize: rust_optimize_, + optimize: rust_optimize, debug: rust_debug, - codegen_units: rust_codegen_units_, - codegen_units_std: rust_codegen_units_std_, + codegen_units: rust_codegen_units, + codegen_units_std: rust_codegen_units_std, rustc_debug_assertions: rust_rustc_debug_assertions, std_debug_assertions: rust_std_debug_assertions, tools_debug_assertions: rust_tools_debug_assertions, - overflow_checks: rust_overflow_checks_, - overflow_checks_std: rust_overflow_checks_std_, - debug_logging: rust_debug_logging_, + overflow_checks: rust_overflow_checks, + overflow_checks_std: rust_overflow_checks_std, + debug_logging: rust_debug_logging, debuginfo_level: rust_debuginfo_level, - debuginfo_level_rustc: rust_debuginfo_level_rustc_, - debuginfo_level_std: rust_debuginfo_level_std_, - debuginfo_level_tools: rust_debuginfo_level_tools_, - debuginfo_level_tests: rust_debuginfo_level_tests_, + debuginfo_level_rustc: rust_debuginfo_level_rustc, + debuginfo_level_std: rust_debuginfo_level_std, + debuginfo_level_tools: rust_debuginfo_level_tools, + debuginfo_level_tests: rust_debuginfo_level_tests, backtrace: rust_backtrace, incremental: rust_incremental, - randomize_layout: rust_randomize_layout_, + randomize_layout: rust_randomize_layout, default_linker: rust_default_linker, channel: rust_channel, musl_root: rust_musl_root, - rpath: rust_rpath_, + rpath: rust_rpath, verbose_tests: rust_verbose_tests, - optimize_tests: rust_optimize_tests_, + optimize_tests: rust_optimize_tests, codegen_tests: rust_codegen_tests, omit_git_hash: rust_omit_git_hash, - dist_src: rust_dist_src_, + dist_src: rust_dist_src, save_toolstates: rust_save_toolstates, - codegen_backends: rust_codegen_backends_, + codegen_backends: rust_codegen_backends, lld: rust_lld_enabled, llvm_tools: rust_llvm_tools, llvm_bitcode_linker: rust_llvm_bitcode_linker, deny_warnings: rust_deny_warnings, backtrace_on_ice: rust_backtrace_on_ice, - verify_llvm_ir: rust_verify_llvm_ir_, - thin_lto_import_instr_limit: rust_thin_lto_import_instr_limit_, - remap_debuginfo: rust_remap_debuginfo_, + verify_llvm_ir: rust_verify_llvm_ir, + thin_lto_import_instr_limit: rust_thin_lto_import_instr_limit, + remap_debuginfo: rust_remap_debuginfo, jemalloc: rust_jemalloc, test_compare_mode: rust_test_compare_mode, llvm_libunwind: rust_llvm_libunwind, control_flow_guard: rust_control_flow_guard, ehcont_guard: rust_ehcont_guard, - new_symbol_mangling: rust_new_symbol_mangling_, - profile_generate: rust_profile_generate_, - profile_use: rust_profile_use_, + new_symbol_mangling: rust_new_symbol_mangling, + profile_generate: rust_profile_generate, + profile_use: rust_profile_use, download_rustc: rust_download_rustc, - lto: rust_lto_, - validate_mir_opts: rust_validate_mir_opts_, - frame_pointers: rust_frame_pointers_, - stack_protector: rust_stack_protector_, - strip: rust_strip_, + lto: rust_lto, + validate_mir_opts: rust_validate_mir_opts, + frame_pointers: rust_frame_pointers, + stack_protector: rust_stack_protector, + strip: rust_strip, lld_mode: rust_lld_mode, - std_features: rust_std_features_, + std_features: rust_std_features, } = toml.rust.unwrap_or_default(); let Llvm { - optimize: llvm_optimize_, - thin_lto: llvm_thin_lto_, - release_debuginfo: llvm_release_debuginfo_, + optimize: llvm_optimize, + thin_lto: llvm_thin_lto, + release_debuginfo: llvm_release_debuginfo, assertions: llvm_assertions_, - tests: llvm_tests_, - enzyme: llvm_enzyme_, + tests: llvm_tests, + enzyme: llvm_enzyme, plugins: llvm_plugin, static_libstdcpp: llvm_static_libstdcpp, - libzstd: llvm_libzstd_, + libzstd: llvm_libzstd, ninja: llvm_ninja, - targets: llvm_targets_, - experimental_targets: llvm_experimental_targets_, - link_jobs: llvm_link_jobs_, + targets: llvm_targets, + experimental_targets: llvm_experimental_targets, + link_jobs: llvm_link_jobs, link_shared: llvm_link_shared_, - version_suffix: llvm_version_suffix_, - clang_cl: llvm_clang_cl_, - cflags: llvm_cflags_, - cxxflags: llvm_cxxflags_, - ldflags: llvm_ldflags_, - use_libcxx: llvm_use_libcxx_, - use_linker: llvm_use_linker_, - allow_old_toolchain: llvm_allow_old_toolchain_, - offload: llvm_offload_, - polly: llvm_polly_, - clang: llvm_clang_, - enable_warnings: llvm_enable_warnings_, + version_suffix: llvm_version_suffix, + clang_cl: llvm_clang_cl, + cflags: llvm_cflags, + cxxflags: llvm_cxxflags, + ldflags: llvm_ldflags, + use_libcxx: llvm_use_libcxx, + use_linker: llvm_use_linker, + allow_old_toolchain: llvm_allow_old_toolchain, + offload: llvm_offload, + polly: llvm_polly, + clang: llvm_clang, + enable_warnings: llvm_enable_warnings, download_ci_llvm: llvm_download_ci_llvm, - build_config: llvm_build_config_, + build_config: llvm_build_config, } = toml.llvm.unwrap_or_default(); let Dist { - sign_folder: dist_sign_folder_, - upload_addr: dist_upload_addr_, - src_tarball: dist_src_tarball_, - compression_formats: dist_compression_formats_, - compression_profile: dist_compression_profile_, - include_mingw_linker: dist_include_mingw_linker_, - vendor: dist_vendor_, + sign_folder: dist_sign_folder, + upload_addr: dist_upload_addr, + src_tarball: dist_src_tarball, + compression_formats: dist_compression_formats, + compression_profile: dist_compression_profile, + include_mingw_linker: dist_include_mingw_linker, + vendor: dist_vendor, } = toml.dist.unwrap_or_default(); let Gcc { download_ci_gcc: gcc_download_ci_gcc } = toml.gcc.unwrap_or_default(); - if rust_optimize_.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { + if rust_optimize.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { eprintln!( "WARNING: setting `optimize` to `false` is known to cause errors and \ should be considered unsupported. Refer to `bootstrap.example.toml` \ @@ -973,7 +973,7 @@ impl Config { // config to the ones used to build the LLVM artifacts on CI, and only notify users // if they've chosen a different value. - if llvm_libzstd_.is_some() { + if llvm_libzstd.is_some() { println!( "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \ like almost all `llvm.*` options, will be ignored and set by the LLVM CI \ @@ -985,7 +985,7 @@ impl Config { } } - if !llvm_from_ci && llvm_thin_lto_.unwrap_or(false) && llvm_link_shared_.is_none() { + if !llvm_from_ci && llvm_thin_lto.unwrap_or(false) && llvm_link_shared_.is_none() { // If we're building with ThinLTO on, by default we want to link // to LLVM shared, to avoid re-doing ThinLTO (which happens in // the link step) with each stage. @@ -1170,31 +1170,31 @@ impl Config { Warnings::Default => rust_deny_warnings.unwrap_or(true), }, backtrace_on_ice: rust_backtrace_on_ice.unwrap_or(false), - llvm_tests: llvm_tests_.unwrap_or_default(), - llvm_enzyme: llvm_enzyme_.unwrap_or_default(), - llvm_offload: llvm_offload_.unwrap_or(false), + llvm_tests: llvm_tests.unwrap_or_default(), + llvm_enzyme: llvm_enzyme.unwrap_or_default(), + llvm_offload: llvm_offload.unwrap_or(false), llvm_plugins: llvm_plugin.unwrap_or_default(), - llvm_optimize: llvm_optimize_.unwrap_or(true), - llvm_release_debuginfo: llvm_release_debuginfo_.unwrap_or(false), + llvm_optimize: llvm_optimize.unwrap_or(true), + llvm_release_debuginfo: llvm_release_debuginfo.unwrap_or(false), llvm_static_stdcpp: llvm_static_libstdcpp.unwrap_or(false), - llvm_libzstd: llvm_libzstd_.unwrap_or(false), - llvm_clang_cl: llvm_clang_cl_, - llvm_targets: llvm_targets_, - llvm_experimental_targets: llvm_experimental_targets_, - llvm_link_jobs: llvm_link_jobs_, - llvm_version_suffix: llvm_version_suffix_, - llvm_use_linker: llvm_use_linker_, - llvm_allow_old_toolchain: llvm_allow_old_toolchain_.unwrap_or(false), - llvm_polly: llvm_polly_.unwrap_or(false), - llvm_clang: llvm_clang_.unwrap_or(false), - llvm_enable_warnings: llvm_enable_warnings_.unwrap_or(false), - llvm_build_config: llvm_build_config_.clone().unwrap_or(Default::default()), + llvm_libzstd: llvm_libzstd.unwrap_or(false), + llvm_clang_cl, + llvm_targets, + llvm_experimental_targets, + llvm_link_jobs, + llvm_version_suffix, + llvm_use_linker, + llvm_allow_old_toolchain: llvm_allow_old_toolchain.unwrap_or(false), + llvm_polly: llvm_polly.unwrap_or(false), + llvm_clang: llvm_clang.unwrap_or(false), + llvm_enable_warnings: llvm_enable_warnings.unwrap_or(false), + llvm_build_config: llvm_build_config.clone().unwrap_or(Default::default()), llvm_tools_enabled: rust_llvm_tools.unwrap_or(true), llvm_bitcode_linker_enabled: rust_llvm_bitcode_linker.unwrap_or(false), - llvm_cflags: llvm_cflags_, - llvm_cxxflags: llvm_cxxflags_, - llvm_ldflags: llvm_ldflags_, - llvm_use_libcxx: llvm_use_libcxx_.unwrap_or(false), + llvm_cflags, + llvm_cxxflags, + llvm_ldflags, + llvm_use_libcxx: llvm_use_libcxx.unwrap_or(false), gcc_ci_mode: match gcc_download_ci_gcc { Some(value) => match value { true => GccCiMode::DownloadFromCi, @@ -1202,49 +1202,49 @@ impl Config { }, None => GccCiMode::default(), }, - rust_optimize: rust_optimize_.unwrap_or(RustOptimize::Bool(true)), - rust_codegen_units: rust_codegen_units_.map(threads_from_config), - rust_codegen_units_std: rust_codegen_units_std_.map(threads_from_config), + rust_optimize: rust_optimize.unwrap_or(RustOptimize::Bool(true)), + rust_codegen_units: rust_codegen_units.map(threads_from_config), + rust_codegen_units_std: rust_codegen_units_std.map(threads_from_config), std_debug_assertions: rust_std_debug_assertions .or(rust_rustc_debug_assertions) .unwrap_or(rust_debug == Some(true)), tools_debug_assertions: rust_tools_debug_assertions .or(rust_rustc_debug_assertions) .unwrap_or(rust_debug == Some(true)), - rust_overflow_checks_std: rust_overflow_checks_std_ - .or(rust_overflow_checks_) + rust_overflow_checks_std: rust_overflow_checks_std + .or(rust_overflow_checks) .unwrap_or(rust_debug == Some(true)), - rust_overflow_checks: rust_overflow_checks_.unwrap_or(rust_debug == Some(true)), - rust_debug_logging: rust_debug_logging_ + rust_overflow_checks: rust_overflow_checks.unwrap_or(rust_debug == Some(true)), + rust_debug_logging: rust_debug_logging .or(rust_rustc_debug_assertions) .unwrap_or(rust_debug == Some(true)), - rust_debuginfo_level_rustc: with_defaults(rust_debuginfo_level_rustc_), - rust_debuginfo_level_std: with_defaults(rust_debuginfo_level_std_), - rust_debuginfo_level_tools: with_defaults(rust_debuginfo_level_tools_), - rust_debuginfo_level_tests: rust_debuginfo_level_tests_.unwrap_or(DebuginfoLevel::None), - rust_rpath: rust_rpath_.unwrap_or(true), - rust_strip: rust_strip_.unwrap_or(false), - rust_frame_pointers: rust_frame_pointers_.unwrap_or(false), - rust_stack_protector: rust_stack_protector_, + rust_debuginfo_level_rustc: with_defaults(rust_debuginfo_level_rustc), + rust_debuginfo_level_std: with_defaults(rust_debuginfo_level_std), + rust_debuginfo_level_tools: with_defaults(rust_debuginfo_level_tools), + rust_debuginfo_level_tests: rust_debuginfo_level_tests.unwrap_or(DebuginfoLevel::None), + rust_rpath: rust_rpath.unwrap_or(true), + rust_strip: rust_strip.unwrap_or(false), + rust_frame_pointers: rust_frame_pointers.unwrap_or(false), + rust_stack_protector, rustc_default_linker: rust_default_linker, - rust_optimize_tests: rust_optimize_tests_.unwrap_or(true), - rust_dist_src: dist_src_tarball_.unwrap_or_else(|| rust_dist_src_.unwrap_or(true)), - rust_codegen_backends: rust_codegen_backends_ + rust_optimize_tests: rust_optimize_tests.unwrap_or(true), + rust_dist_src: dist_src_tarball.unwrap_or_else(|| rust_dist_src.unwrap_or(true)), + rust_codegen_backends: rust_codegen_backends .map(|backends| parse_codegen_backends(backends, "rust")) .unwrap_or(vec![CodegenBackendKind::Llvm]), - rust_verify_llvm_ir: rust_verify_llvm_ir_.unwrap_or(false), - rust_thin_lto_import_instr_limit: rust_thin_lto_import_instr_limit_, - rust_randomize_layout: rust_randomize_layout_.unwrap_or_default(), - rust_remap_debuginfo: rust_remap_debuginfo_.unwrap_or(false), - rust_new_symbol_mangling: rust_new_symbol_mangling_, - rust_profile_use: flags_rust_profile_use.or(rust_profile_use_), - rust_profile_generate: flags_rust_profile_generate.or(rust_profile_generate_), - rust_lto: rust_lto_ + rust_verify_llvm_ir: rust_verify_llvm_ir.unwrap_or(false), + rust_thin_lto_import_instr_limit, + rust_randomize_layout: rust_randomize_layout.unwrap_or_default(), + rust_remap_debuginfo: rust_remap_debuginfo.unwrap_or(false), + rust_new_symbol_mangling, + rust_profile_use: flags_rust_profile_use.or(rust_profile_use), + rust_profile_generate: flags_rust_profile_generate.or(rust_profile_generate), + rust_lto: rust_lto .as_deref() .map(|value| RustcLto::from_str(value).unwrap()) .unwrap_or_default(), - rust_validate_mir_opts: rust_validate_mir_opts_, - rust_std_features: rust_std_features_ + rust_validate_mir_opts, + rust_std_features: rust_std_features .unwrap_or(BTreeSet::from([String::from("panic-unwind")])), llvm_profile_use: flags_llvm_profile_use, llvm_profile_generate: flags_llvm_profile_generate, @@ -1256,11 +1256,11 @@ impl Config { jemalloc: rust_jemalloc.unwrap_or(false), control_flow_guard: rust_control_flow_guard.unwrap_or(false), ehcont_guard: rust_ehcont_guard.unwrap_or(false), - dist_sign_folder: dist_sign_folder_.map(PathBuf::from), - dist_upload_addr: dist_upload_addr_, - dist_compression_formats: dist_compression_formats_, - dist_compression_profile: dist_compression_profile_.unwrap_or("fast".into()), - dist_include_mingw_linker: dist_include_mingw_linker_.unwrap_or(true), + dist_sign_folder: dist_sign_folder.map(PathBuf::from), + dist_upload_addr, + dist_compression_formats, + dist_compression_profile: dist_compression_profile.unwrap_or("fast".into()), + dist_include_mingw_linker: dist_include_mingw_linker.unwrap_or(true), backtrace: rust_backtrace.unwrap_or(true), low_priority: build_low_priority.unwrap_or(false), description: build_description, @@ -1302,7 +1302,7 @@ impl Config { enzyme_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/enzyme")), in_tree_llvm_info: git_info(&exec_ctx, false, &src.join("src/llvm-project")), in_tree_gcc_info: git_info(&exec_ctx, false, &src.join("src/gcc")), - dist_vendor: dist_vendor_.unwrap_or_else(|| { + dist_vendor: dist_vendor.unwrap_or_else(|| { // If we're building from git or tarball sources, enable it by default. rust_info.is_managed_git_subrepository() || rust_info.is_from_tarball() }), @@ -1332,7 +1332,7 @@ impl Config { .collect(), paths: flags_paths, config: toml_path, - llvm_thin_lto: llvm_thin_lto_.unwrap_or(false), + llvm_thin_lto: llvm_thin_lto.unwrap_or(false), rustc_debug_assertions: rust_rustc_debug_assertions.unwrap_or(rust_debug == Some(true)), lld_mode: rust_lld_mode.unwrap_or_default(), initial_cargo_clippy: build_cargo_clippy, From fce2464c8d4de263910e1360f1b2dc6f17663632 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 20 Aug 2025 17:47:23 +0530 Subject: [PATCH 247/252] use local variables coming from toml, directly from toml --- src/bootstrap/src/core/config/config.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index b3fca61709e1c..0be2e33966945 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -665,9 +665,6 @@ impl Config { exec_ctx.set_verbosity(cmp::max(build_verbose.unwrap_or_default() as u8, flags_verbose)); let stage0_metadata = build_helper::stage0_parser::parse_stage0_file(); - let bootstrap_cache_path = build_bootstrap_cache_path; - let patch_binaries_for_nix = build_patch_binaries_for_nix; - let path_modification_cache = Arc::new(Mutex::new(HashMap::new())); let host_target = flags_build @@ -681,7 +678,6 @@ impl Config { }) .unwrap_or_else(|| vec![host_target]); - let submodules = build_submodules; let llvm_assertions = llvm_assertions_.unwrap_or(false); let mut target_config = HashMap::new(); @@ -739,17 +735,17 @@ impl Config { path_modification_cache: path_modification_cache.clone(), src: &src, rust_info: rust_info.clone(), - submodules: &submodules, + submodules: &build_submodules, download_rustc_commit: download_rustc_commit.clone(), host_target, llvm_from_ci, target_config: target_config.clone(), out: out.clone(), - patch_binaries_for_nix, + patch_binaries_for_nix: build_patch_binaries_for_nix, exec_ctx: &exec_ctx, stage0_metadata: &stage0_metadata, llvm_assertions, - bootstrap_cache_path: &bootstrap_cache_path, + bootstrap_cache_path: &build_bootstrap_cache_path, is_running_on_ci, }; @@ -873,7 +869,7 @@ impl Config { } if let Some(patches) = cfg.llvm_has_rust_patches { assert!( - submodules == Some(false) || cfg.llvm_config.is_some(), + build_submodules == Some(false) || cfg.llvm_config.is_some(), "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided" ); target.llvm_has_rust_patches = Some(patches); @@ -1131,7 +1127,7 @@ impl Config { docs: build_docs.unwrap_or(true), locked_deps: build_locked_deps.unwrap_or(false), full_bootstrap: build_full_bootstrap.unwrap_or(false), - bootstrap_cache_path, + bootstrap_cache_path: build_bootstrap_cache_path, extended: build_extended.unwrap_or(false), tools: build_tools, tool: build_tool.unwrap_or_default(), @@ -1341,7 +1337,9 @@ impl Config { && src.join("vendor").exists() && src.join(".cargo/config.toml").exists(), ), + patch_binaries_for_nix: build_patch_binaries_for_nix, cmd: flags_cmd, + submodules: build_submodules, exec_ctx, out, rust_info, @@ -1349,7 +1347,6 @@ impl Config { initial_rustc, initial_sysroot, initial_rustfmt, - submodules, target_config, omit_git_hash, stage, @@ -1362,7 +1359,6 @@ impl Config { channel, is_running_on_ci, path_modification_cache, - patch_binaries_for_nix, stage0_metadata, download_rustc_commit, llvm_link_shared, From b91b31061cdd228a8685f8bfeb0aeac9c9d29265 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 20 Aug 2025 18:07:01 +0530 Subject: [PATCH 248/252] add explicit defaults --- src/bootstrap/src/core/config/config.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 0be2e33966945..11373e3e41104 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1166,10 +1166,10 @@ impl Config { Warnings::Default => rust_deny_warnings.unwrap_or(true), }, backtrace_on_ice: rust_backtrace_on_ice.unwrap_or(false), - llvm_tests: llvm_tests.unwrap_or_default(), - llvm_enzyme: llvm_enzyme.unwrap_or_default(), + llvm_tests: llvm_tests.unwrap_or(false), + llvm_enzyme: llvm_enzyme.unwrap_or(false), llvm_offload: llvm_offload.unwrap_or(false), - llvm_plugins: llvm_plugin.unwrap_or_default(), + llvm_plugins: llvm_plugin.unwrap_or(false), llvm_optimize: llvm_optimize.unwrap_or(true), llvm_release_debuginfo: llvm_release_debuginfo.unwrap_or(false), llvm_static_stdcpp: llvm_static_libstdcpp.unwrap_or(false), @@ -1230,7 +1230,7 @@ impl Config { .unwrap_or(vec![CodegenBackendKind::Llvm]), rust_verify_llvm_ir: rust_verify_llvm_ir.unwrap_or(false), rust_thin_lto_import_instr_limit, - rust_randomize_layout: rust_randomize_layout.unwrap_or_default(), + rust_randomize_layout: rust_randomize_layout.unwrap_or(false), rust_remap_debuginfo: rust_remap_debuginfo.unwrap_or(false), rust_new_symbol_mangling, rust_profile_use: flags_rust_profile_use.or(rust_profile_use), From 5ae81c984f35ed0e4334c57287ac1fbf2467dd5f Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 20 Aug 2025 18:59:34 +0530 Subject: [PATCH 249/252] remove unwanted references, and make more initialization inline --- src/bootstrap/src/core/config/config.rs | 36 ++++++++++--------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 11373e3e41104..9d8f97196b61c 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -623,7 +623,7 @@ impl Config { targets: llvm_targets, experimental_targets: llvm_experimental_targets, link_jobs: llvm_link_jobs, - link_shared: llvm_link_shared_, + link_shared: llvm_link_shared, version_suffix: llvm_version_suffix, clang_cl: llvm_clang_cl, cflags: llvm_cflags, @@ -682,7 +682,6 @@ impl Config { let mut target_config = HashMap::new(); let mut download_rustc_commit = None; - let llvm_link_shared = Cell::default(); let mut llvm_from_ci = false; let mut channel = "dev".to_string(); let mut out = flags_build_dir @@ -764,7 +763,7 @@ impl Config { )); let initial_cargo = build_cargo.unwrap_or_else(|| { - download_beta_toolchain(&mut dwn_ctx); + download_beta_toolchain(&dwn_ctx); initial_sysroot.join("bin").join(exe("cargo", host_target)) }); @@ -848,11 +847,9 @@ impl Config { "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel." ); - let channel_ = read_file_by_commit(&dwn_ctx, Path::new("src/ci/channel"), commit) + channel = read_file_by_commit(&dwn_ctx, Path::new("src/ci/channel"), commit) .trim() .to_owned(); - - channel = channel_; } if let Some(t) = toml.target { @@ -917,6 +914,9 @@ impl Config { dwn_ctx.target_config = target_config.clone(); } + llvm_from_ci = parse_download_ci_llvm(&dwn_ctx, llvm_download_ci_llvm, llvm_assertions); + dwn_ctx.llvm_from_ci = llvm_from_ci; + // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will // build our internal lld and use it as the default linker, by setting the `rust.lld` config // to true by default: @@ -939,13 +939,6 @@ impl Config { rust_lld_enabled.unwrap_or(false) }; - if let Some(v) = llvm_link_shared_ { - llvm_link_shared.set(Some(v)); - } - - llvm_from_ci = parse_download_ci_llvm(&dwn_ctx, llvm_download_ci_llvm, llvm_assertions); - dwn_ctx.llvm_from_ci = llvm_from_ci; - if llvm_from_ci { let warn = |option: &str| { println!( @@ -960,7 +953,7 @@ impl Config { warn("static-libstdcpp"); } - if llvm_link_shared_.is_some() { + if llvm_link_shared.is_some() { warn("link-shared"); } @@ -981,13 +974,6 @@ impl Config { } } - if !llvm_from_ci && llvm_thin_lto.unwrap_or(false) && llvm_link_shared_.is_none() { - // If we're building with ThinLTO on, by default we want to link - // to LLVM shared, to avoid re-doing ThinLTO (which happens in - // the link step) with each stage. - llvm_link_shared.set(Some(true)); - } - if llvm_from_ci { let triple = &host_target.triple; let ci_llvm_bin = ci_llvm_root(&dwn_ctx).join("bin"); @@ -1340,6 +1326,13 @@ impl Config { patch_binaries_for_nix: build_patch_binaries_for_nix, cmd: flags_cmd, submodules: build_submodules, + // If we're building with ThinLTO on, by default we want to link + // to LLVM shared, to avoid re-doing ThinLTO (which happens in + // the link step) with each stage. + llvm_link_shared: Cell::new( + llvm_link_shared + .or((!llvm_from_ci && llvm_thin_lto.unwrap_or(false)).then_some(true)), + ), exec_ctx, out, rust_info, @@ -1361,7 +1354,6 @@ impl Config { path_modification_cache, stage0_metadata, download_rustc_commit, - llvm_link_shared, } } From 433dc2be446c1532f764f410e868a7d7d3b0b07c Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 20 Aug 2025 23:24:53 +0530 Subject: [PATCH 250/252] make download context lean and remove mutable types --- src/bootstrap/src/core/config/config.rs | 98 +++++++++++++------------ src/bootstrap/src/core/download.rs | 70 ++++++++++-------- 2 files changed, 89 insertions(+), 79 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 9d8f97196b61c..5913c871d83d7 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -679,15 +679,11 @@ impl Config { .unwrap_or_else(|| vec![host_target]); let llvm_assertions = llvm_assertions_.unwrap_or(false); - let mut target_config = HashMap::new(); - let mut download_rustc_commit = None; - let mut llvm_from_ci = false; let mut channel = "dev".to_string(); let mut out = flags_build_dir .or(build_build_dir.map(PathBuf::from)) .unwrap_or_else(|| PathBuf::from("build")); - let mut rust_info = GitInfo::Absent; if cfg!(test) { // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly. @@ -730,16 +726,11 @@ impl Config { ); } - let mut dwn_ctx = DownloadContext { + let dwn_ctx = DownloadContext { path_modification_cache: path_modification_cache.clone(), src: &src, - rust_info: rust_info.clone(), submodules: &build_submodules, - download_rustc_commit: download_rustc_commit.clone(), host_target, - llvm_from_ci, - target_config: target_config.clone(), - out: out.clone(), patch_binaries_for_nix: build_patch_binaries_for_nix, exec_ctx: &exec_ctx, stage0_metadata: &stage0_metadata, @@ -749,7 +740,7 @@ impl Config { }; let initial_rustc = build_rustc.unwrap_or_else(|| { - download_beta_toolchain(&dwn_ctx); + download_beta_toolchain(&dwn_ctx, &out); out.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target)) }); @@ -763,7 +754,7 @@ impl Config { )); let initial_cargo = build_cargo.unwrap_or_else(|| { - download_beta_toolchain(&dwn_ctx); + download_beta_toolchain(&dwn_ctx, &out); initial_sysroot.join("bin").join(exe("cargo", host_target)) }); @@ -771,7 +762,6 @@ impl Config { if exec_ctx.dry_run() { out = out.join("tmp-dry-run"); fs::create_dir_all(&out).expect("Failed to create dry-run directory"); - dwn_ctx.out = out.clone(); } let file_content = t!(fs::read_to_string(src.join("src/ci/channel"))); @@ -791,8 +781,7 @@ impl Config { let omit_git_hash = rust_omit_git_hash.unwrap_or(channel == "dev"); - rust_info = git_info(&exec_ctx, omit_git_hash, &src); - dwn_ctx.rust_info = rust_info.clone(); + let rust_info = git_info(&exec_ctx, omit_git_hash, &src); if !is_user_configured_rust_channel && rust_info.is_from_tarball() { channel = ci_channel.into(); @@ -823,9 +812,8 @@ impl Config { ); } - download_rustc_commit = - download_ci_rustc_commit(&dwn_ctx, rust_download_rustc, llvm_assertions); - dwn_ctx.download_rustc_commit = download_rustc_commit.clone(); + let mut download_rustc_commit = + download_ci_rustc_commit(&dwn_ctx, &rust_info, rust_download_rustc, llvm_assertions); if debug_assertions_requested && download_rustc_commit.is_some() { eprintln!( @@ -834,7 +822,6 @@ impl Config { ); // We need to put this later down_ci_rustc_commit. download_rustc_commit = None; - dwn_ctx.download_rustc_commit = None; } // We need to override `rust.channel` if it's manually specified when using the CI rustc. @@ -847,9 +834,10 @@ impl Config { "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel." ); - channel = read_file_by_commit(&dwn_ctx, Path::new("src/ci/channel"), commit) - .trim() - .to_owned(); + channel = + read_file_by_commit(&dwn_ctx, &rust_info, Path::new("src/ci/channel"), commit) + .trim() + .to_owned(); } if let Some(t) = toml.target { @@ -911,11 +899,15 @@ impl Config { target_config.insert(TargetSelection::from_user(&triple), target); } - dwn_ctx.target_config = target_config.clone(); } - llvm_from_ci = parse_download_ci_llvm(&dwn_ctx, llvm_download_ci_llvm, llvm_assertions); - dwn_ctx.llvm_from_ci = llvm_from_ci; + let llvm_from_ci = parse_download_ci_llvm( + &dwn_ctx, + &rust_info, + &download_rustc_commit, + llvm_download_ci_llvm, + llvm_assertions, + ); // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will // build our internal lld and use it as the default linker, by setting the `rust.lld` config @@ -976,18 +968,16 @@ impl Config { if llvm_from_ci { let triple = &host_target.triple; - let ci_llvm_bin = ci_llvm_root(&dwn_ctx).join("bin"); + let ci_llvm_bin = ci_llvm_root(&dwn_ctx, llvm_from_ci, &out).join("bin"); let build_target = target_config.entry(host_target).or_insert_with(|| Target::from_triple(triple)); - dwn_ctx.target_config.entry(host_target).or_insert_with(|| Target::from_triple(triple)); - check_ci_llvm!(build_target.llvm_config); check_ci_llvm!(build_target.llvm_filecheck); build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", host_target))); build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", host_target))); } - let initial_rustfmt = build_rustfmt.or_else(|| maybe_download_rustfmt(&dwn_ctx)); + let initial_rustfmt = build_rustfmt.or_else(|| maybe_download_rustfmt(&dwn_ctx, &out)); if matches!(rust_lld_mode.unwrap_or_default(), LldMode::SelfContained) && !lld_enabled @@ -998,7 +988,7 @@ impl Config { ); } - if lld_enabled && is_system_llvm(&dwn_ctx, host_target) { + if lld_enabled && is_system_llvm(&dwn_ctx, &target_config, llvm_from_ci, host_target) { panic!("Cannot enable LLD with `rust.lld = true` when using external llvm-config."); } @@ -1392,7 +1382,7 @@ impl Config { /// Returns the content of the given file at a specific commit. pub(crate) fn read_file_by_commit(&self, file: &Path, commit: &str) -> String { let dwn_ctx = DownloadContext::from(self); - read_file_by_commit(dwn_ctx, file, commit) + read_file_by_commit(dwn_ctx, &self.rust_info, file, commit) } /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI. @@ -1464,7 +1454,7 @@ impl Config { /// The absolute path to the downloaded LLVM artifacts. pub(crate) fn ci_llvm_root(&self) -> PathBuf { let dwn_ctx = DownloadContext::from(self); - ci_llvm_root(dwn_ctx) + ci_llvm_root(dwn_ctx, self.llvm_from_ci, &self.out) } /// Directory where the extracted `rustc-dev` component is stored. @@ -1628,7 +1618,7 @@ impl Config { )] pub(crate) fn update_submodule(&self, relative_path: &str) { let dwn_ctx = DownloadContext::from(self); - update_submodule(dwn_ctx, relative_path); + update_submodule(dwn_ctx, &self.rust_info, relative_path); } /// Returns true if any of the `paths` have been modified locally. @@ -1744,7 +1734,7 @@ impl Config { /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set. pub fn is_system_llvm(&self, target: TargetSelection) -> bool { let dwn_ctx = DownloadContext::from(self); - is_system_llvm(dwn_ctx, target) + is_system_llvm(dwn_ctx, &self.target_config, self.llvm_from_ci, target) } /// Returns `true` if this is our custom, patched, version of LLVM. @@ -2038,6 +2028,7 @@ pub fn check_stage0_version( pub fn download_ci_rustc_commit<'a>( dwn_ctx: impl AsRef>, + rust_info: &channel::GitInfo, download_rustc: Option, llvm_assertions: bool, ) -> Option { @@ -2057,7 +2048,7 @@ pub fn download_ci_rustc_commit<'a>( None | Some(StringOrBool::Bool(false)) => return None, Some(StringOrBool::Bool(true)) => false, Some(StringOrBool::String(s)) if s == "if-unchanged" => { - if !dwn_ctx.rust_info.is_managed_git_subrepository() { + if !rust_info.is_managed_git_subrepository() { println!( "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources." ); @@ -2071,7 +2062,7 @@ pub fn download_ci_rustc_commit<'a>( } }; - let commit = if dwn_ctx.rust_info.is_managed_git_subrepository() { + let commit = if rust_info.is_managed_git_subrepository() { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let freshness = check_path_modifications_(dwn_ctx, RUSTC_IF_UNCHANGED_ALLOWED_PATHS); @@ -2145,6 +2136,8 @@ pub fn git_config(stage0_metadata: &build_helper::stage0_parser::Stage0) -> GitC pub fn parse_download_ci_llvm<'a>( dwn_ctx: impl AsRef>, + rust_info: &channel::GitInfo, + download_rustc_commit: &Option, download_ci_llvm: Option, asserts: bool, ) -> bool { @@ -2160,7 +2153,7 @@ pub fn parse_download_ci_llvm<'a>( let download_ci_llvm = download_ci_llvm.unwrap_or(default); let if_unchanged = || { - if dwn_ctx.rust_info.is_from_tarball() { + if rust_info.is_from_tarball() { // Git is needed for running "if-unchanged" logic. println!("ERROR: 'if-unchanged' is only compatible with Git managed sources."); crate::exit!(1); @@ -2168,7 +2161,7 @@ pub fn parse_download_ci_llvm<'a>( // Fetching the LLVM submodule is unnecessary for self-tests. #[cfg(not(test))] - update_submodule(dwn_ctx, "src/llvm-project"); + update_submodule(dwn_ctx, rust_info, "src/llvm-project"); // Check for untracked changes in `src/llvm-project` and other important places. let has_changes = has_changes_from_upstream(dwn_ctx, LLVM_INVALIDATION_PATHS); @@ -2183,7 +2176,7 @@ pub fn parse_download_ci_llvm<'a>( match download_ci_llvm { StringOrBool::Bool(b) => { - if !b && dwn_ctx.download_rustc_commit.is_some() { + if !b && download_rustc_commit.is_some() { panic!( "`llvm.download-ci-llvm` cannot be set to `false` if `rust.download-rustc` is set to `true` or `if-unchanged`." ); @@ -2226,9 +2219,13 @@ pub fn has_changes_from_upstream<'a>( fields(relative_path = ?relative_path), ), )] -pub(crate) fn update_submodule<'a>(dwn_ctx: impl AsRef>, relative_path: &str) { +pub(crate) fn update_submodule<'a>( + dwn_ctx: impl AsRef>, + rust_info: &channel::GitInfo, + relative_path: &str, +) { let dwn_ctx = dwn_ctx.as_ref(); - if dwn_ctx.rust_info.is_from_tarball() || !submodules_(dwn_ctx.submodules, &dwn_ctx.rust_info) { + if rust_info.is_from_tarball() || !submodules_(dwn_ctx.submodules, rust_info) { return; } @@ -2357,12 +2354,14 @@ pub fn submodules_(submodules: &Option, rust_info: &channel::GitInfo) -> b /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set. pub fn is_system_llvm<'a>( dwn_ctx: impl AsRef>, + target_config: &HashMap, + llvm_from_ci: bool, target: TargetSelection, ) -> bool { let dwn_ctx = dwn_ctx.as_ref(); - match dwn_ctx.target_config.get(&target) { + match target_config.get(&target) { Some(Target { llvm_config: Some(_), .. }) => { - let ci_llvm = dwn_ctx.llvm_from_ci && is_host_target(&dwn_ctx.host_target, &target); + let ci_llvm = llvm_from_ci && is_host_target(&dwn_ctx.host_target, &target); !ci_llvm } // We're building from the in-tree src/llvm-project sources. @@ -2375,21 +2374,26 @@ pub fn is_host_target(host_target: &TargetSelection, target: &TargetSelection) - host_target == target } -pub(crate) fn ci_llvm_root<'a>(dwn_ctx: impl AsRef>) -> PathBuf { +pub(crate) fn ci_llvm_root<'a>( + dwn_ctx: impl AsRef>, + llvm_from_ci: bool, + out: &Path, +) -> PathBuf { let dwn_ctx = dwn_ctx.as_ref(); - assert!(dwn_ctx.llvm_from_ci); - dwn_ctx.out.join(dwn_ctx.host_target).join("ci-llvm") + assert!(llvm_from_ci); + out.join(dwn_ctx.host_target).join("ci-llvm") } /// Returns the content of the given file at a specific commit. pub(crate) fn read_file_by_commit<'a>( dwn_ctx: impl AsRef>, + rust_info: &channel::GitInfo, file: &Path, commit: &str, ) -> String { let dwn_ctx = dwn_ctx.as_ref(); assert!( - dwn_ctx.rust_info.is_managed_git_subrepository(), + rust_info.is_managed_git_subrepository(), "`Config::read_file_by_commit` is not supported in non-git sources." ); diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 402d6019dabbb..2f3c80559c0ef 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -9,9 +9,8 @@ use std::sync::{Arc, Mutex, OnceLock}; use build_helper::git::PathFreshness; use xz2::bufread::XzDecoder; -use crate::core::config::{BUILDER_CONFIG_FILENAME, Target, TargetSelection}; +use crate::core::config::{BUILDER_CONFIG_FILENAME, TargetSelection}; use crate::utils::build_stamp::BuildStamp; -use crate::utils::channel; use crate::utils::exec::{ExecutionContext, command}; use crate::utils::helpers::{exe, hex_encode, move_file}; use crate::{Config, t}; @@ -73,7 +72,7 @@ impl Config { fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) { let dwn_ctx: DownloadContext<'_> = self.into(); - download_file(dwn_ctx, url, dest_path, help_on_error); + download_file(dwn_ctx, &self.out, url, dest_path, help_on_error); } fn unpack(&self, tarball: &Path, dst: &Path, pattern: &str) { @@ -238,7 +237,7 @@ impl Config { destination: &str, ) { let dwn_ctx: DownloadContext<'_> = self.into(); - download_component(dwn_ctx, mode, filename, prefix, key, destination); + download_component(dwn_ctx, &self.out, mode, filename, prefix, key, destination); } #[cfg(test)] @@ -403,13 +402,8 @@ impl Config { pub(crate) struct DownloadContext<'a> { pub path_modification_cache: Arc, PathFreshness>>>, pub src: &'a Path, - pub rust_info: channel::GitInfo, pub submodules: &'a Option, - pub download_rustc_commit: Option, pub host_target: TargetSelection, - pub llvm_from_ci: bool, - pub target_config: HashMap, - pub out: PathBuf, pub patch_binaries_for_nix: Option, pub exec_ctx: &'a ExecutionContext, pub stage0_metadata: &'a build_helper::stage0_parser::Stage0, @@ -430,12 +424,7 @@ impl<'a> From<&'a Config> for DownloadContext<'a> { path_modification_cache: value.path_modification_cache.clone(), src: &value.src, host_target: value.host_target, - rust_info: value.rust_info.clone(), - download_rustc_commit: value.download_rustc_commit.clone(), submodules: &value.submodules, - llvm_from_ci: value.llvm_from_ci, - target_config: value.target_config.clone(), - out: value.out.clone(), patch_binaries_for_nix: value.patch_binaries_for_nix, exec_ctx: &value.exec_ctx, stage0_metadata: &value.stage0_metadata, @@ -495,6 +484,7 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo #[cfg(test)] pub(crate) fn maybe_download_rustfmt<'a>( dwn_ctx: impl AsRef>, + out: &Path, ) -> Option { Some(PathBuf::new()) } @@ -504,6 +494,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( #[cfg(not(test))] pub(crate) fn maybe_download_rustfmt<'a>( dwn_ctx: impl AsRef>, + out: &Path, ) -> Option { use build_helper::stage0_parser::VersionMetadata; @@ -517,7 +508,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( let channel = format!("{version}-{date}"); let host = dwn_ctx.host_target; - let bin_root = dwn_ctx.out.join(host).join("rustfmt"); + let bin_root = out.join(host).join("rustfmt"); let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host)); let rustfmt_stamp = BuildStamp::new(&bin_root).with_prefix("rustfmt").add_stamp(channel); if rustfmt_path.exists() && rustfmt_stamp.is_up_to_date() { @@ -526,6 +517,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( download_component( dwn_ctx, + out, DownloadSource::Dist, format!("rustfmt-{version}-{build}.tar.xz", build = host.triple), "rustfmt-preview", @@ -535,6 +527,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( download_component( dwn_ctx, + out, DownloadSource::Dist, format!("rustc-{version}-{build}.tar.xz", build = host.triple), "rustc", @@ -543,13 +536,13 @@ pub(crate) fn maybe_download_rustfmt<'a>( ); if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) { - fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("rustfmt"), dwn_ctx.exec_ctx); - fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("cargo-fmt"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &bin_root.join("bin").join("rustfmt"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &bin_root.join("bin").join("cargo-fmt"), dwn_ctx.exec_ctx); let lib_dir = bin_root.join("lib"); for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) { let lib = t!(lib); if path_is_dylib(&lib.path()) { - fix_bin_or_dylib(&dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &lib.path(), dwn_ctx.exec_ctx); } } } @@ -559,10 +552,10 @@ pub(crate) fn maybe_download_rustfmt<'a>( } #[cfg(test)] -pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef>) {} +pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef>, out: &Path) {} #[cfg(not(test))] -pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef>) { +pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef>, out: &Path) { let dwn_ctx = dwn_ctx.as_ref(); dwn_ctx.exec_ctx.verbose(|| { println!("downloading stage0 beta artifacts"); @@ -574,6 +567,7 @@ pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef(dwn_ctx: impl AsRef( dwn_ctx: impl AsRef>, + out: &Path, version: &str, sysroot: &str, stamp_key: &str, @@ -594,7 +590,7 @@ fn download_toolchain<'a>( ) { let dwn_ctx = dwn_ctx.as_ref(); let host = dwn_ctx.host_target.triple; - let bin_root = dwn_ctx.out.join(host).join(sysroot); + let bin_root = out.join(host).join(sysroot); let rustc_stamp = BuildStamp::new(&bin_root).with_prefix("rustc").add_stamp(stamp_key); if !bin_root.join("bin").join(exe("rustc", dwn_ctx.host_target)).exists() @@ -605,20 +601,28 @@ fn download_toolchain<'a>( } let filename = format!("rust-std-{version}-{host}.tar.xz"); let pattern = format!("rust-std-{host}"); - download_component(dwn_ctx, mode.clone(), filename, &pattern, stamp_key, destination); + download_component(dwn_ctx, out, mode.clone(), filename, &pattern, stamp_key, destination); let filename = format!("rustc-{version}-{host}.tar.xz"); - download_component(dwn_ctx, mode.clone(), filename, "rustc", stamp_key, destination); + download_component(dwn_ctx, out, mode.clone(), filename, "rustc", stamp_key, destination); for component in extra_components { let filename = format!("{component}-{version}-{host}.tar.xz"); - download_component(dwn_ctx, mode.clone(), filename, component, stamp_key, destination); + download_component( + dwn_ctx, + out, + mode.clone(), + filename, + component, + stamp_key, + destination, + ); } if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) { - fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("rustc"), dwn_ctx.exec_ctx); - fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("rustdoc"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &bin_root.join("bin").join("rustc"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &bin_root.join("bin").join("rustdoc"), dwn_ctx.exec_ctx); fix_bin_or_dylib( - &dwn_ctx.out, + out, &bin_root.join("libexec").join("rust-analyzer-proc-macro-srv"), dwn_ctx.exec_ctx, ); @@ -626,7 +630,7 @@ fn download_toolchain<'a>( for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) { let lib = t!(lib); if path_is_dylib(&lib.path()) { - fix_bin_or_dylib(&dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &lib.path(), dwn_ctx.exec_ctx); } } } @@ -750,6 +754,7 @@ fn should_fix_bins_and_dylibs( fn download_component<'a>( dwn_ctx: impl AsRef>, + out: &Path, mode: DownloadSource, filename: String, prefix: &str, @@ -763,14 +768,14 @@ fn download_component<'a>( } let cache_dst = - dwn_ctx.bootstrap_cache_path.as_ref().cloned().unwrap_or_else(|| dwn_ctx.out.join("cache")); + dwn_ctx.bootstrap_cache_path.as_ref().cloned().unwrap_or_else(|| out.join("cache")); let cache_dir = cache_dst.join(key); if !cache_dir.exists() { t!(fs::create_dir_all(&cache_dir)); } - let bin_root = dwn_ctx.out.join(dwn_ctx.host_target).join(destination); + let bin_root = out.join(dwn_ctx.host_target).join(destination); let tarball = cache_dir.join(&filename); let (base_url, url, should_verify) = match mode { DownloadSource::CI => { @@ -835,7 +840,7 @@ HELP: if trying to compile an old commit of rustc, disable `download-rustc` in b download-rustc = false "; } - download_file(dwn_ctx, &format!("{base_url}/{url}"), &tarball, help_on_error); + download_file(dwn_ctx, out, &format!("{base_url}/{url}"), &tarball, help_on_error); if let Some(sha256) = checksum && !verify(dwn_ctx.exec_ctx, &tarball, sha256) { @@ -953,6 +958,7 @@ fn unpack(exec_ctx: &ExecutionContext, tarball: &Path, dst: &Path, pattern: &str fn download_file<'a>( dwn_ctx: impl AsRef>, + out: &Path, url: &str, dest_path: &Path, help_on_error: &str, @@ -963,7 +969,7 @@ fn download_file<'a>( println!("download {url}"); }); // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/. - let tempfile = tempdir(&dwn_ctx.out).join(dest_path.file_name().unwrap()); + let tempfile = tempdir(out).join(dest_path.file_name().unwrap()); // While bootstrap itself only supports http and https downloads, downstream forks might // need to download components from other protocols. The match allows them adding more // protocols without worrying about merge conflicts if we change the HTTP implementation. From e261e25c9973a71f9d6cf5ee32640de9e28c6369 Mon Sep 17 00:00:00 2001 From: bit-aloo Date: Wed, 20 Aug 2025 23:40:59 +0530 Subject: [PATCH 251/252] move few complex initialization from config to parse-inner --- src/bootstrap/src/core/config/config.rs | 110 +++++++++++++----------- 1 file changed, 61 insertions(+), 49 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 5913c871d83d7..efc76a0df648c 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -687,7 +687,7 @@ impl Config { if cfg!(test) { // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly. - if out == PathBuf::from("build") { + if out == Path::new("build") { out = Path::new( &env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"), ) @@ -1088,14 +1088,64 @@ impl Config { ) }; + let ccache = match build_ccache { + Some(StringOrBool::String(s)) => Some(s), + Some(StringOrBool::Bool(true)) => Some("ccache".to_string()), + _ => None, + }; + + let explicit_stage_from_config = build_test_stage.is_some() + || build_build_stage.is_some() + || build_doc_stage.is_some() + || build_dist_stage.is_some() + || build_install_stage.is_some() + || build_check_stage.is_some() + || build_bench_stage.is_some(); + + let deny_warnings = match flags_warnings { + Warnings::Deny => true, + Warnings::Warn => false, + Warnings::Default => rust_deny_warnings.unwrap_or(true), + }; + + let gcc_ci_mode = match gcc_download_ci_gcc { + Some(value) => match value { + true => GccCiMode::DownloadFromCi, + false => GccCiMode::BuildLocally, + }, + None => GccCiMode::default(), + }; + + let targets = flags_target + .map(|TargetSelectionList(targets)| targets) + .or_else(|| { + build_target.map(|t| t.iter().map(|t| TargetSelection::from_user(t)).collect()) + }) + .unwrap_or_else(|| hosts.clone()); + + #[allow(clippy::map_identity)] + let skip = flags_skip + .into_iter() + .chain(flags_exclude) + .chain(build_exclude.unwrap_or_default()) + .map(|p| { + // Never return top-level path here as it would break `--skip` + // logic on rustc's internal test framework which is utilized by compiletest. + #[cfg(windows)] + { + PathBuf::from(p.to_string_lossy().replace('/', "\\")) + } + #[cfg(not(windows))] + { + p + } + }) + .collect(); + Config { change_id: toml.change_id.inner, bypass_bootstrap_lock: flags_bypass_bootstrap_lock, - ccache: match build_ccache { - Some(StringOrBool::String(s)) => Some(s), - Some(StringOrBool::Bool(true)) => Some("ccache".to_string()), - _ => None, - }, + ccache, ninja_in_file: llvm_ninja.unwrap_or(true), compiler_docs: build_compiler_docs.unwrap_or(false), library_docs_private_items: build_library_docs_private_items.unwrap_or(false), @@ -1122,13 +1172,7 @@ impl Config { stderr_is_tty: std::io::stderr().is_terminal(), on_fail: flags_on_fail, explicit_stage_from_cli: flags_stage.is_some(), - explicit_stage_from_config: build_test_stage.is_some() - || build_build_stage.is_some() - || build_doc_stage.is_some() - || build_dist_stage.is_some() - || build_install_stage.is_some() - || build_check_stage.is_some() - || build_bench_stage.is_some(), + explicit_stage_from_config, keep_stage: flags_keep_stage, keep_stage_std: flags_keep_stage_std, @@ -1136,11 +1180,7 @@ impl Config { incremental: flags_incremental || rust_incremental == Some(true), dump_bootstrap_shims: flags_dump_bootstrap_shims, free_args: flags_free_args, - deny_warnings: match flags_warnings { - Warnings::Deny => true, - Warnings::Warn => false, - Warnings::Default => rust_deny_warnings.unwrap_or(true), - }, + deny_warnings, backtrace_on_ice: rust_backtrace_on_ice.unwrap_or(false), llvm_tests: llvm_tests.unwrap_or(false), llvm_enzyme: llvm_enzyme.unwrap_or(false), @@ -1167,13 +1207,7 @@ impl Config { llvm_cxxflags, llvm_ldflags, llvm_use_libcxx: llvm_use_libcxx.unwrap_or(false), - gcc_ci_mode: match gcc_download_ci_gcc { - Some(value) => match value { - true => GccCiMode::DownloadFromCi, - false => GccCiMode::BuildLocally, - }, - None => GccCiMode::default(), - }, + gcc_ci_mode, rust_optimize: rust_optimize.unwrap_or(RustOptimize::Bool(true)), rust_codegen_units: rust_codegen_units.map(threads_from_config), rust_codegen_units_std: rust_codegen_units_std.map(threads_from_config), @@ -1278,30 +1312,8 @@ impl Config { // If we're building from git or tarball sources, enable it by default. rust_info.is_managed_git_subrepository() || rust_info.is_from_tarball() }), - targets: flags_target - .map(|TargetSelectionList(targets)| targets) - .or_else(|| { - build_target.map(|t| t.iter().map(|t| TargetSelection::from_user(t)).collect()) - }) - .unwrap_or_else(|| hosts.clone()), - #[allow(clippy::map_identity)] - skip: flags_skip - .into_iter() - .chain(flags_exclude) - .chain(build_exclude.unwrap_or_default()) - .map(|p| { - // Never return top-level path here as it would break `--skip` - // logic on rustc's internal test framework which is utilized by compiletest. - #[cfg(windows)] - { - PathBuf::from(p.to_string_lossy().replace('/', "\\")) - } - #[cfg(not(windows))] - { - p - } - }) - .collect(), + targets, + skip, paths: flags_paths, config: toml_path, llvm_thin_lto: llvm_thin_lto.unwrap_or(false), From c058ce594bb6b899af6402bb6b894448f36ca3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 22 Aug 2025 12:08:58 +0200 Subject: [PATCH 252/252] Sort Config fields and remove some `mut`s from bindings --- src/bootstrap/src/core/config/config.rs | 408 ++++++++++++------------ 1 file changed, 210 insertions(+), 198 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index efc76a0df648c..51e7012d1c40f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -463,7 +463,6 @@ impl Config { ); // Set config values based on flags. - let mut exec_ctx = ExecutionContext::new(flags_verbose, flags_cmd.fail_fast()); exec_ctx.set_dry_run(if flags_dry_run { DryRun::UserSelected } else { DryRun::Disabled }); let mut src = { @@ -479,8 +478,6 @@ impl Config { // Now load the TOML config, as soon as possible let (mut toml, toml_path) = load_toml_config(&src, flags_config, &get_toml); - let is_running_on_ci = flags_ci.unwrap_or(CiEnv::is_ci()); - postprocess_toml(&mut toml, &src, toml_path.clone(), &exec_ctx, &flags_set, &get_toml); // Now override TOML values with flags, to make sure that we won't later override flags with @@ -613,7 +610,7 @@ impl Config { optimize: llvm_optimize, thin_lto: llvm_thin_lto, release_debuginfo: llvm_release_debuginfo, - assertions: llvm_assertions_, + assertions: llvm_assertions, tests: llvm_tests, enzyme: llvm_enzyme, plugins: llvm_plugin, @@ -678,23 +675,33 @@ impl Config { }) .unwrap_or_else(|| vec![host_target]); - let llvm_assertions = llvm_assertions_.unwrap_or(false); + let llvm_assertions = llvm_assertions.unwrap_or(false); let mut target_config = HashMap::new(); let mut channel = "dev".to_string(); - let mut out = flags_build_dir - .or(build_build_dir.map(PathBuf::from)) - .unwrap_or_else(|| PathBuf::from("build")); - - if cfg!(test) { - // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly. - if out == Path::new("build") { - out = Path::new( + let out = flags_build_dir.or(build_build_dir.map(PathBuf::from)).unwrap_or_else(|| { + if cfg!(test) { + // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly. + Path::new( &env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"), ) .parent() .unwrap() - .to_path_buf(); + .to_path_buf() + } else { + PathBuf::from("build") } + }); + + // NOTE: Bootstrap spawns various commands with different working directories. + // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. + let mut out = if !out.is_absolute() { + // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead. + absolute(&out).expect("can't make empty path absolute") + } else { + out + }; + + if cfg!(test) { // When configuring bootstrap for tests, make sure to set the rustc and Cargo to the // same ones used to call the tests (if custom ones are not defined in the toml). If we // don't do that, bootstrap will use its own detection logic to find a suitable rustc @@ -704,13 +711,6 @@ impl Config { build_cargo = build_cargo.take().or(std::env::var_os("CARGO").map(|p| p.into())); } - // NOTE: Bootstrap spawns various commands with different working directories. - // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. - if !out.is_absolute() { - // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead. - out = absolute(&out).expect("can't make empty path absolute"); - } - if !flags_skip_stage0_validation { if let Some(rustc) = &build_rustc { check_stage0_version(rustc, "rustc", &src, &exec_ctx); @@ -726,6 +726,7 @@ impl Config { ); } + let is_running_on_ci = flags_ci.unwrap_or(CiEnv::is_ci()); let dwn_ctx = DownloadContext { path_modification_cache: path_modification_cache.clone(), src: &src, @@ -1142,220 +1143,231 @@ impl Config { }) .collect(); + let cargo_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/cargo")); + let clippy_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/clippy")); + let in_tree_gcc_info = git_info(&exec_ctx, false, &src.join("src/gcc")); + let in_tree_llvm_info = git_info(&exec_ctx, false, &src.join("src/llvm-project")); + let enzyme_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/enzyme")); + let miri_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/miri")); + let rust_analyzer_info = + git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/rust-analyzer")); + let rustfmt_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/rustfmt")); + + let optimized_compiler_builtins = + build_optimized_compiler_builtins.unwrap_or(channel != "dev"); + let vendor = build_vendor.unwrap_or( + rust_info.is_from_tarball() + && src.join("vendor").exists() + && src.join(".cargo/config.toml").exists(), + ); + let verbose_tests = rust_verbose_tests.unwrap_or(exec_ctx.is_verbose()); + Config { - change_id: toml.change_id.inner, + // tidy-alphabetical-start + android_ndk: build_android_ndk, + backtrace: rust_backtrace.unwrap_or(true), + backtrace_on_ice: rust_backtrace_on_ice.unwrap_or(false), + bindir: install_bindir.map(PathBuf::from).unwrap_or("bin".into()), + bootstrap_cache_path: build_bootstrap_cache_path, bypass_bootstrap_lock: flags_bypass_bootstrap_lock, + cargo_info, + cargo_native_static: build_cargo_native_static.unwrap_or(false), ccache, - ninja_in_file: llvm_ninja.unwrap_or(true), + change_id: toml.change_id.inner, + channel, + clippy_info, + cmd: flags_cmd, + codegen_tests: rust_codegen_tests.unwrap_or(true), + color: flags_color, + compile_time_deps: flags_compile_time_deps, compiler_docs: build_compiler_docs.unwrap_or(false), - library_docs_private_items: build_library_docs_private_items.unwrap_or(false), - docs_minification: build_docs_minification.unwrap_or(true), + compiletest_allow_stage0: build_compiletest_allow_stage0.unwrap_or(false), + compiletest_diff_tool: build_compiletest_diff_tool, + compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest.unwrap_or(true), + config: toml_path, + configure_args: build_configure_args.unwrap_or_default(), + control_flow_guard: rust_control_flow_guard.unwrap_or(false), + datadir: install_datadir.map(PathBuf::from), + deny_warnings, + description: build_description, + dist_compression_formats, + dist_compression_profile: dist_compression_profile.unwrap_or("fast".into()), + dist_include_mingw_linker: dist_include_mingw_linker.unwrap_or(true), + dist_sign_folder: dist_sign_folder.map(PathBuf::from), + dist_upload_addr, + dist_vendor: dist_vendor.unwrap_or_else(|| { + // If we're building from git or tarball sources, enable it by default. + rust_info.is_managed_git_subrepository() || rust_info.is_from_tarball() + }), + docdir: install_docdir.map(PathBuf::from), docs: build_docs.unwrap_or(true), - locked_deps: build_locked_deps.unwrap_or(false), - full_bootstrap: build_full_bootstrap.unwrap_or(false), - bootstrap_cache_path: build_bootstrap_cache_path, + docs_minification: build_docs_minification.unwrap_or(true), + download_rustc_commit, + dump_bootstrap_shims: flags_dump_bootstrap_shims, + ehcont_guard: rust_ehcont_guard.unwrap_or(false), + enable_bolt_settings: flags_enable_bolt_settings, + enzyme_info, + exec_ctx, + explicit_stage_from_cli: flags_stage.is_some(), + explicit_stage_from_config, extended: build_extended.unwrap_or(false), - tools: build_tools, - tool: build_tool.unwrap_or_default(), - sanitizers: build_sanitizers.unwrap_or(false), - profiler: build_profiler.unwrap_or(false), + free_args: flags_free_args, + full_bootstrap: build_full_bootstrap.unwrap_or(false), + gcc_ci_mode, + gdb: build_gdb.map(PathBuf::from), + host_target, + hosts, + in_tree_gcc_info, + in_tree_llvm_info, include_default_paths: flags_include_default_paths, - rustc_error_format: flags_rustc_error_format, + incremental: flags_incremental || rust_incremental == Some(true), + initial_cargo, + initial_cargo_clippy: build_cargo_clippy, + initial_rustc, + initial_rustfmt, + initial_sysroot, + is_running_on_ci, + jemalloc: rust_jemalloc.unwrap_or(false), + jobs: Some(threads_from_config(flags_jobs.or(build_jobs).unwrap_or(0))), json_output: flags_json_output, - compile_time_deps: flags_compile_time_deps, - test_compare_mode: rust_test_compare_mode.unwrap_or(false), - color: flags_color, - android_ndk: build_android_ndk, - optimized_compiler_builtins: build_optimized_compiler_builtins - .unwrap_or(channel != "dev"), - stdout_is_tty: std::io::stdout().is_terminal(), - stderr_is_tty: std::io::stderr().is_terminal(), - on_fail: flags_on_fail, - explicit_stage_from_cli: flags_stage.is_some(), - explicit_stage_from_config, - keep_stage: flags_keep_stage, keep_stage_std: flags_keep_stage_std, - jobs: Some(threads_from_config(flags_jobs.or(build_jobs).unwrap_or(0))), - incremental: flags_incremental || rust_incremental == Some(true), - dump_bootstrap_shims: flags_dump_bootstrap_shims, - free_args: flags_free_args, - deny_warnings, - backtrace_on_ice: rust_backtrace_on_ice.unwrap_or(false), - llvm_tests: llvm_tests.unwrap_or(false), + libdir: install_libdir.map(PathBuf::from), + library_docs_private_items: build_library_docs_private_items.unwrap_or(false), + lld_enabled, + lld_mode: rust_lld_mode.unwrap_or_default(), + lldb: build_lldb.map(PathBuf::from), + llvm_allow_old_toolchain: llvm_allow_old_toolchain.unwrap_or(false), + llvm_assertions, + llvm_bitcode_linker_enabled: rust_llvm_bitcode_linker.unwrap_or(false), + llvm_build_config: llvm_build_config.clone().unwrap_or(Default::default()), + llvm_cflags, + llvm_clang: llvm_clang.unwrap_or(false), + llvm_clang_cl, + llvm_cxxflags, + llvm_enable_warnings: llvm_enable_warnings.unwrap_or(false), llvm_enzyme: llvm_enzyme.unwrap_or(false), + llvm_experimental_targets, + llvm_from_ci, + llvm_ldflags, + llvm_libunwind_default: rust_llvm_libunwind + .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")), + llvm_libzstd: llvm_libzstd.unwrap_or(false), + llvm_link_jobs, + // If we're building with ThinLTO on, by default we want to link + // to LLVM shared, to avoid re-doing ThinLTO (which happens in + // the link step) with each stage. + llvm_link_shared: Cell::new( + llvm_link_shared + .or((!llvm_from_ci && llvm_thin_lto.unwrap_or(false)).then_some(true)), + ), llvm_offload: llvm_offload.unwrap_or(false), - llvm_plugins: llvm_plugin.unwrap_or(false), llvm_optimize: llvm_optimize.unwrap_or(true), + llvm_plugins: llvm_plugin.unwrap_or(false), + llvm_polly: llvm_polly.unwrap_or(false), + llvm_profile_generate: flags_llvm_profile_generate, + llvm_profile_use: flags_llvm_profile_use, llvm_release_debuginfo: llvm_release_debuginfo.unwrap_or(false), llvm_static_stdcpp: llvm_static_libstdcpp.unwrap_or(false), - llvm_libzstd: llvm_libzstd.unwrap_or(false), - llvm_clang_cl, llvm_targets, - llvm_experimental_targets, - llvm_link_jobs, - llvm_version_suffix, - llvm_use_linker, - llvm_allow_old_toolchain: llvm_allow_old_toolchain.unwrap_or(false), - llvm_polly: llvm_polly.unwrap_or(false), - llvm_clang: llvm_clang.unwrap_or(false), - llvm_enable_warnings: llvm_enable_warnings.unwrap_or(false), - llvm_build_config: llvm_build_config.clone().unwrap_or(Default::default()), + llvm_tests: llvm_tests.unwrap_or(false), + llvm_thin_lto: llvm_thin_lto.unwrap_or(false), llvm_tools_enabled: rust_llvm_tools.unwrap_or(true), - llvm_bitcode_linker_enabled: rust_llvm_bitcode_linker.unwrap_or(false), - llvm_cflags, - llvm_cxxflags, - llvm_ldflags, llvm_use_libcxx: llvm_use_libcxx.unwrap_or(false), - gcc_ci_mode, - rust_optimize: rust_optimize.unwrap_or(RustOptimize::Bool(true)), + llvm_use_linker, + llvm_version_suffix, + local_rebuild: build_local_rebuild.unwrap_or(false), + locked_deps: build_locked_deps.unwrap_or(false), + low_priority: build_low_priority.unwrap_or(false), + mandir: install_mandir.map(PathBuf::from), + miri_info, + musl_root: rust_musl_root.map(PathBuf::from), + ninja_in_file: llvm_ninja.unwrap_or(true), + nodejs: build_nodejs.map(PathBuf::from), + npm: build_npm.map(PathBuf::from), + omit_git_hash, + on_fail: flags_on_fail, + optimized_compiler_builtins, + out, + patch_binaries_for_nix: build_patch_binaries_for_nix, + path_modification_cache, + paths: flags_paths, + prefix: install_prefix.map(PathBuf::from), + print_step_rusage: build_print_step_rusage.unwrap_or(false), + print_step_timings: build_print_step_timings.unwrap_or(false), + profiler: build_profiler.unwrap_or(false), + python: build_python.map(PathBuf::from), + reproducible_artifacts: flags_reproducible_artifact, + reuse: build_reuse.map(PathBuf::from), + rust_analyzer_info, + rust_codegen_backends: rust_codegen_backends + .map(|backends| parse_codegen_backends(backends, "rust")) + .unwrap_or(vec![CodegenBackendKind::Llvm]), rust_codegen_units: rust_codegen_units.map(threads_from_config), rust_codegen_units_std: rust_codegen_units_std.map(threads_from_config), - std_debug_assertions: rust_std_debug_assertions - .or(rust_rustc_debug_assertions) - .unwrap_or(rust_debug == Some(true)), - tools_debug_assertions: rust_tools_debug_assertions - .or(rust_rustc_debug_assertions) - .unwrap_or(rust_debug == Some(true)), - rust_overflow_checks_std: rust_overflow_checks_std - .or(rust_overflow_checks) - .unwrap_or(rust_debug == Some(true)), - rust_overflow_checks: rust_overflow_checks.unwrap_or(rust_debug == Some(true)), rust_debug_logging: rust_debug_logging .or(rust_rustc_debug_assertions) .unwrap_or(rust_debug == Some(true)), rust_debuginfo_level_rustc: with_defaults(rust_debuginfo_level_rustc), rust_debuginfo_level_std: with_defaults(rust_debuginfo_level_std), - rust_debuginfo_level_tools: with_defaults(rust_debuginfo_level_tools), rust_debuginfo_level_tests: rust_debuginfo_level_tests.unwrap_or(DebuginfoLevel::None), - rust_rpath: rust_rpath.unwrap_or(true), - rust_strip: rust_strip.unwrap_or(false), - rust_frame_pointers: rust_frame_pointers.unwrap_or(false), - rust_stack_protector, - rustc_default_linker: rust_default_linker, - rust_optimize_tests: rust_optimize_tests.unwrap_or(true), + rust_debuginfo_level_tools: with_defaults(rust_debuginfo_level_tools), rust_dist_src: dist_src_tarball.unwrap_or_else(|| rust_dist_src.unwrap_or(true)), - rust_codegen_backends: rust_codegen_backends - .map(|backends| parse_codegen_backends(backends, "rust")) - .unwrap_or(vec![CodegenBackendKind::Llvm]), - rust_verify_llvm_ir: rust_verify_llvm_ir.unwrap_or(false), - rust_thin_lto_import_instr_limit, - rust_randomize_layout: rust_randomize_layout.unwrap_or(false), - rust_remap_debuginfo: rust_remap_debuginfo.unwrap_or(false), - rust_new_symbol_mangling, - rust_profile_use: flags_rust_profile_use.or(rust_profile_use), - rust_profile_generate: flags_rust_profile_generate.or(rust_profile_generate), + rust_frame_pointers: rust_frame_pointers.unwrap_or(false), + rust_info, rust_lto: rust_lto .as_deref() .map(|value| RustcLto::from_str(value).unwrap()) .unwrap_or_default(), - rust_validate_mir_opts, + rust_new_symbol_mangling, + rust_optimize: rust_optimize.unwrap_or(RustOptimize::Bool(true)), + rust_optimize_tests: rust_optimize_tests.unwrap_or(true), + rust_overflow_checks: rust_overflow_checks.unwrap_or(rust_debug == Some(true)), + rust_overflow_checks_std: rust_overflow_checks_std + .or(rust_overflow_checks) + .unwrap_or(rust_debug == Some(true)), + rust_profile_generate: flags_rust_profile_generate.or(rust_profile_generate), + rust_profile_use: flags_rust_profile_use.or(rust_profile_use), + rust_randomize_layout: rust_randomize_layout.unwrap_or(false), + rust_remap_debuginfo: rust_remap_debuginfo.unwrap_or(false), + rust_rpath: rust_rpath.unwrap_or(true), + rust_stack_protector, rust_std_features: rust_std_features .unwrap_or(BTreeSet::from([String::from("panic-unwind")])), - llvm_profile_use: flags_llvm_profile_use, - llvm_profile_generate: flags_llvm_profile_generate, - llvm_libunwind_default: rust_llvm_libunwind - .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")), - enable_bolt_settings: flags_enable_bolt_settings, - reproducible_artifacts: flags_reproducible_artifact, - local_rebuild: build_local_rebuild.unwrap_or(false), - jemalloc: rust_jemalloc.unwrap_or(false), - control_flow_guard: rust_control_flow_guard.unwrap_or(false), - ehcont_guard: rust_ehcont_guard.unwrap_or(false), - dist_sign_folder: dist_sign_folder.map(PathBuf::from), - dist_upload_addr, - dist_compression_formats, - dist_compression_profile: dist_compression_profile.unwrap_or("fast".into()), - dist_include_mingw_linker: dist_include_mingw_linker.unwrap_or(true), - backtrace: rust_backtrace.unwrap_or(true), - low_priority: build_low_priority.unwrap_or(false), - description: build_description, - verbose_tests: rust_verbose_tests.unwrap_or(exec_ctx.is_verbose()), + rust_strip: rust_strip.unwrap_or(false), + rust_thin_lto_import_instr_limit, + rust_validate_mir_opts, + rust_verify_llvm_ir: rust_verify_llvm_ir.unwrap_or(false), + rustc_debug_assertions: rust_rustc_debug_assertions.unwrap_or(rust_debug == Some(true)), + rustc_default_linker: rust_default_linker, + rustc_error_format: flags_rustc_error_format, + rustfmt_info, + sanitizers: build_sanitizers.unwrap_or(false), save_toolstates: rust_save_toolstates.map(PathBuf::from), - print_step_timings: build_print_step_timings.unwrap_or(false), - print_step_rusage: build_print_step_rusage.unwrap_or(false), - musl_root: rust_musl_root.map(PathBuf::from), - prefix: install_prefix.map(PathBuf::from), - sysconfdir: install_sysconfdir.map(PathBuf::from), - datadir: install_datadir.map(PathBuf::from), - docdir: install_docdir.map(PathBuf::from), - bindir: install_bindir.map(PathBuf::from).unwrap_or("bin".into()), - libdir: install_libdir.map(PathBuf::from), - mandir: install_mandir.map(PathBuf::from), - codegen_tests: rust_codegen_tests.unwrap_or(true), - nodejs: build_nodejs.map(PathBuf::from), - npm: build_npm.map(PathBuf::from), - gdb: build_gdb.map(PathBuf::from), - lldb: build_lldb.map(PathBuf::from), - python: build_python.map(PathBuf::from), - reuse: build_reuse.map(PathBuf::from), - cargo_native_static: build_cargo_native_static.unwrap_or(false), - configure_args: build_configure_args.unwrap_or_default(), - compiletest_diff_tool: build_compiletest_diff_tool, - compiletest_allow_stage0: build_compiletest_allow_stage0.unwrap_or(false), - compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest.unwrap_or(true), - tidy_extra_checks: build_tidy_extra_checks, - skip_std_check_if_no_download_rustc: flags_skip_std_check_if_no_download_rustc, - cargo_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/cargo")), - rust_analyzer_info: git_info( - &exec_ctx, - omit_git_hash, - &src.join("src/tools/rust-analyzer"), - ), - clippy_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/clippy")), - miri_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/miri")), - rustfmt_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/rustfmt")), - enzyme_info: git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/enzyme")), - in_tree_llvm_info: git_info(&exec_ctx, false, &src.join("src/llvm-project")), - in_tree_gcc_info: git_info(&exec_ctx, false, &src.join("src/gcc")), - dist_vendor: dist_vendor.unwrap_or_else(|| { - // If we're building from git or tarball sources, enable it by default. - rust_info.is_managed_git_subrepository() || rust_info.is_from_tarball() - }), - targets, skip, - paths: flags_paths, - config: toml_path, - llvm_thin_lto: llvm_thin_lto.unwrap_or(false), - rustc_debug_assertions: rust_rustc_debug_assertions.unwrap_or(rust_debug == Some(true)), - lld_mode: rust_lld_mode.unwrap_or_default(), - initial_cargo_clippy: build_cargo_clippy, - vendor: build_vendor.unwrap_or( - rust_info.is_from_tarball() - && src.join("vendor").exists() - && src.join(".cargo/config.toml").exists(), - ), - patch_binaries_for_nix: build_patch_binaries_for_nix, - cmd: flags_cmd, - submodules: build_submodules, - // If we're building with ThinLTO on, by default we want to link - // to LLVM shared, to avoid re-doing ThinLTO (which happens in - // the link step) with each stage. - llvm_link_shared: Cell::new( - llvm_link_shared - .or((!llvm_from_ci && llvm_thin_lto.unwrap_or(false)).then_some(true)), - ), - exec_ctx, - out, - rust_info, - initial_cargo, - initial_rustc, - initial_sysroot, - initial_rustfmt, - target_config, - omit_git_hash, - stage, + skip_std_check_if_no_download_rustc: flags_skip_std_check_if_no_download_rustc, src, - llvm_from_ci, - llvm_assertions, - lld_enabled, - host_target, - hosts, - channel, - is_running_on_ci, - path_modification_cache, + stage, stage0_metadata, - download_rustc_commit, + std_debug_assertions: rust_std_debug_assertions + .or(rust_rustc_debug_assertions) + .unwrap_or(rust_debug == Some(true)), + stderr_is_tty: std::io::stderr().is_terminal(), + stdout_is_tty: std::io::stdout().is_terminal(), + submodules: build_submodules, + sysconfdir: install_sysconfdir.map(PathBuf::from), + target_config, + targets, + test_compare_mode: rust_test_compare_mode.unwrap_or(false), + tidy_extra_checks: build_tidy_extra_checks, + tool: build_tool.unwrap_or_default(), + tools: build_tools, + tools_debug_assertions: rust_tools_debug_assertions + .or(rust_rustc_debug_assertions) + .unwrap_or(rust_debug == Some(true)), + vendor, + verbose_tests, + // tidy-alphabetical-end } }