diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 3386f83ec810f..9582ac33ff6b7 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1169,7 +1169,7 @@ impl [T] { /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); /// assert!(iter.next().is_none()); /// ``` - #[unstable(feature = "split_inclusive", issue = "none")] + #[unstable(feature = "split_inclusive", issue = "72360")] #[inline] pub fn split_inclusive(&self, pred: F) -> SplitInclusive<'_, T, F> where @@ -1194,7 +1194,7 @@ impl [T] { /// } /// assert_eq!(v, [10, 40, 1, 20, 1, 1]); /// ``` - #[unstable(feature = "split_inclusive", issue = "none")] + #[unstable(feature = "split_inclusive", issue = "72360")] #[inline] pub fn split_inclusive_mut(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F> where @@ -3852,7 +3852,7 @@ impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} /// /// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] pub struct SplitInclusive<'a, T: 'a, P> where P: FnMut(&T) -> bool, @@ -3862,7 +3862,7 @@ where finished: bool, } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl fmt::Debug for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool, @@ -3876,7 +3876,7 @@ where } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl Clone for SplitInclusive<'_, T, P> where P: Clone + FnMut(&T) -> bool, @@ -3886,7 +3886,7 @@ where } } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> where P: FnMut(&T) -> bool, @@ -3915,7 +3915,7 @@ where } } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> where P: FnMut(&T) -> bool, @@ -3940,7 +3940,7 @@ where } } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} /// An iterator over the mutable subslices of the vector which are separated @@ -4065,7 +4065,7 @@ impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} /// /// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] pub struct SplitInclusiveMut<'a, T: 'a, P> where P: FnMut(&T) -> bool, @@ -4075,7 +4075,7 @@ where finished: bool, } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl fmt::Debug for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool, @@ -4088,7 +4088,7 @@ where } } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> where P: FnMut(&T) -> bool, @@ -4128,7 +4128,7 @@ where } } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> where P: FnMut(&T) -> bool, @@ -4162,7 +4162,7 @@ where } } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} /// An iterator over subslices separated by elements that match a predicate diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 2c11d5cd25759..c517286d49898 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -3335,7 +3335,7 @@ impl str { /// .split_inclusive('\n').collect(); /// assert_eq!(v, ["Mary had a little lamb\n", "little lamb\n", "little lamb.\n"]); /// ``` - #[unstable(feature = "split_inclusive", issue = "none")] + #[unstable(feature = "split_inclusive", issue = "72360")] #[inline] pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'a, P> { SplitInclusive(SplitInternal { @@ -4575,7 +4575,7 @@ pub struct SplitAsciiWhitespace<'a> { /// /// [`split_inclusive`]: ../../std/primitive.str.html#method.split_inclusive /// [`str`]: ../../std/primitive.str.html -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] pub struct SplitInclusive<'a, P: Pattern<'a>>(SplitInternal<'a, P>); impl_fn_for_zst! { @@ -4668,7 +4668,7 @@ impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> { #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] impl FusedIterator for SplitAsciiWhitespace<'_> {} -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { type Item = &'a str; @@ -4678,7 +4678,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { } } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitInclusive").field("0", &self.0).finish() @@ -4686,14 +4686,14 @@ impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> { fn clone(&self) -> Self { SplitInclusive(self.0.clone()) } } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator for SplitInclusive<'a, P> { @@ -4703,7 +4703,7 @@ impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator } } -#[unstable(feature = "split_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} /// An iterator of [`u16`] over the string encoded as UTF-16. diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 856387421d90c..5bcd111706f35 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -1322,7 +1322,6 @@ impl<'hir> LoweringContext<'_, 'hir> { "`async` generators are not yet supported" ) .emit(); - return hir::ExprKind::Err; } None => self.generator_kind = Some(hir::GeneratorKind::Gen), } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index c005455a3aab6..d2e53facf5e0a 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1114,16 +1114,13 @@ impl<'tcx> TyCtxt<'tcx> { let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); for (k, v) in resolutions.trait_map { - // FIXME(#71104) Should really be using just `node_id_to_hir_id` but - // some `NodeId` do not seem to have a corresponding HirId. - if let Some(hir_id) = definitions.opt_node_id_to_hir_id(k) { - let map = trait_map.entry(hir_id.owner).or_default(); - let v = v - .into_iter() - .map(|tc| tc.map_import_ids(|id| definitions.node_id_to_hir_id(id))) - .collect(); - map.insert(hir_id.local_id, StableVec::new(v)); - } + let hir_id = definitions.node_id_to_hir_id(k); + let map = trait_map.entry(hir_id.owner).or_default(); + let v = v + .into_iter() + .map(|tc| tc.map_import_ids(|id| definitions.node_id_to_hir_id(id))) + .collect(); + map.insert(hir_id.local_id, StableVec::new(v)); } GlobalCtxt { diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs index 28ec2ca13d5af..9e3f75fdc078c 100644 --- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs @@ -124,8 +124,20 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { traits::NonStructuralMatchTy::Dynamic => { "trait objects cannot be used in patterns".to_string() } + traits::NonStructuralMatchTy::Opaque => { + "opaque types cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Generator => { + "generators cannot be used in patterns".to_string() + } traits::NonStructuralMatchTy::Param => { - bug!("use of constant whose type is a parameter inside a pattern") + bug!("use of a constant whose type is a parameter inside a pattern") + } + traits::NonStructuralMatchTy::Projection => { + bug!("use of a constant whose type is a projection inside a pattern") + } + traits::NonStructuralMatchTy::Foreign => { + bug!("use of a value of a foreign type inside a pattern") } }; diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index bd58e86988a00..b8771d59dd4bd 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -25,6 +25,14 @@ use std::fmt; use super::InferCtxtPrivExt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; +#[derive(Debug)] +pub enum GeneratorInteriorOrUpvar { + // span of interior type + Interior(Span), + // span of upvar + Upvar(Span), +} + // This trait is public to expose the diagnostics methods to clippy. pub trait InferCtxtExt<'tcx> { fn suggest_restricting_param_bound( @@ -128,11 +136,8 @@ pub trait InferCtxtExt<'tcx> { fn note_obligation_cause_for_async_await( &self, err: &mut DiagnosticBuilder<'_>, - target_span: Span, - scope_span: &Option, - await_span: Span, - expr: Option, - snippet: String, + interior_or_upvar_span: GeneratorInteriorOrUpvar, + interior_extra_info: Option<(Option, Span, Option, Option)>, inner_generator_body: Option<&hir::Body<'_>>, outer_generator: Option, trait_ref: ty::TraitRef<'_>, @@ -140,7 +145,6 @@ pub trait InferCtxtExt<'tcx> { tables: &ty::TypeckTables<'_>, obligation: &PredicateObligation<'tcx>, next_code: Option<&ObligationCauseCode<'tcx>>, - from_awaited_ty: Option, ); fn note_obligation_cause_code( @@ -1205,7 +1209,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation.cause.span={:?}", obligation.predicate, obligation.cause.span ); - let source_map = self.tcx.sess.source_map(); let hir = self.tcx.hir(); // Attempt to detect an async-await error by looking at the obligation causes, looking @@ -1354,7 +1357,23 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); eq }; - let target_span = tables + + let mut interior_or_upvar_span = None; + let mut interior_extra_info = None; + + if let Some(upvars) = self.tcx.upvars(generator_did) { + interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| { + let upvar_ty = tables.node_type(*upvar_id); + let upvar_ty = self.resolve_vars_if_possible(&upvar_ty); + if ty_matches(&upvar_ty) { + Some(GeneratorInteriorOrUpvar::Upvar(upvar.span)) + } else { + None + } + }); + }; + + tables .generator_interior_types .iter() .find(|ty::GeneratorInteriorTypeCause { ty, .. }| ty_matches(ty)) @@ -1375,31 +1394,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .map(|expr| expr.span); let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause; - ( - span, - source_map.span_to_snippet(*span), - scope_span, - yield_span, - expr, - from_awaited_ty, - ) + + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span)); + interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty)); }); debug!( - "maybe_note_obligation_cause_for_async_await: target_ty={:?} \ - generator_interior_types={:?} target_span={:?}", - target_ty, tables.generator_interior_types, target_span + "maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \ + generator_interior_types={:?}", + interior_or_upvar_span, tables.generator_interior_types ); - if let Some((target_span, Ok(snippet), scope_span, yield_span, expr, from_awaited_ty)) = - target_span - { + if let Some(interior_or_upvar_span) = interior_or_upvar_span { self.note_obligation_cause_for_async_await( err, - *target_span, - scope_span, - *yield_span, - *expr, - snippet, + interior_or_upvar_span, + interior_extra_info, generator_body, outer_generator, trait_ref, @@ -1407,7 +1416,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { tables, obligation, next_code, - from_awaited_ty, ); true } else { @@ -1420,11 +1428,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { fn note_obligation_cause_for_async_await( &self, err: &mut DiagnosticBuilder<'_>, - target_span: Span, - scope_span: &Option, - yield_span: Span, - expr: Option, - snippet: String, + interior_or_upvar_span: GeneratorInteriorOrUpvar, + interior_extra_info: Option<(Option, Span, Option, Option)>, inner_generator_body: Option<&hir::Body<'_>>, outer_generator: Option, trait_ref: ty::TraitRef<'_>, @@ -1432,7 +1437,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { tables: &ty::TypeckTables<'_>, obligation: &PredicateObligation<'tcx>, next_code: Option<&ObligationCauseCode<'tcx>>, - from_awaited_ty: Option, ) { let source_map = self.tcx.sess.source_map(); @@ -1493,46 +1497,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { format!("does not implement `{}`", trait_ref.print_only_trait_path()) }; - if let Some(await_span) = from_awaited_ty { - // The type causing this obligation is one being awaited at await_span. - let mut span = MultiSpan::from_span(await_span); - - span.push_span_label( - await_span, - format!("await occurs here on type `{}`, which {}", target_ty, trait_explanation), - ); - - err.span_note( - span, - &format!( - "future {not_trait} as it awaits another future which {not_trait}", - not_trait = trait_explanation - ), - ); - } else { - // Look at the last interior type to get a span for the `.await`. - debug!( - "note_obligation_cause_for_async_await generator_interior_types: {:#?}", - tables.generator_interior_types - ); + let mut explain_yield = |interior_span: Span, + yield_span: Span, + scope_span: Option| { let mut span = MultiSpan::from_span(yield_span); - span.push_span_label( - yield_span, - format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), - ); - - span.push_span_label( - target_span, - format!("has type `{}` which {}", target_ty, trait_explanation), - ); - - // If available, use the scope span to annotate the drop location. - if let Some(scope_span) = scope_span { + if let Ok(snippet) = source_map.span_to_snippet(interior_span) { span.push_span_label( - source_map.end_point(*scope_span), - format!("`{}` is later dropped here", snippet), + yield_span, + format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), ); + // If available, use the scope span to annotate the drop location. + if let Some(scope_span) = scope_span { + span.push_span_label( + source_map.end_point(scope_span), + format!("`{}` is later dropped here", snippet), + ); + } } + span.push_span_label( + interior_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); err.span_note( span, @@ -1541,48 +1526,90 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { future_or_generator, trait_explanation, an_await_or_yield ), ); - } - - if let Some(expr_id) = expr { - let expr = hir.expect_expr(expr_id); - debug!("target_ty evaluated from {:?}", expr); - - let parent = hir.get_parent_node(expr_id); - if let Some(hir::Node::Expr(e)) = hir.find(parent) { - let parent_span = hir.span(parent); - let parent_did = parent.owner.to_def_id(); - // ```rust - // impl T { - // fn foo(&self) -> i32 {} - // } - // T.foo(); - // ^^^^^^^ a temporary `&T` created inside this method call due to `&self` - // ``` - // - let is_region_borrow = - tables.expr_adjustments(expr).iter().any(|adj| adj.is_region_borrow()); - - // ```rust - // struct Foo(*const u8); - // bar(Foo(std::ptr::null())).await; - // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor. - // ``` - debug!("parent_def_kind: {:?}", self.tcx.def_kind(parent_did)); - let is_raw_borrow_inside_fn_like_call = match self.tcx.def_kind(parent_did) { - DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(), - _ => false, - }; + }; + match interior_or_upvar_span { + GeneratorInteriorOrUpvar::Interior(interior_span) => { + if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info { + if let Some(await_span) = from_awaited_ty { + // The type causing this obligation is one being awaited at await_span. + let mut span = MultiSpan::from_span(await_span); + span.push_span_label( + await_span, + format!( + "await occurs here on type `{}`, which {}", + target_ty, trait_explanation + ), + ); + err.span_note( + span, + &format!( + "future {not_trait} as it awaits another future which {not_trait}", + not_trait = trait_explanation + ), + ); + } else { + // Look at the last interior type to get a span for the `.await`. + debug!( + "note_obligation_cause_for_async_await generator_interior_types: {:#?}", + tables.generator_interior_types + ); + explain_yield(interior_span, yield_span, scope_span); + } - if (tables.is_method_call(e) && is_region_borrow) - || is_raw_borrow_inside_fn_like_call - { - err.span_help( - parent_span, - "consider moving this into a `let` \ + if let Some(expr_id) = expr { + let expr = hir.expect_expr(expr_id); + debug!("target_ty evaluated from {:?}", expr); + + let parent = hir.get_parent_node(expr_id); + if let Some(hir::Node::Expr(e)) = hir.find(parent) { + let parent_span = hir.span(parent); + let parent_did = parent.owner.to_def_id(); + // ```rust + // impl T { + // fn foo(&self) -> i32 {} + // } + // T.foo(); + // ^^^^^^^ a temporary `&T` created inside this method call due to `&self` + // ``` + // + let is_region_borrow = tables + .expr_adjustments(expr) + .iter() + .any(|adj| adj.is_region_borrow()); + + // ```rust + // struct Foo(*const u8); + // bar(Foo(std::ptr::null())).await; + // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor. + // ``` + debug!("parent_def_kind: {:?}", self.tcx.def_kind(parent_did)); + let is_raw_borrow_inside_fn_like_call = + match self.tcx.def_kind(parent_did) { + DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(), + _ => false, + }; + + if (tables.is_method_call(e) && is_region_borrow) + || is_raw_borrow_inside_fn_like_call + { + err.span_help( + parent_span, + "consider moving this into a `let` \ binding to create a shorter lived borrow", - ); + ); + } + } + } } } + GeneratorInteriorOrUpvar::Upvar(upvar_span) => { + let mut span = MultiSpan::from_span(upvar_span); + span.push_span_label( + upvar_span, + format!("has type `{}` which {}", target_ty, trait_explanation), + ); + err.span_note(span, &format!("captured value {}", trait_explanation)); + } } // Add a note for the item obligation that remains - normally a note pointing to the diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index eb63505b69b41..0b6a60795162f 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -13,6 +13,10 @@ pub enum NonStructuralMatchTy<'tcx> { Adt(&'tcx AdtDef), Param, Dynamic, + Foreign, + Opaque, + Generator, + Projection, } /// This method traverses the structure of `ty`, trying to find an @@ -143,6 +147,22 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { self.found = Some(NonStructuralMatchTy::Dynamic); return true; // Stop visiting. } + ty::Foreign(_) => { + self.found = Some(NonStructuralMatchTy::Foreign); + return true; // Stop visiting. + } + ty::Opaque(..) => { + self.found = Some(NonStructuralMatchTy::Opaque); + return true; // Stop visiting. + } + ty::Projection(..) => { + self.found = Some(NonStructuralMatchTy::Projection); + return true; // Stop visiting. + } + ty::Generator(..) | ty::GeneratorWitness(..) => { + self.found = Some(NonStructuralMatchTy::Generator); + return true; // Stop visiting. + } ty::RawPtr(..) => { // structural-match ignores substructure of // `*const _`/`*mut _`, so skip `super_visit_with`. @@ -159,14 +179,14 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { // structural equality on `T` does not recur into the raw // pointer. Therefore, one can still use `C` in a pattern. - // (But still tell caller to continue search.) + // (But still tell the caller to continue search.) return false; } ty::FnDef(..) | ty::FnPtr(..) => { - // types of formals and return in `fn(_) -> _` are also irrelevant; + // Types of formals and return in `fn(_) -> _` are also irrelevant; // so we do not recur into them via `super_visit_with` // - // (But still tell caller to continue search.) + // (But still tell the caller to continue search.) return false; } ty::Array(_, n) @@ -174,17 +194,44 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { { // rust-lang/rust#62336: ignore type of contents // for empty array. + // + // (But still tell the caller to continue search.) return false; } - _ => { + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { + // These primitive types are always structural match. + // + // `Never` is kind of special here, but as it is not inhabitable, this should be fine. + // + // (But still tell the caller to continue search.) + return false; + } + + ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { + // First check all contained types and then tell the caller to continue searching. ty.super_visit_with(self); return false; } + ty::Closure(..) + | ty::Infer(_) + | ty::Placeholder(_) + | ty::UnnormalizedProjection(..) + | ty::Bound(..) => { + bug!("unexpected type during structural-match checking: {:?}", ty); + } + ty::Error => { + self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check"); + // We still want to check other types after encountering an error, + // as this may still emit relevant errors. + // + // So we continue searching here. + return false; + } }; if !self.seen.insert(adt_def.did) { debug!("Search already seen adt_def: {:?}", adt_def); - // let caller continue its search + // Let caller continue its search. return false; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 9b498d66249e2..9869c50fbb0cf 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2787,3 +2787,9 @@ function focusSearchBar() { function defocusSearchBar() { getSearchInput().blur(); } + +// This is required in firefox. Explanations: when going back in the history, firefox doesn't re-run +// the JS, therefore preventing rustdoc from setting a few things required to be able to reload the +// previous search results (if you navigated to a search result with the keyboard, pressed enter on +// it to navigate to that result, and then came back to this page). +window.onunload = function(){}; diff --git a/src/test/ui/async-await/issue-70818.rs b/src/test/ui/async-await/issue-70818.rs new file mode 100644 index 0000000000000..0609e4fc08170 --- /dev/null +++ b/src/test/ui/async-await/issue-70818.rs @@ -0,0 +1,9 @@ +// edition:2018 + +use std::future::Future; +fn foo(ty: T, ty1: U) -> impl Future + Send { +//~^ Error future cannot be sent between threads safely + async { (ty, ty1) } +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-70818.stderr b/src/test/ui/async-await/issue-70818.stderr new file mode 100644 index 0000000000000..5fb772fa10acb --- /dev/null +++ b/src/test/ui/async-await/issue-70818.stderr @@ -0,0 +1,23 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-70818.rs:4:38 + | +LL | fn foo(ty: T, ty1: U) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` +LL | +LL | async { (ty, ty1) } + | ------------------- this returned value is of type `impl std::future::Future` + | + = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `U` +note: captured value is not `Send` + --> $DIR/issue-70818.rs:6:18 + | +LL | async { (ty, ty1) } + | ^^^ has type `U` which is not `Send` + = note: the return type of a function must have a statically known size +help: consider restricting type parameter `U` + | +LL | fn foo(ty: T, ty1: U) -> impl Future + Send { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs new file mode 100644 index 0000000000000..479d6cd9af765 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs @@ -0,0 +1,20 @@ +#![feature(const_fn, type_alias_impl_trait)] + +type Bar = impl Send; + +// While i32 is structural-match, we do not want to leak this information. +// (See https://github.com/rust-lang/rust/issues/72156) +const fn leak_free() -> Bar { + 7i32 +} +const LEAK_FREE: Bar = leak_free(); + +fn leak_free_test() { + match todo!() { + LEAK_FREE => (), + //~^ opaque types cannot be used in patterns + _ => (), + } +} + +fn main() { } diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr new file mode 100644 index 0000000000000..ae0d8e8d4239c --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr @@ -0,0 +1,8 @@ +error: opaque types cannot be used in patterns + --> $DIR/structural-match-no-leak.rs:14:9 + | +LL | LEAK_FREE => (), + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs new file mode 100644 index 0000000000000..481448d64b1aa --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/structural-match.rs @@ -0,0 +1,21 @@ +#![feature(const_fn, type_alias_impl_trait)] + +type Foo = impl Send; + +// This is not structural-match +struct A; + +const fn value() -> Foo { + A +} +const VALUE: Foo = value(); + +fn test() { + match todo!() { + VALUE => (), + //~^ opaque types cannot be used in patterns + _ => (), + } +} + +fn main() { } diff --git a/src/test/ui/type-alias-impl-trait/structural-match.stderr b/src/test/ui/type-alias-impl-trait/structural-match.stderr new file mode 100644 index 0000000000000..ad9036a87d1d9 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/structural-match.stderr @@ -0,0 +1,8 @@ +error: opaque types cannot be used in patterns + --> $DIR/structural-match.rs:15:9 + | +LL | VALUE => (), + | ^^^^^ + +error: aborting due to previous error +