From d5354eb48ea8705d9f2d4f211b139b43ccdebd16 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Tue, 28 Jun 2022 19:45:15 +0200
Subject: [PATCH 1/2] Add known bug test.

---
 .../lifetimes/bare-trait-object-borrowck.rs   | 27 ++++++++++++
 .../bare-trait-object-borrowck.stderr         | 43 +++++++++++++++++++
 src/test/ui/lifetimes/bare-trait-object.rs    | 27 ++++++++++++
 .../ui/lifetimes/bare-trait-object.stderr     | 21 +++++++++
 4 files changed, 118 insertions(+)
 create mode 100644 src/test/ui/lifetimes/bare-trait-object-borrowck.rs
 create mode 100644 src/test/ui/lifetimes/bare-trait-object-borrowck.stderr
 create mode 100644 src/test/ui/lifetimes/bare-trait-object.rs
 create mode 100644 src/test/ui/lifetimes/bare-trait-object.stderr

diff --git a/src/test/ui/lifetimes/bare-trait-object-borrowck.rs b/src/test/ui/lifetimes/bare-trait-object-borrowck.rs
new file mode 100644
index 0000000000000..ee2c61468cb60
--- /dev/null
+++ b/src/test/ui/lifetimes/bare-trait-object-borrowck.rs
@@ -0,0 +1,27 @@
+#![allow(bare_trait_objects)]
+
+pub struct FormatWith<'a, I, F> {
+    sep: &'a str,
+    /// FormatWith uses interior mutability because Display::fmt takes &self.
+    inner: RefCell<Option<(I, F)>>,
+}
+
+use std::cell::RefCell;
+use std::fmt;
+
+struct Layout;
+
+pub fn new_format<'a, I, F>(iter: I, separator: &'a str, f: F) -> FormatWith<'a, I, F>
+where
+    I: Iterator,
+    F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result,
+{
+    FormatWith { sep: separator, inner: RefCell::new(Some((iter, f))) }
+}
+
+fn main() {
+    let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i)));
+    //~^ ERROR temporary value dropped while borrowed
+    //~| ERROR temporary value dropped while borrowed
+    //~| ERROR `i` does not live long enough
+}
diff --git a/src/test/ui/lifetimes/bare-trait-object-borrowck.stderr b/src/test/ui/lifetimes/bare-trait-object-borrowck.stderr
new file mode 100644
index 0000000000000..d7b059019eb3b
--- /dev/null
+++ b/src/test/ui/lifetimes/bare-trait-object-borrowck.stderr
@@ -0,0 +1,43 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/bare-trait-object-borrowck.rs:23:48
+   |
+LL |     let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i)));
+   |                                          -  ---^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                          |  |  |                        |
+   |                                          |  |  |                        temporary value is freed at the end of this statement
+   |                                          |  |  creates a temporary which is freed while still in use
+   |                                          |  argument requires that borrow lasts for `'1`
+   |                                          has type `&mut dyn FnMut(&'1 (dyn std::fmt::Display + '1)) -> Result<(), std::fmt::Error>`
+   |
+   = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/bare-trait-object-borrowck.rs:23:48
+   |
+LL |     let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i)));
+   |                                          -  ---^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                          |  |  |                        |
+   |                                          |  |  |                        temporary value is freed at the end of this statement
+   |                                          |  |  creates a temporary which is freed while still in use
+   |                                          |  argument requires that borrow lasts for `'1`
+   |                                          has type `&mut dyn FnMut(&'1 (dyn std::fmt::Display + '1)) -> Result<(), std::fmt::Error>`
+   |
+   = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0597]: `i` does not live long enough
+  --> $DIR/bare-trait-object-borrowck.rs:23:71
+   |
+LL |     let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i)));
+   |                                          -  --------------------------^--
+   |                                          |  |                         | |
+   |                                          |  |                         | `i` dropped here while still borrowed
+   |                                          |  |                         borrowed value does not live long enough
+   |                                          |  argument requires that `i` is borrowed for `'1`
+   |                                          has type `&mut dyn FnMut(&'1 (dyn std::fmt::Display + '1)) -> Result<(), std::fmt::Error>`
+   |
+   = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0597, E0716.
+For more information about an error, try `rustc --explain E0597`.
diff --git a/src/test/ui/lifetimes/bare-trait-object.rs b/src/test/ui/lifetimes/bare-trait-object.rs
new file mode 100644
index 0000000000000..dc8b611c03978
--- /dev/null
+++ b/src/test/ui/lifetimes/bare-trait-object.rs
@@ -0,0 +1,27 @@
+// Verify that lifetime resolution correctly accounts for `Fn` bare trait objects.
+
+#![allow(bare_trait_objects)]
+
+// This should work as: fn next_u32(fill_buf: &mut dyn FnMut(&mut [u8]))
+fn next_u32(fill_buf: &mut FnMut(&mut [u8])) {
+    let mut buf: [u8; 4] = [0; 4];
+    fill_buf(&mut buf);
+}
+
+fn explicit(fill_buf: &mut dyn FnMut(&mut [u8])) {
+    let mut buf: [u8; 4] = [0; 4];
+    fill_buf(&mut buf);
+}
+
+fn main() {
+    let _: fn(&mut FnMut(&mut [u8])) = next_u32;
+    //~^ ERROR mismatched types
+    let _: &dyn Fn(&mut FnMut(&mut [u8])) = &next_u32;
+    let _: fn(&mut FnMut(&mut [u8])) = explicit;
+    //~^ ERROR mismatched types
+    let _: &dyn Fn(&mut FnMut(&mut [u8])) = &explicit;
+    let _: fn(&mut dyn FnMut(&mut [u8])) = next_u32;
+    let _: &dyn Fn(&mut dyn FnMut(&mut [u8])) = &next_u32;
+    let _: fn(&mut dyn FnMut(&mut [u8])) = explicit;
+    let _: &dyn Fn(&mut dyn FnMut(&mut [u8])) = &explicit;
+}
diff --git a/src/test/ui/lifetimes/bare-trait-object.stderr b/src/test/ui/lifetimes/bare-trait-object.stderr
new file mode 100644
index 0000000000000..8f06410152e62
--- /dev/null
+++ b/src/test/ui/lifetimes/bare-trait-object.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/bare-trait-object.rs:17:40
+   |
+LL |     let _: fn(&mut FnMut(&mut [u8])) = next_u32;
+   |                                        ^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r, 's> fn(&'r mut (dyn for<'s> FnMut(&'s mut [u8]) + 'r))`
+                 found fn item `for<'r> fn(&'r mut (dyn for<'r> FnMut(&'r mut [u8]) + 'r)) {next_u32}`
+
+error[E0308]: mismatched types
+  --> $DIR/bare-trait-object.rs:20:40
+   |
+LL |     let _: fn(&mut FnMut(&mut [u8])) = explicit;
+   |                                        ^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r, 's> fn(&'r mut (dyn for<'s> FnMut(&'s mut [u8]) + 'r))`
+                 found fn item `for<'r> fn(&'r mut (dyn for<'r> FnMut(&'r mut [u8]) + 'r)) {explicit}`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.

