From bd12d151ee63290b317566db770465301e2dd2a9 Mon Sep 17 00:00:00 2001
From: Yiming Lei <yiming.lei@futurewei.com>
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 <michael@errs.io>
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<P: Tuple + Default, T>(func: impl Fn<P, Output = T>) {
+    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>) {
+        self.0.unpark();
+    }
+}
+
+/// Run a future to completion on the current thread.
+fn block_on<T>(fut: impl Future<Output = T>) -> 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>) {
-        self.0.unpark();
-    }
-}
-
-/// Run a future to completion on the current thread.
-fn block_on<T>(fut: impl Future<Output = T>) -> 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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
 
 warning: 2 warnings emitted
 

From 2f5334dff2cf7be2f1cc33565c55925b58950694 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 21 Dec 2022 05:03:11 +0000
Subject: [PATCH 09/15] forgot a return in drop tracking
 handle_uninhabited_return

---
 .../drop_ranges/cfg_build.rs                  |  1 +
 ...=> unresolved-ct-var.drop_tracking.stderr} | 22 +++---
 src/test/ui/generator/unresolved-ct-var.rs    |  2 +
 .../generator/unresolved-ct-var.stock.stderr  | 78 +++++++++++++++++++
 4 files changed, 92 insertions(+), 11 deletions(-)
 rename src/test/ui/generator/{unresolved-ct-var.stderr => unresolved-ct-var.drop_tracking.stderr} (88%)
 create mode 100644 src/test/ui/generator/unresolved-ct-var.stock.stderr

diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index fd8ea1ad7bff4..16806fdba4fbc 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -233,6 +233,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
             self.tcx()
                 .sess
                 .delay_span_bug(expr.span, format!("could not resolve infer vars in `{ty}`"));
+            return;
         }
         let ty = self.tcx().erase_regions(ty);
         let m = self.tcx().parent_module(expr.hir_id).to_def_id();
diff --git a/src/test/ui/generator/unresolved-ct-var.stderr b/src/test/ui/generator/unresolved-ct-var.drop_tracking.stderr
similarity index 88%
rename from src/test/ui/generator/unresolved-ct-var.stderr
rename to src/test/ui/generator/unresolved-ct-var.drop_tracking.stderr
index fdf00dfad7ab7..a328c43765db2 100644
--- a/src/test/ui/generator/unresolved-ct-var.stderr
+++ b/src/test/ui/generator/unresolved-ct-var.drop_tracking.stderr
@@ -1,5 +1,5 @@
 error[E0277]: `[(); _]` is not a future
-  --> $DIR/unresolved-ct-var.rs:6:44
+  --> $DIR/unresolved-ct-var.rs:8:44
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                 ---------------------------^^^^^^
@@ -13,61 +13,61 @@ LL |         let s = std::array::from_fn(|_| ()).await;
    = note: required for `[(); _]` to implement `IntoFuture`
 
 error[E0698]: type inside `async` block must be known in this context
-  --> $DIR/unresolved-ct-var.rs:6:17
+  --> $DIR/unresolved-ct-var.rs:8:17
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                 ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
    |
 note: the type is part of the `async` block because of this `await`
-  --> $DIR/unresolved-ct-var.rs:6:44
+  --> $DIR/unresolved-ct-var.rs:8:44
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                                            ^^^^^^
 
 error[E0698]: type inside `async` block must be known in this context
-  --> $DIR/unresolved-ct-var.rs:6:17
+  --> $DIR/unresolved-ct-var.rs:8:17
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                 ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
    |
 note: the type is part of the `async` block because of this `await`
-  --> $DIR/unresolved-ct-var.rs:6:44
+  --> $DIR/unresolved-ct-var.rs:8:44
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                                            ^^^^^^
 
 error[E0698]: type inside `async` block must be known in this context
-  --> $DIR/unresolved-ct-var.rs:6:17
+  --> $DIR/unresolved-ct-var.rs:8:17
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                 ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
    |
 note: the type is part of the `async` block because of this `await`
-  --> $DIR/unresolved-ct-var.rs:6:44
+  --> $DIR/unresolved-ct-var.rs:8:44
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                                            ^^^^^^
 
 error[E0698]: type inside `async` block must be known in this context
-  --> $DIR/unresolved-ct-var.rs:6:17
+  --> $DIR/unresolved-ct-var.rs:8:17
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                 ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
    |
 note: the type is part of the `async` block because of this `await`
-  --> $DIR/unresolved-ct-var.rs:6:44
+  --> $DIR/unresolved-ct-var.rs:8:44
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                                            ^^^^^^
 
 error[E0698]: type inside `async` block must be known in this context
-  --> $DIR/unresolved-ct-var.rs:6:17
+  --> $DIR/unresolved-ct-var.rs:8:17
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                 ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
    |
 note: the type is part of the `async` block because of this `await`
