diff options
43 files changed, 598 insertions, 556 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ac750690046..d29e9f9b3f6 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -512,11 +512,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id) } - fn orig_local_def_id(&self, node: NodeId) -> LocalDefId { - self.orig_opt_local_def_id(node) - .unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) - } - /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name /// resolver (if any), after applying any remapping from `get_remapped_def_id`. /// @@ -1521,209 +1516,86 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - let opaque_ty_def_id = self.create_def( - self.current_hir_id_owner.def_id, - opaque_ty_node_id, - DefPathData::ImplTrait, - opaque_ty_span, - ); - debug!(?opaque_ty_def_id); - - // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want - // to capture the lifetimes that appear in the bounds. So visit the bounds to find out - // exactly which ones those are. - let lifetimes_to_remap = match origin { + let captured_lifetimes_to_duplicate = match origin { hir::OpaqueTyOrigin::TyAlias { .. } => { - // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters + // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any + // lifetimes, since we don't have the issue that any are late-bound. Vec::new() } - hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => { - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example, - // we only keep the lifetimes that appear in the `impl Debug` itself: + hir::OpaqueTyOrigin::FnReturn(..) => { + // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` + // example, we only need to duplicate lifetimes that appear in the + // bounds, since those are the only ones that are captured by the opaque. lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) } + hir::OpaqueTyOrigin::AsyncFn(..) => { + unreachable!("should be using `lower_async_fn_ret_ty`") + } }; - debug!(?lifetimes_to_remap); - - let mut new_remapping = FxHashMap::default(); - - // Contains the new lifetime definitions created for the TAIT (if any). - // If this opaque type is only capturing a subset of the lifetimes (those that appear in - // bounds), then create the new lifetime parameters required and create a mapping from the - // old `'a` (on the function) to the new `'a` (on the opaque type). - let collected_lifetimes = - self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping); - debug!(?collected_lifetimes); - debug!(?new_remapping); - - // This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type - // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`. - let collected_lifetime_mapping: Vec<_> = collected_lifetimes - .iter() - .map(|(node_id, lifetime)| { - let id = self.next_node_id(); - let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident); - let def_id = self.local_def_id(*node_id); - (lifetime, def_id) - }) - .collect(); - debug!(?collected_lifetime_mapping); - - self.with_hir_id_owner(opaque_ty_node_id, |lctx| { - // Install the remapping from old to new (if any): - lctx.with_remapping(new_remapping, |lctx| { - // This creates HIR lifetime definitions as `hir::GenericParam`, in the given - // example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection - // containing `&['x]`. - let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map( - |&(new_node_id, lifetime)| { - let hir_id = lctx.lower_node_id(new_node_id); - debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None); - - let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime { - (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided) - } else { - ( - hir::ParamName::Plain(lifetime.ident), - hir::LifetimeParamKind::Explicit, - ) - }; + debug!(?captured_lifetimes_to_duplicate); - hir::GenericParam { - hir_id, - def_id: lctx.local_def_id(new_node_id), - name, - span: lifetime.ident.span, - pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind }, - colon_span: None, - source: hir::GenericParamSource::Generics, - } - }, - )); - debug!(?lifetime_defs); - - // Then when we lower the param bounds, references to 'a are remapped to 'a1, so we - // get back Debug + 'a1, which is suitable for use on the TAIT. - let hir_bounds = lctx.lower_param_bounds(bounds, itctx); - debug!(?hir_bounds); - - let lifetime_mapping = if in_trait { - Some( - &*self.arena.alloc_from_iter( - collected_lifetime_mapping - .iter() - .map(|(lifetime, def_id)| (**lifetime, *def_id)), - ), - ) - } else { - None - }; - - let opaque_ty_item = hir::OpaqueTy { - generics: self.arena.alloc(hir::Generics { - params: lifetime_defs, - predicates: &[], - has_where_clause_predicates: false, - where_clause_span: lctx.lower_span(span), - span: lctx.lower_span(span), - }), - bounds: hir_bounds, - origin, - lifetime_mapping, - in_trait, - }; - debug!(?opaque_ty_item); - - lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span) - }) - }); - - // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. - hir::TyKind::OpaqueDef( - hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, - self.arena.alloc_from_iter( - collected_lifetime_mapping - .iter() - .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), - ), + self.lower_opaque_inner( + opaque_ty_node_id, + origin, in_trait, + captured_lifetimes_to_duplicate, + span, + opaque_ty_span, + |this| this.lower_param_bounds(bounds, itctx), ) } - /// Registers a new opaque type with the proper `NodeId`s and - /// returns the lowered node-ID for the opaque type. - fn generate_opaque_type( + fn lower_opaque_inner( &mut self, - opaque_ty_id: LocalDefId, - opaque_ty_item: hir::OpaqueTy<'hir>, + opaque_ty_node_id: NodeId, + origin: hir::OpaqueTyOrigin, + in_trait: bool, + captured_lifetimes_to_duplicate: Vec<Lifetime>, span: Span, opaque_ty_span: Span, - ) -> hir::OwnerNode<'hir> { - let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(self.arena.alloc(opaque_ty_item)); - // Generate an `type Foo = impl Trait;` declaration. - trace!("registering opaque type with id {:#?}", opaque_ty_id); - let opaque_ty_item = hir::Item { - owner_id: hir::OwnerId { def_id: opaque_ty_id }, - ident: Ident::empty(), - kind: opaque_ty_item_kind, - vis_span: self.lower_span(span.shrink_to_lo()), - span: self.lower_span(opaque_ty_span), - }; - hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item)) - } - - /// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be - /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the - /// new definition, adds it to the remapping with the definition of the given lifetime and - /// returns a list of lifetimes to be lowered afterwards. - fn create_lifetime_defs( - &mut self, - parent_def_id: LocalDefId, - lifetimes_in_bounds: &[Lifetime], - remapping: &mut FxHashMap<LocalDefId, LocalDefId>, - ) -> Vec<(NodeId, Lifetime)> { - let mut result = Vec::new(); + lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], + ) -> hir::TyKind<'hir> { + let opaque_ty_def_id = self.create_def( + self.current_hir_id_owner.def_id, + opaque_ty_node_id, + DefPathData::ImplTrait, + opaque_ty_span, + ); + debug!(?opaque_ty_def_id); - for lifetime in lifetimes_in_bounds { + // Map from captured (old) lifetime to synthetic (new) lifetime. + // Used to resolve lifetimes in the bounds of the opaque. + let mut captured_to_synthesized_mapping = FxHashMap::default(); + // List of (early-bound) synthetic lifetimes that are owned by the opaque. + // This is used to create the `hir::Generics` owned by the opaque. + let mut synthesized_lifetime_definitions = vec![]; + // Pairs of lifetime arg (that resolves to the captured lifetime) + // and the def-id of the (early-bound) synthetic lifetime definition. + // This is used both to create generics for the `TyKind::OpaqueDef` that + // we return, and also as a captured lifetime mapping for RPITITs. + let mut synthesized_lifetime_args = vec![]; + + for lifetime in captured_lifetimes_to_duplicate { let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error); - debug!(?res); - - match res { - LifetimeRes::Param { param: old_def_id, binder: _ } => { - if remapping.get(&old_def_id).is_none() { - let node_id = self.next_node_id(); - - let new_def_id = self.create_def( - parent_def_id, - node_id, - DefPathData::LifetimeNs(lifetime.ident.name), - lifetime.ident.span, - ); - remapping.insert(old_def_id, new_def_id); - - result.push((node_id, *lifetime)); - } - } + let old_def_id = match res { + LifetimeRes::Param { param: old_def_id, binder: _ } => old_def_id, LifetimeRes::Fresh { param, binder: _ } => { debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); - if let Some(old_def_id) = self.orig_opt_local_def_id(param) && remapping.get(&old_def_id).is_none() { - let node_id = self.next_node_id(); - - let new_def_id = self.create_def( - parent_def_id, - node_id, - DefPathData::LifetimeNs(kw::UnderscoreLifetime), - lifetime.ident.span, - ); - remapping.insert(old_def_id, new_def_id); - - result.push((node_id, *lifetime)); + if let Some(old_def_id) = self.orig_opt_local_def_id(param) { + old_def_id + } else { + self.tcx + .sess + .delay_span_bug(lifetime.ident.span, "no def-id for fresh lifetime"); + continue; } } - LifetimeRes::Static | LifetimeRes::Error => {} + // Opaques do not capture `'static` + LifetimeRes::Static | LifetimeRes::Error => { + continue; + } res => { let bug_msg = format!( @@ -1732,10 +1604,113 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); span_bug!(lifetime.ident.span, "{}", bug_msg); } + }; + + if captured_to_synthesized_mapping.get(&old_def_id).is_none() { + // Create a new lifetime parameter local to the opaque. + let duplicated_lifetime_node_id = self.next_node_id(); + let duplicated_lifetime_def_id = self.create_def( + opaque_ty_def_id, + duplicated_lifetime_node_id, + DefPathData::LifetimeNs(lifetime.ident.name), + lifetime.ident.span, + ); + captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id); + // FIXME: Instead of doing this, we could move this whole loop + // into the `with_hir_id_owner`, then just directly construct + // the `hir::GenericParam` here. + synthesized_lifetime_definitions.push(( + duplicated_lifetime_node_id, + duplicated_lifetime_def_id, + lifetime.ident, + )); + + // Now make an arg that we can use for the substs of the opaque tykind. + let id = self.next_node_id(); + let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res); + let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id); + synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id)) } } - result + self.with_hir_id_owner(opaque_ty_node_id, |this| { + // Install the remapping from old to new (if any). This makes sure that + // any lifetimes that would have resolved to the def-id of captured + // lifetimes are remapped to the new *synthetic* lifetimes of the opaque. + let bounds = this + .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this)); + + let generic_params = this.arena.alloc_from_iter( + synthesized_lifetime_definitions.iter().map(|&(new_node_id, new_def_id, ident)| { + let hir_id = this.lower_node_id(new_node_id); + let (name, kind) = if ident.name == kw::UnderscoreLifetime { + (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided) + } else { + (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) + }; + + hir::GenericParam { + hir_id, + def_id: new_def_id, + name, + span: ident.span, + pure_wrt_drop: false, + kind: hir::GenericParamKind::Lifetime { kind }, + colon_span: None, + source: hir::GenericParamSource::Generics, + } + }), + ); + debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); + + let lifetime_mapping = if in_trait { + Some(&*self.arena.alloc_slice(&synthesized_lifetime_args)) + } else { + None + }; + + let opaque_ty_item = hir::OpaqueTy { + generics: this.arena.alloc(hir::Generics { + params: generic_params, + predicates: &[], + has_where_clause_predicates: false, + where_clause_span: this.lower_span(span), + span: this.lower_span(span), + }), + bounds, + origin, + lifetime_mapping, + in_trait, + }; + + // Generate an `type Foo = impl Trait;` declaration. + trace!("registering opaque type with id {:#?}", opaque_ty_def_id); + let opaque_ty_item = hir::Item { + owner_id: hir::OwnerId { def_id: opaque_ty_def_id }, + ident: Ident::empty(), + kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)), + vis_span: this.lower_span(span.shrink_to_lo()), + span: this.lower_span(opaque_ty_span), + }; + + hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item)) + }); + + let generic_args = self.arena.alloc_from_iter( + synthesized_lifetime_args + .iter() + .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), + ); + + // Create the `Foo<...>` reference itself. Note that the `type + // Foo = impl Trait` is, internally, created as a child of the + // async fn, so the *type parameters* are inherited. It's + // only the lifetime parameters that we must supply. + hir::TyKind::OpaqueDef( + hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, + generic_args, + in_trait, + ) } fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] { @@ -1813,9 +1788,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + let fn_def_id = self.local_def_id(fn_node_id); self.lower_async_fn_ret_ty( &decl.output, - fn_node_id, + fn_def_id, ret_id, matches!(kind, FnDeclKind::Trait), ) @@ -1892,151 +1868,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_async_fn_ret_ty( &mut self, output: &FnRetTy, - fn_node_id: NodeId, + fn_def_id: LocalDefId, opaque_ty_node_id: NodeId, in_trait: bool, ) -> hir::FnRetTy<'hir> { - let span = output.span(); - + let span = self.lower_span(output.span()); let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); - let fn_def_id = self.local_def_id(fn_node_id); - - let opaque_ty_def_id = - self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait, opaque_ty_span); - - // When we create the opaque type for this async fn, it is going to have - // to capture all the lifetimes involved in the signature (including in the - // return type). This is done by introducing lifetime parameters for: - // - // - all the explicitly declared lifetimes from the impl and function itself; - // - all the elided lifetimes in the fn arguments; - // - all the elided lifetimes in the return type. - // - // So for example in this snippet: - // - // ```rust - // impl<'a> Foo<'a> { - // async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 { - // // ^ '0 ^ '1 ^ '2 - // // elided lifetimes used below - // } - // } - // ``` - // - // we would create an opaque type like: - // - // ``` - // type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>; - // ``` - // - // and we would then desugar `bar` to the equivalent of: - // - // ```rust - // impl<'a> Foo<'a> { - // fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_> - // } - // ``` - // - // Note that the final parameter to `Bar` is `'_`, not `'2` -- - // this is because the elided lifetimes from the return type - // should be figured out using the ordinary elision rules, and - // this desugaring achieves that. - - // Calculate all the lifetimes that should be captured - // by the opaque type. This should include all in-scope - // lifetime parameters, including those defined in-band. - - // Contains the new lifetime definitions created for the TAIT (if any) generated for the - // return type. - let mut collected_lifetimes = Vec::new(); - let mut new_remapping = FxHashMap::default(); - - let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id); - debug!(?extra_lifetime_params); - for (ident, outer_node_id, outer_res) in extra_lifetime_params { - let outer_def_id = self.orig_local_def_id(outer_node_id); - let inner_node_id = self.next_node_id(); - - // Add a definition for the in scope lifetime def. - let inner_def_id = self.create_def( - opaque_ty_def_id, - inner_node_id, - DefPathData::LifetimeNs(ident.name), - ident.span, - ); - new_remapping.insert(outer_def_id, inner_def_id); - - let inner_res = match outer_res { - // Input lifetime like `'a`: - LifetimeRes::Param { param, .. } => { - LifetimeRes::Param { param, binder: fn_node_id } - } - // Input lifetime like `'1`: - LifetimeRes::Fresh { param, .. } => { - LifetimeRes::Fresh { param, binder: fn_node_id } - } - LifetimeRes::Static | LifetimeRes::Error => continue, - res => { - panic!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, ident, ident.span - ) - } - }; - - let lifetime = Lifetime { id: outer_node_id, ident }; - collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res))); - } - debug!(?collected_lifetimes); - - // We only want to capture the lifetimes that appear in the bounds. So visit the bounds to - // find out exactly which ones those are. - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example, - // we only keep the lifetimes that appear in the `impl Debug` itself: - let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output); - debug!(?lifetimes_to_remap); - - // If this opaque type is only capturing a subset of the lifetimes (those that appear in - // bounds), then create the new lifetime parameters required and create a mapping from the - // old `'a` (on the function) to the new `'a` (on the opaque type). - collected_lifetimes.extend( - self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping) - .into_iter() - .map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)), - ); - debug!(?collected_lifetimes); - debug!(?new_remapping); - - // This creates pairs of HIR lifetimes and def_ids. In the given example `type - // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the - // new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to - // `TestReturn`. - let collected_lifetime_mapping: Vec<_> = collected_lifetimes - .iter() - .map(|(node_id, lifetime, res)| { - let id = self.next_node_id(); - let res = res.unwrap_or( - self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error), - ); - let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res); - let def_id = self.local_def_id(*node_id); - (lifetime, def_id) - }) + let captured_lifetimes: Vec<_> = self + .resolver + .take_extra_lifetime_params(opaque_ty_node_id) + .into_iter() + .map(|(ident, id, _)| Lifetime { id, ident }) .collect(); - debug!(?collected_lifetime_mapping); - self.with_hir_id_owner(opaque_ty_node_id, |this| { - // Install the remapping from old to new (if any): - this.with_remapping(new_remapping, |this| { - // We have to be careful to get elision right here. The - // idea is that we create a lifetime parameter for each - // lifetime in the return type. So, given a return type - // like `async fn foo(..) -> &[&u32]`, we lower to `impl - // Future<Output = &'1 [ &'2 u32 ]>`. - // - // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and - // hence the elision takes place at the fn site. + let opaque_ty_ref = self.lower_opaque_inner( + opaque_ty_node_id, + hir::OpaqueTyOrigin::AsyncFn(fn_def_id), + in_trait, + captured_lifetimes, + span, + opaque_ty_span, + |this| { let future_bound = this.lower_async_fn_output_type_to_future_bound( output, span, @@ -2052,96 +1905,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }, ); - - let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map( - |&(new_node_id, lifetime, _)| { - let hir_id = this.lower_node_id(new_node_id); - debug_assert_ne!(this.opt_local_def_id(new_node_id), None); - - let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime { - (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided) - } else { - ( - hir::ParamName::Plain(lifetime.ident), - hir::LifetimeParamKind::Explicit, - ) - }; - - hir::GenericParam { - hir_id, - def_id: this.local_def_id(new_node_id), - name, - span: lifetime.ident.span, - pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind }, - colon_span: None, - source: hir::GenericParamSource::Generics, - } - }, - )); - debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); - - let lifetime_mapping = if in_trait { - Some( - &*self.arena.alloc_from_iter( - collected_lifetime_mapping - .iter() - .map(|(lifetime, def_id)| (**lifetime, *def_id)), - ), - ) - } else { - None - }; - - let opaque_ty_item = hir::OpaqueTy { - generics: this.arena.alloc(hir::Generics { - params: generic_params, - predicates: &[], - has_where_clause_predicates: false, - where_clause_span: this.lower_span(span), - span: this.lower_span(span), - }), - bounds: arena_vec![this; future_bound], - origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id), - lifetime_mapping, - in_trait, - }; - - trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id); - this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span) - }) - }); - - // As documented above, we need to create the lifetime - // arguments to our opaque type. Continuing with our example, - // we're creating the type arguments for the return type: - // - // ``` - // Bar<'a, 'b, '0, '1, '_> - // ``` - // - // For the "input" lifetime parameters, we wish to create - // references to the parameters themselves, including the - // "implicit" ones created from parameter types (`'a`, `'b`, - // '`0`, `'1`). - // - // For the "output" lifetime parameters, we just want to - // generate `'_`. - let generic_args = self.arena.alloc_from_iter( - collected_lifetime_mapping - .iter() - .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), + arena_vec![this; future_bound] + }, ); - // Create the `Foo<...>` reference itself. Note that the `type - // Foo = impl Trait` is, internally, created as a child of the - // async fn, so the *type parameters* are inherited. It's - // only the lifetime parameters that we must supply. - let opaque_ty_ref = hir::TyKind::OpaqueDef( - hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } }, - generic_args, - in_trait, - ); let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref); hir::FnRetTy::Return(self.arena.alloc(opaque_ty)) } diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs index 3989fc48619..0e0bdf17389 100644 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs @@ -1,6 +1,6 @@ use super::ResolverAstLoweringExt; use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; -use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; +use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; use rustc_hir::def::LifetimeRes; use rustc_middle::span_bug; use rustc_middle::ty::ResolverAstLowering; @@ -94,12 +94,6 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { } } -pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> { - let mut visitor = LifetimeCollectVisitor::new(resolver); - visitor.visit_fn_ret_ty(ret_ty); - visitor.collected_lifetimes -} - pub fn lifetimes_in_bounds( resolver: &ResolverAstLowering, bounds: &GenericBounds, diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 053f5730f6e..7bded6b1d82 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -78,11 +78,11 @@ impl AllocFnFactory<'_, '_> { }; let args = method.inputs.iter().map(|ty| self.arg_ty(ty, &mut abi_args, &mut mk)).collect(); let result = self.call_allocator(method.name, args); - let (output_ty, output_expr) = self.ret_ty(&method.output, result); + let output_ty = self.ret_ty(&method.output); let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty)); let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() }; let sig = FnSig { decl, header, span: self.span }; - let body = Some(self.cx.block_expr(output_expr)); + let body = Some(self.cx.block_expr(result)); let kind = ItemKind::Fn(Box::new(Fn { defaultness: ast::Defaultness::Final, sig, @@ -140,8 +140,7 @@ impl AllocFnFactory<'_, '_> { AllocatorTy::Ptr => { let ident = ident(); args.push(self.cx.param(self.span, ident, self.ptr_u8())); - let arg = self.cx.expr_ident(self.span, ident); - self.cx.expr_cast(self.span, arg, self.ptr_u8()) + self.cx.expr_ident(self.span, ident) } AllocatorTy::Usize => { @@ -156,18 +155,11 @@ impl AllocFnFactory<'_, '_> { } } - fn ret_ty(&self, ty: &AllocatorTy, expr: P<Expr>) -> (P<Ty>, P<Expr>) { + fn ret_ty(&self, ty: &AllocatorTy) -> P<Ty> { match *ty { - AllocatorTy::ResultPtr => { - // We're creating: - // - // #expr as *mut u8 - - let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8()); - (self.ptr_u8(), expr) - } + AllocatorTy::ResultPtr => self.ptr_u8(), - AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(ThinVec::new())), expr), + AllocatorTy::Unit => self.cx.ty(self.span, TyKind::Tup(ThinVec::new())), AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { panic!("can't convert `AllocatorTy` to an output") diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 64c6d17469b..e7c3906d977 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -441,7 +441,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Place(place) => place, LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx), LocalRef::Operand(..) => { - if place_ref.has_deref() { + if place_ref.is_indirect_first_projection() { base = 1; let cg_base = self.codegen_consume( bx, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 0ef5522729a..a6edc6fb363 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -247,7 +247,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { AddressOf(_, place) => { // Figure out whether this is an addr_of of an already raw place. - let place_base_raw = if place.has_deref() { + let place_base_raw = if place.is_indirect_first_projection() { let ty = self.frame().body.local_decls[place.local].ty; ty.is_unsafe_ptr() } else { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index d4532873854..60dc9b20077 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -391,6 +391,10 @@ fn run_compiler( pretty::print_after_hir_lowering(tcx, *ppm); Ok(()) })?; + + // Make sure the `output_filenames` query is run for its side + // effects of writing the dep-info and reporting errors. + queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(())); } else { let krate = queries.parse()?.steal(); pretty::print_after_parsing(sess, &krate, *ppm); diff --git a/compiler/rustc_error_codes/src/error_codes/E0577.md b/compiler/rustc_error_codes/src/error_codes/E0577.md index eba2d3b1417..383ca61f6c4 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0577.md +++ b/compiler/rustc_error_codes/src/error_codes/E0577.md @@ -3,7 +3,7 @@ Something other than a module was found in visibility scope. Erroneous code example: ```compile_fail,E0577,edition2018 -pub struct Sea; +pub enum Sea {} pub (in crate::Sea) struct Shark; // error! diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bc05565fed4..c6f8d1e211d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2675,7 +2675,7 @@ pub struct OpaqueTy<'hir> { /// /// This mapping associated a captured lifetime (first parameter) with the new /// early-bound lifetime that was generated for the opaque. - pub lifetime_mapping: Option<&'hir [(Lifetime, LocalDefId)]>, + pub lifetime_mapping: Option<&'hir [(&'hir Lifetime, LocalDefId)]>, /// Whether the opaque is a return-position impl trait (or async future) /// originating from a trait method. This makes it so that the opaque is /// lowered as an associated type. diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 2950ce683a3..83220be6883 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -82,7 +82,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen tcx, def_id, lifetime_mapping.iter().map(|(lifetime, def_id)| { - (*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span)) + (**lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span)) }), tcx.generics_of(def_id.to_def_id()), &mut predicates, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c290462fc20..2c9d212a6a6 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -58,6 +58,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::GenericArgKind; +use rustc_middle::ty::ToPredicate; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef}; use rustc_session::config::ExpectedValues; @@ -68,6 +69,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, Span}; use rustc_target::abi::Abi; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy}; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -673,6 +675,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { if ty.is_copy_modulo_regions(cx.tcx, param_env) { return; } + if type_implements_negative_copy_modulo_regions(cx.tcx, ty, param_env) { + return; + } // We shouldn't recommend implementing `Copy` on stateful things, // such as iterators. @@ -708,6 +713,24 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { } } +/// Check whether a `ty` has a negative `Copy` implementation, ignoring outlives constraints. +fn type_implements_negative_copy_modulo_regions<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> bool { + let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]); + let pred = ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Negative }; + let obligation = traits::Obligation { + cause: traits::ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: ty::Binder::dummy(pred).to_predicate(tcx), + }; + + tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) +} + declare_lint! { /// The `missing_debug_implementations` lint detects missing /// implementations of [`fmt::Debug`] for public types. diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 70311a5c576..25982a45853 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1496,7 +1496,7 @@ pub enum InvalidNanComparisons { #[diag(lint_invalid_nan_comparisons_eq_ne)] EqNe { #[subdiagnostic] - suggestion: InvalidNanComparisonsSuggestion, + suggestion: Option<InvalidNanComparisonsSuggestion>, }, #[diag(lint_invalid_nan_comparisons_lt_le_gt_ge)] LtLeGtGe, diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 24bc16af2ee..1ba746eddeb 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -572,32 +572,36 @@ fn lint_nan<'tcx>( } fn eq_ne( + cx: &LateContext<'_>, e: &hir::Expr<'_>, l: &hir::Expr<'_>, r: &hir::Expr<'_>, f: impl FnOnce(Span, Span) -> InvalidNanComparisonsSuggestion, ) -> InvalidNanComparisons { - let suggestion = + // FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const. + let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| { if let Some(l_span) = l.span.find_ancestor_inside(e.span) && - let Some(r_span) = r.span.find_ancestor_inside(e.span) { + let Some(r_span) = r.span.find_ancestor_inside(e.span) + { f(l_span, r_span) } else { InvalidNanComparisonsSuggestion::Spanless - }; + } + }); InvalidNanComparisons::EqNe { suggestion } } let lint = match binop.node { hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, l) => { - eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { + eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { nan_plus_binop: l_span.until(r_span), float: r_span.shrink_to_hi(), neg: (binop.node == hir::BinOpKind::Ne).then(|| r_span.shrink_to_lo()), }) } hir::BinOpKind::Eq | hir::BinOpKind::Ne if is_nan(cx, r) => { - eq_ne(e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { + eq_ne(cx, e, l, r, |l_span, r_span| InvalidNanComparisonsSuggestion::Spanful { nan_plus_binop: l_span.shrink_to_hi().to(r_span), float: l_span.shrink_to_hi(), neg: (binop.node == hir::BinOpKind::Ne).then(|| l_span.shrink_to_lo()), diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c1f87d79b83..ddb5e248cdc 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1592,14 +1592,13 @@ impl<'tcx> Place<'tcx> { self.projection.iter().any(|elem| elem.is_indirect()) } - /// If MirPhase >= Derefered and if projection contains Deref, - /// It's guaranteed to be in the first place - pub fn has_deref(&self) -> bool { - // To make sure this is not accidentally used in wrong mir phase - debug_assert!( - self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref) - ); - self.projection.first() == Some(&PlaceElem::Deref) + /// Returns `true` if this `Place`'s first projection is `Deref`. + /// + /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later, + /// `Deref` projections can only occur as the first projection. In that case this method + /// is equivalent to `is_indirect`, but faster. + pub fn is_indirect_first_projection(&self) -> bool { + self.as_ref().is_indirect_first_projection() } /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or @@ -1672,9 +1671,16 @@ impl<'tcx> PlaceRef<'tcx> { self.projection.iter().any(|elem| elem.is_indirect()) } - /// If MirPhase >= Derefered and if projection contains Deref, - /// It's guaranteed to be in the first place - pub fn has_deref(&self) -> bool { + /// Returns `true` if this `Place`'s first projection is `Deref`. + /// + /// This is useful because for MIR phases `AnalysisPhase::PostCleanup` and later, + /// `Deref` projections can only occur as the first projection. In that case this method + /// is equivalent to `is_indirect`, but faster. + pub fn is_indirect_first_projection(&self) -> bool { + // To make sure this is not accidentally used in wrong mir phase + debug_assert!( + self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref) + ); self.projection.first() == Some(&PlaceElem::Deref) } diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 8d78ec04821..17bb8fc37ad 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -839,7 +839,7 @@ impl Map { tail_elem: Option<TrackElem>, f: &mut impl FnMut(ValueIndex), ) { - if place.has_deref() { + if place.is_indirect_first_projection() { // We do not track indirect places. return; } diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index d9e7339f1b2..75473ca53fb 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -60,7 +60,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag { let basic_blocks = body.basic_blocks.as_mut(); let local_decls = &body.local_decls; let needs_retag = |place: &Place<'tcx>| { - !place.has_deref() // we're not really interested in stores to "outside" locations, they are hard to keep track of anyway + !place.is_indirect_first_projection() // we're not really interested in stores to "outside" locations, they are hard to keep track of anyway && may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx) && !local_decls[place.local].is_deref_temp() }; diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 47d9f52bfb5..9a3798eea3b 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -154,7 +154,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { if let Operand::Move(place) = *operand // A move out of a projection of a copy is equivalent to a copy of the original projection. - && !place.has_deref() + && !place.is_indirect_first_projection() && !self.fully_moved.contains(place.local) { *operand = Operand::Copy(place); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 734321e97d8..1ffc4597772 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -338,38 +338,9 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { return shim::build_adt_ctor(tcx, def.to_def_id()); } - let context = tcx - .hir() - .body_const_context(def) - .expect("mir_for_ctfe should not be used for runtime functions"); - let body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone(); let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const); - - match context { - // Do not const prop functions, either they get executed at runtime or exported to metadata, - // so we run const prop on them, or they don't, in which case we const evaluate some control - // flow paths of the function and any errors in those paths will get emitted as const eval - // errors. - hir::ConstContext::ConstFn => {} - // Static items always get evaluated, so we can just let const eval see if any erroneous - // control flow paths get executed. - hir::ConstContext::Static(_) => {} - // Associated constants get const prop run so we detect common failure situations in the - // crate that defined the constant. - // Technically we want to not run on regular const items, but oli-obk doesn't know how to - // conveniently detect that at this point without looking at the HIR. - hir::ConstContext::Const => { - pm::run_passes( - tcx, - &mut body, - &[&const_prop::ConstProp], - Some(MirPhase::Runtime(RuntimePhase::Optimized)), - ); - } - } - pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None); body diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 2f432799022..80d6a47ff53 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -278,7 +278,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { }; match self.r.resolve_path( &segments, - Some(TypeNS), + None, parent_scope, finalize.then(|| Finalize::new(id, path.span)), None, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7b590d16d8c..65fa077dcd9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -904,9 +904,12 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), &sig.decl.output, ); + + if let Some((async_node_id, span)) = sig.header.asyncness.opt_return_id() { + this.record_lifetime_params_for_impl_trait(async_node_id, span); + } }, ); - self.record_lifetime_params_for_async(fn_id, sig.header.asyncness.opt_return_id()); return; } FnKind::Fn(..) => { @@ -942,12 +945,14 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, .iter() .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)), &declaration.output, - ) + ); + + if let Some((async_node_id, span)) = async_node_id { + this.record_lifetime_params_for_impl_trait(async_node_id, span); + } }, ); - this.record_lifetime_params_for_async(fn_id, async_node_id); - if let Some(body) = body { // Ignore errors in function bodies if this is rustdoc // Be sure not to set this until the function signature has been resolved. @@ -1694,6 +1699,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Leave the responsibility to create the `LocalDefId` to lowering. let param = self.r.next_node_id(); let res = LifetimeRes::Fresh { param, binder }; + self.record_lifetime_param(param, res); // Record the created lifetime parameter so lowering can pick it up and add it to HIR. self.r @@ -3944,11 +3950,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { if path.len() > 1 && let Some(res) = result.full_res() + && let Some((&last_segment, prev_segs)) = path.split_last() + && prev_segs.iter().all(|seg| !seg.has_generic_args) && res != Res::Err && path[0].ident.name != kw::PathRoot && path[0].ident.name != kw::DollarCrate { - let last_segment = *path.last().unwrap(); let unqualified_result = { match self.resolve_path(&[last_segment], Some(ns), None) { PathResult::NonModule(path_res) => path_res.expect_full_res(), @@ -4325,39 +4332,32 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ) } - /// Construct the list of in-scope lifetime parameters for async lowering. + /// Construct the list of in-scope lifetime parameters for impl trait lowering. /// We include all lifetime parameters, either named or "Fresh". /// The order of those parameters does not matter, as long as it is /// deterministic. - fn record_lifetime_params_for_async( - &mut self, - fn_id: NodeId, - async_node_id: Option<(NodeId, Span)>, - ) { - if let Some((async_node_id, span)) = async_node_id { - let mut extra_lifetime_params = - self.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default(); - for rib in self.lifetime_ribs.iter().rev() { - extra_lifetime_params.extend( - rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)), - ); - match rib.kind { - LifetimeRibKind::Item => break, - LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { - if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) { - extra_lifetime_params.extend(earlier_fresh); - } - } - LifetimeRibKind::Generics { .. } => {} - _ => { - // We are in a function definition. We should only find `Generics` - // and `AnonymousCreateParameter` inside the innermost `Item`. - span_bug!(span, "unexpected rib kind: {:?}", rib.kind) + fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId, span: Span) { + let mut extra_lifetime_params = vec![]; + + for rib in self.lifetime_ribs.iter().rev() { + extra_lifetime_params + .extend(rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res))); + match rib.kind { + LifetimeRibKind::Item => break, + LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { + if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) { + extra_lifetime_params.extend(earlier_fresh); } } + LifetimeRibKind::Generics { .. } => {} + _ => { + // We are in a function definition. We should only find `Generics` + // and `AnonymousCreateParameter` inside the innermost `Item`. + span_bug!(span, "unexpected rib kind: {:?}", rib.kind) + } } - self.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params); } + self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params); } fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option<Res> { diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index c4bdec0ee28..e377843cdb4 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -1063,3 +1063,34 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::BoundTy { BoundTy { var: self.var.as_usize(), kind: self.kind.stable(tables) } } } + +impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { + type T = stable_mir::ty::Allocation; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + let size = self.size(); + let mut bytes: Vec<Option<u8>> = self + .inspect_with_uninit_and_ptr_outside_interpreter(0..size.bytes_usize()) + .iter() + .copied() + .map(Some) + .collect(); + for (i, b) in bytes.iter_mut().enumerate() { + if !self.init_mask().get(rustc_target::abi::Size::from_bytes(i)) { + *b = None; + } + } + stable_mir::ty::Allocation { + bytes: bytes, + provenance: { + let mut ptrs = Vec::new(); + for (size, prov) in self.provenance().ptrs().iter() { + ptrs.push((size.bytes_usize(), opaque(prov))); + } + stable_mir::ty::ProvenanceMap { ptrs } + }, + align: self.align.bytes(), + mutability: self.mutability.stable(tables), + } + } +} diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index 025225b8d19..df28fc4eed9 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -242,3 +242,25 @@ pub struct BoundTy { pub var: usize, pub kind: BoundTyKind, } + +pub type Bytes = Vec<Option<u8>>; +pub type Size = usize; +pub type Prov = Opaque; +pub type Align = u64; +pub type InitMaskMaterialized = Vec<u64>; + +/// Stores the provenance information of pointers stored in memory. +#[derive(Clone, Debug)] +pub struct ProvenanceMap { + /// Provenance in this map applies from the given offset for an entire pointer-size worth of + /// bytes. Two entries in this map are always at least a pointer size apart. + pub ptrs: Vec<(Size, Prov)>, +} + +#[derive(Clone, Debug)] +pub struct Allocation { + pub bytes: Bytes, + pub provenance: ProvenanceMap, + pub align: Align, + pub mutability: Mutability, +} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 5ec9ddfe64a..60c49f665a6 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -391,13 +391,19 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { debug!("rerunning goal to check result is stable"); self.search_graph.reset_encountered_overflow(encountered_overflow); let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); - let new_canonical_response = EvalCtxt::evaluate_canonical_goal( + let Ok(new_canonical_response) = EvalCtxt::evaluate_canonical_goal( self.tcx(), self.search_graph, canonical_goal, // FIXME(-Ztrait-solver=next): we do not track what happens in `evaluate_canonical_goal` &mut ProofTreeBuilder::new_noop(), - )?; + ) else { + bug!( + "goal went from {certainty:?} to error: re-canonicalized goal={canonical_goal:#?} \ + first_response={canonical_response:#?}, + second response was error" + ); + }; // We only check for modulo regions as we convert all regions in // the input to new existentials, even if they're expected to be // `'static` or a placeholder region. diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index a6d6230d3a6..d7ca9c22dad 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -86,6 +86,46 @@ /// } /// ``` /// +/// If we `derive`: +/// +/// ``` +/// #[derive(Copy, Clone)] +/// struct Generate<T>(fn() -> T); +/// ``` +/// +/// the auto-derived implementations will have unnecessary `T: Copy` and `T: Clone` bounds: +/// +/// ``` +/// # struct Generate<T>(fn() -> T); +/// +/// // Automatically derived +/// impl<T: Copy> Copy for Generate<T> { } +/// +/// // Automatically derived +/// impl<T: Clone> Clone for Generate<T> { +/// fn clone(&self) -> Generate<T> { +/// Generate(Clone::clone(&self.0)) +/// } +/// } +/// ``` +/// +/// The bounds are unnecessary because clearly the function itself should be +/// copy- and cloneable even if its return type is not: +/// +/// ```compile_fail,E0599 +/// #[derive(Copy, Clone)] +/// struct Generate<T>(fn() -> T); +/// +/// struct NotCloneable; +/// +/// fn generate_not_cloneable() -> NotCloneable { +/// NotCloneable +/// } +/// +/// Generate(generate_not_cloneable).clone(); // error: trait bounds were not satisfied +/// // Note: With the manual implementations the above line will compile. +/// ``` +/// /// ## Additional implementors /// /// In addition to the [implementors listed below][impls], diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index de638552fa3..be04dfe042e 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -361,6 +361,12 @@ macro_rules! impl_fold_via_try_fold { (rfold -> try_rfold) => { impl_fold_via_try_fold! { @internal rfold -> try_rfold } }; + (spec_fold -> spec_try_fold) => { + impl_fold_via_try_fold! { @internal spec_fold -> spec_try_fold } + }; + (spec_rfold -> spec_try_rfold) => { + impl_fold_via_try_fold! { @internal spec_rfold -> spec_try_rfold } + }; (@internal $fold:ident -> $try_fold:ident) => { #[inline] fn $fold<AAA, FFF>(mut self, init: AAA, fold: FFF) -> AAA diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 182d9f758ad..4c8af4eba78 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -379,4 +379,66 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { fn nth_back(&mut self, n: usize) -> Option<I::Item> { (**self).nth_back(n) } + fn rfold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.spec_rfold(init, f) + } + fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + self.spec_try_rfold(init, f) + } +} + +/// Helper trait to specialize `rfold` and `rtry_fold` for `&mut I where I: Sized` +trait DoubleEndedIteratorRefSpec: DoubleEndedIterator { + fn spec_rfold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B; + + fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>; +} + +impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIteratorRefSpec for &mut I { + default fn spec_rfold<B, F>(self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x); + } + accum + } + + default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x)?; + } + try { accum } + } +} + +impl<I: DoubleEndedIterator> DoubleEndedIteratorRefSpec for &mut I { + impl_fold_via_try_fold! { spec_rfold -> spec_try_rfold } + + fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + (**self).try_rfold(init, f) + } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 98835228308..cecc120a6e2 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -4018,4 +4018,66 @@ impl<I: Iterator + ?Sized> Iterator for &mut I { fn nth(&mut self, n: usize) -> Option<Self::Item> { (**self).nth(n) } + fn fold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.spec_fold(init, f) + } + fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + self.spec_try_fold(init, f) + } +} + +/// Helper trait to specialize `fold` and `try_fold` for `&mut I where I: Sized` +trait IteratorRefSpec: Iterator { + fn spec_fold<B, F>(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B; + + fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>; +} + +impl<I: Iterator + ?Sized> IteratorRefSpec for &mut I { + default fn spec_fold<B, F>(self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x); + } + accum + } + + default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x)?; + } + try { accum } + } +} + +impl<I: Iterator> IteratorRefSpec for &mut I { + impl_fold_via_try_fold! { spec_fold -> spec_try_fold } + + fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + (**self).try_fold(init, f) + } } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 137bd9c9451..bc011a6c354 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1170,7 +1170,7 @@ fn referent_used_exactly_once<'tcx>( && let [location] = *local_assignments(mir, local).as_slice() && let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index) && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind - && !place.has_deref() + && !place.is_indirect_first_projection() // Ensure not in a loop (https://github.com/rust-lang/rust-clippy/issues/9710) && TriColorDepthFirstSearch::new(&mir.basic_blocks).run_from(location.block, &mut CycleDetector).is_none() { diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs index 5f8eaebf531..67b745373f0 100644 --- a/src/tools/tidy/src/fluent_alphabetical.rs +++ b/src/tools/tidy/src/fluent_alphabetical.rs @@ -23,7 +23,7 @@ fn check_alphabetic(filename: &str, fluent: &str, bad: &mut bool) { tidy_error!( bad, "{filename}: message `{}` appears before `{}`, but is alphabetically later than it -run tidy with `--bless` to sort the file correctly", +run `./x.py test tidy --bless` to sort the file correctly", name.as_str(), next.as_str() ); diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 930b7408390..3414924007b 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -10,7 +10,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: usize = 1893; +const ISSUES_ENTRY_LIMIT: usize = 1891; const ROOT_ENTRY_LIMIT: usize = 866; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ diff --git a/tests/run-make/pretty-print-with-dep-file/Makefile b/tests/run-make/pretty-print-with-dep-file/Makefile new file mode 100644 index 00000000000..fa8089eb6a5 --- /dev/null +++ b/tests/run-make/pretty-print-with-dep-file/Makefile @@ -0,0 +1,9 @@ +include ../tools.mk + +all: + $(RUSTC) --emit=dep-info -Zunpretty=expanded with-dep.rs + $(CGREP) "with-dep.rs" < $(TMPDIR)/with-dep.d + -rm $(TMPDIR)/with-dep.d + + $(RUSTC) --emit=dep-info -Zunpretty=normal with-dep.rs + ! test -f $(TMPDIR)/with-dep.d diff --git a/tests/run-make/pretty-print-with-dep-file/with-dep.rs b/tests/run-make/pretty-print-with-dep-file/with-dep.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make/pretty-print-with-dep-file/with-dep.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml index 9cec6d2bbe8..f742b3186e5 100644 --- a/tests/rustdoc-gui/scrape-examples-toggle.goml +++ b/tests/rustdoc-gui/scrape-examples-toggle.goml @@ -28,18 +28,18 @@ define-function: ( call-function: ("check-color", { "theme": "ayu", - "toggle_line_color": "rgb(153, 153, 153)", - "toggle_line_hover_color": "rgb(197, 197, 197)", + "toggle_line_color": "#999", + "toggle_line_hover_color": "#c5c5c5", }) call-function: ("check-color", { "theme": "dark", - "toggle_line_color": "rgb(153, 153, 153)", - "toggle_line_hover_color": "rgb(197, 197, 197)", + "toggle_line_color": "#999", + "toggle_line_hover_color": "#c5c5c5", }) call-function: ("check-color", { "theme": "light", - "toggle_line_color": "rgb(204, 204, 204)", - "toggle_line_hover_color": "rgb(153, 153, 153)", + "toggle_line_color": "#ccc", + "toggle_line_hover_color": "#999", }) // Toggling all docs will close additional examples diff --git a/tests/ui/issues/issue-100605.rs b/tests/ui/issues/issue-100605.rs deleted file mode 100644 index 917a45c15bb..00000000000 --- a/tests/ui/issues/issue-100605.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn takes_option(_arg: Option<&String>) {} - -fn main() { - takes_option(&None); //~ ERROR 4:18: 4:23: mismatched types [E0308] - - let x = String::from("x"); - let res = Some(x); - takes_option(&res); //~ ERROR 8:18: 8:22: mismatched types [E0308] -} diff --git a/tests/ui/lint/invalid-nan-comparison.stderr b/tests/ui/lint/invalid-nan-comparison.stderr index 054c06d38b3..f2d55c107ba 100644 --- a/tests/ui/lint/invalid-nan-comparison.stderr +++ b/tests/ui/lint/invalid-nan-comparison.stderr @@ -5,11 +5,6 @@ LL | const TEST: bool = 5f32 == f32::NAN; | ^^^^^^^^^^^^^^^^ | = note: `#[warn(invalid_nan_comparisons)]` on by default -help: use `f32::is_nan()` or `f64::is_nan()` instead - | -LL - const TEST: bool = 5f32 == f32::NAN; -LL + const TEST: bool = 5f32.is_nan(); - | warning: incorrect NaN comparison, NaN cannot be directly compared to itself --> $DIR/invalid-nan-comparison.rs:14:5 diff --git a/tests/ui/lint/missing-copy-implementations-negative-copy.rs b/tests/ui/lint/missing-copy-implementations-negative-copy.rs new file mode 100644 index 00000000000..b29d2209fa9 --- /dev/null +++ b/tests/ui/lint/missing-copy-implementations-negative-copy.rs @@ -0,0 +1,15 @@ +// Regression test for issue #101980. +// Ensure that we don't suggest impl'ing `Copy` for a type if it already impl's `!Copy`. + +// check-pass + +#![feature(negative_impls)] +#![deny(missing_copy_implementations)] + +pub struct Struct { + pub field: i32, +} + +impl !Copy for Struct {} + +fn main() {} diff --git a/tests/ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs b/tests/ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs new file mode 100644 index 00000000000..83349dd3350 --- /dev/null +++ b/tests/ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs @@ -0,0 +1,10 @@ +#![deny(unused_qualifications)] +// check-pass +fn bar() { + match Option::<Option<()>>::None { + Some(v) => {} + None => {} + } +} + +fn main() {} diff --git a/tests/ui/resolve/unresolved-segments-visibility.rs b/tests/ui/resolve/unresolved-segments-visibility.rs new file mode 100644 index 00000000000..c26171f75d2 --- /dev/null +++ b/tests/ui/resolve/unresolved-segments-visibility.rs @@ -0,0 +1,11 @@ +// Check that we do not ICE due to unresolved segments in visibility path. +#![crate_type = "lib"] + +extern crate alloc as b; + +mod foo { + mod bar { + pub(in b::string::String::newy) extern crate alloc as e; + //~^ ERROR failed to resolve: `String` is a struct, not a module [E0433] + } +} diff --git a/tests/ui/resolve/unresolved-segments-visibility.stderr b/tests/ui/resolve/unresolved-segments-visibility.stderr new file mode 100644 index 00000000000..0a11549cdbf --- /dev/null +++ b/tests/ui/resolve/unresolved-segments-visibility.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: `String` is a struct, not a module + --> $DIR/unresolved-segments-visibility.rs:8:27 + | +LL | pub(in b::string::String::newy) extern crate alloc as e; + | ^^^^^^ `String` is a struct, not a module + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/span/visibility-ty-params.rs b/tests/ui/span/visibility-ty-params.rs index d77febe0aa2..11c2cf44cb4 100644 --- a/tests/ui/span/visibility-ty-params.rs +++ b/tests/ui/span/visibility-ty-params.rs @@ -4,7 +4,7 @@ macro_rules! m { struct S<T>(T); m!{ S<u8> } //~ ERROR unexpected generic arguments in path - //~| ERROR expected module, found struct `S` + //~| ERROR failed to resolve: `S` is a struct, not a module [E0433] mod m { m!{ m<> } //~ ERROR unexpected generic arguments in path diff --git a/tests/ui/span/visibility-ty-params.stderr b/tests/ui/span/visibility-ty-params.stderr index 067893fd22d..97d05c4644e 100644 --- a/tests/ui/span/visibility-ty-params.stderr +++ b/tests/ui/span/visibility-ty-params.stderr @@ -4,11 +4,11 @@ error: unexpected generic arguments in path LL | m!{ S<u8> } | ^^^^ -error[E0577]: expected module, found struct `S` +error[E0433]: failed to resolve: `S` is a struct, not a module --> $DIR/visibility-ty-params.rs:6:5 | LL | m!{ S<u8> } - | ^^^^^ not a module + | ^ `S` is a struct, not a module error: unexpected generic arguments in path --> $DIR/visibility-ty-params.rs:10:10 @@ -18,4 +18,4 @@ LL | m!{ m<> } error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0577`. +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/type/option-ref-advice.rs b/tests/ui/type/option-ref-advice.rs new file mode 100644 index 00000000000..2dcee5a2eb9 --- /dev/null +++ b/tests/ui/type/option-ref-advice.rs @@ -0,0 +1,11 @@ +// Regression test for https://github.com/rust-lang/rust/issues/100605 + +fn takes_option(_arg: Option<&String>) {} + +fn main() { + takes_option(&None); //~ ERROR 6:18: 6:23: mismatched types [E0308] + + let x = String::from("x"); + let res = Some(x); + takes_option(&res); //~ ERROR 10:18: 10:22: mismatched types [E0308] +} diff --git a/tests/ui/issues/issue-100605.stderr b/tests/ui/type/option-ref-advice.stderr index 6f11f44755a..d4dbef3013f 100644 --- a/tests/ui/issues/issue-100605.stderr +++ b/tests/ui/type/option-ref-advice.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-100605.rs:4:18 + --> $DIR/option-ref-advice.rs:6:18 | LL | takes_option(&None); | ------------ ^^^^^ expected `Option<&String>`, found `&Option<_>` @@ -9,7 +9,7 @@ LL | takes_option(&None); = note: expected enum `Option<&String>` found reference `&Option<_>` note: function defined here - --> $DIR/issue-100605.rs:1:4 + --> $DIR/option-ref-advice.rs:3:4 | LL | fn takes_option(_arg: Option<&String>) {} | ^^^^^^^^^^^^ --------------------- @@ -20,7 +20,7 @@ LL + takes_option(None); | error[E0308]: mismatched types - --> $DIR/issue-100605.rs:8:18 + --> $DIR/option-ref-advice.rs:10:18 | LL | takes_option(&res); | ------------ ^^^^ expected `Option<&String>`, found `&Option<String>` @@ -30,7 +30,7 @@ LL | takes_option(&res); = note: expected enum `Option<&String>` found reference `&Option<String>` note: function defined here - --> $DIR/issue-100605.rs:1:4 + --> $DIR/option-ref-advice.rs:3:4 | LL | fn takes_option(_arg: Option<&String>) {} | ^^^^^^^^^^^^ --------------------- diff --git a/tests/ui/use/use-self-type.stderr b/tests/ui/use/use-self-type.stderr index 3da04a851f6..498df34fe32 100644 --- a/tests/ui/use/use-self-type.stderr +++ b/tests/ui/use/use-self-type.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions +error[E0433]: failed to resolve: `Self` cannot be used in imports --> $DIR/use-self-type.rs:7:16 | LL | pub(in Self::f) struct Z; - | ^^^^ `Self` is only available in impls, traits, and type definitions + | ^^^^ `Self` cannot be used in imports error[E0432]: unresolved import `Self` --> $DIR/use-self-type.rs:6:13 |