From 21a12e8ab78f7e67a4ddc1d13d289a496f2f619d Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Sat, 25 Jun 2022 19:16:56 +0200
Subject: [PATCH 2/2] Handle fresh lifetimes on bare trait objects.

---
 compiler/rustc_ast_lowering/src/lib.rs        | 27 ++++++++++++
 compiler/rustc_resolve/src/late.rs            | 24 +++++++++++
 .../lifetimes/bare-trait-object-borrowck.rs   |  5 +--
 .../bare-trait-object-borrowck.stderr         | 43 -------------------
 src/test/ui/lifetimes/bare-trait-object.rs    |  4 +-
 .../ui/lifetimes/bare-trait-object.stderr     | 21 ---------
 6 files changed, 53 insertions(+), 71 deletions(-)
 delete mode 100644 src/test/ui/lifetimes/bare-trait-object-borrowck.stderr
 delete mode 100644 src/test/ui/lifetimes/bare-trait-object.stderr

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index e8b92eaad5c8d..cab2de0ced87c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1174,6 +1174,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         param_mode: ParamMode,
         itctx: ImplTraitContext,
     ) -> hir::Ty<'hir> {
+        // Check whether we should interpret this as a bare trait object.
+        // This check mirrors the one in late resolution.  We only introduce this special case in
+        // the rare occurence we need to lower `Fresh` anonymous lifetimes.
+        // The other cases when a qpath should be opportunistically made a trait object are handled
+        // by `ty_path`.
+        if qself.is_none()
+            && let Some(partial_res) = self.resolver.get_partial_res(t.id)
+            && partial_res.unresolved_segments() == 0
+            && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+        {
+            let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
+                let bound = this.lower_poly_trait_ref(
+                    &PolyTraitRef {
+                        bound_generic_params: vec![],
+                        trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
+                        span: t.span
+                    },
+                    itctx,
+                );
+                let bounds = this.arena.alloc_from_iter([bound]);
+                let lifetime_bound = this.elided_dyn_bound(t.span);
+                (bounds, lifetime_bound)
+            });
+            let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
+            return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
+        }
+
         let id = self.lower_node_id(t.id);
         let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
         self.ty_path(id, t.span, qpath)
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 640d13ea43547..ced32904c0acb 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -611,6 +611,30 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
             TyKind::Path(ref qself, ref path) => {
                 self.diagnostic_metadata.current_type_path = Some(ty);
                 self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
+
+                // Check whether we should interpret this as a bare trait object.
+                if qself.is_none()
+                    && let Some(partial_res) = self.r.partial_res_map.get(&ty.id)
+                    && partial_res.unresolved_segments() == 0
+                    && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
+                {
+                    // This path is actually a bare trait object.  In case of a bare `Fn`-trait
+                    // object with anonymous lifetimes, we need this rib to correctly place the
+                    // synthetic lifetimes.
+                    let span = ty.span.shrink_to_lo().to(path.span.shrink_to_lo());
+                    self.with_generic_param_rib(
+                        &[],
+                        NormalRibKind,
+                        LifetimeRibKind::Generics {
+                            binder: ty.id,
+                            kind: LifetimeBinderKind::PolyTrait,
+                            span,
+                        },
+                        |this| this.visit_path(&path, ty.id),
+                    );
+                    self.diagnostic_metadata.current_type_path = prev_ty;
+                    return;
+                }
             }
             TyKind::ImplicitSelf => {
                 let self_ty = Ident::with_dummy_span(kw::SelfUpper);
diff --git a/src/test/ui/lifetimes/bare-trait-object-borrowck.rs b/src/test/ui/lifetimes/bare-trait-object-borrowck.rs
index ee2c61468cb60..45f5e4ae129a1 100644
--- a/src/test/ui/lifetimes/bare-trait-object-borrowck.rs
+++ b/src/test/ui/lifetimes/bare-trait-object-borrowck.rs
@@ -1,5 +1,5 @@
 #![allow(bare_trait_objects)]
-
+// check-pass
 pub struct FormatWith<'a, I, F> {
     sep: &'a str,
     /// FormatWith uses interior mutability because Display::fmt takes &self.
@@ -21,7 +21,4 @@ where
 
 fn main() {
     let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i)));