-  --> $DIR/unresolved-ct-var.rs:6:44
+  --> $DIR/unresolved-ct-var.rs:8:44
    |
 LL |         let s = std::array::from_fn(|_| ()).await;
    |                                            ^^^^^^
diff --git a/src/test/ui/generator/unresolved-ct-var.rs b/src/test/ui/generator/unresolved-ct-var.rs
index 0a1570fc2395e..6720f46588723 100644
--- a/src/test/ui/generator/unresolved-ct-var.rs
+++ b/src/test/ui/generator/unresolved-ct-var.rs
@@ -1,5 +1,7 @@
 // incremental
 // edition:2021
+// revisions: drop_tracking stock
+//[drop_tracking] compile-flags: -Zdrop-tracking
 
 fn main() {
     let _ = async {
diff --git a/src/test/ui/generator/unresolved-ct-var.stock.stderr b/src/test/ui/generator/unresolved-ct-var.stock.stderr
new file mode 100644
index 0000000000000..a328c43765db2
--- /dev/null
+++ b/src/test/ui/generator/unresolved-ct-var.stock.stderr
@@ -0,0 +1,78 @@
+error[E0277]: `[(); _]` is not a future
+  --> $DIR/unresolved-ct-var.rs:8:44
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                 ---------------------------^^^^^^
+   |                 |                          |
+   |                 |                          `[(); _]` is not a future
+   |                 |                          help: remove the `.await`
+   |                 this call returns `[(); _]`
+   |
+   = help: the trait `Future` is not implemented for `[(); _]`
+   = note: [(); _] must be a future or must implement `IntoFuture` to be awaited
+   = note: required for `[(); _]` to implement `IntoFuture`
+
+error[E0698]: type inside `async` block must be known in this context
+  --> $DIR/unresolved-ct-var.rs:8:17
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                 ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
+   |
+note: the type is part of the `async` block because of this `await`
+  --> $DIR/unresolved-ct-var.rs:8:44
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                                            ^^^^^^
+
+error[E0698]: type inside `async` block must be known in this context
+  --> $DIR/unresolved-ct-var.rs:8:17
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                 ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
+   |
+note: the type is part of the `async` block because of this `await`
+  --> $DIR/unresolved-ct-var.rs:8:44
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                                            ^^^^^^
+
+error[E0698]: type inside `async` block must be known in this context
+  --> $DIR/unresolved-ct-var.rs:8:17
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                 ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
+   |
+note: the type is part of the `async` block because of this `await`
+  --> $DIR/unresolved-ct-var.rs:8:44
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                                            ^^^^^^
+
+error[E0698]: type inside `async` block must be known in this context
+  --> $DIR/unresolved-ct-var.rs:8:17
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                 ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
+   |
+note: the type is part of the `async` block because of this `await`
+  --> $DIR/unresolved-ct-var.rs:8:44
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                                            ^^^^^^
+
+error[E0698]: type inside `async` block must be known in this context
+  --> $DIR/unresolved-ct-var.rs:8:17
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                 ^^^^^^^^^^^^^^^^^^^ cannot infer the value of const parameter `N` declared on the function `from_fn`
+   |
+note: the type is part of the `async` block because of this `await`
+  --> $DIR/unresolved-ct-var.rs:8:44
+   |
+LL |         let s = std::array::from_fn(|_| ()).await;
+   |                                            ^^^^^^
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0277, E0698.
+For more information about an error, try `rustc --explain E0277`.

From 9c9fa567f8ca5bf43b481407ab78508652970594 Mon Sep 17 00:00:00 2001
From: Krasimir Georgiev <krasimir@google.com>
Date: Wed, 21 Dec 2022 14:19:04 +0000
Subject: [PATCH 10/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 <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 21 Dec 2022 17:44:30 +0000
Subject: [PATCH 11/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<A>` in `impl<A, B> for C<B> in D<A>`
                     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<T> foreign_crate::ForeignTrait for AliasOfForeignType<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------
    | |                                       |
-   | |                                       `AliasOfForeignType<T>` 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 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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <julianknodt@gmail.com>
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<T: Parse<PARSE_MODE = { ParseMode::Raw }>> RenderRaw for T {}

From f20f86ec4e9d7d545cd00e401a77f2268e26553b Mon Sep 17 00:00:00 2001
From: Eric Holk <eric@theincredibleholk.org>
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 <michael@errs.io>
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<TypeError<'tcx>>,
+        _error: Option<TypeError<'tcx>>,
     ) {
         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<TypeError<'tcx>>,
+    ) {
+        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 = <dyn AstConv<'_>>::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 {<i32 as Ord>::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 {<i32 as Ord>::max}`
+  --> $DIR/assoc-ct-for-assoc-method.rs:22:27
+   |
+LL |     let y: i32 = i32::max - 42;
+   |                  -------- ^ -- {integer}
+   |                  |
+   |                  fn(i32, i32) -> i32 {<i32 as Ord>::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`.