From dea80f716cabc76f42621a062f3ad4b2b7a0dca2 Mon Sep 17 00:00:00 2001 From: arferreira Date: Mon, 20 Apr 2026 13:14:29 -0400 Subject: [PATCH 01/40] Normalize .. and . in diagnostic file paths --- compiler/rustc_span/src/lib.rs | 39 +++++++++++++------ compiler/rustc_span/src/source_map.rs | 2 +- compiler/rustc_span/src/source_map/tests.rs | 11 ++++++ src/tools/compiletest/src/runtest.rs | 10 +++++ tests/ui/README.md | 4 ++ .../generic_arg_infer/issue-91614.stderr | 4 +- tests/ui/diagnostics/auxiliary/helper.rs | 3 ++ tests/ui/diagnostics/auxiliary/sub/mod.rs | 2 + tests/ui/diagnostics/normalize-path.rs | 9 +++++ tests/ui/diagnostics/normalize-path.stderr | 11 ++++++ 10 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 tests/ui/diagnostics/auxiliary/helper.rs create mode 100644 tests/ui/diagnostics/auxiliary/sub/mod.rs create mode 100644 tests/ui/diagnostics/normalize-path.rs create mode 100644 tests/ui/diagnostics/normalize-path.stderr diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f6ae748560750..b23d072a9253e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -22,6 +22,7 @@ #![feature(diagnostic_on_unknown)] #![feature(map_try_insert)] #![feature(negative_impls)] +#![feature(normalize_lexically)] #![feature(read_buf)] #![feature(rustc_attrs)] // tidy-alphabetical-end @@ -499,6 +500,15 @@ impl RealFileName { .file_name() .map_or_else(|| "".into(), |f| f.to_string_lossy()), FileNameDisplayPreference::Scope(scope) => self.path(scope).to_string_lossy(), + FileNameDisplayPreference::Diagnostics(scope) => { + let path = self.path(scope); + match path.normalize_lexically() { + Ok(normalized) => { + Cow::Owned(normalized.into_os_string().to_string_lossy().into_owned()) + } + Err(_) => path.to_string_lossy(), + } + } } } } @@ -536,15 +546,23 @@ enum FileNameDisplayPreference { Local, Short, Scope(RemapPathScopeComponents), + Diagnostics(RemapPathScopeComponents), +} + +impl<'a> FileNameDisplay<'a> { + pub fn to_string_lossy(&self) -> Cow<'a, str> { + match self.inner { + FileName::Real(inner) => inner.to_string_lossy(self.display_pref), + _ => Cow::from(self.to_string()), + } + } } impl fmt::Display for FileNameDisplay<'_> { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use FileName::*; match *self.inner { - Real(ref name) => { - write!(fmt, "{}", name.to_string_lossy(self.display_pref)) - } + Real(ref name) => write!(fmt, "{}", name.to_string_lossy(self.display_pref)), CfgSpec(_) => write!(fmt, ""), MacroExpansion(_) => write!(fmt, ""), Anon(_) => write!(fmt, ""), @@ -557,15 +575,6 @@ impl fmt::Display for FileNameDisplay<'_> { } } -impl<'a> FileNameDisplay<'a> { - pub fn to_string_lossy(&self) -> Cow<'a, str> { - match self.inner { - FileName::Real(inner) => inner.to_string_lossy(self.display_pref), - _ => Cow::from(self.to_string()), - } - } -} - impl FileName { pub fn is_real(&self) -> bool { use FileName::*; @@ -612,6 +621,12 @@ impl FileName { FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Scope(scope) } } + /// Like `display`, but with `.` and `..` resolved lexically. See #51349. + #[inline] + pub fn display_normalized(&self, scope: RemapPathScopeComponents) -> FileNameDisplay<'_> { + FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Diagnostics(scope) } + } + pub fn macro_expansion_source_code(src: &str) -> FileName { let mut hasher = StableHasher::new(); src.hash(&mut hasher); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 80d1bae71ae89..cf92e3386cde1 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -521,7 +521,7 @@ impl SourceMap { } pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> { - filename.display(RemapPathScopeComponents::DIAGNOSTICS) + filename.display_normalized(RemapPathScopeComponents::DIAGNOSTICS) } pub fn is_multiline(&self, sp: Span) -> bool { diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 4cc243667f224..acc186a007fca 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -797,3 +797,14 @@ fn read_binary_file_handles_lying_stat() { let bin = RealFileLoader.read_binary_file(kernel_max).unwrap(); assert_eq!(&real[..], &bin[..]); } + +#[test] +fn filename_for_diagnostics_resolves_parent_dir() { + let sm = SourceMap::new(FilePathMapping::empty()); + + let with_parent = filename(&sm, "tests/sub/../helper.rs"); + assert_eq!(sm.filename_for_diagnostics(&with_parent).to_string(), path_str("tests/helper.rs")); + + let clean = filename(&sm, "tests/clean.rs"); + assert_eq!(sm.filename_for_diagnostics(&clean).to_string(), path_str("tests/clean.rs")); +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 8f45e037d0fc9..6a3372def36ac 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2491,12 +2491,22 @@ impl<'test> TestCx<'test> { let parent_dir = self.testpaths.file.parent().unwrap(); normalize_path(parent_dir, "$DIR"); + // After #51349, rustc normalizes `tests/x/y/../aux/foo.rs` to + // `tests/x/aux/foo.rs`. Replace the grandparent with `$DIR/..` so + // stderrs keep the pre-normalization form. + if let Some(grandparent_dir) = parent_dir.parent() { + normalize_path(grandparent_dir, "$DIR/.."); + } + if self.props.remap_src_base { let mut remapped_parent_dir = Utf8PathBuf::from(FAKE_SRC_BASE); if self.testpaths.relative_dir != Utf8Path::new("") { remapped_parent_dir.push(&self.testpaths.relative_dir); } normalize_path(&remapped_parent_dir, "$DIR"); + if let Some(remapped_grandparent) = remapped_parent_dir.parent() { + normalize_path(remapped_grandparent, "$DIR/.."); + } } let base_dir = Utf8Path::new("/rustc/FAKE_PREFIX"); diff --git a/tests/ui/README.md b/tests/ui/README.md index a3617fb6b07c9..e91b3b4b75e80 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -446,6 +446,10 @@ Everything to do with `--diagnostic-width`. Exercises `#[diagnostic::*]` namespaced attributes. See [RFC 3368 Diagnostic attribute namespace](https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md). +## `tests/ui/diagnostics/` + +Tests for diagnostic output quality, such as path normalization in error messages. + ## `tests/ui/did_you_mean/` Tests for miscellaneous suggestions. diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index 164bcc7111ca6..6a2952604587e 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -5,7 +5,7 @@ LL | let y = Mask::<_, _>::splat(false); | ^ ------------ type must be known at this point | note: required by a const generic parameter in `Mask` - --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL + --> $SRC_DIR/portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the value of const parameter `N` is specified | LL | let y: Mask<_, N> = Mask::<_, _>::splat(false); @@ -18,7 +18,7 @@ LL | let y = Mask::<_, _>::splat(false); | ^ -------------------------- type must be known at this point | note: required by a const generic parameter in `Mask::::splat` - --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL + --> $SRC_DIR/portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the value of const parameter `N` is specified | LL | let y: Mask<_, N> = Mask::<_, _>::splat(false); diff --git a/tests/ui/diagnostics/auxiliary/helper.rs b/tests/ui/diagnostics/auxiliary/helper.rs new file mode 100644 index 0000000000000..83103ab7bd71f --- /dev/null +++ b/tests/ui/diagnostics/auxiliary/helper.rs @@ -0,0 +1,3 @@ +pub fn foo() -> u32 { + "not a u32" +} diff --git a/tests/ui/diagnostics/auxiliary/sub/mod.rs b/tests/ui/diagnostics/auxiliary/sub/mod.rs new file mode 100644 index 0000000000000..dd531abbce552 --- /dev/null +++ b/tests/ui/diagnostics/auxiliary/sub/mod.rs @@ -0,0 +1,2 @@ +#[path = "../helper.rs"] +mod helper; diff --git a/tests/ui/diagnostics/normalize-path.rs b/tests/ui/diagnostics/normalize-path.rs new file mode 100644 index 0000000000000..1b1fb998abf01 --- /dev/null +++ b/tests/ui/diagnostics/normalize-path.rs @@ -0,0 +1,9 @@ +// Verify that diagnostic file paths are lexically normalized. +// Without the fix for #51349, the error location would show +// `auxiliary/sub/../helper.rs` instead of `auxiliary/helper.rs`. +#[path = "auxiliary/sub/mod.rs"] +mod sub; + +fn main() {} + +//~? ERROR mismatched types diff --git a/tests/ui/diagnostics/normalize-path.stderr b/tests/ui/diagnostics/normalize-path.stderr new file mode 100644 index 0000000000000..9eb92e54853e1 --- /dev/null +++ b/tests/ui/diagnostics/normalize-path.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/auxiliary/helper.rs:2:5 + | +LL | pub fn foo() -> u32 { + | --- expected `u32` because of return type +LL | "not a u32" + | ^^^^^^^^^^^ expected `u32`, found `&str` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From 0da8bd366f03535a639c195c0eba539dd53205f1 Mon Sep 17 00:00:00 2001 From: arferreira Date: Thu, 13 Aug 2026 19:41:20 -0400 Subject: [PATCH 02/40] Print unnormalized diagnostic paths under --verbose Signed-off-by: arferreira --- compiler/rustc_interface/src/interface.rs | 8 +++++++- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_span/src/source_map.rs | 20 +++++++++++++++++-- compiler/rustc_span/src/source_map/tests.rs | 17 ++++++++++++++++ .../ui/diagnostics/normalize-path-verbose.rs | 10 ++++++++++ .../diagnostics/normalize-path-verbose.stderr | 11 ++++++++++ tests/ui/diagnostics/normalize-path.rs | 6 +++--- 7 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 tests/ui/diagnostics/normalize-path-verbose.rs create mode 100644 tests/ui/diagnostics/normalize-path-verbose.stderr diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 2737d2ca854a5..f145b1129aa60 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -401,7 +401,13 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.opts.edition, jobs, &config.extra_symbols, - SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }, + SourceMapInputs { + file_loader, + path_mapping, + hash_kind, + checksum_hash_kind, + verbose: config.opts.verbose, + }, |current_gcx| { // The previous `early_dcx` can't be reused here because it doesn't // impl `Send`. Creating a new one is fine. diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 24c7ff8484a5e..8d2e167c81238 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -53,6 +53,7 @@ where path_mapping: sessopts.file_path_mapping(), hash_kind, checksum_hash_kind, + verbose: sessopts.verbose, }); rustc_span::create_session_globals_then(DEFAULT_EDITION, &[], sm_inputs, || { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index cf92e3386cde1..88fc0922791ad 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -192,6 +192,7 @@ pub struct SourceMapInputs { pub path_mapping: FilePathMapping, pub hash_kind: SourceFileHashAlgorithm, pub checksum_hash_kind: Option, + pub verbose: bool, } pub struct SourceMap { @@ -213,6 +214,10 @@ pub struct SourceMap { /// /// If this is equal to `hash_kind` then the checksum won't be computed twice. checksum_hash_kind: Option, + + /// Whether `--verbose` was passed. Diagnostics then print paths without + /// lexical normalization. + verbose: bool, } impl std::fmt::Debug for SourceMap { @@ -224,6 +229,7 @@ impl std::fmt::Debug for SourceMap { working_dir, hash_kind, checksum_hash_kind, + verbose, } = self; f.debug_struct("SourceMap") @@ -233,6 +239,7 @@ impl std::fmt::Debug for SourceMap { .field("working_dir", working_dir) .field("hash_kind", hash_kind) .field("checksum_hash_kind", checksum_hash_kind) + .field("verbose", verbose) .finish() } } @@ -244,11 +251,12 @@ impl SourceMap { path_mapping, hash_kind: SourceFileHashAlgorithm::Md5, checksum_hash_kind: None, + verbose: false, }) } pub fn with_inputs( - SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }: SourceMapInputs, + SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind, verbose }: SourceMapInputs, ) -> SourceMap { let cwd = file_loader .current_directory() @@ -262,6 +270,7 @@ impl SourceMap { path_mapping, hash_kind, checksum_hash_kind, + verbose, } } @@ -520,8 +529,15 @@ impl SourceMap { self.lookup_char_pos(sp.lo()).file.name.clone() } + /// Paths are normalized lexically, which can name the wrong file if a + /// component is a symlink. `--verbose` skips normalization and prints the + /// path as given. pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> { - filename.display_normalized(RemapPathScopeComponents::DIAGNOSTICS) + if self.verbose { + filename.display(RemapPathScopeComponents::DIAGNOSTICS) + } else { + filename.display_normalized(RemapPathScopeComponents::DIAGNOSTICS) + } } pub fn is_multiline(&self, sp: Span) -> bool { diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index acc186a007fca..b97c96787a96b 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -808,3 +808,20 @@ fn filename_for_diagnostics_resolves_parent_dir() { let clean = filename(&sm, "tests/clean.rs"); assert_eq!(sm.filename_for_diagnostics(&clean).to_string(), path_str("tests/clean.rs")); } + +#[test] +fn filename_for_diagnostics_verbose_keeps_parent_dir() { + let sm = SourceMap::with_inputs(SourceMapInputs { + file_loader: Box::new(RealFileLoader), + path_mapping: FilePathMapping::empty(), + hash_kind: SourceFileHashAlgorithm::Md5, + checksum_hash_kind: None, + verbose: true, + }); + + let with_parent = filename(&sm, "tests/sub/../helper.rs"); + assert_eq!( + sm.filename_for_diagnostics(&with_parent).to_string(), + path_str("tests/sub/../helper.rs"), + ); +} diff --git a/tests/ui/diagnostics/normalize-path-verbose.rs b/tests/ui/diagnostics/normalize-path-verbose.rs new file mode 100644 index 0000000000000..8955ce10da98b --- /dev/null +++ b/tests/ui/diagnostics/normalize-path-verbose.rs @@ -0,0 +1,10 @@ +//@ compile-flags: --verbose + +// Check that `--verbose` prints diagnostic paths as given, without lexical +// normalization. See #51349. +#[path = "auxiliary/sub/mod.rs"] +mod sub; + +fn main() {} + +//~? ERROR mismatched types diff --git a/tests/ui/diagnostics/normalize-path-verbose.stderr b/tests/ui/diagnostics/normalize-path-verbose.stderr new file mode 100644 index 0000000000000..ef1c9416f46c1 --- /dev/null +++ b/tests/ui/diagnostics/normalize-path-verbose.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/auxiliary/sub/../helper.rs:2:5 + | +LL | pub fn foo() -> u32 { + | --- expected `u32` because of return type +LL | "not a u32" + | ^^^^^^^^^^^ expected `u32`, found `&str` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/diagnostics/normalize-path.rs b/tests/ui/diagnostics/normalize-path.rs index 1b1fb998abf01..bc041c790e529 100644 --- a/tests/ui/diagnostics/normalize-path.rs +++ b/tests/ui/diagnostics/normalize-path.rs @@ -1,6 +1,6 @@ -// Verify that diagnostic file paths are lexically normalized. -// Without the fix for #51349, the error location would show -// `auxiliary/sub/../helper.rs` instead of `auxiliary/helper.rs`. +// Check that diagnostic file paths are lexically normalized: +// the error below points at `auxiliary/helper.rs`, not `auxiliary/sub/../helper.rs`. +// See #51349. #[path = "auxiliary/sub/mod.rs"] mod sub; From 07683989587570cff17c939062afb606ac289ddb Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sat, 29 Aug 2026 18:07:41 +0700 Subject: [PATCH 03/40] Fix async `#[track_caller]` feature gate tests Previously, these tests were testing the wrong feature gate, and had unnecessary type errors. --- .../track-caller/async-block.afn.stderr | 12 ++-- .../track-caller/async-block.cls.stderr | 42 +++++++++++++ .../track-caller/async-block.nofeat.stderr | 12 ++-- .../async-await/track-caller/async-block.rs | 27 ++++---- .../async-closure-gate.afn.stderr | 61 +++++-------------- .../async-closure-gate.cls.stderr | 24 ++++++++ .../async-closure-gate.nofeat.stderr | 61 +++++-------------- .../track-caller/async-closure-gate.rs | 54 ++++++++-------- 8 files changed, 150 insertions(+), 143 deletions(-) create mode 100644 tests/ui/async-await/track-caller/async-block.cls.stderr create mode 100644 tests/ui/async-await/track-caller/async-closure-gate.cls.stderr diff --git a/tests/ui/async-await/track-caller/async-block.afn.stderr b/tests/ui/async-await/track-caller/async-block.afn.stderr index b6a7481a4d119..89ebe2df60609 100644 --- a/tests/ui/async-await/track-caller/async-block.afn.stderr +++ b/tests/ui/async-await/track-caller/async-block.afn.stderr @@ -1,7 +1,7 @@ error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-block.rs:8:13 + --> $DIR/async-block.rs:11:13 | -LL | let _ = #[track_caller] async { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -9,9 +9,9 @@ LL | let _ = #[track_caller] async { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-block.rs:15:13 + --> $DIR/async-block.rs:19:13 | -LL | let _ = #[track_caller] async { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -19,9 +19,9 @@ LL | let _ = #[track_caller] async { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-block.rs:23:17 + --> $DIR/async-block.rs:28:17 | -LL | let _ = #[track_caller] async { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information diff --git a/tests/ui/async-await/track-caller/async-block.cls.stderr b/tests/ui/async-await/track-caller/async-block.cls.stderr new file mode 100644 index 0000000000000..0e9dbc4afa05f --- /dev/null +++ b/tests/ui/async-await/track-caller/async-block.cls.stderr @@ -0,0 +1,42 @@ +error: `#[track_caller]` on async functions is a no-op + --> $DIR/async-block.rs:16:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | +LL | / async fn foo() { +LL | | let _ = #[track_caller] +LL | | +LL | | async {}; +LL | | } + | |_- this function will not propagate the caller location + | + = note: see issue #110011 for more information + = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +note: the lint level is defined here + --> $DIR/async-block.rs:6:9 + | +LL | #![deny(ungated_async_fn_track_caller)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[track_caller]` on async functions is a no-op + --> $DIR/async-block.rs:24:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | +LL | / async fn foo2() { +LL | | let _ = async { +LL | | let _ = #[track_caller] +... | +LL | | }; +LL | | } + | |_- this function will not propagate the caller location + | + = note: see issue #110011 for more information + = help: add `#![feature(async_fn_track_caller)]` 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 2 previous errors + diff --git a/tests/ui/async-await/track-caller/async-block.nofeat.stderr b/tests/ui/async-await/track-caller/async-block.nofeat.stderr index b6a7481a4d119..89ebe2df60609 100644 --- a/tests/ui/async-await/track-caller/async-block.nofeat.stderr +++ b/tests/ui/async-await/track-caller/async-block.nofeat.stderr @@ -1,7 +1,7 @@ error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-block.rs:8:13 + --> $DIR/async-block.rs:11:13 | -LL | let _ = #[track_caller] async { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -9,9 +9,9 @@ LL | let _ = #[track_caller] async { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-block.rs:15:13 + --> $DIR/async-block.rs:19:13 | -LL | let _ = #[track_caller] async { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -19,9 +19,9 @@ LL | let _ = #[track_caller] async { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-block.rs:23:17 + --> $DIR/async-block.rs:28:17 | -LL | let _ = #[track_caller] async { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information diff --git a/tests/ui/async-await/track-caller/async-block.rs b/tests/ui/async-await/track-caller/async-block.rs index 900d5ef25504d..f56921c017d12 100644 --- a/tests/ui/async-await/track-caller/async-block.rs +++ b/tests/ui/async-await/track-caller/async-block.rs @@ -1,27 +1,32 @@ //@ edition:2021 -//@ revisions: afn nofeat +//@ revisions: afn cls afn_cls nofeat +//@[afn_cls] check-pass #![feature(stmt_expr_attributes)] -#![cfg_attr(afn, feature(async_fn_track_caller))] +#![deny(ungated_async_fn_track_caller)] +#![cfg_attr(any(afn, afn_cls), feature(async_fn_track_caller))] +#![cfg_attr(any(cls, afn_cls), feature(closure_track_caller))] fn main() { - let _ = #[track_caller] async { - //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] - }; + let _ = #[track_caller] + //[nofeat,afn]~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + async {}; } #[track_caller] +//[cls]~^ ERROR `#[track_caller]` on async functions is a no-op async fn foo() { - let _ = #[track_caller] async { - //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] - }; + let _ = #[track_caller] + //[nofeat,afn]~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + async {}; } #[track_caller] +//[cls]~^ ERROR `#[track_caller]` on async functions is a no-op async fn foo2() { let _ = async { - let _ = #[track_caller] async { - //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] - }; + let _ = #[track_caller] + //[nofeat,afn]~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + async {}; }; } diff --git a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr index 6887a904211ec..fb774290bde4e 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr +++ b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr @@ -1,7 +1,7 @@ error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:8:13 + --> $DIR/async-closure-gate.rs:11:13 | -LL | let _ = #[track_caller] async || { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -9,9 +9,9 @@ LL | let _ = #[track_caller] async || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:15:13 + --> $DIR/async-closure-gate.rs:19:13 | -LL | let _ = #[track_caller] async || { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -19,9 +19,9 @@ LL | let _ = #[track_caller] async || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:21:13 + --> $DIR/async-closure-gate.rs:25:13 | -LL | let _ = #[track_caller] || { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -29,9 +29,9 @@ LL | let _ = #[track_caller] || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:29:17 + --> $DIR/async-closure-gate.rs:32:17 | -LL | let _ = #[track_caller] || { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -39,9 +39,9 @@ LL | let _ = #[track_caller] || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:37:9 + --> $DIR/async-closure-gate.rs:40:9 | -LL | #[track_caller] || { +LL | #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -49,48 +49,15 @@ LL | #[track_caller] || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:47:13 + --> $DIR/async-closure-gate.rs:49:13 | -LL | #[track_caller] || { +LL | #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information = help: add `#![feature(closure_track_caller)]` 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[E0308]: mismatched types - --> $DIR/async-closure-gate.rs:27:5 - | -LL | fn foo3() { - | - help: try adding a return type: `-> impl Future` -LL | / async { -LL | | -LL | | let _ = #[track_caller] || { -... | -LL | | } - | |_____^ expected `()`, found `async` block - | - = note: expected unit type `()` - found `async` block `{async block@$DIR/async-closure-gate.rs:27:5: 27:10}` - -error[E0308]: mismatched types - --> $DIR/async-closure-gate.rs:44:5 - | -LL | fn foo5() { - | - help: try adding a return type: `-> impl Future` -LL | / async { -LL | | -LL | | let _ = || { -LL | | #[track_caller] || { -... | -LL | | }; -LL | | } - | |_____^ expected `()`, found `async` block - | - = note: expected unit type `()` - found `async` block `{async block@$DIR/async-closure-gate.rs:44:5: 44:10}` - -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0308, E0658. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/track-caller/async-closure-gate.cls.stderr b/tests/ui/async-await/track-caller/async-closure-gate.cls.stderr new file mode 100644 index 0000000000000..5fe7a2fb7d36a --- /dev/null +++ b/tests/ui/async-await/track-caller/async-closure-gate.cls.stderr @@ -0,0 +1,24 @@ +error: `#[track_caller]` on async functions is a no-op + --> $DIR/async-closure-gate.rs:16:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | +LL | / async fn foo() { +LL | | let _ = #[track_caller] +LL | | +LL | | async || {}; +LL | | } + | |_- this function will not propagate the caller location + | + = note: see issue #110011 for more information + = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +note: the lint level is defined here + --> $DIR/async-closure-gate.rs:6:9 + | +LL | #![deny(ungated_async_fn_track_caller)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr index 6887a904211ec..fb774290bde4e 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr +++ b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr @@ -1,7 +1,7 @@ error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:8:13 + --> $DIR/async-closure-gate.rs:11:13 | -LL | let _ = #[track_caller] async || { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -9,9 +9,9 @@ LL | let _ = #[track_caller] async || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:15:13 + --> $DIR/async-closure-gate.rs:19:13 | -LL | let _ = #[track_caller] async || { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -19,9 +19,9 @@ LL | let _ = #[track_caller] async || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:21:13 + --> $DIR/async-closure-gate.rs:25:13 | -LL | let _ = #[track_caller] || { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -29,9 +29,9 @@ LL | let _ = #[track_caller] || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:29:17 + --> $DIR/async-closure-gate.rs:32:17 | -LL | let _ = #[track_caller] || { +LL | let _ = #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -39,9 +39,9 @@ LL | let _ = #[track_caller] || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:37:9 + --> $DIR/async-closure-gate.rs:40:9 | -LL | #[track_caller] || { +LL | #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information @@ -49,48 +49,15 @@ LL | #[track_caller] || { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:47:13 + --> $DIR/async-closure-gate.rs:49:13 | -LL | #[track_caller] || { +LL | #[track_caller] | ^^^^^^^^^^^^^^^ | = note: see issue #87417 for more information = help: add `#![feature(closure_track_caller)]` 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[E0308]: mismatched types - --> $DIR/async-closure-gate.rs:27:5 - | -LL | fn foo3() { - | - help: try adding a return type: `-> impl Future` -LL | / async { -LL | | -LL | | let _ = #[track_caller] || { -... | -LL | | } - | |_____^ expected `()`, found `async` block - | - = note: expected unit type `()` - found `async` block `{async block@$DIR/async-closure-gate.rs:27:5: 27:10}` - -error[E0308]: mismatched types - --> $DIR/async-closure-gate.rs:44:5 - | -LL | fn foo5() { - | - help: try adding a return type: `-> impl Future` -LL | / async { -LL | | -LL | | let _ = || { -LL | | #[track_caller] || { -... | -LL | | }; -LL | | } - | |_____^ expected `()`, found `async` block - | - = note: expected unit type `()` - found `async` block `{async block@$DIR/async-closure-gate.rs:44:5: 44:10}` - -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0308, E0658. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/track-caller/async-closure-gate.rs b/tests/ui/async-await/track-caller/async-closure-gate.rs index e72ce2afa45fd..13d3a5787ca9d 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.rs +++ b/tests/ui/async-await/track-caller/async-closure-gate.rs @@ -1,52 +1,54 @@ //@ edition:2021 -//@ revisions: afn nofeat +//@ revisions: afn cls afn_cls nofeat +//@[afn_cls] check-pass #![feature(stmt_expr_attributes)] -#![cfg_attr(afn, feature(async_fn_track_caller))] +#![deny(ungated_async_fn_track_caller)] +#![cfg_attr(any(afn, afn_cls), feature(async_fn_track_caller))] +#![cfg_attr(any(cls, afn_cls), feature(closure_track_caller))] fn main() { - let _ = #[track_caller] async || { - //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] - }; + let _ = #[track_caller] + //[nofeat,afn]~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + async || {}; } #[track_caller] +//[cls]~^ ERROR `#[track_caller]` on async functions is a no-op async fn foo() { - let _ = #[track_caller] async || { - //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] - }; + let _ = #[track_caller] + //[nofeat,afn]~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + async || {}; } async fn foo2() { - let _ = #[track_caller] || { - //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] - }; + let _ = #[track_caller] + //[nofeat,afn]~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + || {}; } fn foo3() { - async { - //~^ ERROR mismatched types - let _ = #[track_caller] || { - //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] - }; - } + let _ = async { + let _ = #[track_caller] + //[nofeat,afn]~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + || {}; + }; } async fn foo4() { let _ = || { - #[track_caller] || { - //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] - }; + #[track_caller] + //[nofeat,afn]~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + || {}; }; } fn foo5() { - async { - //~^ ERROR mismatched types + let _ = async { let _ = || { - #[track_caller] || { - //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] - }; + #[track_caller] + //[nofeat,afn]~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + || {}; }; - } + }; } From 88fb17e4a4a6e768f2476bcf8f2682915d07e8bc Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sat, 29 Aug 2026 18:17:31 +0700 Subject: [PATCH 04/40] Add a test revision to panic-track-caller.rs --- .../panic-track-caller.cls.stderr | 6 +- .../panic-track-caller.nofeat.stderr | 6 +- .../track-caller/panic-track-caller.rs | 55 ++++++++++--------- 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr index 464cbfba2acfe..762e4add96e41 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr @@ -3,7 +3,7 @@ warning: `#[track_caller]` on async functions is a no-op | LL | #[track_caller] | ^^^^^^^^^^^^^^^ -... +LL | LL | / async fn bar_track_caller() { LL | | panic!() LL | | } @@ -15,11 +15,11 @@ LL | | } = note: `#[warn(ungated_async_fn_track_caller)]` on by default warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:67:5 + --> $DIR/panic-track-caller.rs:66:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ -... +LL | LL | / async fn bar_assoc() { LL | | panic!(); LL | | } diff --git a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr index 464cbfba2acfe..762e4add96e41 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr @@ -3,7 +3,7 @@ warning: `#[track_caller]` on async functions is a no-op | LL | #[track_caller] | ^^^^^^^^^^^^^^^ -... +LL | LL | / async fn bar_track_caller() { LL | | panic!() LL | | } @@ -15,11 +15,11 @@ LL | | } = note: `#[warn(ungated_async_fn_track_caller)]` on by default warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:67:5 + --> $DIR/panic-track-caller.rs:66:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ -... +LL | LL | / async fn bar_assoc() { LL | | panic!(); LL | | } diff --git a/tests/ui/async-await/track-caller/panic-track-caller.rs b/tests/ui/async-await/track-caller/panic-track-caller.rs index bd12bf11d6c84..7e6a913fa78c7 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.rs +++ b/tests/ui/async-await/track-caller/panic-track-caller.rs @@ -1,11 +1,11 @@ //@ run-pass //@ edition:2021 -//@ revisions: afn cls nofeat +//@ revisions: afn cls afn_cls nofeat //@ needs-unwind // gate-test-async_fn_track_caller #![feature(stmt_expr_attributes)] -#![cfg_attr(afn, feature(async_fn_track_caller))] -#![cfg_attr(cls, feature(closure_track_caller))] +#![cfg_attr(any(afn, afn_cls), feature(async_fn_track_caller))] +#![cfg_attr(any(cls, afn_cls), feature(closure_track_caller))] #![allow(unused)] use std::future::Future; @@ -51,8 +51,7 @@ async fn foo() { } #[track_caller] -//[cls]~^ WARN `#[track_caller]` on async functions is a no-op -//[nofeat]~^^ WARN `#[track_caller]` on async functions is a no-op +//[cls,nofeat]~^ WARN `#[track_caller]` on async functions is a no-op async fn bar_track_caller() { panic!() } @@ -65,8 +64,7 @@ struct Foo; impl Foo { #[track_caller] - //[cls]~^ WARN `#[track_caller]` on async functions is a no-op - //[nofeat]~^^ WARN `#[track_caller]` on async functions is a no-op + //[cls,nofeat]~^ WARN `#[track_caller]` on async functions is a no-op async fn bar_assoc() { panic!(); } @@ -76,21 +74,23 @@ async fn foo_assoc() { Foo::bar_assoc().await } -// Since compilation is expected to fail for this fn when using -// `nofeat`, we test that separately in `async-closure-gate.rs` -#[cfg(cls)] +// Since compilation is expected to fail for this fn when `closure_track_caller` +// is disabled, we test that separately in `async-closure-gate.rs` +#[cfg(any(cls, afn_cls))] async fn foo_closure() { - let c = #[track_caller] async || { + let c = #[track_caller] + async || { panic!(); }; c().await } -// Since compilation is expected to fail for this fn when using -// `nofeat`, we test that separately in `async-block.rs` -#[cfg(cls)] +// Since compilation is expected to fail for this fn when `closure_track_caller` +// is disabled, we test that separately in `async-closure-gate.rs` +#[cfg(any(cls, afn_cls))] async fn foo_block() { - let a = #[track_caller] async { + let a = #[track_caller] + async { panic!(); }; a.await @@ -113,22 +113,27 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { } fn main() { - assert_eq!(panicked_at(|| block_on(foo())), 46 -); + assert_eq!(panicked_at(|| block_on(foo())), 46); - #[cfg(afn)] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 61); + #[cfg(any(afn, afn_cls))] + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 60); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 57); + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 56); - #[cfg(afn)] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 76); + #[cfg(any(afn, afn_cls))] + assert_eq!(panicked_at(|| block_on(foo_assoc())), 74); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 71); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 69); + // FIXME(closure_track_caller): if closure_track_caller is enabled, but + // async_fn_track_caller is disabled, then #[track_caller] on async closures + // silently do nothing. Either it should function, or we should emit a warning. + // See #161961 #[cfg(cls)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 84); + assert_eq!(panicked_at(|| block_on(foo_closure())), 83); + #[cfg(afn_cls)] + assert_eq!(panicked_at(|| block_on(foo_closure())), 85); - #[cfg(cls)] + #[cfg(any(cls, afn_cls))] assert_eq!(panicked_at(|| block_on(foo_block())), 96); } From 95ded567ed9e32a769339ee92b1576dcd532836e Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sat, 29 Aug 2026 18:27:40 +0700 Subject: [PATCH 05/40] In panic-track-caller.rs, split call and await into different lines. This is done so that we can test whether the location used is at the function call site or the await site. --- .../panic-track-caller.cls.stderr | 4 +-- .../panic-track-caller.nofeat.stderr | 4 +-- .../track-caller/panic-track-caller.rs | 35 +++++++++++-------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr index 762e4add96e41..2721918972b2a 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr @@ -1,5 +1,5 @@ warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:53:1 + --> $DIR/panic-track-caller.rs:54:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | | } = note: `#[warn(ungated_async_fn_track_caller)]` on by default warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:66:5 + --> $DIR/panic-track-caller.rs:68:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr index 762e4add96e41..2721918972b2a 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr @@ -1,5 +1,5 @@ warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:53:1 + --> $DIR/panic-track-caller.rs:54:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | | } = note: `#[warn(ungated_async_fn_track_caller)]` on by default warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:66:5 + --> $DIR/panic-track-caller.rs:68:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/track-caller/panic-track-caller.rs b/tests/ui/async-await/track-caller/panic-track-caller.rs index 7e6a913fa78c7..15fff0d281694 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.rs +++ b/tests/ui/async-await/track-caller/panic-track-caller.rs @@ -47,7 +47,8 @@ async fn bar() { } async fn foo() { - bar().await + let future = bar(); + future.await; } #[track_caller] @@ -57,7 +58,8 @@ async fn bar_track_caller() { } async fn foo_track_caller() { - bar_track_caller().await + let future = bar_track_caller(); + future.await; } struct Foo; @@ -71,29 +73,31 @@ impl Foo { } async fn foo_assoc() { - Foo::bar_assoc().await + let future = Foo::bar_assoc(); + future.await; } // Since compilation is expected to fail for this fn when `closure_track_caller` // is disabled, we test that separately in `async-closure-gate.rs` #[cfg(any(cls, afn_cls))] async fn foo_closure() { - let c = #[track_caller] + let closure = #[track_caller] async || { panic!(); }; - c().await + let future = closure(); + future.await; } // Since compilation is expected to fail for this fn when `closure_track_caller` // is disabled, we test that separately in `async-closure-gate.rs` #[cfg(any(cls, afn_cls))] async fn foo_block() { - let a = #[track_caller] + let future = #[track_caller] async { panic!(); }; - a.await + future.await; } fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { @@ -112,28 +116,31 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { x } +// FIXME(async_fn_track_caller): Currently, #[track_caller] on an async function +// uses the location where the future is awaited. +// The correct behavior as per T-lang is to use the location where the function is called. fn main() { assert_eq!(panicked_at(|| block_on(foo())), 46); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 60); + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 62); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 56); + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 57); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 74); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 77); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 69); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 71); // FIXME(closure_track_caller): if closure_track_caller is enabled, but // async_fn_track_caller is disabled, then #[track_caller] on async closures // silently do nothing. Either it should function, or we should emit a warning. // See #161961 #[cfg(cls)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 83); + assert_eq!(panicked_at(|| block_on(foo_closure())), 86); #[cfg(afn_cls)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 85); + assert_eq!(panicked_at(|| block_on(foo_closure())), 89); #[cfg(any(cls, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_block())), 96); + assert_eq!(panicked_at(|| block_on(foo_block())), 100); } From 40b84d357bbe33b41ca8fc5150769fea9868092d Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sat, 29 Aug 2026 18:33:49 +0700 Subject: [PATCH 06/40] Add manual polling test to panic-track-caller.rs --- .../panic-track-caller.cls.stderr | 17 ++++++++++++++- .../panic-track-caller.nofeat.stderr | 17 ++++++++++++++- .../track-caller/panic-track-caller.rs | 21 ++++++++++++++++++- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr index 2721918972b2a..7b116387169c2 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr @@ -29,5 +29,20 @@ LL | | } = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -warning: 2 warnings emitted +warning: `#[track_caller]` on async functions is a no-op + --> $DIR/panic-track-caller.rs:103:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | +LL | / async fn bar_manual_poll() { +LL | | panic!(); +LL | | } + | |_- this function will not propagate the caller location + | + = note: see issue #110011 for more information + = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +warning: 3 warnings emitted diff --git a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr index 2721918972b2a..7b116387169c2 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr @@ -29,5 +29,20 @@ LL | | } = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -warning: 2 warnings emitted +warning: `#[track_caller]` on async functions is a no-op + --> $DIR/panic-track-caller.rs:103:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | +LL | / async fn bar_manual_poll() { +LL | | panic!(); +LL | | } + | |_- this function will not propagate the caller location + | + = note: see issue #110011 for more information + = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +warning: 3 warnings emitted diff --git a/tests/ui/async-await/track-caller/panic-track-caller.rs b/tests/ui/async-await/track-caller/panic-track-caller.rs index 15fff0d281694..41835977f8d6c 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.rs +++ b/tests/ui/async-await/track-caller/panic-track-caller.rs @@ -100,6 +100,20 @@ async fn foo_block() { future.await; } +#[track_caller] +//[cls,nofeat]~^ WARN `#[track_caller]` on async functions is a no-op +async fn bar_manual_poll() { + panic!(); +} + +fn foo_manual_poll() { + let future = bar_manual_poll(); + let future = std::pin::pin!(future); + let mut cx = std::task::Context::from_waker(std::task::Waker::noop()); + let res = future.poll(&mut cx); + assert_eq!(res, std::task::Poll::Ready(())); +} + fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { let loc = Arc::new(Mutex::new(None)); @@ -117,7 +131,7 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { } // FIXME(async_fn_track_caller): Currently, #[track_caller] on an async function -// uses the location where the future is awaited. +// uses the location where the future is awaited or polled. // The correct behavior as per T-lang is to use the location where the function is called. fn main() { assert_eq!(panicked_at(|| block_on(foo())), 46); @@ -143,4 +157,9 @@ fn main() { #[cfg(any(cls, afn_cls))] assert_eq!(panicked_at(|| block_on(foo_block())), 100); + + #[cfg(any(afn, afn_cls))] + assert_eq!(panicked_at(|| foo_manual_poll()), 113); + #[cfg(any(cls, nofeat))] + assert_eq!(panicked_at(|| foo_manual_poll()), 106); } From 785e7096639aafe2658a1805bb6023a86b9079fa Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sat, 29 Aug 2026 18:55:00 +0700 Subject: [PATCH 07/40] Also test async track_caller in miri --- .../tests/pass/async-panic-track-caller.rs | 168 ++++++++++++++++++ .../panic-track-caller.cls.stderr | 6 +- .../panic-track-caller.nofeat.stderr | 6 +- .../track-caller/panic-track-caller.rs | 23 +-- 4 files changed, 187 insertions(+), 16 deletions(-) create mode 100644 src/tools/miri/tests/pass/async-panic-track-caller.rs diff --git a/src/tools/miri/tests/pass/async-panic-track-caller.rs b/src/tools/miri/tests/pass/async-panic-track-caller.rs new file mode 100644 index 0000000000000..8cb43f8fef9ce --- /dev/null +++ b/src/tools/miri/tests/pass/async-panic-track-caller.rs @@ -0,0 +1,168 @@ +// This test is duplicated (with changes) at +// tests/ui/async-await/track-caller/panic-track-caller.rs + +//@ edition:2021 +//@ revisions: afn cls afn_cls nofeat +// +// +// Padding comment so that the line numbers are the same as panic-track-caller.rs +#![feature(stmt_expr_attributes)] +#![cfg_attr(any(afn, afn_cls), feature(async_fn_track_caller))] +#![cfg_attr(any(cls, afn_cls), feature(closure_track_caller))] +#![allow(unused)] + +use std::future::Future; +use std::panic; +use std::sync::{Arc, Mutex}; +use std::task::{Context, Poll, Wake}; +use std::thread::{self, Thread}; + +/// A waker that wakes up the current thread when called. +struct ThreadWaker(Thread); + +impl Wake for ThreadWaker { + fn wake(self: Arc) { + self.0.unpark(); + } +} + +/// Run a future to completion on the current thread. +fn block_on(fut: impl Future) -> T { + // Pin the future so it can be polled. + let mut fut = Box::pin(fut); + + // Create a new context to be passed to the future. + let t = thread::current(); + let waker = Arc::new(ThreadWaker(t)).into(); + let mut cx = Context::from_waker(&waker); + + // Run the future to completion. + loop { + match fut.as_mut().poll(&mut cx) { + Poll::Ready(res) => return res, + Poll::Pending => thread::park(), + } + } +} + +async fn bar() { + panic!() +} + +async fn foo() { + let future = bar(); + future.await; +} + +#[cfg_attr(any(cls, nofeat), expect(ungated_async_fn_track_caller))] +#[track_caller] +async fn bar_track_caller() { + panic!() +} + +async fn foo_track_caller() { + let future = bar_track_caller(); + future.await; +} + +struct Foo; + +impl Foo { + #[cfg_attr(any(cls, nofeat), expect(ungated_async_fn_track_caller))] + #[track_caller] + async fn bar_assoc() { + panic!(); + } +} + +async fn foo_assoc() { + let future = Foo::bar_assoc(); + future.await; +} + +// Since compilation is expected to fail for this fn when `closure_track_caller` +// is disabled, we test that separately in `async-closure-gate.rs` +#[cfg(any(cls, afn_cls))] +async fn foo_closure() { + let closure = #[track_caller] + async || { + panic!(); + }; + let future = closure(); + future.await; +} + +// Since compilation is expected to fail for this fn when `closure_track_caller` +// is disabled, we test that separately in `async-closure-gate.rs` +#[cfg(any(cls, afn_cls))] +async fn foo_block() { + let future = #[track_caller] + async { + panic!(); + }; + future.await; +} + +#[cfg_attr(any(cls, nofeat), expect(ungated_async_fn_track_caller))] +#[track_caller] +async fn bar_manual_poll() { + panic!(); +} + +fn foo_manual_poll() { + let future = bar_manual_poll(); + let future = std::pin::pin!(future); + let mut cx = std::task::Context::from_waker(std::task::Waker::noop()); + let res = future.poll(&mut cx); + assert_eq!(res, std::task::Poll::Ready(())); +} + +fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { + let loc = Arc::new(Mutex::new(None)); + + let hook = panic::take_hook(); + { + let loc = loc.clone(); + panic::set_hook(Box::new(move |info| { + *loc.lock().unwrap() = info.location().map(|loc| loc.line()) + })); + } + panic::catch_unwind(f).unwrap_err(); + panic::set_hook(hook); + let x = loc.lock().unwrap().unwrap(); + x +} + +// FIXME(async_fn_track_caller): Currently, #[track_caller] on an async function +// uses the location where the future is awaited or polled. +// The correct behavior as per T-lang is to use the location where the function is called. +fn main() { + assert_eq!(panicked_at(|| block_on(foo())), 49); + + #[cfg(any(afn, afn_cls))] + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 65); + #[cfg(any(cls, nofeat))] + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 60); + + #[cfg(any(afn, afn_cls))] + assert_eq!(panicked_at(|| block_on(foo_assoc())), 80); + #[cfg(any(cls, nofeat))] + assert_eq!(panicked_at(|| block_on(foo_assoc())), 74); + + // FIXME(closure_track_caller): if closure_track_caller is enabled, but + // async_fn_track_caller is disabled, then #[track_caller] on async closures + // silently do nothing. Either it should function, or we should emit a warning. + // See #161961 + #[cfg(cls)] + assert_eq!(panicked_at(|| block_on(foo_closure())), 89); + #[cfg(afn_cls)] + assert_eq!(panicked_at(|| block_on(foo_closure())), 92); + + #[cfg(any(cls, afn_cls))] + assert_eq!(panicked_at(|| block_on(foo_block())), 103); + + #[cfg(any(afn, afn_cls))] + assert_eq!(panicked_at(|| foo_manual_poll()), 116); + #[cfg(any(cls, nofeat))] + assert_eq!(panicked_at(|| foo_manual_poll()), 109); +} diff --git a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr index 7b116387169c2..7890592095b15 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr @@ -1,5 +1,5 @@ warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:54:1 + --> $DIR/panic-track-caller.rs:57:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | | } = note: `#[warn(ungated_async_fn_track_caller)]` on by default warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:68:5 + --> $DIR/panic-track-caller.rs:71:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | | } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:103:1 + --> $DIR/panic-track-caller.rs:106:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr index 7b116387169c2..7890592095b15 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr @@ -1,5 +1,5 @@ warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:54:1 + --> $DIR/panic-track-caller.rs:57:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | | } = note: `#[warn(ungated_async_fn_track_caller)]` on by default warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:68:5 + --> $DIR/panic-track-caller.rs:71:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | | } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:103:1 + --> $DIR/panic-track-caller.rs:106:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/track-caller/panic-track-caller.rs b/tests/ui/async-await/track-caller/panic-track-caller.rs index 41835977f8d6c..d0e09a396217f 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.rs +++ b/tests/ui/async-await/track-caller/panic-track-caller.rs @@ -1,3 +1,6 @@ +// This test is duplicated (with changes) at +// src/tools/miri/tests/pass/async-panic-track-caller.rs + //@ run-pass //@ edition:2021 //@ revisions: afn cls afn_cls nofeat @@ -134,32 +137,32 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { // uses the location where the future is awaited or polled. // The correct behavior as per T-lang is to use the location where the function is called. fn main() { - assert_eq!(panicked_at(|| block_on(foo())), 46); + assert_eq!(panicked_at(|| block_on(foo())), 49); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 62); + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 65); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 57); + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 60); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 77); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 80); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 71); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 74); // FIXME(closure_track_caller): if closure_track_caller is enabled, but // async_fn_track_caller is disabled, then #[track_caller] on async closures // silently do nothing. Either it should function, or we should emit a warning. // See #161961 #[cfg(cls)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 86); - #[cfg(afn_cls)] assert_eq!(panicked_at(|| block_on(foo_closure())), 89); + #[cfg(afn_cls)] + assert_eq!(panicked_at(|| block_on(foo_closure())), 92); #[cfg(any(cls, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_block())), 100); + assert_eq!(panicked_at(|| block_on(foo_block())), 103); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| foo_manual_poll()), 113); + assert_eq!(panicked_at(|| foo_manual_poll()), 116); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| foo_manual_poll()), 106); + assert_eq!(panicked_at(|| foo_manual_poll()), 109); } From e9bdbfd470c0d0272ff060c1949296f17809378d Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Sat, 29 Aug 2026 21:52:23 +0700 Subject: [PATCH 08/40] Exclude gcc from panic-track-caller test --- .../tests/pass/async-panic-track-caller.rs | 22 ++++++++++--------- .../panic-track-caller.cls.stderr | 6 ++--- .../panic-track-caller.nofeat.stderr | 6 ++--- .../track-caller/panic-track-caller.rs | 22 ++++++++++--------- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/tools/miri/tests/pass/async-panic-track-caller.rs b/src/tools/miri/tests/pass/async-panic-track-caller.rs index 8cb43f8fef9ce..46ab0984dbdec 100644 --- a/src/tools/miri/tests/pass/async-panic-track-caller.rs +++ b/src/tools/miri/tests/pass/async-panic-track-caller.rs @@ -5,6 +5,8 @@ //@ revisions: afn cls afn_cls nofeat // // +// +// // Padding comment so that the line numbers are the same as panic-track-caller.rs #![feature(stmt_expr_attributes)] #![cfg_attr(any(afn, afn_cls), feature(async_fn_track_caller))] @@ -137,32 +139,32 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { // uses the location where the future is awaited or polled. // The correct behavior as per T-lang is to use the location where the function is called. fn main() { - assert_eq!(panicked_at(|| block_on(foo())), 49); + assert_eq!(panicked_at(|| block_on(foo())), 51); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 65); + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 67); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 60); + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 62); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 80); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 82); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 74); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 76); // FIXME(closure_track_caller): if closure_track_caller is enabled, but // async_fn_track_caller is disabled, then #[track_caller] on async closures // silently do nothing. Either it should function, or we should emit a warning. // See #161961 #[cfg(cls)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 89); + assert_eq!(panicked_at(|| block_on(foo_closure())), 91); #[cfg(afn_cls)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 92); + assert_eq!(panicked_at(|| block_on(foo_closure())), 94); #[cfg(any(cls, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_block())), 103); + assert_eq!(panicked_at(|| block_on(foo_block())), 105); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| foo_manual_poll()), 116); + assert_eq!(panicked_at(|| foo_manual_poll()), 118); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| foo_manual_poll()), 109); + assert_eq!(panicked_at(|| foo_manual_poll()), 111); } diff --git a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr index 7890592095b15..5611e53f50a40 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr @@ -1,5 +1,5 @@ warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:57:1 + --> $DIR/panic-track-caller.rs:59:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | | } = note: `#[warn(ungated_async_fn_track_caller)]` on by default warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:71:5 + --> $DIR/panic-track-caller.rs:73:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | | } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:106:1 + --> $DIR/panic-track-caller.rs:108:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr index 7890592095b15..5611e53f50a40 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr @@ -1,5 +1,5 @@ warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:57:1 + --> $DIR/panic-track-caller.rs:59:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | | } = note: `#[warn(ungated_async_fn_track_caller)]` on by default warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:71:5 + --> $DIR/panic-track-caller.rs:73:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL | | } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:106:1 + --> $DIR/panic-track-caller.rs:108:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/track-caller/panic-track-caller.rs b/tests/ui/async-await/track-caller/panic-track-caller.rs index d0e09a396217f..294150500170d 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.rs +++ b/tests/ui/async-await/track-caller/panic-track-caller.rs @@ -1,6 +1,8 @@ // This test is duplicated (with changes) at // src/tools/miri/tests/pass/async-panic-track-caller.rs +// FIXME: catch_unwind is broken in gcc. Will be fixed in the next rustc_codegen_gcc sync. +//@ ignore-backends: gcc //@ run-pass //@ edition:2021 //@ revisions: afn cls afn_cls nofeat @@ -137,32 +139,32 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { // uses the location where the future is awaited or polled. // The correct behavior as per T-lang is to use the location where the function is called. fn main() { - assert_eq!(panicked_at(|| block_on(foo())), 49); + assert_eq!(panicked_at(|| block_on(foo())), 51); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 65); + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 67); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 60); + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 62); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 80); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 82); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 74); + assert_eq!(panicked_at(|| block_on(foo_assoc())), 76); // FIXME(closure_track_caller): if closure_track_caller is enabled, but // async_fn_track_caller is disabled, then #[track_caller] on async closures // silently do nothing. Either it should function, or we should emit a warning. // See #161961 #[cfg(cls)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 89); + assert_eq!(panicked_at(|| block_on(foo_closure())), 91); #[cfg(afn_cls)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 92); + assert_eq!(panicked_at(|| block_on(foo_closure())), 94); #[cfg(any(cls, afn_cls))] - assert_eq!(panicked_at(|| block_on(foo_block())), 103); + assert_eq!(panicked_at(|| block_on(foo_block())), 105); #[cfg(any(afn, afn_cls))] - assert_eq!(panicked_at(|| foo_manual_poll()), 116); + assert_eq!(panicked_at(|| foo_manual_poll()), 118); #[cfg(any(cls, nofeat))] - assert_eq!(panicked_at(|| foo_manual_poll()), 109); + assert_eq!(panicked_at(|| foo_manual_poll()), 111); } From d00696d3ecbef19d9680514032231380ff396193 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Sun, 30 Aug 2026 13:26:19 +0700 Subject: [PATCH 09/40] Add run-native to async-panic-track-caller.rs Co-authored-by: Ralf Jung --- src/tools/miri/tests/pass/async-panic-track-caller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/tests/pass/async-panic-track-caller.rs b/src/tools/miri/tests/pass/async-panic-track-caller.rs index 46ab0984dbdec..062e07cffc8b9 100644 --- a/src/tools/miri/tests/pass/async-panic-track-caller.rs +++ b/src/tools/miri/tests/pass/async-panic-track-caller.rs @@ -3,7 +3,7 @@ //@ edition:2021 //@ revisions: afn cls afn_cls nofeat -// +//@ run-native // // // From 1c4440205607cd18ccfb30abe065bf0f62b5dd18 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 31 Aug 2026 14:46:11 +1000 Subject: [PATCH 10/40] Preliminary cleanup in coverage codegen - Rename `generate_*` functions to `emit_*`, since they emit LLVM globals - Consistently use qualified paths in `counter_for_term` - Remove an unnecessary Clone from `llvm_cov::Regions` --- .../src/coverageinfo/llvm_cov.rs | 2 +- .../src/coverageinfo/mapgen.rs | 14 ++++++------- .../src/coverageinfo/mapgen/covfun.rs | 20 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs index a58202834cfa5..93d0b09578315 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs @@ -64,7 +64,7 @@ pub(crate) fn write_filenames_to_buffer(filenames: &[impl AsRef]) -> Vec, pub(crate) expansion_regions: Vec, diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 18818fd1a56c0..e9543ebeecf99 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -74,7 +74,7 @@ pub(crate) fn finalize(cx: &mut CodegenCx<'_, '_>) { unused::prepare_covfun_records_for_unused_functions(cx, &mut covfun_records); } - // If there are no covfun records for this CGU, don't generate a covmap record. + // If there are no covfun records for this CGU, don't emit a covmap record. // Emitting a covmap record without any covfun records causes `llvm-cov` to // fail when generating coverage reports, and if there are no covfun records // then the covmap record isn't useful anyway. @@ -89,13 +89,13 @@ pub(crate) fn finalize(cx: &mut CodegenCx<'_, '_>) { GlobalFileTable::build(tcx, covfun_records.iter().flat_map(|c| c.all_source_files())); for covfun in &covfun_records { - covfun::generate_covfun_record(cx, &global_file_table, covfun) + covfun::emit_covfun_record(cx, &global_file_table, covfun); } - // Generate the coverage map header, which contains the filenames used by + // Emit the coverage map header, which contains the filenames used by // this CGU's coverage mappings, and store it in a well-known global. // (This is skipped if we returned early due to having no covfun records.) - generate_covmap_record(cx, covmap_version, &global_file_table.filenames_buffer); + emit_covmap_record(cx, covmap_version, &global_file_table.filenames_buffer); } /// Maps "global" (per-CGU) file ID numbers to their underlying source file paths. @@ -218,10 +218,10 @@ impl VirtualFileMapping { } } -/// Generates the contents of the covmap record for this CGU, which mostly -/// consists of a header and a list of filenames. The record is then stored +/// Generates and emits the covmap record for this CGU, which mostly +/// consists of a header and a list of filenames. The record is emitted /// as a global variable in the `__llvm_covmap` section. -fn generate_covmap_record<'ll>( +fn emit_covmap_record<'ll>( cx: &mut CodegenCx<'ll, '_>, version: CovmapVersion, filenames_buffer: &[u8], diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index 28985448fd1c1..b83570911c3a0 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -77,15 +77,15 @@ pub(crate) fn prepare_covfun_record<'tcx>( Some(covfun) } -pub(crate) fn counter_for_term(term: CovTerm) -> ffi::Counter { - use ffi::Counter; +fn counter_for_term(term: CovTerm) -> ffi::Counter { match term { - CovTerm::Zero => Counter::ZERO, - CovTerm::Counter(id) => { - Counter { kind: ffi::CounterKind::CounterValueReference, id: CounterId::as_u32(id) } - } + CovTerm::Zero => ffi::Counter::ZERO, + CovTerm::Counter(id) => ffi::Counter { + kind: ffi::CounterKind::CounterValueReference, + id: CounterId::as_u32(id), + }, CovTerm::Expression(id) => { - Counter { kind: ffi::CounterKind::Expression, id: ExpressionId::as_u32(id) } + ffi::Counter { kind: ffi::CounterKind::Expression, id: ExpressionId::as_u32(id) } } } } @@ -174,10 +174,10 @@ fn fill_region_tables<'tcx>( } } -/// Generates the contents of the covfun record for this function, which -/// contains the function's coverage mapping data. The record is then stored +/// Generates and emits the covfun record for this function, which +/// contains the function's coverage mapping data. The record is emitted /// as a global variable in the `__llvm_covfun` section. -pub(crate) fn generate_covfun_record<'tcx>( +pub(crate) fn emit_covfun_record<'tcx>( cx: &mut CodegenCx<'_, 'tcx>, global_file_table: &GlobalFileTable, covfun: &CovfunRecord<'tcx>, From be8a828aa9b2532c8d726adcafdab72831db9dcf Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 29 Aug 2026 17:15:24 +1000 Subject: [PATCH 11/40] Resolve spans to file-coordinates in a separate step One of the key tasks in coverage codegen is to take the source-code spans that were recorded during MIR instrumentation, and resolve them to physical coordinates in their respective files. In rare cases this resolution can fail, which leads to the awkward possibility that a function might lose _all_ of its mappings for a particular file/expansion. If that happens, we need to avoid emitting a covfun file section containing no regions, because doing so would trigger errors in LLVM. The existing code does handle this edge case, but in a way that won't generalise to multiple files/expansions. Having an explicit intermediate resolution step will make it easier to add support for expansion regions in the future. --- .../src/coverageinfo/mapgen.rs | 30 --- .../src/coverageinfo/mapgen/covfun.rs | 175 ++++++++++++------ 2 files changed, 118 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index e9543ebeecf99..3dac4b3e0167f 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -1,11 +1,9 @@ use std::assert_matches; -use std::sync::Arc; use itertools::Itertools; use rustc_abi::Align; use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods}; use rustc_data_structures::fx::FxIndexMap; -use rustc_index::IndexVec; use rustc_middle::ty::TyCtxt; use rustc_span::{FileName, RemapPathScopeComponents, SourceFile, StableSourceFileId}; use tracing::debug; @@ -190,34 +188,6 @@ rustc_index::newtype_index! { struct LocalFileId {} } -/// Holds a mapping from "local" (per-function) file IDs to their corresponding -/// source files. -#[derive(Debug, Default)] -struct VirtualFileMapping { - local_file_table: IndexVec>, -} - -impl VirtualFileMapping { - fn push_file(&mut self, source_file: &Arc) -> LocalFileId { - self.local_file_table.push(Arc::clone(source_file)) - } - - /// Resolves all of the filenames in this local file mapping to a list of - /// global file IDs in its CGU, for inclusion in this function's - /// `__llvm_covfun` record. - /// - /// The global file IDs are returned as `u32` to make FFI easier. - fn resolve_all(&self, global_file_table: &GlobalFileTable) -> Option> { - self.local_file_table - .iter() - .map(|file| try { - let id = global_file_table.get_existing_id(file)?; - GlobalFileId::as_u32(id) - }) - .collect::>>() - } -} - /// Generates and emits the covmap record for this CGU, which mostly /// consists of a header and a list of filenames. The record is emitted /// as a global variable in the `__llvm_covmap` section. diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index b83570911c3a0..d01ed8765302e 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -5,13 +5,15 @@ //! [^win]: On Windows the section name is `.lcovfun`. use std::ffi::CString; +use std::iter; use std::sync::Arc; use rustc_abi::Align; use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods as _, ConstCodegenMethods}; +use rustc_index::IndexVec; use rustc_middle::mir::coverage::{ - BasicCoverageBlock, CounterId, CovTerm, CoverageCodegenInfo, CoverageMirInfo, Expression, - ExpressionId, Mapping, MappingKind, Op, + BasicCoverageBlock, CounterId, CovTerm, CoverageCodegenInfo, Expression, ExpressionId, Mapping, + MappingKind, Op, }; use rustc_middle::ty::{Instance, TyCtxt}; use rustc_span::{SourceFile, Span}; @@ -19,7 +21,7 @@ use rustc_target::spec::HasTargetSpec; use tracing::debug; use crate::common::CodegenCx; -use crate::coverageinfo::mapgen::{GlobalFileTable, VirtualFileMapping, spans}; +use crate::coverageinfo::mapgen::{GlobalFileTable, LocalFileId, spans}; use crate::coverageinfo::{ffi, llvm_cov}; use crate::llvm; @@ -34,16 +36,15 @@ pub(crate) struct CovfunRecord<'tcx> { source_hash: u64, is_used: bool, - virtual_file_mapping: VirtualFileMapping, expressions: Vec, - regions: llvm_cov::Regions, + mappings: ResolvedMappings, } impl<'tcx> CovfunRecord<'tcx> { /// Iterator that yields all source files referred to by this function's /// coverage mappings. Used to build the global file table for the CGU. pub(crate) fn all_source_files(&self) -> impl Iterator { - self.virtual_file_mapping.local_file_table.iter().map(Arc::as_ref) + self.mappings.all_source_files() } } @@ -56,24 +57,17 @@ pub(crate) fn prepare_covfun_record<'tcx>( let cg_info = tcx.coverage_codegen_info(instance.def)?; let expressions = prepare_expressions(cg_info); + let mappings = prepare_resolved_mappings(tcx, cg_info, is_used, &mir_info.mappings)?; - let mut covfun = CovfunRecord { + let covfun = CovfunRecord { _instance: instance, mangled_function_name: tcx.symbol_name(instance).name, source_hash: if is_used { mir_info.function_source_hash } else { 0 }, is_used, - virtual_file_mapping: VirtualFileMapping::default(), expressions, - regions: llvm_cov::Regions::default(), + mappings, }; - fill_region_tables(tcx, mir_info, cg_info, &mut covfun); - - if covfun.regions.has_no_regions() { - debug!(?covfun, "function has no mappings to embed; skipping"); - return None; - } - Some(covfun) } @@ -110,16 +104,60 @@ fn prepare_expressions(cg_info: &CoverageCodegenInfo) -> Vec>() } -/// Populates the mapping region tables in the current function's covfun record. -fn fill_region_tables<'tcx>( +/// Intermediate representation of coverage mappings, after all mapping spans +/// have been resolved to file coordinates (or discarded), but before producing +/// a final [`llvm_cov::Regions`]. +/// +/// Having a separate resolution step makes it easier to handle edge cases +/// where a function (or someday an expansion) manages to lose all of its spans, +/// without accidentally emitting invalid covfun records containing empty files. +#[derive(Debug)] +struct ResolvedMappings { + /// Source file for all of the [`spans::Coords`] in these mappings. + source_file: Arc, + + code_mappings: Vec, + branch_mappings: Vec, +} + +impl ResolvedMappings { + fn ensure_nonempty(self) -> Option { + let ResolvedMappings { source_file: _, code_mappings, branch_mappings } = &self; + if code_mappings.is_empty() && branch_mappings.is_empty() { None } else { Some(self) } + } + + fn all_source_files(&self) -> impl Iterator { + // FIXME(Zalathar): When expansion regions are supported, this also needs to yield + // any source files used by descendant expansions. + let ResolvedMappings { source_file, code_mappings: _, branch_mappings: _ } = self; + iter::once(source_file.as_ref()) + } +} + +/// Resolved from [`MappingKind::Code`], and the precursor to [`ffi::CodeRegion`]. +#[derive(Debug)] +struct CodeMapping { + coords: spans::Coords, + counter: ffi::Counter, +} + +/// Resolved from [`MappingKind::Branch`], and the precursor to [`ffi::BranchRegion`]. +#[derive(Debug)] +struct BranchMapping { + coords: spans::Coords, + true_counter: ffi::Counter, + false_counter: ffi::Counter, +} + +fn prepare_resolved_mappings<'tcx>( tcx: TyCtxt<'tcx>, - mir_info: &'tcx CoverageMirInfo, cg_info: &'tcx CoverageCodegenInfo, - covfun: &mut CovfunRecord<'tcx>, -) { + is_used: bool, + mappings: &[Mapping], +) -> Option { // If this function is unused, replace all counters with zero. let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter { - let term = if covfun.is_used { + let term = if is_used { cg_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term") } else { CovTerm::Zero @@ -130,14 +168,9 @@ fn fill_region_tables<'tcx>( // Currently a function's mappings must all be in the same file, so use the // first mapping's span to determine the file. let source_map = tcx.sess.source_map(); - let Some(first_span) = (try { mir_info.mappings.first()?.span }) else { - debug_assert!(false, "function has no mappings: {covfun:?}"); - return; - }; + let first_span = mappings.first()?.span; let source_file = source_map.lookup_source_file(first_span.lo()); - let local_file_id = covfun.virtual_file_mapping.push_file(&source_file); - // In rare cases, _all_ of a function's spans are discarded, and coverage // codegen needs to handle that gracefully to avoid #133606. // It's hard for tests to trigger this organically, so instead we set @@ -147,30 +180,57 @@ fn fill_region_tables<'tcx>( if discard_all { None } else { spans::make_coords(source_map, &source_file, span) } }; + let mut code_mappings = vec![]; + let mut branch_mappings = vec![]; + + for &Mapping { ref kind, span } in mappings { + let Some(coords) = make_coords(span) else { continue }; + match *kind { + MappingKind::Code { bcb } => { + code_mappings.push(CodeMapping { coords, counter: counter_for_bcb(bcb) }) + } + MappingKind::Branch { true_bcb, false_bcb } => branch_mappings.push(BranchMapping { + coords, + true_counter: counter_for_bcb(true_bcb), + false_counter: counter_for_bcb(false_bcb), + }), + } + } + + ResolvedMappings { source_file, code_mappings, branch_mappings }.ensure_nonempty() +} + +/// Populates the mapping region tables for the current function's covfun record. +fn fill_region_tables( + global_file_table: &GlobalFileTable, + mappings: &ResolvedMappings, + virtual_file_mapping: &mut IndexVec, + regions: &mut llvm_cov::Regions, +) { + let ResolvedMappings { source_file, code_mappings, branch_mappings } = mappings; + let Some(global_file_id) = global_file_table.get_existing_id(source_file) else { + debug_assert!(false, "couldn't find an existing global-file-id for {source_file:?}"); + return; + }; + let llvm_cov::Regions { code_regions, expansion_regions: _, // FIXME(Zalathar): Fill out support for expansion regions branch_regions, - } = &mut covfun.regions; + } = regions; - // For each counter/region pair in this function+file, convert it to a - // form suitable for FFI. - for &Mapping { ref kind, span } in &mir_info.mappings { - let Some(coords) = make_coords(span) else { continue }; + // The global file IDs are stored as `u32` to make FFI easier. + // FIXME(Zalathar): Consider giving `newtype_index!` a safe transmute to `&[u32]`. + let local_file_id = virtual_file_mapping.push(global_file_id.as_u32()); + + for &CodeMapping { coords, counter } in code_mappings { let cov_span = coords.make_coverage_span(local_file_id); + code_regions.push(ffi::CodeRegion { cov_span, counter }); + } - match *kind { - MappingKind::Code { bcb } => { - code_regions.push(ffi::CodeRegion { cov_span, counter: counter_for_bcb(bcb) }); - } - MappingKind::Branch { true_bcb, false_bcb } => { - branch_regions.push(ffi::BranchRegion { - cov_span, - true_counter: counter_for_bcb(true_bcb), - false_counter: counter_for_bcb(false_bcb), - }); - } - } + for &BranchMapping { coords, true_counter, false_counter } in branch_mappings { + let cov_span = coords.make_coverage_span(local_file_id); + branch_regions.push(ffi::BranchRegion { cov_span, true_counter, false_counter }); } } @@ -187,24 +247,25 @@ pub(crate) fn emit_covfun_record<'tcx>( mangled_function_name, source_hash, is_used, - ref virtual_file_mapping, ref expressions, - ref regions, + ref mappings, } = covfun; - let Some(local_file_table) = virtual_file_mapping.resolve_all(global_file_table) else { - debug_assert!( - false, - "all local files should be present in the global file table: \ - global_file_table = {global_file_table:?}, \ - virtual_file_mapping = {virtual_file_mapping:?}" - ); + let mut regions = llvm_cov::Regions::default(); + let mut virtual_file_mapping = IndexVec::new(); + fill_region_tables(global_file_table, mappings, &mut virtual_file_mapping, &mut regions); + + if regions.has_no_regions() { + debug_assert!(false, "mappings should have produced at least one region: {mappings:#?}"); return; - }; + } // Encode the function's coverage mappings into a buffer. - let coverage_mapping_buffer = - llvm_cov::write_function_mappings_to_buffer(&local_file_table, expressions, regions); + let coverage_mapping_buffer = llvm_cov::write_function_mappings_to_buffer( + &virtual_file_mapping.raw, + expressions, + ®ions, + ); // A covfun record consists of four target-endian integers, followed by the // encoded mapping data in bytes. Note that the length field is 32 bits. From 41258df4130f7c8eaab4d3177d156b1661587456 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 30 Aug 2026 16:19:50 +0200 Subject: [PATCH 12/40] Move more `rustdoc-html` tests using `--test` into the right folder --- .../doctest}/async-move-doctest.rs | 2 + .../doctest/async-move-doctest.stdout | 6 +++ .../doctest}/comment-in-doctest.rs | 2 + .../doctest/comment-in-doctest.stdout | 6 +++ .../doctest}/demo-allocator-54478.rs | 7 +++- .../doctest/demo-allocator-54478.stdout | 6 +++ .../doctest}/doc-cfg-target-feature.rs | 3 +- .../doctest/doc-cfg-target-feature.stdout | 39 +++++++++++++++++++ .../doctest}/doc-test-attr-18199.rs | 5 ++- .../doctest/doc-test-attr-18199.stdout | 6 +++ .../doctest}/edition-doctest.rs | 4 +- .../rustdoc-ui/doctest/edition-doctest.stdout | 7 ++++ .../doctest}/edition-flag.rs | 2 + tests/rustdoc-ui/doctest/edition-flag.stdout | 6 +++ .../doctest}/force-target-feature.rs | 5 ++- .../doctest/force-target-feature.stdout | 27 +++++++++++++ .../doctest}/ice-type-error-19181.rs | 3 ++ .../doctest/ice-type-error-19181.stdout | 5 +++ .../doctest}/no-run-still-checks-lints.rs | 3 +- .../doctest/no-run-still-checks-lints.stdout | 29 ++++++++++++++ .../doctest}/process-termination.rs | 4 +- .../doctest/process-termination.stdout | 8 ++++ .../doctest}/sanitizer-option.rs | 4 +- .../doctest/test-option-check-2.rs} | 5 ++- .../doctest/test-option-check-2.stdout | 8 ++++ .../doctest/test-option-check.rs} | 2 + .../doctest/test-option-check.stdout | 6 +++ .../lints/renamed-lint-still-applies.rs | 10 ----- 28 files changed, 200 insertions(+), 20 deletions(-) rename tests/{rustdoc-html/async => rustdoc-ui/doctest}/async-move-doctest.rs (77%) create mode 100644 tests/rustdoc-ui/doctest/async-move-doctest.stdout rename tests/{rustdoc-html => rustdoc-ui/doctest}/comment-in-doctest.rs (89%) create mode 100644 tests/rustdoc-ui/doctest/comment-in-doctest.stdout rename tests/{rustdoc-html => rustdoc-ui/doctest}/demo-allocator-54478.rs (93%) create mode 100644 tests/rustdoc-ui/doctest/demo-allocator-54478.stdout rename tests/{rustdoc-html/doc-cfg => rustdoc-ui/doctest}/doc-cfg-target-feature.rs (78%) create mode 100644 tests/rustdoc-ui/doctest/doc-cfg-target-feature.stdout rename tests/{rustdoc-html => rustdoc-ui/doctest}/doc-test-attr-18199.rs (74%) create mode 100644 tests/rustdoc-ui/doctest/doc-test-attr-18199.stdout rename tests/{rustdoc-html => rustdoc-ui/doctest}/edition-doctest.rs (87%) create mode 100644 tests/rustdoc-ui/doctest/edition-doctest.stdout rename tests/{rustdoc-html => rustdoc-ui/doctest}/edition-flag.rs (63%) create mode 100644 tests/rustdoc-ui/doctest/edition-flag.stdout rename tests/{rustdoc-html => rustdoc-ui/doctest}/force-target-feature.rs (64%) create mode 100644 tests/rustdoc-ui/doctest/force-target-feature.stdout rename tests/{rustdoc-html => rustdoc-ui/doctest}/ice-type-error-19181.rs (65%) create mode 100644 tests/rustdoc-ui/doctest/ice-type-error-19181.stdout rename tests/{rustdoc-html => rustdoc-ui/doctest}/no-run-still-checks-lints.rs (55%) create mode 100644 tests/rustdoc-ui/doctest/no-run-still-checks-lints.stdout rename tests/{rustdoc-html => rustdoc-ui/doctest}/process-termination.rs (80%) create mode 100644 tests/rustdoc-ui/doctest/process-termination.stdout rename tests/{rustdoc-html => rustdoc-ui/doctest}/sanitizer-option.rs (86%) rename tests/{rustdoc-html/test_option_check/test.rs => rustdoc-ui/doctest/test-option-check-2.rs} (54%) create mode 100644 tests/rustdoc-ui/doctest/test-option-check-2.stdout rename tests/{rustdoc-html/test_option_check/bar.rs => rustdoc-ui/doctest/test-option-check.rs} (65%) create mode 100644 tests/rustdoc-ui/doctest/test-option-check.stdout delete mode 100644 tests/rustdoc-ui/lints/renamed-lint-still-applies.rs diff --git a/tests/rustdoc-html/async/async-move-doctest.rs b/tests/rustdoc-ui/doctest/async-move-doctest.rs similarity index 77% rename from tests/rustdoc-html/async/async-move-doctest.rs rename to tests/rustdoc-ui/doctest/async-move-doctest.rs index e18ec353533df..f491a9a04f851 100644 --- a/tests/rustdoc-html/async/async-move-doctest.rs +++ b/tests/rustdoc-ui/doctest/async-move-doctest.rs @@ -1,5 +1,7 @@ //@ compile-flags:--test +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ edition:2018 +//@ check-pass // Prior to setting the default edition for the doctest pre-parser, // this doctest would fail due to a fatal parsing error. diff --git a/tests/rustdoc-ui/doctest/async-move-doctest.stdout b/tests/rustdoc-ui/doctest/async-move-doctest.stdout new file mode 100644 index 0000000000000..4790438d4602f --- /dev/null +++ b/tests/rustdoc-ui/doctest/async-move-doctest.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/async-move-doctest.rs - (line 10) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/comment-in-doctest.rs b/tests/rustdoc-ui/doctest/comment-in-doctest.rs similarity index 89% rename from tests/rustdoc-html/comment-in-doctest.rs rename to tests/rustdoc-ui/doctest/comment-in-doctest.rs index e580aa2bb72c6..2caec5db9c920 100644 --- a/tests/rustdoc-html/comment-in-doctest.rs +++ b/tests/rustdoc-ui/doctest/comment-in-doctest.rs @@ -1,4 +1,6 @@ //@ compile-flags:--test +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass // comments, both doc comments and regular ones, used to trick rustdoc's doctest parser into // thinking that everything after it was part of the regular program. combined with the librustc_ast diff --git a/tests/rustdoc-ui/doctest/comment-in-doctest.stdout b/tests/rustdoc-ui/doctest/comment-in-doctest.stdout new file mode 100644 index 0000000000000..5cb97c53f37fd --- /dev/null +++ b/tests/rustdoc-ui/doctest/comment-in-doctest.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/comment-in-doctest.rs - (line 12) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/demo-allocator-54478.rs b/tests/rustdoc-ui/doctest/demo-allocator-54478.rs similarity index 93% rename from tests/rustdoc-html/demo-allocator-54478.rs rename to tests/rustdoc-ui/doctest/demo-allocator-54478.rs index 80acfc0ff58a1..073d83e11120e 100644 --- a/tests/rustdoc-html/demo-allocator-54478.rs +++ b/tests/rustdoc-ui/doctest/demo-allocator-54478.rs @@ -1,4 +1,9 @@ // https://github.com/rust-lang/rust/issues/54478 + +//@ compile-flags:--test +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + #![crate_name="foo"] // Issue #54478: regression test showing that we can demonstrate @@ -15,8 +20,6 @@ // decided to change `rustdoc` to behave more like the compiler's // default setting, by leaving off `-C prefer-dynamic`. -//@ compile-flags:--test - //! This is a doc comment //! //! ```rust diff --git a/tests/rustdoc-ui/doctest/demo-allocator-54478.stdout b/tests/rustdoc-ui/doctest/demo-allocator-54478.stdout new file mode 100644 index 0000000000000..f32d9a5b7d932 --- /dev/null +++ b/tests/rustdoc-ui/doctest/demo-allocator-54478.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/demo-allocator-54478.rs - (line 25) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/doc-cfg/doc-cfg-target-feature.rs b/tests/rustdoc-ui/doctest/doc-cfg-target-feature.rs similarity index 78% rename from tests/rustdoc-html/doc-cfg/doc-cfg-target-feature.rs rename to tests/rustdoc-ui/doctest/doc-cfg-target-feature.rs index b66e86e36af8b..99a133a6829c5 100644 --- a/tests/rustdoc-html/doc-cfg/doc-cfg-target-feature.rs +++ b/tests/rustdoc-ui/doctest/doc-cfg-target-feature.rs @@ -1,6 +1,7 @@ //@ only-x86_64 +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ compile-flags:--test -//@ should-fail +//@ failure-status: 101 // #49723: rustdoc didn't add target features when extracting or running doctests diff --git a/tests/rustdoc-ui/doctest/doc-cfg-target-feature.stdout b/tests/rustdoc-ui/doctest/doc-cfg-target-feature.stdout new file mode 100644 index 0000000000000..d71b1032e60ec --- /dev/null +++ b/tests/rustdoc-ui/doctest/doc-cfg-target-feature.stdout @@ -0,0 +1,39 @@ + +running 1 test +test $DIR/doc-cfg-target-feature.rs - foo (line 14) ... FAILED + +failures: + +---- $DIR/doc-cfg-target-feature.rs - foo (line 14) stdout ---- +warning: the feature `cfg_target_feature` has been stable since 1.27.0 and no longer requires an attribute to enable + --> $DIR/doc-cfg-target-feature.rs:14:12 + | +LL | #![feature(cfg_target_feature)] + | ^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(stable_features)]` on by default + +warning: 1 warning emitted + +Test executable failed (exit status: 101). + +stderr: + +thread 'main' ($TID) panicked at $DIR/doc-cfg-target-feature.rs:7:1: +assertion failed: false +stack backtrace: + 0: __rustc::rust_begin_unwind + 1: core::panicking::panic_fmt + 2: core::panicking::panic + 3: rust_out::main::_doctest_main__home_imperio_rust_rust_tests_rustdoc_ui_doctest_doc_cfg_target_feature_rs_14_0 + 4: rust_out::main + 5: >::call_once +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. + + + +failures: + $DIR/doc-cfg-target-feature.rs - foo (line 14) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/doc-test-attr-18199.rs b/tests/rustdoc-ui/doctest/doc-test-attr-18199.rs similarity index 74% rename from tests/rustdoc-html/doc-test-attr-18199.rs rename to tests/rustdoc-ui/doctest/doc-test-attr-18199.rs index 64016e32eeeb1..8350f244fccac 100644 --- a/tests/rustdoc-html/doc-test-attr-18199.rs +++ b/tests/rustdoc-ui/doctest/doc-test-attr-18199.rs @@ -1,6 +1,9 @@ -//@ compile-flags:--test // https://github.com/rust-lang/rust/issues/18199 +//@ compile-flags:--test +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + #![doc(test(attr(feature(staged_api))))] /// ``` diff --git a/tests/rustdoc-ui/doctest/doc-test-attr-18199.stdout b/tests/rustdoc-ui/doctest/doc-test-attr-18199.stdout new file mode 100644 index 0000000000000..a182a3b911af6 --- /dev/null +++ b/tests/rustdoc-ui/doctest/doc-test-attr-18199.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/doc-test-attr-18199.rs - foo (line 9) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/edition-doctest.rs b/tests/rustdoc-ui/doctest/edition-doctest.rs similarity index 87% rename from tests/rustdoc-html/edition-doctest.rs rename to tests/rustdoc-ui/doctest/edition-doctest.rs index f43c074f806bd..066475dae7bf0 100644 --- a/tests/rustdoc-html/edition-doctest.rs +++ b/tests/rustdoc-ui/doctest/edition-doctest.rs @@ -1,4 +1,6 @@ -//@ compile-flags:--test +//@ compile-flags:--test --test-args=--test-threads=1 +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass /// ```rust,edition2018 /// #![feature(try_blocks)] diff --git a/tests/rustdoc-ui/doctest/edition-doctest.stdout b/tests/rustdoc-ui/doctest/edition-doctest.stdout new file mode 100644 index 0000000000000..40d0df0575a76 --- /dev/null +++ b/tests/rustdoc-ui/doctest/edition-doctest.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test $DIR/edition-doctest.rs - foo (line 24) - compile fail ... ok +test $DIR/edition-doctest.rs - foo (line 5) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/edition-flag.rs b/tests/rustdoc-ui/doctest/edition-flag.rs similarity index 63% rename from tests/rustdoc-html/edition-flag.rs rename to tests/rustdoc-ui/doctest/edition-flag.rs index c57c8d50b2357..51235634dbf4a 100644 --- a/tests/rustdoc-html/edition-flag.rs +++ b/tests/rustdoc-ui/doctest/edition-flag.rs @@ -1,5 +1,7 @@ //@ compile-flags:--test //@ edition:2018 +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass /// ```rust /// fn main() { diff --git a/tests/rustdoc-ui/doctest/edition-flag.stdout b/tests/rustdoc-ui/doctest/edition-flag.stdout new file mode 100644 index 0000000000000..4833a6dcf9adf --- /dev/null +++ b/tests/rustdoc-ui/doctest/edition-flag.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/edition-flag.rs - main (line 6) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/force-target-feature.rs b/tests/rustdoc-ui/doctest/force-target-feature.rs similarity index 64% rename from tests/rustdoc-html/force-target-feature.rs rename to tests/rustdoc-ui/doctest/force-target-feature.rs index fa71bbeea2747..c3f9798147074 100644 --- a/tests/rustdoc-html/force-target-feature.rs +++ b/tests/rustdoc-ui/doctest/force-target-feature.rs @@ -1,6 +1,9 @@ //@ only-x86_64 //@ compile-flags:--test -C target-feature=+avx -//@ should-fail +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![feature(doc_cfg)] /// (written on a spider's web) Some Struct /// diff --git a/tests/rustdoc-ui/doctest/force-target-feature.stdout b/tests/rustdoc-ui/doctest/force-target-feature.stdout new file mode 100644 index 0000000000000..861a742075623 --- /dev/null +++ b/tests/rustdoc-ui/doctest/force-target-feature.stdout @@ -0,0 +1,27 @@ + +running 1 test +test $DIR/force-target-feature.rs - SomeStruct (line 10) ... FAILED + +failures: + +---- $DIR/force-target-feature.rs - SomeStruct (line 10) stdout ---- +Test executable failed (exit status: 101). + +stderr: + +thread 'main' ($TID) panicked at $DIR/force-target-feature.rs:3:1: +oh no +stack backtrace: + 0: std::panicking::begin_panic::<&str> + 1: rust_out::main::_doctest_main__home_imperio_rust_rust_tests_rustdoc_ui_doctest_force_target_feature_rs_10_0 + 2: rust_out::main + 3: >::call_once +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. + + + +failures: + $DIR/force-target-feature.rs - SomeStruct (line 10) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/ice-type-error-19181.rs b/tests/rustdoc-ui/doctest/ice-type-error-19181.rs similarity index 65% rename from tests/rustdoc-html/ice-type-error-19181.rs rename to tests/rustdoc-ui/doctest/ice-type-error-19181.rs index 02c6404762222..accb9e2cab1f4 100644 --- a/tests/rustdoc-html/ice-type-error-19181.rs +++ b/tests/rustdoc-ui/doctest/ice-type-error-19181.rs @@ -1,4 +1,7 @@ //@ compile-flags:--test +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + // https://github.com/rust-lang/rust/issues/19181 // rustdoc should not panic when target crate has compilation errors diff --git a/tests/rustdoc-ui/doctest/ice-type-error-19181.stdout b/tests/rustdoc-ui/doctest/ice-type-error-19181.stdout new file mode 100644 index 0000000000000..7326c0a25a069 --- /dev/null +++ b/tests/rustdoc-ui/doctest/ice-type-error-19181.stdout @@ -0,0 +1,5 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/no-run-still-checks-lints.rs b/tests/rustdoc-ui/doctest/no-run-still-checks-lints.rs similarity index 55% rename from tests/rustdoc-html/no-run-still-checks-lints.rs rename to tests/rustdoc-ui/doctest/no-run-still-checks-lints.rs index 73e311b72d5e5..cae6331f4723d 100644 --- a/tests/rustdoc-html/no-run-still-checks-lints.rs +++ b/tests/rustdoc-ui/doctest/no-run-still-checks-lints.rs @@ -1,5 +1,6 @@ //@ compile-flags:--test -//@ should-fail +//@ failure-status: 101 +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" #![doc(test(attr(deny(warnings))))] diff --git a/tests/rustdoc-ui/doctest/no-run-still-checks-lints.stdout b/tests/rustdoc-ui/doctest/no-run-still-checks-lints.stdout new file mode 100644 index 0000000000000..86d1b4d3094b6 --- /dev/null +++ b/tests/rustdoc-ui/doctest/no-run-still-checks-lints.stdout @@ -0,0 +1,29 @@ + +running 1 test +test $DIR/no-run-still-checks-lints.rs - foo (line 7) - compile ... FAILED + +failures: + +---- $DIR/no-run-still-checks-lints.rs - foo (line 7) stdout ---- +error: unused variable: `a` + --> $DIR/no-run-still-checks-lints.rs:8:5 + | +LL | let a = 3; + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/no-run-still-checks-lints.rs:6:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/no-run-still-checks-lints.rs - foo (line 7) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/process-termination.rs b/tests/rustdoc-ui/doctest/process-termination.rs similarity index 80% rename from tests/rustdoc-html/process-termination.rs rename to tests/rustdoc-ui/doctest/process-termination.rs index 73a86e57424a2..02ac594b3f0d4 100644 --- a/tests/rustdoc-html/process-termination.rs +++ b/tests/rustdoc-ui/doctest/process-termination.rs @@ -1,4 +1,6 @@ -//@ compile-flags:--test +//@ compile-flags:--test --test-args=--test-threads=1 +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass /// A check of using various process termination strategies /// diff --git a/tests/rustdoc-ui/doctest/process-termination.stdout b/tests/rustdoc-ui/doctest/process-termination.stdout new file mode 100644 index 0000000000000..3e15b9a5df80a --- /dev/null +++ b/tests/rustdoc-ui/doctest/process-termination.stdout @@ -0,0 +1,8 @@ + +running 3 tests +test $DIR/process-termination.rs - check_process_termination (line 16) ... ok +test $DIR/process-termination.rs - check_process_termination (line 22) ... ok +test $DIR/process-termination.rs - check_process_termination (line 9) ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/sanitizer-option.rs b/tests/rustdoc-ui/doctest/sanitizer-option.rs similarity index 86% rename from tests/rustdoc-html/sanitizer-option.rs rename to tests/rustdoc-ui/doctest/sanitizer-option.rs index 7b0038138f09f..5f29f1b8bac7e 100644 --- a/tests/rustdoc-html/sanitizer-option.rs +++ b/tests/rustdoc-ui/doctest/sanitizer-option.rs @@ -1,7 +1,9 @@ //@ needs-sanitizer-support //@ needs-sanitizer-address //@ compile-flags: --test -Z sanitizer=address -C unsafe-allow-abi-mismatch=sanitizer -// +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + // #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern // function that is provided by the sanitizer runtime, if flag is not passed // correctly, then linking will fail. diff --git a/tests/rustdoc-html/test_option_check/test.rs b/tests/rustdoc-ui/doctest/test-option-check-2.rs similarity index 54% rename from tests/rustdoc-html/test_option_check/test.rs rename to tests/rustdoc-ui/doctest/test-option-check-2.rs index af7a5827690f0..2e74da1eca794 100644 --- a/tests/rustdoc-html/test_option_check/test.rs +++ b/tests/rustdoc-ui/doctest/test-option-check-2.rs @@ -1,6 +1,9 @@ -//@ compile-flags: --test +//@ compile-flags: --test --test-args=--test-threads=1 //@ check-test-line-numbers-match +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass +#[path = "test-option-check.rs"] pub mod bar; /// This is a Foo; diff --git a/tests/rustdoc-ui/doctest/test-option-check-2.stdout b/tests/rustdoc-ui/doctest/test-option-check-2.stdout new file mode 100644 index 0000000000000..ab2db4938dfab --- /dev/null +++ b/tests/rustdoc-ui/doctest/test-option-check-2.stdout @@ -0,0 +1,8 @@ + +running 3 tests +test $DIR/test-option-check-2.rs - Bar (line 18) ... ok +test $DIR/test-option-check-2.rs - Foo (line 11) ... ok +test $DIR/test-option-check.rs - bar::foooo (line 8) ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-html/test_option_check/bar.rs b/tests/rustdoc-ui/doctest/test-option-check.rs similarity index 65% rename from tests/rustdoc-html/test_option_check/bar.rs rename to tests/rustdoc-ui/doctest/test-option-check.rs index 7c2309a79d4b9..e5d3350e3f981 100644 --- a/tests/rustdoc-html/test_option_check/bar.rs +++ b/tests/rustdoc-ui/doctest/test-option-check.rs @@ -1,5 +1,7 @@ //@ compile-flags: --test //@ check-test-line-numbers-match +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass /// This looks like another awesome test! /// diff --git a/tests/rustdoc-ui/doctest/test-option-check.stdout b/tests/rustdoc-ui/doctest/test-option-check.stdout new file mode 100644 index 0000000000000..38f949612a47a --- /dev/null +++ b/tests/rustdoc-ui/doctest/test-option-check.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/test-option-check.rs - foooo (line 8) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs b/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs deleted file mode 100644 index a4d3a4b497117..0000000000000 --- a/tests/rustdoc-ui/lints/renamed-lint-still-applies.rs +++ /dev/null @@ -1,10 +0,0 @@ -// compile-args: --crate-type lib -#![deny(broken_intra_doc_links)] -//~^ WARNING renamed to `rustdoc::broken_intra_doc_links` -//! [x] -//~^ ERROR unresolved link - -#![deny(rustdoc::non_autolinks)] -//~^ WARNING renamed to `rustdoc::bare_urls` -//! http://example.com -//~^ ERROR not a hyperlink From 614d9ea42ce84b46371e653f882496877ce277b4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 30 Aug 2026 16:24:44 +0200 Subject: [PATCH 13/40] Fix invalid `compile-args` ui tests argument --- .../lints/renamed-lint-still-applies.stderr | 12 ++++++------ tests/ui/lint/forbid-error-capped.rs | 1 - tests/ui/lint/forbid-error-capped.stderr | 4 ++-- tests/ui/mir/issue-71793-inline-args-storage.rs | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr b/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr index 88807dfb495d0..f4428ff6e5983 100644 --- a/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr +++ b/tests/rustdoc-ui/lints/renamed-lint-still-applies.stderr @@ -1,5 +1,5 @@ warning: lint `broken_intra_doc_links` has been renamed to `rustdoc::broken_intra_doc_links` - --> $DIR/renamed-lint-still-applies.rs:2:9 + --> $DIR/renamed-lint-still-applies.rs:3:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::broken_intra_doc_links` @@ -7,33 +7,33 @@ LL | #![deny(broken_intra_doc_links)] = note: `#[warn(renamed_and_removed_lints)]` on by default warning: lint `rustdoc::non_autolinks` has been renamed to `rustdoc::bare_urls` - --> $DIR/renamed-lint-still-applies.rs:7:9 + --> $DIR/renamed-lint-still-applies.rs:8:9 | LL | #![deny(rustdoc::non_autolinks)] | ^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `rustdoc::bare_urls` error: unresolved link to `x` - --> $DIR/renamed-lint-still-applies.rs:4:6 + --> $DIR/renamed-lint-still-applies.rs:5:6 | LL | //! [x] | ^ no item named `x` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` note: the lint level is defined here - --> $DIR/renamed-lint-still-applies.rs:2:9 + --> $DIR/renamed-lint-still-applies.rs:3:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ error: this URL is not a hyperlink - --> $DIR/renamed-lint-still-applies.rs:9:5 + --> $DIR/renamed-lint-still-applies.rs:10:5 | LL | //! http://example.com | ^^^^^^^^^^^^^^^^^^ | = note: bare URLs are not automatically turned into clickable links note: the lint level is defined here - --> $DIR/renamed-lint-still-applies.rs:7:9 + --> $DIR/renamed-lint-still-applies.rs:8:9 | LL | #![deny(rustdoc::non_autolinks)] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/forbid-error-capped.rs b/tests/ui/lint/forbid-error-capped.rs index e458ddf90746e..bfa72beac5828 100644 --- a/tests/ui/lint/forbid-error-capped.rs +++ b/tests/ui/lint/forbid-error-capped.rs @@ -1,5 +1,4 @@ //@ check-pass -// compile-args: --cap-lints=warn -Fwarnings // This checks that the forbid attribute checking is ignored when the forbidden // lint is capped. diff --git a/tests/ui/lint/forbid-error-capped.stderr b/tests/ui/lint/forbid-error-capped.stderr index 479e7b9412d57..3de8c2fe0ce61 100644 --- a/tests/ui/lint/forbid-error-capped.stderr +++ b/tests/ui/lint/forbid-error-capped.stderr @@ -1,5 +1,5 @@ warning: allow(unused) incompatible with previous forbid - --> $DIR/forbid-error-capped.rs:8:10 + --> $DIR/forbid-error-capped.rs:7:10 | LL | #![forbid(warnings)] | -------- `forbid` level set here @@ -14,7 +14,7 @@ warning: 1 warning emitted Future incompatibility report: Future breakage diagnostic: warning: allow(unused) incompatible with previous forbid - --> $DIR/forbid-error-capped.rs:8:10 + --> $DIR/forbid-error-capped.rs:7:10 | LL | #![forbid(warnings)] | -------- `forbid` level set here diff --git a/tests/ui/mir/issue-71793-inline-args-storage.rs b/tests/ui/mir/issue-71793-inline-args-storage.rs index 0ed4d4723731e..38ce28a035346 100644 --- a/tests/ui/mir/issue-71793-inline-args-storage.rs +++ b/tests/ui/mir/issue-71793-inline-args-storage.rs @@ -1,10 +1,10 @@ // Verifies that inliner emits StorageLive & StorageDead when introducing // temporaries for arguments, so that they don't become part of the coroutine. // Regression test for #71793. -// + //@ check-pass //@ edition:2018 -// compile-args: -Zmir-opt-level=3 +//@ compile-flags: -Zmir-opt-level=3 #![crate_type = "lib"] From f92efc873b925b3a25038ff526b9b5cdad5b4230 Mon Sep 17 00:00:00 2001 From: Shun Sakai Date: Tue, 1 Sep 2026 02:19:18 +0900 Subject: [PATCH 14/40] docs(num): clarify conditions under which error occurs --- library/core/src/convert/num.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 64e429b2f2591..c0d8fd670d7ad 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -336,8 +336,7 @@ macro_rules! impl_try_from_unbounded { type Error = TryFromIntError; /// Tries to create the target number type from a source - /// number type. This returns an error if the source value - /// is outside of the range of the target type. + /// number type. This never returns an error. #[inline] fn try_from(value: $source) -> Result { Ok(value as Self) @@ -356,7 +355,7 @@ macro_rules! impl_try_from_lower_bounded { /// Tries to create the target number type from a source /// number type. This returns an error if the source value - /// is outside of the range of the target type. + #[doc = concat!("is less than [`", stringify!($target), "::MIN`].")] #[inline] fn try_from(u: $source) -> Result { if u >= 0 { @@ -379,7 +378,7 @@ macro_rules! impl_try_from_upper_bounded { /// Tries to create the target number type from a source /// number type. This returns an error if the source value - /// is outside of the range of the target type. + #[doc = concat!("is greater than [`", stringify!($target), "::MAX`].")] #[inline] fn try_from(u: $source) -> Result { if u > (Self::MAX as $source) { From 7a38c0c984f6d05be47cda885b66bc48b3b23ae3 Mon Sep 17 00:00:00 2001 From: Yukang Date: Tue, 1 Sep 2026 14:00:23 +0800 Subject: [PATCH 15/40] Add regression test for for-loop temporary scope --- ...es-for-iterator-temp-scope-issue-160741.rs | 22 +++++++++++++++++++ ...or-iterator-temp-scope-issue-160741.stderr | 19 ++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/ui/lint/unused-braces-for-iterator-temp-scope-issue-160741.rs create mode 100644 tests/ui/lint/unused-braces-for-iterator-temp-scope-issue-160741.stderr diff --git a/tests/ui/lint/unused-braces-for-iterator-temp-scope-issue-160741.rs b/tests/ui/lint/unused-braces-for-iterator-temp-scope-issue-160741.rs new file mode 100644 index 0000000000000..6c85b8e50c5e3 --- /dev/null +++ b/tests/ui/lint/unused-braces-for-iterator-temp-scope-issue-160741.rs @@ -0,0 +1,22 @@ +//! A block around a Rust 2024 `for` iterator expression may shorten the lifetime of temporaries. + +//@ edition: 2024 +//@ check-pass + +#![warn(unused_braces)] + +use std::sync::{Arc, Mutex}; + +struct State { + values: Vec, + total: u32, +} + +fn main() { + let data = Arc::new(Mutex::new(State { values: vec![1, 2, 3], total: 0 })); + + for value in { data.lock().unwrap().values.clone() } { + //~^ WARN unnecessary braces around `for` iterator expression + data.lock().unwrap().total += value; + } +} diff --git a/tests/ui/lint/unused-braces-for-iterator-temp-scope-issue-160741.stderr b/tests/ui/lint/unused-braces-for-iterator-temp-scope-issue-160741.stderr new file mode 100644 index 0000000000000..6658184c9a5bd --- /dev/null +++ b/tests/ui/lint/unused-braces-for-iterator-temp-scope-issue-160741.stderr @@ -0,0 +1,19 @@ +warning: unnecessary braces around `for` iterator expression + --> $DIR/unused-braces-for-iterator-temp-scope-issue-160741.rs:18:18 + | +LL | for value in { data.lock().unwrap().values.clone() } { + | ^^ ^^ + | +note: the lint level is defined here + --> $DIR/unused-braces-for-iterator-temp-scope-issue-160741.rs:6:9 + | +LL | #![warn(unused_braces)] + | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - for value in { data.lock().unwrap().values.clone() } { +LL + for value in data.lock().unwrap().values.clone() { + | + +warning: 1 warning emitted + From 16b206a7ae3a672df2441fe5657252e2484d8911 Mon Sep 17 00:00:00 2001 From: albab-hasan Date: Sun, 23 Aug 2026 14:32:16 +0600 Subject: [PATCH 16/40] suggest calling a fn item used as the iterator of a `for` loop `suggest_fn_call` only fired when the failing obligation came from `ObligationCauseCode::FunctionArg`, so a fn item or closure used as the iterator of a `for` loop got no structured suggestion to call it. the iterator of a `for` loop is passed to `IntoIterator::into_iter`, so the failing `Iterator` goal is a derived obligation and the cause span carries the loop desugaring, which makes `can_be_used_for_suggestions` return false. carry the `HirId` of the iterator expression in `ObligationCauseCode::ForLoopIterator` and gate the suggestion on the span of that expression instead. https://github.com/rust-lang/rust/issues/161564 --- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 27 ++++++-- ...est-calling-fn-in-for-loop-issue-161564.rs | 37 ++++++++++ ...calling-fn-in-for-loop-issue-161564.stderr | 68 +++++++++++++++++++ 5 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 tests/ui/suggestions/suggest-calling-fn-in-for-loop-issue-161564.rs create mode 100644 tests/ui/suggestions/suggest-calling-fn-in-for-loop-issue-161564.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 6ebf382083f25..8e3be44caf959 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -555,7 +555,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { LangItem::IntoIterIntoIter | LangItem::IteratorNext if expr.span.is_desugaring(DesugaringKind::ForLoop) => { - Some(ObligationCauseCode::ForLoopIterator) + Some(ObligationCauseCode::ForLoopIterator(arg.hir_id)) } LangItem::TryTraitFromOutput if expr.span.is_desugaring(DesugaringKind::TryBlock) => diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 9736aabf29009..4dfc8d7c9705d 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -374,7 +374,7 @@ pub enum ObligationCauseCode<'tcx> { AwaitableExpr(HirId), - ForLoopIterator, + ForLoopIterator(HirId), QuestionMark, 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 7921250a85a9e..a7f05d756af0f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1119,12 +1119,29 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .collect::>() .join(", "); - if let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code() - && obligation.cause.span.can_be_used_for_suggestions() - { + let callee_hir_id = match obligation.cause.code() { + ObligationCauseCode::FunctionArg { arg_hir_id, .. } + if obligation.cause.span.can_be_used_for_suggestions() => + { + Some(*arg_hir_id) + } + // The iterator of a `for` loop is passed to `IntoIterator::into_iter`, so the failing + // `Iterator` goal is a derived obligation and `cause.span` carries the loop's + // desugaring context. The expression is still the user's, which its own span attests. + code => match code.peel_derives() { + ObligationCauseCode::ForLoopIterator(iter_hir_id) + if self.tcx.hir_span(*iter_hir_id).can_be_used_for_suggestions() => + { + Some(*iter_hir_id) + } + _ => None, + }, + }; + + if let Some(callee_hir_id) = callee_hir_id { let span = obligation.cause.span; - let arg_expr = match self.tcx.hir_node(*arg_hir_id) { + let arg_expr = match self.tcx.hir_node(callee_hir_id) { hir::Node::Expr(expr) => Some(expr), _ => None, }; @@ -3779,7 +3796,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(..) | ObligationCauseCode::AwaitableExpr(_) - | ObligationCauseCode::ForLoopIterator + | ObligationCauseCode::ForLoopIterator(_) | ObligationCauseCode::QuestionMark | ObligationCauseCode::CheckAssociatedTypeBounds { .. } | ObligationCauseCode::LetElse diff --git a/tests/ui/suggestions/suggest-calling-fn-in-for-loop-issue-161564.rs b/tests/ui/suggestions/suggest-calling-fn-in-for-loop-issue-161564.rs new file mode 100644 index 0000000000000..5d50346b5b6fe --- /dev/null +++ b/tests/ui/suggestions/suggest-calling-fn-in-for-loop-issue-161564.rs @@ -0,0 +1,37 @@ +//@ edition: 2021 + +//! Check that a fn item used as the iterator of a `for` loop is suggested to be called, the way +//! it already is when it is passed as a function argument. + +struct S; + +trait T { + fn assoc_in_trait() -> std::vec::IntoIter; +} + +impl T for S { + fn assoc_in_trait() -> std::vec::IntoIter { + vec![1u8].into_iter() + } +} + +impl S { + fn inherent_assoc() -> impl Iterator { + [1u8].into_iter() + } +} + +fn free_fn() -> impl Iterator { + [1u8].into_iter() +} + +fn main() { + for _ in S::inherent_assoc {} //~ ERROR [E0277] + for _ in ::assoc_in_trait {} //~ ERROR [E0277] + for _ in free_fn {} //~ ERROR [E0277] + + let closure = || vec![1u8].into_iter(); + for _ in closure {} //~ ERROR [E0277] + + for _ in || vec![1u8].into_iter() {} //~ ERROR [E0277] +} diff --git a/tests/ui/suggestions/suggest-calling-fn-in-for-loop-issue-161564.stderr b/tests/ui/suggestions/suggest-calling-fn-in-for-loop-issue-161564.stderr new file mode 100644 index 0000000000000..e2edaebb65c9b --- /dev/null +++ b/tests/ui/suggestions/suggest-calling-fn-in-for-loop-issue-161564.stderr @@ -0,0 +1,68 @@ +error[E0277]: `fn() -> impl Iterator {S::inherent_assoc}` is not an iterator + --> $DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:29:14 + | +LL | for _ in S::inherent_assoc {} + | ^^^^^^^^^^^^^^^^^ `fn() -> impl Iterator {S::inherent_assoc}` is not an iterator + | + = help: the trait `Iterator` is not implemented for fn item `fn() -> impl Iterator {S::inherent_assoc}` + = note: required for `fn() -> impl Iterator {S::inherent_assoc}` to implement `IntoIterator` +help: use parentheses to call this associated function + | +LL | for _ in S::inherent_assoc() {} + | ++ + +error[E0277]: `fn() -> std::vec::IntoIter {::assoc_in_trait}` is not an iterator + --> $DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:30:14 + | +LL | for _ in ::assoc_in_trait {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ `fn() -> std::vec::IntoIter {::assoc_in_trait}` is not an iterator + | + = help: the trait `Iterator` is not implemented for fn item `fn() -> std::vec::IntoIter {::assoc_in_trait}` + = note: required for `fn() -> std::vec::IntoIter {::assoc_in_trait}` to implement `IntoIterator` +help: use parentheses to call this associated function + | +LL | for _ in ::assoc_in_trait() {} + | ++ + +error[E0277]: `fn() -> impl Iterator {free_fn}` is not an iterator + --> $DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:31:14 + | +LL | for _ in free_fn {} + | ^^^^^^^ `fn() -> impl Iterator {free_fn}` is not an iterator + | + = help: the trait `Iterator` is not implemented for fn item `fn() -> impl Iterator {free_fn}` + = note: required for `fn() -> impl Iterator {free_fn}` to implement `IntoIterator` +help: use parentheses to call this function + | +LL | for _ in free_fn() {} + | ++ + +error[E0277]: `{closure@$DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:33:19: 33:21}` is not an iterator + --> $DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:34:14 + | +LL | for _ in closure {} + | ^^^^^^^ `{closure@$DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:33:19: 33:21}` is not an iterator + | + = help: the trait `Iterator` is not implemented for closure `{closure@$DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:33:19: 33:21}` + = note: required for `{closure@$DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:33:19: 33:21}` to implement `IntoIterator` +help: use parentheses to call this closure + | +LL | for _ in closure() {} + | ++ + +error[E0277]: `{closure@$DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:36:14: 36:16}` is not an iterator + --> $DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:36:14 + | +LL | for _ in || vec![1u8].into_iter() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ `{closure@$DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:36:14: 36:16}` is not an iterator + | + = help: the trait `Iterator` is not implemented for closure `{closure@$DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:36:14: 36:16}` + = note: required for `{closure@$DIR/suggest-calling-fn-in-for-loop-issue-161564.rs:36:14: 36:16}` to implement `IntoIterator` +help: use parentheses to call this closure + | +LL | for _ in (|| vec![1u8].into_iter())() {} + | + +++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. From a97dc3135416f40b49ac345074643e3805e1624f Mon Sep 17 00:00:00 2001 From: albab-hasan Date: Tue, 1 Sep 2026 13:17:42 +0600 Subject: [PATCH 17/40] suggest calling a function item that is being dereferenced dereferencing an uncalled function only said the function type cannot be dereferenced. it now suggests the call, gated on the return type actually being dereferenceable. https://github.com/rust-lang/rust/issues/161564#issuecomment-5383101040 --- compiler/rustc_hir_typeck/src/expr.rs | 10 +++ ...uggest-calling-fn-in-deref-issue-161564.rs | 73 ++++++++++++++++++ ...st-calling-fn-in-deref-issue-161564.stderr | 75 +++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 tests/ui/suggestions/suggest-calling-fn-in-deref-issue-161564.rs create mode 100644 tests/ui/suggestions/suggest-calling-fn-in-deref-issue-161564.stderr diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 8e3be44caf959..548177a150b9a 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -430,6 +430,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(sp) = tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) { err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } + // The operand may be an uncalled function, in which case it is its return type + // the user meant to dereference. Only suggest the call when that return type is + // itself dereferenceable, mirroring the checks `lookup_derefing` just failed. + self.suggest_fn_call(&mut err, oprnd, oprnd_t, |output| { + output.builtin_deref(true).is_some() + || self.tcx.lang_items().deref_trait().is_some_and(|deref_trait| { + self.type_implements_trait(deref_trait, [output], self.param_env) + .may_apply() + }) + }); Ty::new_error(tcx, err.emit()) }), hir::UnOp::Not => { diff --git a/tests/ui/suggestions/suggest-calling-fn-in-deref-issue-161564.rs b/tests/ui/suggestions/suggest-calling-fn-in-deref-issue-161564.rs new file mode 100644 index 0000000000000..6f1bf4e4589b8 --- /dev/null +++ b/tests/ui/suggestions/suggest-calling-fn-in-deref-issue-161564.rs @@ -0,0 +1,73 @@ +// Dereferencing an uncalled function item should suggest calling it, rather than +// only complaining that the function's own type cannot be dereferenced. + +pub fn ret_ref() -> &'static usize { + &const { 12 } +} + +pub fn ret_val() -> usize { + 12 +} + +pub fn with_args(_: u8) -> &'static usize { + &const { 12 } +} + +pub fn ret_box() -> Box { + Box::new(12) +} + +struct S; + +impl S { + fn assoc() -> &'static usize { + &const { 12 } + } +} + +pub fn fn_item() { + let _a = *ret_ref; + //~^ ERROR type `fn() -> &'static usize {ret_ref}` cannot be dereferenced + //~| HELP use parentheses to call this function +} + +pub fn takes_args() { + let _a = *with_args; + //~^ ERROR type `fn(u8) -> &'static usize {with_args}` cannot be dereferenced + //~| HELP use parentheses to call this function +} + +pub fn assoc_fn() { + let _a = *S::assoc; + //~^ ERROR type `fn() -> &'static usize {S::assoc}` cannot be dereferenced + //~| HELP use parentheses to call this associated function +} + +pub fn overloaded_deref() { + let _a = *ret_box; + //~^ ERROR type `fn() -> Box {ret_box}` cannot be dereferenced + //~| HELP use parentheses to call this function +} + +pub fn fn_pointer() { + let f: fn() -> &'static usize = ret_ref; + let _a = *f; + //~^ ERROR type `fn() -> &'static usize` cannot be dereferenced + //~| HELP use parentheses to call this function pointer +} + +pub fn closure() { + let c = || &const { 12usize }; + let _a = *c; + //~^ ERROR cannot be dereferenced + //~| HELP use parentheses to call this closure +} + +// Negative case: calling this one still would not produce something dereferenceable, +// so no suggestion should be offered. +pub fn not_derefable_when_called() { + let _a = *ret_val; + //~^ ERROR type `fn() -> usize {ret_val}` cannot be dereferenced +} + +fn main() {} diff --git a/tests/ui/suggestions/suggest-calling-fn-in-deref-issue-161564.stderr b/tests/ui/suggestions/suggest-calling-fn-in-deref-issue-161564.stderr new file mode 100644 index 0000000000000..a119a368450c3 --- /dev/null +++ b/tests/ui/suggestions/suggest-calling-fn-in-deref-issue-161564.stderr @@ -0,0 +1,75 @@ +error[E0614]: type `fn() -> &'static usize {ret_ref}` cannot be dereferenced + --> $DIR/suggest-calling-fn-in-deref-issue-161564.rs:29:14 + | +LL | let _a = *ret_ref; + | ^^^^^^^^ can't be dereferenced + | +help: use parentheses to call this function + | +LL | let _a = *ret_ref(); + | ++ + +error[E0614]: type `fn(u8) -> &'static usize {with_args}` cannot be dereferenced + --> $DIR/suggest-calling-fn-in-deref-issue-161564.rs:35:14 + | +LL | let _a = *with_args; + | ^^^^^^^^^^ can't be dereferenced + | +help: use parentheses to call this function + | +LL | let _a = *with_args(/* u8 */); + | ++++++++++ + +error[E0614]: type `fn() -> &'static usize {S::assoc}` cannot be dereferenced + --> $DIR/suggest-calling-fn-in-deref-issue-161564.rs:41:14 + | +LL | let _a = *S::assoc; + | ^^^^^^^^^ can't be dereferenced + | +help: use parentheses to call this associated function + | +LL | let _a = *S::assoc(); + | ++ + +error[E0614]: type `fn() -> Box {ret_box}` cannot be dereferenced + --> $DIR/suggest-calling-fn-in-deref-issue-161564.rs:47:14 + | +LL | let _a = *ret_box; + | ^^^^^^^^ can't be dereferenced + | +help: use parentheses to call this function + | +LL | let _a = *ret_box(); + | ++ + +error[E0614]: type `fn() -> &'static usize` cannot be dereferenced + --> $DIR/suggest-calling-fn-in-deref-issue-161564.rs:54:14 + | +LL | let _a = *f; + | ^^ can't be dereferenced + | +help: use parentheses to call this function pointer + | +LL | let _a = *f(); + | ++ + +error[E0614]: type `{closure@$DIR/suggest-calling-fn-in-deref-issue-161564.rs:60:13: 60:15}` cannot be dereferenced + --> $DIR/suggest-calling-fn-in-deref-issue-161564.rs:61:14 + | +LL | let _a = *c; + | ^^ can't be dereferenced + | +help: use parentheses to call this closure + | +LL | let _a = *c(); + | ++ + +error[E0614]: type `fn() -> usize {ret_val}` cannot be dereferenced + --> $DIR/suggest-calling-fn-in-deref-issue-161564.rs:69:14 + | +LL | let _a = *ret_val; + | ^^^^^^^^ can't be dereferenced + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0614`. From cb5e3df331e1684fd591c95658c033aed368175d Mon Sep 17 00:00:00 2001 From: Sang-Woo Kim Date: Tue, 1 Sep 2026 08:43:32 +0000 Subject: [PATCH 18/40] std: don't reference `libc::O_NOFOLLOW` on VxWorks in `set_perm_nofollow` VxWorks' libc defines no `O_NOFOLLOW`, so building std for x86_64-wrs-vxworks stopped compiling once `set_perm_nofollow` was consolidated into `sys/fs/unix.rs` without a vxworks guard. VxWorks also has no way to express a no-follow permission change: its `fchmodat` rejects `AT_SYMLINK_NOFOLLOW` with `ENOTSUP`. Return `Unsupported`, matching the existing Android stub. --- library/std/src/sys/fs/unix.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 1045a7b7e2f56..acd2c7f5dfbd1 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1884,6 +1884,13 @@ pub fn set_perm(p: &CStr, perm: FilePermissions) -> io::Result<()> { cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ()) } +#[cfg(target_os = "vxworks")] +pub fn set_perm_nofollow(_p: &CStr, _perm: FilePermissions) -> io::Result<()> { + // VxWorks has no `O_NOFOLLOW`, and its `fchmodat` rejects + // `AT_SYMLINK_NOFOLLOW` with `ENOTSUP`, so a no-follow chmod is unsupported. + Err(crate::io::ErrorKind::Unsupported.into()) +} + #[cfg(target_os = "android")] pub fn set_perm_nofollow(_p: &CStr, _perm: FilePermissions) -> io::Result<()> { // Currently Android seems to be having inconsistent behavior with fchmodat @@ -1896,7 +1903,7 @@ pub fn set_perm_nofollow(_p: &CStr, _perm: FilePermissions) -> io::Result<()> { Err(crate::io::ErrorKind::Unsupported.into()) } -#[cfg(not(target_os = "android"))] +#[cfg(not(any(target_os = "android", target_os = "vxworks")))] pub fn set_perm_nofollow(p: &CStr, perm: FilePermissions) -> io::Result<()> { #[inline] /// Helper function for fallback open with `O_NOFOLLOW` + `fchmod` behavior From 5ba810f06513b45387f1ed249a49b3ed75c8f47f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Sep 2026 14:18:42 +0200 Subject: [PATCH 19/40] Normalize more rustdoc-ui doctest output --- tests/rustdoc-ui/doctest/doc-cfg-target-feature.rs | 1 + tests/rustdoc-ui/doctest/doc-cfg-target-feature.stdout | 10 +++++----- tests/rustdoc-ui/doctest/force-target-feature.rs | 1 + tests/rustdoc-ui/doctest/force-target-feature.stdout | 8 ++++---- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/rustdoc-ui/doctest/doc-cfg-target-feature.rs b/tests/rustdoc-ui/doctest/doc-cfg-target-feature.rs index 99a133a6829c5..a55b31d61e3d0 100644 --- a/tests/rustdoc-ui/doctest/doc-cfg-target-feature.rs +++ b/tests/rustdoc-ui/doctest/doc-cfg-target-feature.rs @@ -1,5 +1,6 @@ //@ only-x86_64 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "rust_out::main::.+" -> "rust_out::main::$$PATH" //@ compile-flags:--test //@ failure-status: 101 diff --git a/tests/rustdoc-ui/doctest/doc-cfg-target-feature.stdout b/tests/rustdoc-ui/doctest/doc-cfg-target-feature.stdout index d71b1032e60ec..6526e9898dd2f 100644 --- a/tests/rustdoc-ui/doctest/doc-cfg-target-feature.stdout +++ b/tests/rustdoc-ui/doctest/doc-cfg-target-feature.stdout @@ -1,12 +1,12 @@ running 1 test -test $DIR/doc-cfg-target-feature.rs - foo (line 14) ... FAILED +test $DIR/doc-cfg-target-feature.rs - foo (line 15) ... FAILED failures: ----- $DIR/doc-cfg-target-feature.rs - foo (line 14) stdout ---- +---- $DIR/doc-cfg-target-feature.rs - foo (line 15) stdout ---- warning: the feature `cfg_target_feature` has been stable since 1.27.0 and no longer requires an attribute to enable - --> $DIR/doc-cfg-target-feature.rs:14:12 + --> $DIR/doc-cfg-target-feature.rs:15:12 | LL | #![feature(cfg_target_feature)] | ^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ stack backtrace: 0: __rustc::rust_begin_unwind 1: core::panicking::panic_fmt 2: core::panicking::panic - 3: rust_out::main::_doctest_main__home_imperio_rust_rust_tests_rustdoc_ui_doctest_doc_cfg_target_feature_rs_14_0 + 3: rust_out::main::$PATH 4: rust_out::main 5: >::call_once note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. @@ -33,7 +33,7 @@ note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose bac failures: - $DIR/doc-cfg-target-feature.rs - foo (line 14) + $DIR/doc-cfg-target-feature.rs - foo (line 15) test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/doctest/force-target-feature.rs b/tests/rustdoc-ui/doctest/force-target-feature.rs index c3f9798147074..f39e7cf3a9094 100644 --- a/tests/rustdoc-ui/doctest/force-target-feature.rs +++ b/tests/rustdoc-ui/doctest/force-target-feature.rs @@ -1,6 +1,7 @@ //@ only-x86_64 //@ compile-flags:--test -C target-feature=+avx //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "rust_out::main::.+" -> "rust_out::main::$$PATH" //@ failure-status: 101 #![feature(doc_cfg)] diff --git a/tests/rustdoc-ui/doctest/force-target-feature.stdout b/tests/rustdoc-ui/doctest/force-target-feature.stdout index 861a742075623..fb898dd14b2c9 100644 --- a/tests/rustdoc-ui/doctest/force-target-feature.stdout +++ b/tests/rustdoc-ui/doctest/force-target-feature.stdout @@ -1,10 +1,10 @@ running 1 test -test $DIR/force-target-feature.rs - SomeStruct (line 10) ... FAILED +test $DIR/force-target-feature.rs - SomeStruct (line 11) ... FAILED failures: ----- $DIR/force-target-feature.rs - SomeStruct (line 10) stdout ---- +---- $DIR/force-target-feature.rs - SomeStruct (line 11) stdout ---- Test executable failed (exit status: 101). stderr: @@ -13,7 +13,7 @@ thread 'main' ($TID) panicked at $DIR/force-target-feature.rs:3:1: oh no stack backtrace: 0: std::panicking::begin_panic::<&str> - 1: rust_out::main::_doctest_main__home_imperio_rust_rust_tests_rustdoc_ui_doctest_force_target_feature_rs_10_0 + 1: rust_out::main::$PATH 2: rust_out::main 3: >::call_once note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. @@ -21,7 +21,7 @@ note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose bac failures: - $DIR/force-target-feature.rs - SomeStruct (line 10) + $DIR/force-target-feature.rs - SomeStruct (line 11) test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME From 9ed2e0c0cac7ce208faf5055b0452abdc04167a0 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 1 Sep 2026 20:44:08 +0200 Subject: [PATCH 20/40] reformat itanium mangling test to be more readable --- ...data-id-itanium-cxx-abi-primitive-types.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs index 93845d0519541..cb8eb13ac75ed 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs @@ -15,114 +15,133 @@ pub fn foo2(_: (), _: c_void) {} // CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo3(_: (), _: c_void, _: c_void) {} // CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo4(_: *mut ()) {} // CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo5(_: *mut (), _: *mut c_void) {} // CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo6(_: *mut (), _: *mut c_void, _: *mut c_void) {} // CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo7(_: *const ()) {} // CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo8(_: *const (), _: *const c_void) {} // CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo9(_: *const (), _: *const c_void, _: *const c_void) {} // CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo10(_: bool) {} // CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo11(_: bool, _: bool) {} // CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo12(_: bool, _: bool, _: bool) {} // CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo13(_: i8) {} // CHECK: define{{.*}}5foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo14(_: i8, _: i8) {} // CHECK: define{{.*}}5foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo15(_: i8, _: i8, _: i8) {} // CHECK: define{{.*}}5foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo16(_: i16) {} // CHECK: define{{.*}}5foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo17(_: i16, _: i16) {} // CHECK: define{{.*}}5foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo18(_: i16, _: i16, _: i16) {} // CHECK: define{{.*}}5foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo19(_: i32) {} // CHECK: define{{.*}}5foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo20(_: i32, _: i32) {} // CHECK: define{{.*}}5foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo21(_: i32, _: i32, _: i32) {} // CHECK: define{{.*}}5foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo22(_: i64) {} // CHECK: define{{.*}}5foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo23(_: i64, _: i64) {} // CHECK: define{{.*}}5foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo24(_: i64, _: i64, _: i64) {} // CHECK: define{{.*}}5foo24{{.*}}!type ![[TYPE24:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo25(_: i128) {} // CHECK: define{{.*}}5foo25{{.*}}!type ![[TYPE25:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo26(_: i128, _: i128) {} // CHECK: define{{.*}}5foo26{{.*}}!type ![[TYPE26:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo27(_: i128, _: i128, _: i128) {} // CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo28(_: isize) {} // CHECK: define{{.*}}5foo28{{.*}}!type ![[TYPE28:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo29(_: isize, _: isize) {} // CHECK: define{{.*}}5foo29{{.*}}!type ![[TYPE29:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo30(_: isize, _: isize, _: isize) {} // CHECK: define{{.*}}5foo30{{.*}}!type ![[TYPE30:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo31(_: u8) {} // CHECK: define{{.*}}5foo31{{.*}}!type ![[TYPE31:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo32(_: u8, _: u8) {} // CHECK: define{{.*}}5foo32{{.*}}!type ![[TYPE32:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo33(_: u8, _: u8, _: u8) {} // CHECK: define{{.*}}5foo33{{.*}}!type ![[TYPE33:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo34(_: u16) {} // CHECK: define{{.*}}5foo34{{.*}}!type ![[TYPE34:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo35(_: u16, _: u16) {} // CHECK: define{{.*}}5foo35{{.*}}!type ![[TYPE35:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo36(_: u16, _: u16, _: u16) {} // CHECK: define{{.*}}5foo36{{.*}}!type ![[TYPE36:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo37(_: u32) {} // CHECK: define{{.*}}5foo37{{.*}}!type ![[TYPE37:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo38(_: u32, _: u32) {} // CHECK: define{{.*}}5foo38{{.*}}!type ![[TYPE38:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo39(_: u32, _: u32, _: u32) {} // CHECK: define{{.*}}5foo39{{.*}}!type ![[TYPE39:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo40(_: u64) {} // CHECK: define{{.*}}5foo40{{.*}}!type ![[TYPE40:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo41(_: u64, _: u64) {} // CHECK: define{{.*}}5foo41{{.*}}!type ![[TYPE41:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo42(_: u64, _: u64, _: u64) {} // CHECK: define{{.*}}5foo42{{.*}}!type ![[TYPE42:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo43(_: u128) {} // CHECK: define{{.*}}5foo43{{.*}}!type ![[TYPE43:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo44(_: u128, _: u128) {} // CHECK: define{{.*}}5foo44{{.*}}!type ![[TYPE44:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo45(_: u128, _: u128, _: u128) {} // CHECK: define{{.*}}5foo45{{.*}}!type ![[TYPE45:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo46(_: usize) {} // CHECK: define{{.*}}5foo46{{.*}}!type ![[TYPE46:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo47(_: usize, _: usize) {} // CHECK: define{{.*}}5foo47{{.*}}!type ![[TYPE47:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo48(_: usize, _: usize, _: usize) {} // CHECK: define{{.*}}5foo48{{.*}}!type ![[TYPE48:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo49(_: f32) {} // CHECK: define{{.*}}5foo49{{.*}}!type ![[TYPE49:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo50(_: f32, _: f32) {} // CHECK: define{{.*}}5foo50{{.*}}!type ![[TYPE50:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo51(_: f32, _: f32, _: f32) {} // CHECK: define{{.*}}5foo51{{.*}}!type ![[TYPE51:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo52(_: f64) {} // CHECK: define{{.*}}5foo52{{.*}}!type ![[TYPE52:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo53(_: f64, _: f64) {} // CHECK: define{{.*}}5foo53{{.*}}!type ![[TYPE53:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo54(_: f64, _: f64, _: f64) {} // CHECK: define{{.*}}5foo54{{.*}}!type ![[TYPE54:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo55(_: char) {} // CHECK: define{{.*}}5foo55{{.*}}!type ![[TYPE55:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo56(_: char, _: char) {} // CHECK: define{{.*}}5foo56{{.*}}!type ![[TYPE56:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo57(_: char, _: char, _: char) {} // CHECK: define{{.*}}5foo57{{.*}}!type ![[TYPE57:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + pub fn foo58(_: &str) {} // CHECK: define{{.*}}5foo58{{.*}}!type ![[TYPE58:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo59(_: &str, _: &str) {} From 7a44484407077776e30120f5e72cdef2820e8856 Mon Sep 17 00:00:00 2001 From: Leonard Chan Date: Fri, 24 Jul 2026 23:03:20 +0000 Subject: [PATCH 21/40] fuchsia: Add safestack as a supported sanitizer for x86_64 fuchsia Make it also enabled by default just like it is for clang. --- .../rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs | 4 +++- .../stack-protector/stack-protector-target-support.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs index dbff5e30828a9..b8fb1fb6d3a52 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs @@ -9,7 +9,9 @@ pub(crate) fn target() -> Target { base.features = "+cmpxchg16b,+lahfsahf,+popcnt,+sse3,+sse4.1,+sse4.2,+ssse3".into(); base.max_atomic_width = Some(128); base.stack_probes = StackProbeType::Inline; - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK; + base.supported_sanitizers = + SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::SAFESTACK; + base.default_sanitizers = SanitizerSet::SAFESTACK; base.supports_xray = true; Target { diff --git a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs index 9f182985d1573..f883e7ac8691f 100644 --- a/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs +++ b/tests/assembly-llvm/stack-protector/stack-protector-target-support.rs @@ -177,13 +177,15 @@ //@ compile-flags: -C opt-level=2 #![crate_type = "lib"] -#![feature(no_core, lang_items)] +#![feature(no_core, lang_items, sanitize)] #![crate_type = "lib"] #![no_core] extern crate minicore; use minicore::*; +// We only do this because we can't disable default sanitizers via compile-flags. +#[sanitize(safestack = "off")] #[no_mangle] pub fn foo() { // CHECK: foo{{:|()}} From 09db86657d425ed3b4a07fbcd3910a09d6ab7152 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Sep 2026 21:32:43 +0200 Subject: [PATCH 22/40] Add missing `rustdoc-ui` test output --- tests/rustdoc-ui/doctest/sanitizer-option.stdout | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/rustdoc-ui/doctest/sanitizer-option.stdout diff --git a/tests/rustdoc-ui/doctest/sanitizer-option.stdout b/tests/rustdoc-ui/doctest/sanitizer-option.stdout new file mode 100644 index 0000000000000..62040048335f2 --- /dev/null +++ b/tests/rustdoc-ui/doctest/sanitizer-option.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/sanitizer-option.rs - z_flag_is_passed_to_rustc (line 11) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + From 1d08a6b9ff707d19caf72d8ba427ec2ffa399739 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 1 Sep 2026 12:49:07 -0700 Subject: [PATCH 23/40] Prefer `LLVMGetVersion` for runtime info Our `LLVMRustVersion*` functions get hard-coded `LLVM_VERSION_*` values when we build `RustWrapper.cpp`, but this could be different than the actual LLVM library at runtime. This should never happen with toolchains from `rustup`, but with external LLVM in a distro build, for example, `rustc` and `LLVM` can be upgraded independently. Most of the time when we check the LLVM version, we're only looking at the major version anyway, and we already assert that these are equal in `configure_llvm`. However, for anything that does check the minor or patch version too, the runtime version is probably more relevant. --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 ++++++-- compiler/rustc_codegen_llvm/src/llvm_util.rs | 11 ++++++----- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 4 ---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 684bba7a717db..c20b4ccd776da 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2172,9 +2172,13 @@ unsafe extern "C" { pub(crate) safe fn LLVMRustCoverageMappingVersion() -> u32; pub(crate) fn LLVMRustDebugMetadataVersion() -> u32; + + /// Returns the LLVM major version that the compiler was built with. + /// + /// Note that this is hard-coded as `LLVM_VERSION_MAJOR` when `RustWrapper.cpp` is built. This + /// could be different than what the runtime LLVM library reports in `LLVMGetVersion`, so we + /// assert their equality in `configure_llvm`. pub(crate) fn LLVMRustVersionMajor() -> u32; - pub(crate) fn LLVMRustVersionMinor() -> u32; - pub(crate) fn LLVMRustVersionPatch() -> u32; /// Add LLVM module flags. /// diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 82ddcca3e1530..a5441b1ef1135 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -50,10 +50,7 @@ unsafe fn configure_llvm(sess: &Session) { // Check to ensure we're running against the correct LLVM version. unsafe { - let mut llvm_major = 0; - let mut llvm_minor = 0; - let mut llvm_patch = 0; - llvm::LLVMGetVersion(&mut llvm_major, &mut llvm_minor, &mut llvm_patch); + let (llvm_major, llvm_minor, llvm_patch) = get_version(); let expected_version = llvm::LLVMRustVersionMajor(); if llvm_major != expected_version { sess.dcx().emit_fatal(diagnostics::LlvmVersionMismatch { @@ -465,7 +462,11 @@ pub(crate) fn print_version() { pub(crate) fn get_version() -> (u32, u32, u32) { // Can be called without initializing LLVM unsafe { - (llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor(), llvm::LLVMRustVersionPatch()) + let mut llvm_major = 0; + let mut llvm_minor = 0; + let mut llvm_patch = 0; + llvm::LLVMGetVersion(&mut llvm_major, &mut llvm_minor, &mut llvm_patch); + (llvm_major, llvm_minor, llvm_patch) } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 189296dc9c4c8..6947c4766eccf 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -885,10 +885,6 @@ extern "C" uint32_t LLVMRustDebugMetadataVersion() { return DEBUG_METADATA_VERSION; } -extern "C" uint32_t LLVMRustVersionPatch() { return LLVM_VERSION_PATCH; } - -extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } - extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } // FFI equivalent of LLVM's `llvm::Module::ModFlagBehavior`. From 45b97ea0cc2cf6b6d8d0a9bbb1906dc8d29a53d9 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 1 Sep 2026 21:39:11 +0200 Subject: [PATCH 24/40] itanium mangling: use minicore --- ...ype-metadata-id-itanium-cxx-abi-primitive-types.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs index cb8eb13ac75ed..52204755f47dd 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs @@ -1,13 +1,18 @@ // Verifies that type metadata identifiers for functions are emitted correctly // for primitive types. // +//@ add-minicore //@ needs-sanitizer-cfi -//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 +//@ compile-flags: -Clto -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer +//@ minicore-compile-flags: -Ccodegen-units=1 #![crate_type = "lib"] +#![feature(no_core)] +#![no_core] -extern crate core; -use core::ffi::*; +extern crate minicore; +use minicore::*; pub fn foo1(_: ()) {} // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} From bb0bcf25cca2f9996c5d374f4fd8d914965a03f6 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 1 Sep 2026 21:04:19 +0200 Subject: [PATCH 25/40] add itanium mangling test for `f16` and `f128` --- ...data-id-itanium-cxx-abi-primitive-types.rs | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs index 52204755f47dd..59e794df69990 100644 --- a/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs +++ b/tests/codegen-llvm/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs @@ -3,12 +3,12 @@ // //@ add-minicore //@ needs-sanitizer-cfi -//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=0 -C link-dead-code //@ compile-flags: -Clto -Zsanitizer=cfi -Ctarget-feature=-crt-static -C unsafe-allow-abi-mismatch=sanitizer //@ minicore-compile-flags: -Ccodegen-units=1 #![crate_type = "lib"] -#![feature(no_core)] +#![feature(no_core, f16, f128)] #![no_core] extern crate minicore; @@ -154,6 +154,20 @@ pub fn foo59(_: &str, _: &str) {} pub fn foo60(_: &str, _: &str, _: &str) {} // CHECK: define{{.*}}5foo60{{.*}}!type ![[TYPE60:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo61(_: f16) {} +// CHECK: define{{.*}}5foo61{{.*}}!type ![[TYPE61:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo62(_: f16, _: f16) {} +// CHECK: define{{.*}}5foo62{{.*}}!type ![[TYPE62:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo63(_: f16, _: f16, _: f16) {} +// CHECK: define{{.*}}5foo63{{.*}}!type ![[TYPE63:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +pub fn foo64(_: f128) {} +// CHECK: define{{.*}}5foo64{{.*}}!type ![[TYPE64:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo65(_: f128, _: f128) {} +// CHECK: define{{.*}}5foo65{{.*}}!type ![[TYPE65:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +pub fn foo66(_: f128, _: f128, _: f128) {} +// CHECK: define{{.*}}5foo66{{.*}}!type ![[TYPE66:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvE"} // CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvE"} // CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_E"} @@ -212,3 +226,9 @@ pub fn foo60(_: &str, _: &str, _: &str) {} // CHECK: ![[TYPE58]] = !{i64 0, !"_ZTSFvu3refIu3strEE"} // CHECK: ![[TYPE59]] = !{i64 0, !"_ZTSFvu3refIu3strES0_E"} // CHECK: ![[TYPE60]] = !{i64 0, !"_ZTSFvu3refIu3strES0_S0_E"} +// CHECK: ![[TYPE61]] = !{i64 0, !"_ZTSFvDhE"} +// CHECK: ![[TYPE62]] = !{i64 0, !"_ZTSFvDhDhE"} +// CHECK: ![[TYPE63]] = !{i64 0, !"_ZTSFvDhDhDhE"} +// CHECK: ![[TYPE64]] = !{i64 0, !"_ZTSFvgE"} +// CHECK: ![[TYPE65]] = !{i64 0, !"_ZTSFvggE"} +// CHECK: ![[TYPE66]] = !{i64 0, !"_ZTSFvgggE"} From 47fc75df4415debfcd437c61cf80b00d125089ce Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Tue, 1 Sep 2026 22:01:02 +0200 Subject: [PATCH 26/40] Revert "retrieve supported GCC targets from the sysroot" This reverts commit 5a5b84aa5fbb5cdef0ecc667fd7afdc876dab08e. --- src/tools/compiletest/src/cli.rs | 9 ------- src/tools/compiletest/src/common.rs | 3 --- src/tools/compiletest/src/directives.rs | 26 +------------------ src/tools/compiletest/src/rustdoc_gui_test.rs | 1 - 4 files changed, 1 insertion(+), 38 deletions(-) diff --git a/src/tools/compiletest/src/cli.rs b/src/tools/compiletest/src/cli.rs index 45681eabe03a3..893f5b76724b8 100644 --- a/src/tools/compiletest/src/cli.rs +++ b/src/tools/compiletest/src/cli.rs @@ -401,13 +401,6 @@ pub(crate) fn parse_config(args: Vec) -> Config { let iteration_count = args.iteration_count.unwrap_or(Config::DEFAULT_ITERATION_COUNT); assert!(iteration_count > 0, "`--iteration-count` must be a positive integer"); - let gcc_supported_target_tuples = match default_codegen_backend { - CodegenBackend::Gcc => { - directives::find_gcc_supported_targets(&args.sysroot_base, &args.host) - } - CodegenBackend::Llvm | CodegenBackend::Cranelift => vec![], - }; - // FIXME: this run scheme is... confusing. let run = args.run.and_then(|mode| match mode.as_str() { "auto" => None, @@ -455,8 +448,6 @@ pub(crate) fn parse_config(args: Vec) -> Config { force_pass_mode: args.pass, force_rerun: args.force_rerun, - gcc_supported_target_tuples, - gdb: args.gdb, gdb_version, git_hash: args.git_hash, diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 4123dcf5b600a..8c580d3520dfd 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -770,9 +770,6 @@ pub(crate) struct Config { /// Whether to ignore `//@ ignore-backends`. pub(crate) bypass_ignore_backends: bool, - /// Target tuples for which we've found libgccjit.so. - pub(crate) gcc_supported_target_tuples: Vec, - /// Number of parallel jobs configured for the build. /// /// This is forwarded from bootstrap's `jobs` configuration. diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 3499821f7b6e0..3459273c922a1 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -851,30 +851,6 @@ pub(crate) fn extract_llvm_version_from_binary(binary_path: &str) -> Option Vec { - // E.g. `lib/rustlib/x86_64-unknown-linux-gnu/codegen-backends/lib`. - let backends_dir = - sysroot_base.join("lib").join("rustlib").join(host).join("codegen-backends").join("lib"); - - match std::fs::read_dir(&backends_dir) { - Ok(entries) => { - // Search for `aarch64-unknown-linux-gnu/libgccjit.so` et cetera. - let target_tuples: Vec<_> = entries - .filter_map(|entry| entry.ok()) - .filter(|entry| entry.path().join("libgccjit.so").exists()) - .filter_map(|entry| entry.file_name().into_string().ok()) - .collect(); - - if target_tuples.is_empty() { - panic!("did not find `libgccjit.so` for any target in {backends_dir}"); - } - - target_tuples - } - Err(e) => panic!("unable to find `libgccjit.so` for any target in {backends_dir}: {e:?}",), - } -} - /// Takes a directive of the form `" [- ]"`, returns the numeric representation /// of `` and `` as tuple: `(, )`. /// @@ -1255,7 +1231,7 @@ fn ignore_unsupported_backend_target(config: &Config, line: &DirectiveLine<'_>) return IgnoreDecision::Continue; }; - if !config.gcc_supported_target_tuples.iter().any(|t| t == target) { + if target != "x86_64-unknown-linux-gnu" { IgnoreDecision::Ignore { reason: format!( "backend `{}` cannot build for target `{target}`", diff --git a/src/tools/compiletest/src/rustdoc_gui_test.rs b/src/tools/compiletest/src/rustdoc_gui_test.rs index b2d23bcf8ec0a..5a768519f616d 100644 --- a/src/tools/compiletest/src/rustdoc_gui_test.rs +++ b/src/tools/compiletest/src/rustdoc_gui_test.rs @@ -143,7 +143,6 @@ fn incomplete_config_for_rustdoc_gui_test() -> Config { default_codegen_backend: CodegenBackend::Llvm, override_codegen_backend: None, bypass_ignore_backends: Default::default(), - gcc_supported_target_tuples: vec![], jobs: Default::default(), parallel_frontend_threads: Config::DEFAULT_PARALLEL_FRONTEND_THREADS, iteration_count: Config::DEFAULT_ITERATION_COUNT, From b0ba8b100ef633a153432dfe94dcaf11486133ca Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Sep 2026 15:57:03 +1000 Subject: [PATCH 27/40] Introduce `PerOwnerLoweringState` `LoweringContext` has 14 fields that get swapped in and out in `with_hir_id_owner`. This is fragile and gross. This commit moves those fields into a new struct, `PerOwnerLoweringState`, which means they can be swapped in and out cleanly. Other changes: - All `self.foo` accesses to those 14 fields become `self.curr_owner.foo`. - Field renames: - `current_hir_id_owner` -> `owner_id` - `current_disambiguator` -> `disambiguator` - `LoweringContext::make_owner_info` becomes `PerOwnerLoweringState::into_owner_info`; this makes sense because it consumes the `PerOwnerLoweringState`. - Stronger assertions: `into_owner_info` has assertions that now apply to the `with_lctx` path as well as the `with_hir_id_owner` path. --- .../src/delegation/attributes.rs | 6 +- .../src/delegation/generics.rs | 2 +- .../rustc_ast_lowering/src/delegation/mod.rs | 10 +- .../src/delegation/resolution.rs | 4 +- compiler/rustc_ast_lowering/src/expr.rs | 17 +- compiler/rustc_ast_lowering/src/item.rs | 42 +- compiler/rustc_ast_lowering/src/lib.rs | 393 +++++++++--------- compiler/rustc_ast_lowering/src/pat.rs | 8 +- compiler/rustc_ast_lowering/src/path.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 7 +- 10 files changed, 241 insertions(+), 250 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation/attributes.rs b/compiler/rustc_ast_lowering/src/delegation/attributes.rs index 885ee0d51c730..834f85450a2cd 100644 --- a/compiler/rustc_ast_lowering/src/delegation/attributes.rs +++ b/compiler/rustc_ast_lowering/src/delegation/attributes.rs @@ -43,17 +43,17 @@ impl<'hir> LoweringContext<'_, 'hir> { let &DelegationResolution { span, sig_id, .. } = resolution; const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO; - let new_attrs = self.create_new_attrs(span, sig_id, self.attrs.get(&PARENT_ID)); + let new_attrs = self.create_new_attrs(span, sig_id, self.curr_owner.attrs.get(&PARENT_ID)); if !new_attrs.is_empty() { - let new_attrs = match self.attrs.get(&PARENT_ID) { + let new_attrs = match self.curr_owner.attrs.get(&PARENT_ID) { Some(existing_attrs) => self.arena.alloc_from_iter( existing_attrs.iter().map(|a| a.clone()).chain(new_attrs.into_iter()), ), None => self.arena.alloc_from_iter(new_attrs.into_iter()), }; - self.attrs.insert(PARENT_ID, new_attrs); + self.curr_owner.attrs.insert(PARENT_ID, new_attrs); } } diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index 911ec5956006d..867ed364433e7 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -587,7 +587,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }; // Important: we don't use `self.next_id()` as we want to execute - // `lower_node_id` routine so param's id is added to `self.children`. + // `lower_node_id` routine so param's id is added to `self.curr_owner.children`. let hir_id = self.lower_node_id(node_id); Some(hir::GenericParam { diff --git a/compiler/rustc_ast_lowering/src/delegation/mod.rs b/compiler/rustc_ast_lowering/src/delegation/mod.rs index 3b9074e67bdd2..a92b62517e61d 100644 --- a/compiler/rustc_ast_lowering/src/delegation/mod.rs +++ b/compiler/rustc_ast_lowering/src/delegation/mod.rs @@ -140,9 +140,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let id = match source { DelegationSource::Single => None, DelegationSource::List(expn_id) => Some(expn_id), - DelegationSource::Glob => { - Some(self.tcx.expn_that_defined(self.owner.def_id).expect_local()) - } + DelegationSource::Glob => Some( + self.tcx + .expn_that_defined(self.curr_owner.owner.def_id) + .expect_local(), + ), }; id.map(|id| (id, unused_target_expr)) @@ -335,7 +337,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let overwrites = self_resolver.overwrites; // Target expr needs to lower `self` path. - self.ident_and_label_to_local_id.insert(pat_node_id, param_local_id); + self.curr_owner.ident_and_label_to_local_id.insert(pat_node_id, param_local_id); let block = cfg_select! { debug_assertions => { diff --git a/compiler/rustc_ast_lowering/src/delegation/resolution.rs b/compiler/rustc_ast_lowering/src/delegation/resolution.rs index dd1b9518e6d7f..85604223c8509 100644 --- a/compiler/rustc_ast_lowering/src/delegation/resolution.rs +++ b/compiler/rustc_ast_lowering/src/delegation/resolution.rs @@ -73,7 +73,7 @@ pub(super) mod resolver { #[inline] pub(crate) fn owner_id(&self) -> LocalDefId { - self.0.owner.def_id + self.0.curr_owner.owner.def_id } /// (from `tests\ui\delegation\target-expr-removal-defs-inside.rs`): @@ -91,7 +91,7 @@ pub(super) mod resolver { #[inline] pub(crate) fn is_definition(&self, id: NodeId) -> bool { self.0.resolver.owners.contains_key(&id) - || self.0.owner.node_id_to_def_id.contains_key(&id) + || self.0.curr_owner.owner.node_id_to_def_id.contains_key(&id) } #[inline] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4d5b98fd1ac00..0a4a2ae7145e3 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -172,7 +172,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } // Merge attributes into the inner expression. if !e.attrs.is_empty() { - let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); + let old_attrs = + self.curr_owner.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); let new_attrs = self .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e)) .into_iter() @@ -181,7 +182,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if new_attrs.is_empty() { return ex; } - self.attrs.insert(ex.hir_id.local_id, new_attrs); + self.curr_owner.attrs.insert(ex.hir_id.local_id, new_attrs); } return ex; } @@ -884,7 +885,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled. pub(super) fn maybe_forward_track_caller(&mut self, outer_hir_id: HirId, inner_hir_id: HirId) { if self.tcx.features().async_fn_track_caller() - && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) + && let Some(attrs) = self.curr_owner.attrs.get(&outer_hir_id.local_id) && let Some(t) = attrs.iter().find(|a| { matches!( a, @@ -892,7 +893,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }) { - self.attrs.insert(inner_hir_id.local_id, std::slice::from_ref(t)); + self.curr_owner.attrs.insert(inner_hir_id.local_id, std::slice::from_ref(t)); } } @@ -1505,16 +1506,16 @@ impl<'hir> LoweringContext<'_, 'hir> { dest_hir_id: hir::HirId, ) -> Option