-    //~^ ERROR temporary value dropped while borrowed
-    //~| ERROR temporary value dropped while borrowed
-    //~| ERROR `i` does not live long enough
 }
diff --git a/src/test/ui/lifetimes/bare-trait-object-borrowck.stderr b/src/test/ui/lifetimes/bare-trait-object-borrowck.stderr
deleted file mode 100644
index d7b059019eb3b..0000000000000
--- a/src/test/ui/lifetimes/bare-trait-object-borrowck.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/bare-trait-object-borrowck.rs:23:48
-   |
-LL |     let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i)));
-   |                                          -  ---^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |                                          |  |  |                        |
-   |                                          |  |  |                        temporary value is freed at the end of this statement
-   |                                          |  |  creates a temporary which is freed while still in use
-   |                                          |  argument requires that borrow lasts for `'1`
-   |                                          has type `&mut dyn FnMut(&'1 (dyn std::fmt::Display + '1)) -> Result<(), std::fmt::Error>`
-   |
-   = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/bare-trait-object-borrowck.rs:23:48
-   |
-LL |     let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i)));
-   |                                          -  ---^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |                                          |  |  |                        |
-   |                                          |  |  |                        temporary value is freed at the end of this statement
-   |                                          |  |  creates a temporary which is freed while still in use
-   |                                          |  argument requires that borrow lasts for `'1`
-   |                                          has type `&mut dyn FnMut(&'1 (dyn std::fmt::Display + '1)) -> Result<(), std::fmt::Error>`
-   |
-   = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0597]: `i` does not live long enough
-  --> $DIR/bare-trait-object-borrowck.rs:23:71
-   |
-LL |     let _ = new_format(0..32, " | ", |i, f| f(&format_args!("0x{:x}", i)));
-   |                                          -  --------------------------^--
-   |                                          |  |                         | |
-   |                                          |  |                         | `i` dropped here while still borrowed
-   |                                          |  |                         borrowed value does not live long enough
-   |                                          |  argument requires that `i` is borrowed for `'1`
-   |                                          has type `&mut dyn FnMut(&'1 (dyn std::fmt::Display + '1)) -> Result<(), std::fmt::Error>`
-   |
-   = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0597, E0716.
-For more information about an error, try `rustc --explain E0597`.
diff --git a/src/test/ui/lifetimes/bare-trait-object.rs b/src/test/ui/lifetimes/bare-trait-object.rs
index dc8b611c03978..9eff618c734d5 100644
--- a/src/test/ui/lifetimes/bare-trait-object.rs
+++ b/src/test/ui/lifetimes/bare-trait-object.rs
@@ -1,5 +1,5 @@
 // Verify that lifetime resolution correctly accounts for `Fn` bare trait objects.
