From f0227e8b9fc502156532d9ce0d6164705af299f4 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 25 Jun 2022 19:16:56 +0200 Subject: [PATCH] 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`.