From bd12d151ee63290b317566db770465301e2dd2a9 Mon Sep 17 00:00:00 2001 From: Yiming Lei Date: Thu, 15 Dec 2022 22:25:11 -0800 Subject: [PATCH 01/15] add function to tell if the current ambiguity error matches a previous one in ambiguity_errors if 2 errors of the kind and ident and span of the ident, b1, b2 and misc1 misc2 are the same then these 2 ambiguity errors matched prevent identical ambiguity error from pushing into vector of ambiguity_errors this will fix #105177 --- compiler/rustc_resolve/src/lib.rs | 26 ++++++++++++++-- .../local-modularized-tricky-fail-1.rs | 1 - .../local-modularized-tricky-fail-1.stderr | 31 ++----------------- src/test/ui/imports/macros.rs | 1 - src/test/ui/imports/macros.stderr | 29 +++-------------- 5 files changed, 32 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 24e4b5bdd3f50..5d0b4c0419f0a 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1686,6 +1686,24 @@ impl<'a> Resolver<'a> { .or_insert_with(|| self.arenas.alloc_name_resolution()) } + // Test if AmbiguityError ambi is any identical to any one inside ambiguity_errors + fn matches_previous_ambiguity_error(&mut self, ambi: &AmbiguityError<'_>) -> bool { + for ambiguity_error in &self.ambiguity_errors { + // if the span location and ident as well as its span are the same + if ambiguity_error.kind == ambi.kind + && ambiguity_error.ident == ambi.ident + && ambiguity_error.ident.span == ambi.ident.span + && ambiguity_error.b1.span == ambi.b1.span + && ambiguity_error.b2.span == ambi.b2.span + && ambiguity_error.misc1 == ambi.misc1 + && ambiguity_error.misc2 == ambi.misc2 + { + return true; + } + } + false + } + fn record_use( &mut self, ident: Ident, @@ -1693,14 +1711,18 @@ impl<'a> Resolver<'a> { is_lexical_scope: bool, ) { if let Some((b2, kind)) = used_binding.ambiguity { - self.ambiguity_errors.push(AmbiguityError { + let ambiguity_error = AmbiguityError { kind, ident, b1: used_binding, b2, misc1: AmbiguityErrorMisc::None, misc2: AmbiguityErrorMisc::None, - }); + }; + if !self.matches_previous_ambiguity_error(&ambiguity_error) { + // avoid dumplicated span information to be emitt out + self.ambiguity_errors.push(ambiguity_error); + } } if let NameBindingKind::Import { import, binding, ref used } = used_binding.kind { // Avoid marking `extern crate` items that refer to a name from extern prelude, diff --git a/src/test/ui/imports/local-modularized-tricky-fail-1.rs b/src/test/ui/imports/local-modularized-tricky-fail-1.rs index 37fe0eceed6b8..29e9b8ec841f5 100644 --- a/src/test/ui/imports/local-modularized-tricky-fail-1.rs +++ b/src/test/ui/imports/local-modularized-tricky-fail-1.rs @@ -26,7 +26,6 @@ mod inner1 { } exported!(); //~ ERROR `exported` is ambiguous - //~| ERROR `exported` is ambiguous mod inner2 { define_exported!(); diff --git a/src/test/ui/imports/local-modularized-tricky-fail-1.stderr b/src/test/ui/imports/local-modularized-tricky-fail-1.stderr index c048d2ea20420..20eadaaaa56b8 100644 --- a/src/test/ui/imports/local-modularized-tricky-fail-1.stderr +++ b/src/test/ui/imports/local-modularized-tricky-fail-1.stderr @@ -23,33 +23,8 @@ LL | use inner1::*; = help: consider adding an explicit import of `exported` to disambiguate = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0659]: `exported` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:28:1 - | -LL | exported!(); - | ^^^^^^^^ ambiguous name - | - = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution -note: `exported` could refer to the macro defined here - --> $DIR/local-modularized-tricky-fail-1.rs:5:5 - | -LL | / macro_rules! exported { -LL | | () => () -LL | | } - | |_____^ -... -LL | define_exported!(); - | ------------------ in this macro invocation -note: `exported` could also refer to the macro imported here - --> $DIR/local-modularized-tricky-fail-1.rs:22:5 - | -LL | use inner1::*; - | ^^^^^^^^^ - = help: consider adding an explicit import of `exported` to disambiguate - = note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0659]: `panic` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:36:5 + --> $DIR/local-modularized-tricky-fail-1.rs:35:5 | LL | panic!(); | ^^^^^ ambiguous name @@ -70,7 +45,7 @@ LL | define_panic!(); = note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0659]: `include` is ambiguous - --> $DIR/local-modularized-tricky-fail-1.rs:47:1 + --> $DIR/local-modularized-tricky-fail-1.rs:46:1 | LL | include!(); | ^^^^^^^ ambiguous name @@ -90,6 +65,6 @@ LL | define_include!(); = help: use `crate::include` to refer to this macro unambiguously = note: this error originates in the macro `define_include` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/imports/macros.rs b/src/test/ui/imports/macros.rs index f39711898cdf0..f2a22ad620b11 100644 --- a/src/test/ui/imports/macros.rs +++ b/src/test/ui/imports/macros.rs @@ -14,7 +14,6 @@ mod m1 { mod m2 { use two_macros::*; m! { //~ ERROR ambiguous - //~| ERROR ambiguous use foo::m; } } diff --git a/src/test/ui/imports/macros.stderr b/src/test/ui/imports/macros.stderr index 110548d1d6ae1..e34e5359b48fa 100644 --- a/src/test/ui/imports/macros.stderr +++ b/src/test/ui/imports/macros.stderr @@ -6,7 +6,7 @@ LL | m! { | = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution note: `m` could refer to the macro imported here - --> $DIR/macros.rs:18:13 + --> $DIR/macros.rs:17:13 | LL | use foo::m; | ^^^^^^ @@ -18,43 +18,24 @@ LL | use two_macros::*; = help: consider adding an explicit import of `m` to disambiguate error[E0659]: `m` is ambiguous - --> $DIR/macros.rs:16:5 - | -LL | m! { - | ^ ambiguous name - | - = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution -note: `m` could refer to the macro imported here - --> $DIR/macros.rs:18:13 - | -LL | use foo::m; - | ^^^^^^ -note: `m` could also refer to the macro imported here - --> $DIR/macros.rs:15:9 - | -LL | use two_macros::*; - | ^^^^^^^^^^^^^ - = help: consider adding an explicit import of `m` to disambiguate - -error[E0659]: `m` is ambiguous - --> $DIR/macros.rs:30:9 + --> $DIR/macros.rs:29:9 | LL | m! { | ^ ambiguous name | = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution note: `m` could refer to the macro imported here - --> $DIR/macros.rs:31:17 + --> $DIR/macros.rs:30:17 | LL | use two_macros::n as m; | ^^^^^^^^^^^^^^^^^^ note: `m` could also refer to the macro imported here - --> $DIR/macros.rs:23:9 + --> $DIR/macros.rs:22:9 | LL | use two_macros::m; | ^^^^^^^^^^^^^ = help: use `self::m` to refer to this macro unambiguously -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0659`. From 738b0c06730e4e2c74901d554dcb7d1b40b5cd0a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Dec 2022 18:30:12 +0000 Subject: [PATCH 02/15] Re-enable fn trait call notation error --- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- src/test/ui/unboxed-closures/non-tupled-call.rs | 17 +++++++++++++++++ .../ui/unboxed-closures/non-tupled-call.stderr | 9 +++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/unboxed-closures/non-tupled-call.rs create mode 100644 src/test/ui/unboxed-closures/non-tupled-call.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index d1e0964112bc5..877680053f090 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -214,7 +214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "cannot use call notation; the first type parameter \ for the function trait is neither a tuple nor unit" ) - .delay_as_bug(); + .emit(); (self.err_args(provided_args.len()), None) } } diff --git a/src/test/ui/unboxed-closures/non-tupled-call.rs b/src/test/ui/unboxed-closures/non-tupled-call.rs new file mode 100644 index 0000000000000..08bea4f1678b6 --- /dev/null +++ b/src/test/ui/unboxed-closures/non-tupled-call.rs @@ -0,0 +1,17 @@ +#![feature(fn_traits, unboxed_closures, tuple_trait)] + +use std::default::Default; +use std::marker::Tuple; + +fn wrap(func: impl Fn) { + let x: P = Default::default(); + // Should be: `func.call(x);` + func(x); + //~^ ERROR cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit +} + +fn foo() {} + +fn main() { + wrap(foo); +} diff --git a/src/test/ui/unboxed-closures/non-tupled-call.stderr b/src/test/ui/unboxed-closures/non-tupled-call.stderr new file mode 100644 index 0000000000000..35ac9ebe29103 --- /dev/null +++ b/src/test/ui/unboxed-closures/non-tupled-call.stderr @@ -0,0 +1,9 @@ +error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit + --> $DIR/non-tupled-call.rs:9:5 + | +LL | func(x); + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0059`. From 04926e0534be77ed1b33602057d60d0bb14c1d66 Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Tue, 22 Nov 2022 21:15:27 +0000 Subject: [PATCH 03/15] Switch `#[track_caller]` back to a no-op unless feature gate is enabled This patch fixes a regression, in which `#[track_caller]`, which was previously a no-op, was changed to actually turn on the behavior. This should instead only happen behind the `closure_track_caller` feature gate. Also, add a warning for the user to understand how their code will compile depending on the feature gate being turned on or not. Fixes #104588 --- .../locales/en-US/lint.ftl | 2 + compiler/rustc_lint/src/builtin.rs | 45 ++++++++++- .../issue-104588-no-op-panic-track-caller.rs | 78 +++++++++++++++++++ ...sue-104588-no-op-panic-track-caller.stderr | 12 +++ .../issue-104588-no-op-track-caller.rs | 9 +++ .../issue-104588-no-op-track-caller.stderr | 12 +++ 6 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.rs create mode 100644 src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.stderr create mode 100644 src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs create mode 100644 src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 7e28f22c0ba8b..3980f9a2a7a58 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -350,6 +350,8 @@ lint_builtin_mutable_transmutes = lint_builtin_unstable_features = unstable feature +lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled + lint_builtin_unreachable_pub = unreachable `pub` {$what} .suggestion = consider restricting its visibility .help = or consider exporting it for use by other crates diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index cd19e65b6fc32..d7d91a12e6584 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -25,6 +25,7 @@ use crate::{ types::{transparent_newtype_field, CItemKind}, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, }; +use hir::IsAsync; use rustc_ast::attr; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; @@ -40,7 +41,10 @@ use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, Gate use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; -use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin}; +use rustc_hir::intravisit::FnKind as HirFnKind; +use rustc_hir::{ + Body, FnDecl, ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin, +}; use rustc_index::vec::Idx; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::{LayoutError, LayoutOf}; @@ -1370,6 +1374,45 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { } } +declare_lint! { + /// `#[track_caller]` is a no-op without corresponding feature flag + UNGATED_ASYNC_FN_TRACK_CALLER, + Warn, + "enabling track_caller on an async fn is a no-op unless the closure_track_caller feature is enabled" +} + +declare_lint_pass!( + /// Explains corresponding feature flag must be enabled for the `#[track_caller] attribute to + /// do anything + UngatedAsyncFnTrackCaller => [UNGATED_ASYNC_FN_TRACK_CALLER] +); + +impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { + fn check_fn( + &mut self, + cx: &LateContext<'_>, + fn_kind: HirFnKind<'_>, + _: &'tcx FnDecl<'_>, + _: &'tcx Body<'_>, + span: Span, + hir_id: HirId, + ) { + if let HirFnKind::ItemFn(_, _, _) = fn_kind && fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller { + // Now, check if the function has the `#[track_caller]` attribute + let attrs = cx.tcx.hir().attrs(hir_id); + let maybe_track_caller = attrs.iter().find(|attr| attr.has_name(sym::track_caller)); + if let Some(attr) = maybe_track_caller { + cx.struct_span_lint( + UNGATED_ASYNC_FN_TRACK_CALLER, + span.with_hi(attr.span.hi()), + fluent::lint_ungated_async_fn_track_caller, + |lint| lint, + ); + } + } + } +} + declare_lint! { /// The `unreachable_pub` lint triggers for `pub` items not reachable from /// the crate root. diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.rs b/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.rs new file mode 100644 index 0000000000000..5ef40408e2693 --- /dev/null +++ b/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.rs @@ -0,0 +1,78 @@ +// run-pass +// edition:2021 +// needs-unwind + + +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() { + bar().await +} + +#[track_caller] //~ WARN `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled [ungated_async_fn_track_caller] +async fn bar_track_caller() { + panic!() +} + +async fn foo_track_caller() { + bar_track_caller().await +} + +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 +} + +fn main() { + assert_eq!(panicked_at(|| block_on(foo())), 41); + // Since the `closure_track_caller` feature is not enabled, the + // `track_caller annotation does nothing. + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 50); +} diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.stderr b/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.stderr new file mode 100644 index 0000000000000..5bfd9ed8490fd --- /dev/null +++ b/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.stderr @@ -0,0 +1,12 @@ +warning: `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled + --> $DIR/issue-104588-no-op-panic-track-caller.rs:48:16 + | +LL | #[track_caller] + | ________________^ +LL | | async fn bar_track_caller() { + | |_ + | + = note: `#[warn(ungated_async_fn_track_caller)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs new file mode 100644 index 0000000000000..146d3c9ec53dc --- /dev/null +++ b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs @@ -0,0 +1,9 @@ +// check-pass +// edition:2021 + +#[track_caller] //~ WARN `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled +async fn foo() {} + +fn main() { + foo(); +} diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr new file mode 100644 index 0000000000000..bf66cc9ea90fc --- /dev/null +++ b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr @@ -0,0 +1,12 @@ +warning: `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled + --> $DIR/issue-104588-no-op-track-caller.rs:4:16 + | +LL | #[track_caller] + | ________________^ +LL | | async fn foo() {} + | |_ + | + = note: `#[warn(ungated_async_fn_track_caller)]` on by default + +warning: 1 warning emitted + From dc2c4ce578bd3bee824e1b30789cfa6cb777e059 Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Thu, 24 Nov 2022 03:39:47 +0000 Subject: [PATCH 04/15] Update code based on PR comments This patch does the following: - Refactor some repeated lines into a single one - Split the `ungated_async_fn_caller` lint into multiple lines, and make one of those lines only print out on nightly - Use test revisions instead of copying an existing test --- .../locales/en-US/lint.ftl | 3 +- compiler/rustc_lint/src/builtin.rs | 12 ++- .../issue-104588-no-op-panic-track-caller.rs | 78 ------------------- ...sue-104588-no-op-panic-track-caller.stderr | 12 --- .../issue-104588-no-op-track-caller.rs | 2 +- .../issue-104588-no-op-track-caller.stderr | 12 +-- .../panic-track-caller.nofeat.stderr | 14 ++++ .../track-caller/panic-track-caller.rs | 24 ++++-- 8 files changed, 51 insertions(+), 106 deletions(-) delete mode 100644 src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.rs delete mode 100644 src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.stderr create mode 100644 src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 3980f9a2a7a58..a36a511bd4aa6 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -350,7 +350,8 @@ lint_builtin_mutable_transmutes = lint_builtin_unstable_features = unstable feature -lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled +lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op + .suggestion = enable this feature lint_builtin_unreachable_pub = unreachable `pub` {$what} .suggestion = consider restricting its visibility diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index d7d91a12e6584..e90572cb23880 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1404,10 +1404,16 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { if let Some(attr) = maybe_track_caller { cx.struct_span_lint( UNGATED_ASYNC_FN_TRACK_CALLER, - span.with_hi(attr.span.hi()), + attr.span, fluent::lint_ungated_async_fn_track_caller, - |lint| lint, - ); + |lint| { + lint.span_label(span, "this function will not propagate the caller location"); + if cx.tcx.sess.is_nightly_build() { + lint.span_suggestion(attr.span, fluent::suggestion, "#[closure_track_caller]", Applicability::MachineApplicable); + } + lint + } + ); } } } diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.rs b/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.rs deleted file mode 100644 index 5ef40408e2693..0000000000000 --- a/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.rs +++ /dev/null @@ -1,78 +0,0 @@ -// run-pass -// edition:2021 -// needs-unwind - - -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() { - bar().await -} - -#[track_caller] //~ WARN `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled [ungated_async_fn_track_caller] -async fn bar_track_caller() { - panic!() -} - -async fn foo_track_caller() { - bar_track_caller().await -} - -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 -} - -fn main() { - assert_eq!(panicked_at(|| block_on(foo())), 41); - // Since the `closure_track_caller` feature is not enabled, the - // `track_caller annotation does nothing. - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 50); -} diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.stderr b/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.stderr deleted file mode 100644 index 5bfd9ed8490fd..0000000000000 --- a/src/test/ui/async-await/track-caller/issue-104588-no-op-panic-track-caller.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled - --> $DIR/issue-104588-no-op-panic-track-caller.rs:48:16 - | -LL | #[track_caller] - | ________________^ -LL | | async fn bar_track_caller() { - | |_ - | - = note: `#[warn(ungated_async_fn_track_caller)]` on by default - -warning: 1 warning emitted - diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs index 146d3c9ec53dc..6443e14296da8 100644 --- a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs +++ b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs @@ -1,7 +1,7 @@ // check-pass // edition:2021 -#[track_caller] //~ WARN `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled +#[track_caller] //~ WARN `#[track_caller]` on async functions is a no-op async fn foo() {} fn main() { diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr index bf66cc9ea90fc..bd39c9d092cac 100644 --- a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr +++ b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr @@ -1,10 +1,10 @@ -warning: `#[track_caller]` on async functions is a no-op, unless the `closure_track_caller` feature is enabled - --> $DIR/issue-104588-no-op-track-caller.rs:4:16 +warning: `#[track_caller]` on async functions is a no-op + --> $DIR/issue-104588-no-op-track-caller.rs:4:1 | -LL | #[track_caller] - | ________________^ -LL | | async fn foo() {} - | |_ +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ help: enable this feature: `#[closure_track_caller]` +LL | async fn foo() {} + | ----------------- this function will not propagate the caller location | = note: `#[warn(ungated_async_fn_track_caller)]` on by default diff --git a/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr new file mode 100644 index 0000000000000..e0201f2238ddb --- /dev/null +++ b/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr @@ -0,0 +1,14 @@ +warning: `#[track_caller]` on async functions is a no-op + --> $DIR/panic-track-caller.rs:50:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ help: enable this feature: `#[closure_track_caller]` +LL | / async fn bar_track_caller() { +LL | | panic!() +LL | | } + | |_- this function will not propagate the caller location + | + = note: `#[warn(ungated_async_fn_track_caller)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/async-await/track-caller/panic-track-caller.rs b/src/test/ui/async-await/track-caller/panic-track-caller.rs index 066cf97628fa5..ee37e64be4fa3 100644 --- a/src/test/ui/async-await/track-caller/panic-track-caller.rs +++ b/src/test/ui/async-await/track-caller/panic-track-caller.rs @@ -1,7 +1,9 @@ // run-pass // edition:2021 +// revisions: feat nofeat // needs-unwind -#![feature(closure_track_caller, async_closure, stmt_expr_attributes)] +#![feature(async_closure, stmt_expr_attributes)] +#![cfg_attr(feat, feature(closure_track_caller))] use std::future::Future; use std::panic; @@ -45,7 +47,7 @@ async fn foo() { bar().await } -#[track_caller] +#[track_caller] //[nofeat]~ WARN `#[track_caller]` on async functions is a no-op async fn bar_track_caller() { panic!() } @@ -91,8 +93,20 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { } fn main() { - assert_eq!(panicked_at(|| block_on(foo())), 41); - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 54); - assert_eq!(panicked_at(|| block_on(foo_assoc())), 67); + assert_eq!(panicked_at(|| block_on(foo())), 43); + + #[cfg(feat)] + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 56); + #[cfg(nofeat)] + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 52); + + #[cfg(feat)] + assert_eq!(panicked_at(|| block_on(foo_assoc())), 69); + #[cfg(nofeat)] + assert_eq!(panicked_at(|| block_on(foo_assoc())), 64); + + #[cfg(feat)] + assert_eq!(panicked_at(|| block_on(foo_closure())), 76); + #[cfg(feat)] assert_eq!(panicked_at(|| block_on(foo_closure())), 74); } From e28a07a0a157b63dc11e9f590484d5332866623a Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Thu, 24 Nov 2022 03:48:27 +0000 Subject: [PATCH 05/15] update wording of lint --- compiler/rustc_error_messages/locales/en-US/lint.ftl | 2 +- compiler/rustc_lint/src/builtin.rs | 2 +- .../track-caller/issue-104588-no-op-track-caller.stderr | 2 +- .../async-await/track-caller/panic-track-caller.nofeat.stderr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index a36a511bd4aa6..0d5507835a9e9 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -351,7 +351,7 @@ lint_builtin_mutable_transmutes = lint_builtin_unstable_features = unstable feature lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op - .suggestion = enable this feature + .suggestion = enable this unstable feature lint_builtin_unreachable_pub = unreachable `pub` {$what} .suggestion = consider restricting its visibility diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e90572cb23880..c353f74251652 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1409,7 +1409,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { |lint| { lint.span_label(span, "this function will not propagate the caller location"); if cx.tcx.sess.is_nightly_build() { - lint.span_suggestion(attr.span, fluent::suggestion, "#[closure_track_caller]", Applicability::MachineApplicable); + lint.span_suggestion(attr.span, fluent::suggestion, "closure_track_caller", Applicability::MachineApplicable); } lint } diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr index bd39c9d092cac..b41077a0b924d 100644 --- a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr +++ b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr @@ -2,7 +2,7 @@ warning: `#[track_caller]` on async functions is a no-op --> $DIR/issue-104588-no-op-track-caller.rs:4:1 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ help: enable this feature: `#[closure_track_caller]` + | ^^^^^^^^^^^^^^^ help: enable this unstable feature: `closure_track_caller` LL | async fn foo() {} | ----------------- this function will not propagate the caller location | diff --git a/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr index e0201f2238ddb..71d4b00cc6e8b 100644 --- a/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr +++ b/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr @@ -2,7 +2,7 @@ warning: `#[track_caller]` on async functions is a no-op --> $DIR/panic-track-caller.rs:50:1 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ help: enable this feature: `#[closure_track_caller]` + | ^^^^^^^^^^^^^^^ help: enable this unstable feature: `closure_track_caller` LL | / async fn bar_track_caller() { LL | | panic!() LL | | } From 2d060034f0fd5f5780c7fd41046901b8e0cdf7e8 Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Wed, 7 Dec 2022 20:13:22 +0000 Subject: [PATCH 06/15] Update track_caller logic/lint after rebase --- compiler/rustc_ast_lowering/src/expr.rs | 53 ++++++++++--------- compiler/rustc_lint/src/builtin.rs | 16 ++++-- compiler/rustc_lint/src/lib.rs | 1 + .../panic-track-caller.nofeat.stderr | 12 ++++- .../track-caller/panic-track-caller.rs | 7 +-- 5 files changed, 52 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a3f5c18f2e75c..a58c74dbc333a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -656,34 +656,35 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Closure(c) }; - let track_caller = self - .attrs - .get(&outer_hir_id.local_id) - .map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))); - let hir_id = self.lower_node_id(closure_node_id); - if track_caller { - let unstable_span = self.mark_span_with_reason( - DesugaringKind::Async, - span, - self.allow_gen_future.clone(), - ); - self.lower_attrs( - hir_id, - &[Attribute { - kind: AttrKind::Normal(ptr::P(NormalAttr { - item: AttrItem { - path: Path::from_ident(Ident::new(sym::track_caller, span)), - args: AttrArgs::Empty, + let unstable_span = self.mark_span_with_reason( + DesugaringKind::Async, + span, + self.allow_gen_future.clone(), + ); + if self.tcx.features().closure_track_caller { + let track_caller = self + .attrs + .get(&outer_hir_id.local_id) + .map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))); + if track_caller { + self.lower_attrs( + hir_id, + &[Attribute { + kind: AttrKind::Normal(ptr::P(NormalAttr { + item: AttrItem { + path: Path::from_ident(Ident::new(sym::track_caller, span)), + args: AttrArgs::Empty, + tokens: None, + }, tokens: None, - }, - tokens: None, - })), - id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(), - style: AttrStyle::Outer, - span: unstable_span, - }], - ); + })), + id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(), + style: AttrStyle::Outer, + span: unstable_span, + }], + ); + } } let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) }; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c353f74251652..6d3e33f2b6295 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1397,7 +1397,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { span: Span, hir_id: HirId, ) { - if let HirFnKind::ItemFn(_, _, _) = fn_kind && fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller { + if fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller { // Now, check if the function has the `#[track_caller]` attribute let attrs = cx.tcx.hir().attrs(hir_id); let maybe_track_caller = attrs.iter().find(|attr| attr.has_name(sym::track_caller)); @@ -1407,12 +1407,20 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { attr.span, fluent::lint_ungated_async_fn_track_caller, |lint| { - lint.span_label(span, "this function will not propagate the caller location"); + lint.span_label( + span, + "this function will not propagate the caller location", + ); if cx.tcx.sess.is_nightly_build() { - lint.span_suggestion(attr.span, fluent::suggestion, "closure_track_caller", Applicability::MachineApplicable); + lint.span_suggestion( + attr.span, + fluent::suggestion, + "closure_track_caller", + Applicability::MachineApplicable, + ); } lint - } + }, ); } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 11022eb80ea5f..1275d6f223c7a 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -219,6 +219,7 @@ late_lint_methods!( // May Depend on constants elsewhere UnusedBrokenConst: UnusedBrokenConst, UnstableFeatures: UnstableFeatures, + UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller, ArrayIntoIter: ArrayIntoIter::default(), DropTraitConstraints: DropTraitConstraints, TemporaryCStringAsPtr: TemporaryCStringAsPtr, diff --git a/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr index 71d4b00cc6e8b..f313658c4464e 100644 --- a/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr +++ b/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr @@ -10,5 +10,15 @@ LL | | } | = note: `#[warn(ungated_async_fn_track_caller)]` on by default -warning: 1 warning emitted +warning: `#[track_caller]` on async functions is a no-op + --> $DIR/panic-track-caller.rs:62:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ help: enable this unstable feature: `closure_track_caller` +LL | / async fn bar_assoc() { +LL | | panic!(); +LL | | } + | |_____- this function will not propagate the caller location + +warning: 2 warnings emitted diff --git a/src/test/ui/async-await/track-caller/panic-track-caller.rs b/src/test/ui/async-await/track-caller/panic-track-caller.rs index ee37e64be4fa3..02077db7c629a 100644 --- a/src/test/ui/async-await/track-caller/panic-track-caller.rs +++ b/src/test/ui/async-await/track-caller/panic-track-caller.rs @@ -59,7 +59,7 @@ async fn foo_track_caller() { struct Foo; impl Foo { - #[track_caller] + #[track_caller] //[nofeat]~ WARN `#[track_caller]` on async functions is a no-op async fn bar_assoc() { panic!(); } @@ -104,9 +104,4 @@ fn main() { assert_eq!(panicked_at(|| block_on(foo_assoc())), 69); #[cfg(nofeat)] assert_eq!(panicked_at(|| block_on(foo_assoc())), 64); - - #[cfg(feat)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 76); - #[cfg(feat)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 74); } From f702e89f9de9ffb651ffb3b6b8dde5d9ffd1e4d5 Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Wed, 7 Dec 2022 20:26:56 +0000 Subject: [PATCH 07/15] Add lint doc comment --- compiler/rustc_lint/src/builtin.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 6d3e33f2b6295..7c16bc1eade61 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1375,7 +1375,26 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { } declare_lint! { - /// `#[track_caller]` is a no-op without corresponding feature flag + /// The `ungated_async_fn_track_caller` lint warns when the + /// `#[track_caller]` attribute is used on an async function, method, or + /// closure, without enabling the corresponding unstable feature flag. + /// + /// ### Example + /// + /// ```rust + /// #[track_caller] + /// async fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The attribute must be used in conjunction with the + /// [`closure_track_caller` feature flag]. Otherwise, the `#[track_caller]` + /// annotation will function as as no-op. + /// + /// [`closure_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/closure-track-caller.html UNGATED_ASYNC_FN_TRACK_CALLER, Warn, "enabling track_caller on an async fn is a no-op unless the closure_track_caller feature is enabled" From 9650a4168f2d5f4edb3338a484ab5c8d1a4b0e52 Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Wed, 21 Dec 2022 03:13:28 +0000 Subject: [PATCH 08/15] Improve code based on feedback. This patch improves the readability of some of the code by using if-let-chains. Also, make use of the `add_feature_diagnostics` function. --- compiler/rustc_ast_lowering/src/expr.rs | 42 +++++++++---------- .../locales/en-US/lint.ftl | 2 +- compiler/rustc_lint/src/builtin.rs | 26 +++++------- .../issue-104588-no-op-track-caller.rs | 9 ---- .../issue-104588-no-op-track-caller.stderr | 12 ------ .../panic-track-caller.nofeat.stderr | 9 +++- 6 files changed, 38 insertions(+), 62 deletions(-) delete mode 100644 src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs delete mode 100644 src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a58c74dbc333a..805050e681b0d 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -662,29 +662,27 @@ impl<'hir> LoweringContext<'_, 'hir> { span, self.allow_gen_future.clone(), ); - if self.tcx.features().closure_track_caller { - let track_caller = self - .attrs - .get(&outer_hir_id.local_id) - .map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))); - if track_caller { - self.lower_attrs( - hir_id, - &[Attribute { - kind: AttrKind::Normal(ptr::P(NormalAttr { - item: AttrItem { - path: Path::from_ident(Ident::new(sym::track_caller, span)), - args: AttrArgs::Empty, - tokens: None, - }, + + if self.tcx.features().closure_track_caller + && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) + && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) + { + self.lower_attrs( + hir_id, + &[Attribute { + kind: AttrKind::Normal(ptr::P(NormalAttr { + item: AttrItem { + path: Path::from_ident(Ident::new(sym::track_caller, span)), + args: AttrArgs::Empty, tokens: None, - })), - id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(), - style: AttrStyle::Outer, - span: unstable_span, - }], - ); - } + }, + tokens: None, + })), + id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(), + style: AttrStyle::Outer, + span: unstable_span, + }], + ); } let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) }; diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 0d5507835a9e9..2eb409a5ddd5e 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -351,7 +351,7 @@ lint_builtin_mutable_transmutes = lint_builtin_unstable_features = unstable feature lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op - .suggestion = enable this unstable feature + .label = this function will not propagate the caller location lint_builtin_unreachable_pub = unreachable `pub` {$what} .suggestion = consider restricting its visibility diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 7c16bc1eade61..d6de6e70ead80 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1416,33 +1416,27 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { span: Span, hir_id: HirId, ) { - if fn_kind.asyncness() == IsAsync::Async && !cx.tcx.features().closure_track_caller { + if fn_kind.asyncness() == IsAsync::Async + && !cx.tcx.features().closure_track_caller + && let attrs = cx.tcx.hir().attrs(hir_id) // Now, check if the function has the `#[track_caller]` attribute - let attrs = cx.tcx.hir().attrs(hir_id); - let maybe_track_caller = attrs.iter().find(|attr| attr.has_name(sym::track_caller)); - if let Some(attr) = maybe_track_caller { + && let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::track_caller)) + { cx.struct_span_lint( UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, fluent::lint_ungated_async_fn_track_caller, |lint| { - lint.span_label( - span, - "this function will not propagate the caller location", + lint.span_label(span, fluent::label); + rustc_session::parse::add_feature_diagnostics( + lint, + &cx.tcx.sess.parse_sess, + sym::closure_track_caller, ); - if cx.tcx.sess.is_nightly_build() { - lint.span_suggestion( - attr.span, - fluent::suggestion, - "closure_track_caller", - Applicability::MachineApplicable, - ); - } lint }, ); } - } } } diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs deleted file mode 100644 index 6443e14296da8..0000000000000 --- a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.rs +++ /dev/null @@ -1,9 +0,0 @@ -// check-pass -// edition:2021 - -#[track_caller] //~ WARN `#[track_caller]` on async functions is a no-op -async fn foo() {} - -fn main() { - foo(); -} diff --git a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr b/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr deleted file mode 100644 index b41077a0b924d..0000000000000 --- a/src/test/ui/async-await/track-caller/issue-104588-no-op-track-caller.stderr +++ /dev/null @@ -1,12 +0,0 @@ -warning: `#[track_caller]` on async functions is a no-op - --> $DIR/issue-104588-no-op-track-caller.rs:4:1 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ help: enable this unstable feature: `closure_track_caller` -LL | async fn foo() {} - | ----------------- this function will not propagate the caller location - | - = note: `#[warn(ungated_async_fn_track_caller)]` on by default - -warning: 1 warning emitted - diff --git a/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr index f313658c4464e..51ea225f4cbd4 100644 --- a/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr +++ b/src/test/ui/async-await/track-caller/panic-track-caller.nofeat.stderr @@ -2,23 +2,28 @@ warning: `#[track_caller]` on async functions is a no-op --> $DIR/panic-track-caller.rs:50:1 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ help: enable this unstable feature: `closure_track_caller` + | ^^^^^^^^^^^^^^^ LL | / async fn bar_track_caller() { LL | | panic!() LL | | } | |_- this function will not propagate the caller location | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable = 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:62:5 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ help: enable this unstable feature: `closure_track_caller` + | ^^^^^^^^^^^^^^^ LL | / async fn bar_assoc() { LL | | panic!(); LL | | } | |_____- this function will not propagate the caller location + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable warning: 2 warnings emitted From 9c9fa567f8ca5bf43b481407ab78508652970594 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Wed, 21 Dec 2022 14:19:04 +0000 Subject: [PATCH 09/15] codegen tests: adapt patterns to also work with v0 symbol mangling No functional changes intended. These tests were failing under `new-symbol-mangling = true`. This adapts the patterns to work in this case. --- src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs | 3 ++- src/test/codegen/unwind-and-panic-abort.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs b/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs index 8447bbeb1ed20..34fd401f9e42b 100644 --- a/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs +++ b/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs @@ -9,7 +9,8 @@ // CHECK: @rust_item_that_can_unwind() unnamed_addr [[ATTR0:#[0-9]+]] #[no_mangle] pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() { - // CHECK: call void @_ZN4core9panicking15panic_no_unwind + // Handle both legacy and v0 symbol mangling. + // CHECK: call void @{{.*core9panicking15panic_no_unwind}} may_unwind(); } diff --git a/src/test/codegen/unwind-and-panic-abort.rs b/src/test/codegen/unwind-and-panic-abort.rs index f238741e599f6..b370191bf8c82 100644 --- a/src/test/codegen/unwind-and-panic-abort.rs +++ b/src/test/codegen/unwind-and-panic-abort.rs @@ -9,7 +9,8 @@ extern "C-unwind" { // CHECK: Function Attrs:{{.*}}nounwind // CHECK-NEXT: define{{.*}}void @foo -// CHECK: call void @_ZN4core9panicking15panic_no_unwind +// Handle both legacy and v0 symbol mangling. +// CHECK: call void @{{.*core9panicking15panic_no_unwind}} #[no_mangle] pub unsafe extern "C" fn foo() { bar(); From a9af75cdbc2f31fe0f68854d5b579616c4393839 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 21 Dec 2022 17:44:30 +0000 Subject: [PATCH 10/15] Give opaque types a better coherence error --- .../src/coherence/orphan.rs | 23 ++++++++++++------- .../ui/type-alias-impl-trait/coherence.stderr | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index cc5114dba5efe..c6d4aeefc80e5 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -184,11 +184,19 @@ fn emit_orphan_check_error<'tcx>( ty::Adt(def, _) => tcx.mk_adt(*def, ty::List::empty()), _ => ty, }; - let this = "this".to_string(); - let (ty, postfix) = match &ty.kind() { - ty::Slice(_) => (this, " because slices are always foreign"), - ty::Array(..) => (this, " because arrays are always foreign"), - ty::Tuple(..) => (this, " because tuples are always foreign"), + let msg = |ty: &str, postfix: &str| { + format!("{ty} is not defined in the current crate{postfix}") + }; + let this = |name: &str| msg("this", &format!(" because {name} are always foreign")); + let msg = match &ty.kind() { + ty::Slice(_) => this("slices"), + ty::Array(..) => this("arrays"), + ty::Tuple(..) => this("tuples"), + ty::Alias(ty::Opaque, ..) => { + "type alias impl trait is treated as if it were foreign, \ + because its hidden type could be from a foreign crate" + .to_string() + } ty::RawPtr(ptr_ty) => { emit_newtype_suggestion_for_raw_ptr( full_impl_span, @@ -198,12 +206,11 @@ fn emit_orphan_check_error<'tcx>( &mut err, ); - (format!("`{}`", ty), " because raw pointers are always foreign") + msg(&format!("`{ty}`"), " because raw pointers are always foreign") } - _ => (format!("`{}`", ty), ""), + _ => msg(&format!("`{ty}`"), ""), }; - let msg = format!("{} is not defined in the current crate{}", ty, postfix); if is_target_ty { // Point at `D` in `impl for C in D` err.span_label(self_ty_span, &msg); diff --git a/src/test/ui/type-alias-impl-trait/coherence.stderr b/src/test/ui/type-alias-impl-trait/coherence.stderr index c923eb08ab312..00b0dbbb583fd 100644 --- a/src/test/ui/type-alias-impl-trait/coherence.stderr +++ b/src/test/ui/type-alias-impl-trait/coherence.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl foreign_crate::ForeignTrait for AliasOfForeignType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------- | | | - | | `AliasOfForeignType` is not defined in the current crate + | | type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead From 5dfa6a8922245d0587c4acf3c9b004e5875066bf Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 21 Dec 2022 13:28:42 -0700 Subject: [PATCH 11/15] rustdoc: simplify link anchor to section expand JS --- src/librustdoc/html/static/js/main.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 3f97e4e2e39f0..60e4e7492240c 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -813,16 +813,14 @@ function loadCss(cssUrl) { hideSidebar(); }); - onEachLazy(document.getElementsByTagName("a"), el => { + onEachLazy(document.querySelectorAll("a[href^='#']"), el => { // For clicks on internal links ( tags with a hash property), we expand the section we're // jumping to *before* jumping there. We can't do this in onHashChange, because it changes // the height of the document so we wind up scrolled to the wrong place. - if (el.hash) { - el.addEventListener("click", () => { - expandSection(el.hash.slice(1)); - hideSidebar(); - }); - } + el.addEventListener("click", () => { + expandSection(el.hash.slice(1)); + hideSidebar(); + }); }); onEachLazy(document.querySelectorAll(".rustdoc-toggle > summary:not(.hideme)"), el => { From ccbba0a60e3b094aeb48991cac9b6e342eb3e229 Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Wed, 21 Dec 2022 23:22:56 +0000 Subject: [PATCH 12/15] Update track_caller tests; run fmt --- compiler/rustc_ast_lowering/src/expr.rs | 7 ++----- .../track-caller/async-closure-gate.rs | 1 - .../track-caller/async-closure-gate.stderr | 15 +-------------- .../track-caller/panic-track-caller.rs | 6 ++++++ 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 805050e681b0d..3634e6e47ce12 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -657,11 +657,8 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let hir_id = self.lower_node_id(closure_node_id); - let unstable_span = self.mark_span_with_reason( - DesugaringKind::Async, - span, - self.allow_gen_future.clone(), - ); + let unstable_span = + self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); if self.tcx.features().closure_track_caller && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) diff --git a/src/test/ui/async-await/track-caller/async-closure-gate.rs b/src/test/ui/async-await/track-caller/async-closure-gate.rs index 9593fdb1908e2..d9d556855991b 100644 --- a/src/test/ui/async-await/track-caller/async-closure-gate.rs +++ b/src/test/ui/async-await/track-caller/async-closure-gate.rs @@ -5,6 +5,5 @@ fn main() { let _ = #[track_caller] async || { //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] - //~| ERROR `#[track_caller]` on closures is currently unstable [E0658] }; } diff --git a/src/test/ui/async-await/track-caller/async-closure-gate.stderr b/src/test/ui/async-await/track-caller/async-closure-gate.stderr index be3d110eccdb0..498f1b43b9bca 100644 --- a/src/test/ui/async-await/track-caller/async-closure-gate.stderr +++ b/src/test/ui/async-await/track-caller/async-closure-gate.stderr @@ -7,19 +7,6 @@ LL | let _ = #[track_caller] async || { = note: see issue #87417 for more information = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable -error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:6:38 - | -LL | let _ = #[track_caller] async || { - | ______________________________________^ -LL | | -LL | | -LL | | }; - | |_____^ - | - = note: see issue #87417 for more information - = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/async-await/track-caller/panic-track-caller.rs b/src/test/ui/async-await/track-caller/panic-track-caller.rs index 02077db7c629a..f45243b0ea6f5 100644 --- a/src/test/ui/async-await/track-caller/panic-track-caller.rs +++ b/src/test/ui/async-await/track-caller/panic-track-caller.rs @@ -69,6 +69,9 @@ 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(feat)] async fn foo_closure() { let c = #[track_caller] async || { panic!(); @@ -104,4 +107,7 @@ fn main() { assert_eq!(panicked_at(|| block_on(foo_assoc())), 69); #[cfg(nofeat)] assert_eq!(panicked_at(|| block_on(foo_assoc())), 64); + + #[cfg(feat)] + assert_eq!(panicked_at(|| block_on(foo_closure())), 79); } From 8a4cbf4f7b7777b7553dd6ae05c7d57e5a20ebfa Mon Sep 17 00:00:00 2001 From: kadmin Date: Wed, 21 Dec 2022 23:54:29 +0000 Subject: [PATCH 13/15] Fix ICE Left a todo awhile ago (I think), so fill it in to print a const for `Term`s. --- src/librustdoc/html/format.rs | 8 ++++---- src/test/rustdoc/issue-105952.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 src/test/rustdoc/issue-105952.rs diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 39e2a90222670..5ad24bf268133 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1655,10 +1655,10 @@ impl clean::types::Term { &'a self, cx: &'a Context<'tcx>, ) -> impl fmt::Display + 'a + Captures<'tcx> { - match self { - clean::types::Term::Type(ty) => ty.print(cx), - _ => todo!(), - } + display_fn(move |f| match self { + clean::types::Term::Type(ty) => fmt::Display::fmt(&ty.print(cx), f), + clean::types::Term::Constant(ct) => fmt::Display::fmt(&ct.print(cx.tcx()), f), + }) } } diff --git a/src/test/rustdoc/issue-105952.rs b/src/test/rustdoc/issue-105952.rs new file mode 100644 index 0000000000000..e3f1df0063dfb --- /dev/null +++ b/src/test/rustdoc/issue-105952.rs @@ -0,0 +1,14 @@ +#![crate_name = "foo"] + +#![feature(associated_const_equality)] +pub enum ParseMode { + Raw, +} +pub trait Parse { + const PARSE_MODE: ParseMode; +} +pub trait RenderRaw {} + +// @hasraw foo/trait.RenderRaw.html 'impl' +// @hasraw foo/trait.RenderRaw.html 'ParseMode::Raw' +impl> RenderRaw for T {} From f20f86ec4e9d7d545cd00e401a77f2268e26553b Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 21 Dec 2022 17:28:42 -0800 Subject: [PATCH 14/15] Change comment to doc comment --- compiler/rustc_resolve/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5d0b4c0419f0a..447a43ca8b299 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1686,7 +1686,7 @@ impl<'a> Resolver<'a> { .or_insert_with(|| self.arenas.alloc_name_resolution()) } - // Test if AmbiguityError ambi is any identical to any one inside ambiguity_errors + /// Test if AmbiguityError ambi is any identical to any one inside ambiguity_errors fn matches_previous_ambiguity_error(&mut self, ambi: &AmbiguityError<'_>) -> bool { for ambiguity_error in &self.ambiguity_errors { // if the span location and ident as well as its span are the same From 20052c83c037ee76dfc0e95f5c42c929250e6b71 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 17 Dec 2022 20:11:29 +0000 Subject: [PATCH 15/15] Suggest associated const on capitalization error --- compiler/rustc_hir_typeck/src/demand.rs | 25 ++++-- compiler/rustc_hir_typeck/src/expr.rs | 10 +-- .../src/fn_ctxt/suggestions.rs | 84 ++++++++++++++++++- .../suggestions/assoc-ct-for-assoc-method.rs | 25 ++++++ .../assoc-ct-for-assoc-method.stderr | 47 +++++++++++ 5 files changed, 178 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/suggestions/assoc-ct-for-assoc-method.rs create mode 100644 src/test/ui/suggestions/assoc-ct-for-assoc-method.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 479aaf2e1a7b5..e68bd1297c878 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -23,24 +23,24 @@ use std::cmp::min; use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub fn emit_coerce_suggestions( + pub fn emit_type_mismatch_suggestions( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, - error: Option>, + _error: Option>, ) { if expr_ty == expected { return; } - self.annotate_expected_due_to_let_ty(err, expr, error); - // Use `||` to give these suggestions a precedence let _ = self.suggest_missing_parentheses(err, expr) + || self.suggest_associated_const(err, expr, expected) || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr) + || self.suggest_option_to_bool(err, expr, expr_ty, expected) || self.suggest_compatible_variants(err, expr, expected, expr_ty) || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty) || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) @@ -49,9 +49,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected) || self.suggest_copied_or_cloned(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected) - || self.suggest_option_to_bool(err, expr, expr_ty, expected) || self.suggest_floating_point_literal(err, expr, expected); + } + pub fn emit_coerce_suggestions( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'tcx>, + expr_ty: Ty<'tcx>, + expected: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, + error: Option>, + ) { + if expr_ty == expected { + return; + } + + self.annotate_expected_due_to_let_ty(err, expr, error); + self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error); self.note_type_is_not_clone(err, expected, expr_ty, expr); self.note_need_for_fn_pointer(err, expected, expr_ty); self.note_internal_mutation_in_method(err, expr, expected, expr_ty); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index edbbb7272ac77..ae641b26eeedb 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -104,16 +104,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { - // FIXME(compiler-errors): We probably should fold some of the - // `suggest_` functions from `emit_coerce_suggestions` into here, - // since some of those aren't necessarily just coerce suggestions. - let _ = self.suggest_deref_ref_or_into( + let _ = self.emit_type_mismatch_suggestions( &mut err, expr.peel_drop_temps(), - expected_ty, ty, + expected_ty, None, - ) || self.suggest_option_to_bool(&mut err, expr, ty, expected_ty); + None, + ); extend_err(&mut err); err.emit(); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index c9d179de39f39..efec024463334 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1,6 +1,7 @@ use super::FnCtxt; use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel}; +use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir as hir; @@ -15,10 +16,11 @@ use rustc_infer::traits::{self, StatementAsExpression}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{ self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty, + TypeVisitable, }; use rustc_session::errors::ExprParenthesesNeeded; -use rustc_span::symbol::sym; -use rustc_span::Span; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::{Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::DefIdOrName; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -1236,6 +1238,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub(crate) fn suggest_associated_const( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + expected_ty: Ty<'tcx>, + ) -> bool { + let Some((DefKind::AssocFn, old_def_id)) = self.typeck_results.borrow().type_dependent_def(expr.hir_id) else { + return false; + }; + let old_item_name = self.tcx.item_name(old_def_id); + let capitalized_name = Symbol::intern(&old_item_name.as_str().to_uppercase()); + if old_item_name == capitalized_name { + return false; + } + let (item, segment) = match expr.kind { + hir::ExprKind::Path(QPath::Resolved( + Some(ty), + hir::Path { segments: [segment], .. }, + )) + | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => { + let self_ty = >::ast_ty_to_ty(self, ty); + if let Ok(pick) = self.probe_for_name( + Mode::Path, + Ident::new(capitalized_name, segment.ident.span), + IsSuggestion(true), + self_ty, + expr.hir_id, + ProbeScope::TraitsInScope, + ) { + (pick.item, segment) + } else { + return false; + } + } + hir::ExprKind::Path(QPath::Resolved( + None, + hir::Path { segments: [.., segment], .. }, + )) => { + // we resolved through some path that doesn't end in the item name, + // better not do a bad suggestion by accident. + if old_item_name != segment.ident.name { + return false; + } + if let Some(item) = self + .tcx + .associated_items(self.tcx.parent(old_def_id)) + .filter_by_name_unhygienic(capitalized_name) + .next() + { + (*item, segment) + } else { + return false; + } + } + _ => return false, + }; + if item.def_id == old_def_id || self.tcx.def_kind(item.def_id) != DefKind::AssocConst { + // Same item + return false; + } + let item_ty = self.tcx.type_of(item.def_id); + // FIXME(compiler-errors): This check is *so* rudimentary + if item_ty.needs_subst() { + return false; + } + if self.can_coerce(item_ty, expected_ty) { + err.span_suggestion_verbose( + segment.ident.span, + format!("try referring to the associated const `{capitalized_name}` instead",), + capitalized_name, + Applicability::MachineApplicable, + ); + true + } else { + false + } + } + fn is_loop(&self, id: hir::HirId) -> bool { let node = self.tcx.hir().get(id); matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. })) diff --git a/src/test/ui/suggestions/assoc-ct-for-assoc-method.rs b/src/test/ui/suggestions/assoc-ct-for-assoc-method.rs new file mode 100644 index 0000000000000..fe2227769894c --- /dev/null +++ b/src/test/ui/suggestions/assoc-ct-for-assoc-method.rs @@ -0,0 +1,25 @@ +struct MyS; + +impl MyS { + const FOO: i32 = 1; + fn foo() -> MyS { + MyS + } +} + +fn main() { + let x: i32 = MyS::foo; + //~^ ERROR mismatched types + //~| HELP try referring to the + + let z: i32 = i32::max; + //~^ ERROR mismatched types + //~| HELP try referring to the + + // This example is still broken though... This is a hard suggestion to make, + // because we don't have access to the associated const probing code to make + // this suggestion where it's emitted, i.e. in trait selection. + let y: i32 = i32::max - 42; + //~^ ERROR cannot subtract + //~| HELP use parentheses +} diff --git a/src/test/ui/suggestions/assoc-ct-for-assoc-method.stderr b/src/test/ui/suggestions/assoc-ct-for-assoc-method.stderr new file mode 100644 index 0000000000000..afef38f129674 --- /dev/null +++ b/src/test/ui/suggestions/assoc-ct-for-assoc-method.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/assoc-ct-for-assoc-method.rs:11:18 + | +LL | let x: i32 = MyS::foo; + | --- ^^^^^^^^ expected `i32`, found fn item + | | + | expected due to this + | + = note: expected type `i32` + found fn item `fn() -> MyS {MyS::foo}` +help: try referring to the associated const `FOO` instead + | +LL | let x: i32 = MyS::FOO; + | ~~~ + +error[E0308]: mismatched types + --> $DIR/assoc-ct-for-assoc-method.rs:15:18 + | +LL | let z: i32 = i32::max; + | --- ^^^^^^^^ expected `i32`, found fn item + | | + | expected due to this + | + = note: expected type `i32` + found fn item `fn(i32, i32) -> i32 {::max}` +help: try referring to the associated const `MAX` instead + | +LL | let z: i32 = i32::MAX; + | ~~~ + +error[E0369]: cannot subtract `{integer}` from `fn(i32, i32) -> i32 {::max}` + --> $DIR/assoc-ct-for-assoc-method.rs:22:27 + | +LL | let y: i32 = i32::max - 42; + | -------- ^ -- {integer} + | | + | fn(i32, i32) -> i32 {::max} + | +help: use parentheses to call this associated function + | +LL | let y: i32 = i32::max(/* i32 */, /* i32 */) - 42; + | ++++++++++++++++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`.