-
+// check-pass
 #![allow(bare_trait_objects)]
 
 // This should work as: fn next_u32(fill_buf: &mut dyn FnMut(&mut [u8]))
@@ -15,10 +15,8 @@ fn explicit(fill_buf: &mut dyn FnMut(&mut [u8])) {
 
 fn main() {
     let _: fn(&mut FnMut(&mut [u8])) = next_u32;
-    //~^ ERROR mismatched types
     let _: &dyn Fn(&mut FnMut(&mut [u8])) = &next_u32;
     let _: fn(&mut FnMut(&mut [u8])) = explicit;
-    //~^ ERROR mismatched types
     let _: &dyn Fn(&mut FnMut(&mut [u8])) = &explicit;
     let _: fn(&mut dyn FnMut(&mut [u8])) = next_u32;
     let _: &dyn Fn(&mut dyn FnMut(&mut [u8])) = &next_u32;
diff --git a/src/test/ui/lifetimes/bare-trait-object.stderr b/src/test/ui/lifetimes/bare-trait-object.stderr
deleted file mode 100644
index 8f06410152e62..0000000000000
--- a/src/test/ui/lifetimes/bare-trait-object.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/bare-trait-object.rs:17:40
-   |
-LL |     let _: fn(&mut FnMut(&mut [u8])) = next_u32;
-   |                                        ^^^^^^^^ one type is more general than the other
-   |
-   = note: expected fn pointer `for<'r, 's> fn(&'r mut (dyn for<'s> FnMut(&'s mut [u8]) + 'r))`
-                 found fn item `for<'r> fn(&'r mut (dyn for<'r> FnMut(&'r mut [u8]) + 'r)) {next_u32}`
-
-error[E0308]: mismatched types
-  --> $DIR/bare-trait-object.rs:20:40
-   |
-LL |     let _: fn(&mut FnMut(&mut [u8])) = explicit;
-   |                                        ^^^^^^^^ one type is more general than the other
-   |
-   = note: expected fn pointer `for<'r, 's> fn(&'r mut (dyn for<'s> FnMut(&'s mut [u8]) + 'r))`
-                 found fn item `for<'r> fn(&'r mut (dyn for<'r> FnMut(&'r mut [u8]) + 'r)) {explicit}`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.