diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index cb40d4ed9a6df..5bcb11fd515a0 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -480,17 +480,19 @@ impl<'tcx> CPlace<'tcx> { // fn(&T) -> for<'l> fn(&'l T) is allowed } (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { - let from_traits = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from_traits); - let to_traits = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_traits); - assert_eq!( - from_traits, to_traits, - "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", - from_traits, to_traits, fx, - ); + for (from, to) in from_traits.iter().zip(to_traits) { + let from = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); + let to = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to); + assert_eq!( + from, to, + "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", + from_traits, to_traits, fx, + ); + } // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed } _ => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 183fb314a00da..fdec3c9fb7362 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -496,7 +496,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn print_dyn_existential( self, - _predicates: &'tcx ty::List>, + _predicates: &'tcx ty::List>>, ) -> Result { Err(NonTrivialPath) } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 16563d21ff133..bfeef4904893a 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -786,7 +786,7 @@ impl<'tcx> LateContext<'tcx> { fn print_dyn_existential( self, - _predicates: &'tcx ty::List>, + _predicates: &'tcx ty::List>>, ) -> Result { Ok(()) } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 80ef855c3859e..d1a9d518fae87 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -70,7 +70,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{ BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, INVALID_HTML_TAGS, - MISSING_DOC_CODE_EXAMPLES, NON_AUTOLINKS, PRIVATE_DOC_TESTS, + INVALID_RUST_CODEBLOCK, MISSING_DOC_CODE_EXAMPLES, NON_AUTOLINKS, PRIVATE_DOC_TESTS, }; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -320,6 +320,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS, INVALID_CODEBLOCK_ATTRIBUTES, + INVALID_RUST_CODEBLOCK, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, INVALID_HTML_TAGS diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 2a5ad5e6c98a6..5e1f94c071c65 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -218,8 +218,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } ty::Dynamic(binder, _) => { let mut has_emitted = false; - for predicate in binder.skip_binder().iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = + predicate.skip_binder() + { let def_id = trait_ref.def_id; let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post,); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a9358c9610a5e..76fe3a55e7112 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1847,6 +1847,18 @@ declare_lint! { "codeblock attribute looks a lot like a known one" } +declare_lint! { + /// The `invalid_rust_codeblock` lint detects Rust code blocks in + /// documentation examples that are invalid (e.g. empty, not parsable as + /// Rust code). This is a `rustdoc` only lint, see the documentation in the + /// [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_rust_codeblock + pub INVALID_RUST_CODEBLOCK, + Warn, + "codeblock could not be parsed as valid Rust or is empty" +} + declare_lint! { /// The `missing_crate_level_docs` lint detects if documentation is /// missing at the crate root. This is a `rustdoc` only lint, see the @@ -2847,6 +2859,7 @@ declare_lint_pass! { BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS, INVALID_CODEBLOCK_ATTRIBUTES, + INVALID_RUST_CODEBLOCK, MISSING_CRATE_LEVEL_DOCS, MISSING_DOC_CODE_EXAMPLES, INVALID_HTML_TAGS, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 7b67d15f64a2e..4dfe3e8487762 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -319,10 +319,6 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { self.opaque.position() } - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - fn type_shorthands(&mut self) -> &mut FxHashMap, usize> { &mut self.type_shorthands } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index bcf85797313f2..80b58642136ee 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -132,7 +132,6 @@ pub use self::pointer::{Pointer, PointerArithmetic}; /// Uniquely identifies one of the following: /// - A constant /// - A static -/// - A const fn where all arguments (if any) are zero-sized types #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, Lift)] pub struct GlobalId<'tcx> { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index b2fc3710cd673..df594690215bd 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -69,7 +69,6 @@ impl OpaqueEncoder for rustc_serialize::opaque::Encoder { pub trait TyEncoder<'tcx>: Encoder { const CLEAR_CROSS_CRATE: bool; - fn tcx(&self) -> TyCtxt<'tcx>; fn position(&self) -> usize; fn type_shorthands(&mut self) -> &mut FxHashMap, usize>; fn predicate_shorthands(&mut self) -> &mut FxHashMap, usize>; @@ -321,10 +320,14 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> + for ty::List>> +{ fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { let len = decoder.read_usize()?; - Ok(decoder.tcx().mk_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) + Ok(decoder + .tcx() + .mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?) } } @@ -373,7 +376,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::N impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List>, - &'tcx ty::List>, + &'tcx ty::List>>, &'tcx Allocation, &'tcx mir::Body<'tcx>, &'tcx mir::UnsafetyCheckResult, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a8d007c0be27d..adf02412b96d3 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -87,7 +87,7 @@ pub struct CtxtInterners<'tcx> { substs: InternedSet<'tcx, InternalSubsts<'tcx>>, canonical_var_infos: InternedSet<'tcx, List>>, region: InternedSet<'tcx, RegionKind>, - existential_predicates: InternedSet<'tcx, List>>, + poly_existential_predicates: InternedSet<'tcx, List>>>, predicate: InternedSet<'tcx, PredicateInner<'tcx>>, predicates: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, @@ -103,7 +103,7 @@ impl<'tcx> CtxtInterners<'tcx> { type_list: Default::default(), substs: Default::default(), region: Default::default(), - existential_predicates: Default::default(), + poly_existential_predicates: Default::default(), canonical_var_infos: Default::default(), predicate: Default::default(), predicates: Default::default(), @@ -1623,7 +1623,7 @@ nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>} nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} -nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>} +nop_list_lift! {poly_existential_predicates; ty::Binder> => ty::Binder>} nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>} nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>} nop_list_lift! {projs; ProjectionKind => ProjectionKind} @@ -2064,7 +2064,8 @@ slice_interners!( type_list: _intern_type_list(Ty<'tcx>), substs: _intern_substs(GenericArg<'tcx>), canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo<'tcx>), - existential_predicates: _intern_existential_predicates(ExistentialPredicate<'tcx>), + poly_existential_predicates: + _intern_poly_existential_predicates(ty::Binder>), predicates: _intern_predicates(Predicate<'tcx>), projs: _intern_projs(ProjectionKind), place_elems: _intern_place_elems(PlaceElem<'tcx>), @@ -2295,7 +2296,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_dynamic( self, - obj: ty::Binder<&'tcx List>>, + obj: &'tcx List>>, reg: ty::Region<'tcx>, ) -> Ty<'tcx> { self.mk_ty(Dynamic(obj, reg)) @@ -2425,13 +2426,17 @@ impl<'tcx> TyCtxt<'tcx> { Place { local: place.local, projection: self.intern_place_elems(&projection) } } - pub fn intern_existential_predicates( + pub fn intern_poly_existential_predicates( self, - eps: &[ExistentialPredicate<'tcx>], - ) -> &'tcx List> { + eps: &[ty::Binder>], + ) -> &'tcx List>> { assert!(!eps.is_empty()); - assert!(eps.array_windows().all(|[a, b]| a.stable_cmp(self, b) != Ordering::Greater)); - self._intern_existential_predicates(eps) + assert!( + eps.array_windows() + .all(|[a, b]| a.skip_binder().stable_cmp(self, &b.skip_binder()) + != Ordering::Greater) + ); + self._intern_poly_existential_predicates(eps) } pub fn intern_predicates(self, preds: &[Predicate<'tcx>]) -> &'tcx List> { @@ -2488,13 +2493,16 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn mk_existential_predicates< - I: InternAs<[ExistentialPredicate<'tcx>], &'tcx List>>, + pub fn mk_poly_existential_predicates< + I: InternAs< + [ty::Binder>], + &'tcx List>>, + >, >( self, iter: I, ) -> I::Output { - iter.intern_with(|xs| self.intern_existential_predicates(xs)) + iter.intern_with(|xs| self.intern_poly_existential_predicates(xs)) } pub fn mk_predicates], &'tcx List>>>( diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 5ec0ec0c56ad6..97af927dfcba2 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -58,7 +58,7 @@ pub enum TypeError<'tcx> { CyclicTy(Ty<'tcx>), CyclicConst(&'tcx ty::Const<'tcx>), ProjectionMismatched(ExpectedFound), - ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), + ExistentialMismatch(ExpectedFound<&'tcx ty::List>>>), ObjectUnsafeCoercion(DefId), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 8b97a87f214b8..4de3d15924862 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -160,19 +160,15 @@ impl FlagComputation { } &ty::Dynamic(obj, r) => { - self.bound_computation(obj, |computation, obj| { - for predicate in obj.iter() { - match predicate { - ty::ExistentialPredicate::Trait(tr) => { - computation.add_substs(tr.substs) - } - ty::ExistentialPredicate::Projection(p) => { - computation.add_existential_projection(&p); - } - ty::ExistentialPredicate::AutoTrait(_) => {} + for predicate in obj.iter() { + self.bound_computation(predicate, |computation, predicate| match predicate { + ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), + ty::ExistentialPredicate::Projection(p) => { + computation.add_existential_projection(&p); } - } - }); + ty::ExistentialPredicate::AutoTrait(_) => {} + }); + } self.add_region(r); } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 2e00be2395b8c..c79e06b7fdd32 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -63,7 +63,7 @@ pub trait Printer<'tcx>: Sized { fn print_dyn_existential( self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result; fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result; @@ -343,7 +343,9 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { } } -impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::List> { +impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> + for &'tcx ty::List>> +{ type Output = P::DynExistential; type Error = P::Error; fn print(&self, cx: P) -> Result { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 38f8e779f6a92..09ef69e9690ab 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -209,6 +209,17 @@ pub trait PrettyPrinter<'tcx>: value.as_ref().skip_binder().print(self) } + fn wrap_binder Result>( + self, + value: &ty::Binder, + f: F, + ) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, + { + f(value.as_ref().skip_binder(), self) + } + /// Prints comma-separated elements. fn comma_sep(mut self, mut elems: impl Iterator) -> Result where @@ -753,72 +764,77 @@ pub trait PrettyPrinter<'tcx>: fn pretty_print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { - define_scoped_cx!(self); - // Generate the main trait ref, including associated types. let mut first = true; if let Some(principal) = predicates.principal() { - p!(print_def_path(principal.def_id, &[])); - - let mut resugared = false; - - // Special-case `Fn(...) -> ...` and resugar it. - let fn_trait_kind = self.tcx().fn_trait_kind_from_lang_item(principal.def_id); - if !self.tcx().sess.verbose() && fn_trait_kind.is_some() { - if let ty::Tuple(ref args) = principal.substs.type_at(0).kind() { - let mut projections = predicates.projection_bounds(); - if let (Some(proj), None) = (projections.next(), projections.next()) { - let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); - p!(pretty_fn_sig(&tys, false, proj.ty)); - resugared = true; + self = self.wrap_binder(&principal, |principal, mut cx| { + define_scoped_cx!(cx); + p!(print_def_path(principal.def_id, &[])); + + let mut resugared = false; + + // Special-case `Fn(...) -> ...` and resugar it. + let fn_trait_kind = cx.tcx().fn_trait_kind_from_lang_item(principal.def_id); + if !cx.tcx().sess.verbose() && fn_trait_kind.is_some() { + if let ty::Tuple(ref args) = principal.substs.type_at(0).kind() { + let mut projections = predicates.projection_bounds(); + if let (Some(proj), None) = (projections.next(), projections.next()) { + let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); + p!(pretty_fn_sig(&tys, false, proj.skip_binder().ty)); + resugared = true; + } } } - } - // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, - // in order to place the projections inside the `<...>`. - if !resugared { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = self.tcx().mk_ty_infer(ty::FreshTy(0)); - let principal = principal.with_self_ty(self.tcx(), dummy_self); + // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, + // in order to place the projections inside the `<...>`. + if !resugared { + // Use a type that can't appear in defaults of type parameters. + let dummy_cx = cx.tcx().mk_ty_infer(ty::FreshTy(0)); + let principal = principal.with_self_ty(cx.tcx(), dummy_cx); + + let args = cx.generic_args_to_print( + cx.tcx().generics_of(principal.def_id), + principal.substs, + ); + + // Don't print `'_` if there's no unerased regions. + let print_regions = args.iter().any(|arg| match arg.unpack() { + GenericArgKind::Lifetime(r) => *r != ty::ReErased, + _ => false, + }); + let mut args = args.iter().cloned().filter(|arg| match arg.unpack() { + GenericArgKind::Lifetime(_) => print_regions, + _ => true, + }); + let mut projections = predicates.projection_bounds(); - let args = self.generic_args_to_print( - self.tcx().generics_of(principal.def_id), - principal.substs, - ); + let arg0 = args.next(); + let projection0 = projections.next(); + if arg0.is_some() || projection0.is_some() { + let args = arg0.into_iter().chain(args); + let projections = projection0.into_iter().chain(projections); - // Don't print `'_` if there's no unerased regions. - let print_regions = args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Lifetime(r) => *r != ty::ReErased, - _ => false, - }); - let mut args = args.iter().cloned().filter(|arg| match arg.unpack() { - GenericArgKind::Lifetime(_) => print_regions, - _ => true, - }); - let mut projections = predicates.projection_bounds(); - - let arg0 = args.next(); - let projection0 = projections.next(); - if arg0.is_some() || projection0.is_some() { - let args = arg0.into_iter().chain(args); - let projections = projection0.into_iter().chain(projections); - - p!(generic_delimiters(|mut cx| { - cx = cx.comma_sep(args)?; - if arg0.is_some() && projection0.is_some() { - write!(cx, ", ")?; - } - cx.comma_sep(projections) - })); + p!(generic_delimiters(|mut cx| { + cx = cx.comma_sep(args)?; + if arg0.is_some() && projection0.is_some() { + write!(cx, ", ")?; + } + cx.comma_sep(projections) + })); + } } - } + Ok(cx) + })?; + first = false; } + define_scoped_cx!(self); + // Builtin bounds. // FIXME(eddyb) avoid printing twice (needed to ensure // that the auto traits are sorted *and* printed via cx). @@ -1391,7 +1407,7 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { fn print_dyn_existential( self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { self.pretty_print_dyn_existential(predicates) } @@ -1537,6 +1553,17 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { self.pretty_in_binder(value) } + fn wrap_binder Result>( + self, + value: &ty::Binder, + f: C, + ) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, + { + self.pretty_wrap_binder(value, f) + } + fn typed_value( mut self, f: impl FnOnce(Self) -> Result, @@ -1790,6 +1817,22 @@ impl FmtPrinter<'_, 'tcx, F> { Ok(inner) } + pub fn pretty_wrap_binder Result>( + self, + value: &ty::Binder, + f: C, + ) -> Result + where + T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>, + { + let old_region_index = self.region_index; + let (new, new_value) = self.name_all_regions(value)?; + let mut inner = f(&new_value.0, new)?; + inner.region_index = old_region_index; + inner.binder_depth -= 1; + Ok(inner) + } + fn prepare_late_bound_region_info(&mut self, value: &ty::Binder) where T: TypeFoldable<'tcx>, @@ -1906,12 +1949,12 @@ impl ty::Binder> { forward_display_to_print! { Ty<'tcx>, - &'tcx ty::List>, + &'tcx ty::List>>, &'tcx ty::Const<'tcx>, // HACK(eddyb) these are exhaustive instead of generic, // because `for<'tcx>` isn't possible yet. - ty::Binder<&'tcx ty::List>>, + ty::Binder>, ty::Binder>, ty::Binder>, ty::Binder>, diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 3eed94b1ffbc0..e006dfeb66336 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -1044,9 +1044,6 @@ where { const CLEAR_CROSS_CRATE: bool = false; - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } fn position(&self) -> usize { self.encoder.encoder_position() } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index ef5034e218da4..af7fc42971954 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -603,7 +603,7 @@ pub fn super_relate_consts>( new_const_val.map(|val| tcx.mk_const(ty::Const { val, ty: a.ty })) } -impl<'tcx> Relate<'tcx> for &'tcx ty::List> { +impl<'tcx> Relate<'tcx> for &'tcx ty::List>> { fn relate>( relation: &mut R, a: Self, @@ -616,9 +616,10 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { // in `a`. let mut a_v: Vec<_> = a.into_iter().collect(); let mut b_v: Vec<_> = b.into_iter().collect(); - a_v.sort_by(|a, b| a.stable_cmp(tcx, b)); + // `skip_binder` here is okay because `stable_cmp` doesn't look at binders + a_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); a_v.dedup(); - b_v.sort_by(|a, b| a.stable_cmp(tcx, b)); + b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); b_v.dedup(); if a_v.len() != b_v.len() { return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))); @@ -626,14 +627,18 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { let v = a_v.into_iter().zip(b_v.into_iter()).map(|(ep_a, ep_b)| { use crate::ty::ExistentialPredicate::*; - match (ep_a, ep_b) { - (Trait(a), Trait(b)) => Ok(Trait(relation.relate(a, b)?)), - (Projection(a), Projection(b)) => Ok(Projection(relation.relate(a, b)?)), - (AutoTrait(a), AutoTrait(b)) if a == b => Ok(AutoTrait(a)), + match (ep_a.skip_binder(), ep_b.skip_binder()) { + (Trait(a), Trait(b)) => Ok(ty::Binder::bind(Trait( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + (Projection(a), Projection(b)) => Ok(ty::Binder::bind(Projection( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + (AutoTrait(a), AutoTrait(b)) if a == b => Ok(ep_a.rebind(AutoTrait(a))), _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))), } }); - Ok(tcx.mk_existential_predicates(v)?) + Ok(tcx.mk_poly_existential_predicates(v)?) } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 94e69a93a6b18..8af5792b3fb68 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -843,9 +843,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List>> { fn super_fold_with>(self, folder: &mut F) -> Self { - ty::util::fold_list(self, folder, |tcx, v| tcx.intern_existential_predicates(v)) + ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v)) } fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index fc9dcdf1775e6..62d1dda37d675 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -152,7 +152,7 @@ pub enum TyKind<'tcx> { FnPtr(PolyFnSig<'tcx>), /// A trait, defined with `trait`. - Dynamic(Binder<&'tcx List>>, ty::Region<'tcx>), + Dynamic(&'tcx List>>, ty::Region<'tcx>), /// The anonymous type of a closure. Used to represent the type of /// `|a| a`. @@ -762,7 +762,7 @@ impl<'tcx> Binder> { } } -impl<'tcx> List> { +impl<'tcx> List>> { /// Returns the "principal `DefId`" of this set of existential predicates. /// /// A Rust trait object type consists (in addition to a lifetime bound) @@ -788,64 +788,42 @@ impl<'tcx> List> { /// is `{Send, Sync}`, while there is no principal. These trait objects /// have a "trivial" vtable consisting of just the size, alignment, /// and destructor. - pub fn principal(&self) -> Option> { - match self[0] { - ExistentialPredicate::Trait(tr) => Some(tr), - _ => None, - } + pub fn principal(&self) -> Option>> { + self[0] + .map_bound(|this| match this { + ExistentialPredicate::Trait(tr) => Some(tr), + _ => None, + }) + .transpose() } pub fn principal_def_id(&self) -> Option { - self.principal().map(|trait_ref| trait_ref.def_id) + self.principal().map(|trait_ref| trait_ref.skip_binder().def_id) } #[inline] pub fn projection_bounds<'a>( &'a self, - ) -> impl Iterator> + 'a { - self.iter().filter_map(|predicate| match predicate { - ExistentialPredicate::Projection(projection) => Some(projection), - _ => None, + ) -> impl Iterator>> + 'a { + self.iter().filter_map(|predicate| { + predicate + .map_bound(|pred| match pred { + ExistentialPredicate::Projection(projection) => Some(projection), + _ => None, + }) + .transpose() }) } #[inline] pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { - self.iter().filter_map(|predicate| match predicate { + self.iter().filter_map(|predicate| match predicate.skip_binder() { ExistentialPredicate::AutoTrait(did) => Some(did), _ => None, }) } } -impl<'tcx> Binder<&'tcx List>> { - pub fn principal(&self) -> Option>> { - self.map_bound(|b| b.principal()).transpose() - } - - pub fn principal_def_id(&self) -> Option { - self.skip_binder().principal_def_id() - } - - #[inline] - pub fn projection_bounds<'a>( - &'a self, - ) -> impl Iterator> + 'a { - self.skip_binder().projection_bounds().map(Binder::bind) - } - - #[inline] - pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { - self.skip_binder().auto_traits() - } - - pub fn iter<'a>( - &'a self, - ) -> impl DoubleEndedIterator>> + 'tcx { - self.skip_binder().iter().map(Binder::bind) - } -} - /// A complete reference to a trait. These take numerous guises in syntax, /// but perhaps the most recognizable form is in a where-clause: /// diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 6e09ae4340645..f13b4b7b91924 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -31,6 +31,19 @@ fn eval_body_using_ecx<'mir, 'tcx>( ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); let tcx = *ecx.tcx; + assert!( + cid.promoted.is_some() + || matches!( + ecx.tcx.def_kind(cid.instance.def_id()), + DefKind::Const + | DefKind::Static + | DefKind::ConstParam + | DefKind::AnonConst + | DefKind::AssocConst + ), + "Unexpected DefKind: {:?}", + ecx.tcx.def_kind(cid.instance.def_id()) + ); let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack); @@ -40,15 +53,6 @@ fn eval_body_using_ecx<'mir, 'tcx>( let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom); - // Assert all args (if any) are zero-sized types; `eval_body_using_ecx` doesn't - // make sense if the body is expecting nontrivial arguments. - // (The alternative would be to use `eval_fn_call` with an args slice.) - for arg in body.args_iter() { - let decl = body.local_decls.get(arg).expect("arg missing from local_decls"); - let layout = ecx.layout_of(decl.ty.subst(tcx, cid.instance.substs))?; - assert!(layout.is_zst()) - } - ecx.push_stack_frame( cid.instance, body, diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 740c965e591bf..72912dd76ff52 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -1,6 +1,4 @@ use rustc_middle::mir; -use rustc_middle::ty::layout::HasTyCtxt; -use rustc_middle::ty::InstanceDef; use rustc_middle::ty::{self, Ty}; use std::borrow::Borrow; use std::collections::hash_map::Entry; @@ -17,60 +15,13 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{Align, Size}; use crate::interpret::{ - self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx, - InterpResult, Memory, OpTy, PlaceTy, Pointer, Scalar, + self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, Memory, + OpTy, PlaceTy, Pointer, Scalar, }; use super::error::*; impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { - /// Evaluate a const function where all arguments (if any) are zero-sized types. - /// The evaluation is memoized thanks to the query system. - /// - /// Returns `true` if the call has been evaluated. - fn try_eval_const_fn_call( - &mut self, - instance: ty::Instance<'tcx>, - ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, - args: &[OpTy<'tcx>], - ) -> InterpResult<'tcx, bool> { - trace!("try_eval_const_fn_call: {:?}", instance); - // Because `#[track_caller]` adds an implicit non-ZST argument, we also cannot - // perform this optimization on items tagged with it. - if instance.def.requires_caller_location(self.tcx()) { - return Ok(false); - } - // Only memoize instrinsics. This was added in #79594 while adding the `const_allocate` intrinsic. - // We only memoize intrinsics because it would be unsound to memoize functions - // which might interact with the heap. - // Additionally, const_allocate intrinsic is impure and thus should not be memoized; - // it will not be memoized because it has non-ZST args - if !matches!(instance.def, InstanceDef::Intrinsic(_)) { - return Ok(false); - } - // For the moment we only do this for functions which take no arguments - // (or all arguments are ZSTs) so that we don't memoize too much. - if args.iter().any(|a| !a.layout.is_zst()) { - return Ok(false); - } - - let dest = match ret { - Some((dest, _)) => dest, - // Don't memoize diverging function calls. - None => return Ok(false), - }; - - let gid = GlobalId { instance, promoted: None }; - - let place = self.eval_to_allocation(gid)?; - - self.copy_op(place.into(), dest)?; - - self.return_to_block(ret.map(|r| r.1))?; - trace!("{:?}", self.dump_place(*dest)); - Ok(true) - } - /// "Intercept" a function call to a panic-related function /// because we have something special to do for it. /// If this returns successfully (`Ok`), the function should just be evaluated normally. @@ -253,7 +204,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], - ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + _ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, _unwind: Option, // unwinding is not supported in consts ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { debug!("find_mir_or_eval_fn: {:?}", instance); @@ -263,13 +214,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // Execution might have wandered off into other crates, so we cannot do a stability- // sensitive check here. But we can at least rule out functions that are not const // at all. - if ecx.tcx.is_const_fn_raw(def.did) { - // If this function is a `const fn` then under certain circumstances we - // can evaluate call via the query system, thus memoizing all future calls. - if ecx.try_eval_const_fn_call(instance, ret, args)? { - return Ok(None); - } - } else { + if !ecx.tcx.is_const_fn_raw(def.did) { // Some functions we support even if they are non-const -- but avoid testing // that for const fn! ecx.hook_panic_fn(instance, args)?; diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index 554ada1ab254c..e1ec4cc5e973c 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -74,7 +74,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { let mut first = true; for p in predicates { diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 6fbcc140978a7..b16a99d7f0dca 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -284,6 +284,33 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { return None; } + // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially. + // for example, this should not be optimized: + // + // ```rust + // enum E<'a> { Empty, Some(&'a E<'a>), } + // let Some(Some(_)) = e; + // ``` + // + // ```mir + // bb0: { + // _2 = discriminant(*_1) + // switchInt(_2) -> [...] + // } + // bb1: { + // _3 = discriminant(*(((*_1) as Some).0: &E)) + // switchInt(_3) -> [...] + // } + // ``` + let discr_place = discr_info.place_of_adt_discr_read; + let this_discr_place = this_bb_discr_info.place_of_adt_discr_read; + if discr_place.local == this_discr_place.local + && this_discr_place.projection.starts_with(discr_place.projection) + { + trace!("NO: one target is the projection of another"); + return None; + } + // if we reach this point, the optimization applies, and we should be able to optimize this case // store the info that is needed to apply the optimization diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 4414bf57c6b7d..3b4249a93e1fb 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -184,8 +184,8 @@ where ty::Dynamic(predicates, ..) => { // All traits in the list are considered the "primary" part of the type // and are visited by shallow visitors. - for predicate in predicates.skip_binder() { - let trait_ref = match predicate { + for predicate in predicates { + let trait_ref = match predicate.skip_binder() { ty::ExistentialPredicate::Trait(trait_ref) => trait_ref, ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx), ty::ExistentialPredicate::AutoTrait(def_id) => { diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index eba8e1a0613fb..6356a7e783255 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -222,7 +222,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { let mut first = true; for p in predicates { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index c28c2fecfbb43..0294fb23c568c 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -465,9 +465,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { ty::Dynamic(predicates, r) => { self.push("D"); - self = self.in_binder(&predicates, |cx, predicates| { - cx.print_dyn_existential(predicates) - })?; + self = self.print_dyn_existential(predicates)?; self = r.print(self)?; } @@ -486,26 +484,29 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List>, + predicates: &'tcx ty::List>>, ) -> Result { for predicate in predicates { - match predicate { - ty::ExistentialPredicate::Trait(trait_ref) => { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = self.tcx.mk_ty_infer(ty::FreshTy(0)); - let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self); - self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; - } - ty::ExistentialPredicate::Projection(projection) => { - let name = self.tcx.associated_item(projection.item_def_id).ident; - self.push("p"); - self.push_ident(&name.as_str()); - self = projection.ty.print(self)?; - } - ty::ExistentialPredicate::AutoTrait(def_id) => { - self = self.print_def_path(def_id, &[])?; + self = self.in_binder(&predicate, |mut cx, predicate| { + match predicate { + ty::ExistentialPredicate::Trait(trait_ref) => { + // Use a type that can't appear in defaults of type parameters. + let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0)); + let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self); + cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?; + } + ty::ExistentialPredicate::Projection(projection) => { + let name = cx.tcx.associated_item(projection.item_def_id).ident; + cx.push("p"); + cx.push_ident(&name.as_str()); + cx = projection.ty.print(cx)?; + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + cx = cx.print_def_path(*def_id, &[])?; + } } - } + Ok(cx) + })?; } self.push("E"); Ok(self) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 1b5375938af6d..69f66f6e6b1aa 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -219,8 +219,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } if let ty::Dynamic(traits, _) = self_ty.kind() { - for t in traits.skip_binder() { - if let ty::ExistentialPredicate::Trait(trait_ref) = t { + for t in traits.iter() { + if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index d912a00d6b702..8b275db89f191 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -551,8 +551,9 @@ fn object_ty_for_trait<'tcx>( let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); - let trait_predicate = - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait( + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), + )); let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) .flat_map(|super_trait_ref| { @@ -569,24 +570,19 @@ fn object_ty_for_trait<'tcx>( let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| { // We *can* get bound lifetimes here in cases like // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. - // - // binder moved to (*)... - let super_trait_ref = super_trait_ref.skip_binder(); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - ty: tcx.mk_projection(item.def_id, super_trait_ref.substs), - item_def_id: item.def_id, - substs: super_trait_ref.substs, + super_trait_ref.map_bound(|super_trait_ref| { + ty::ExistentialPredicate::Projection(ty::ExistentialProjection { + ty: tcx.mk_projection(item.def_id, super_trait_ref.substs), + item_def_id: item.def_id, + substs: super_trait_ref.substs, + }) }) }); - let existential_predicates = - tcx.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); + let existential_predicates = tcx + .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - let object_ty = tcx.mk_dynamic( - // (*) ... binder re-introduced here - ty::Binder::bind(existential_predicates), - lifetime, - ); + let object_ty = tcx.mk_dynamic(existential_predicates, lifetime); debug!("object_ty_for_trait: object_ty=`{}`", object_ty); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index ed22d5849e2b1..ab09fcfd8cc7b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -375,24 +375,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty()); let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref); let data = match *self_ty.kind() { - ty::Dynamic(data, ..) => { - self.infcx - .replace_bound_vars_with_fresh_vars( - obligation.cause.span, - HigherRankedType, - data, - ) - .0 - } + ty::Dynamic(data, ..) => data, _ => span_bug!(obligation.cause.span, "object candidate with non-object"), }; - let object_trait_ref = data - .principal() - .unwrap_or_else(|| { - span_bug!(obligation.cause.span, "object candidate with no principal") - }) - .with_self_ty(self.tcx(), self_ty); + let object_trait_ref = data.principal().unwrap_or_else(|| { + span_bug!(obligation.cause.span, "object candidate with no principal") + }); + let object_trait_ref = self + .infcx + .replace_bound_vars_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + object_trait_ref, + ) + .0; + let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty); let mut nested = vec![]; @@ -711,15 +709,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { // See `assemble_candidates_for_unsizing` for more info. - let existential_predicates = data_a.map_bound(|data_a| { - let iter = data_a - .principal() - .map(ty::ExistentialPredicate::Trait) - .into_iter() - .chain(data_a.projection_bounds().map(ty::ExistentialPredicate::Projection)) - .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); - tcx.mk_existential_predicates(iter) - }); + let iter = data_a + .principal() + .map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) + .into_iter() + .chain( + data_a + .projection_bounds() + .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), + ) + .chain( + data_b + .auto_traits() + .map(ty::ExistentialPredicate::AutoTrait) + .map(ty::Binder::dummy), + ); + let existential_predicates = tcx.mk_poly_existential_predicates(iter); let source_trait = tcx.mk_dynamic(existential_predicates, r_b); // Require that the traits involved in this upcast are **equal**; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 5bcb16d21e09c..3f58fd72f409c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -706,7 +706,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { fn from_object_ty( &mut self, ty: Ty<'tcx>, - data: ty::Binder<&'tcx ty::List>>, + data: &'tcx ty::List>>, region: ty::Region<'tcx>, ) { // Imagine a type like this: @@ -769,7 +769,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// `infer::required_region_bounds`, see that for more information. pub fn object_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, - existential_predicates: ty::Binder<&'tcx ty::List>>, + existential_predicates: &'tcx ty::List>>, ) -> Vec> { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 9afb980f84d27..3a747b09cd4c4 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -615,7 +615,7 @@ impl<'tcx> LowerInto<'tcx, Option LowerInto<'tcx, chalk_ir::Binders>>> - for Binder<&'tcx ty::List>> + for &'tcx ty::List>> { fn lower_into( self, @@ -627,48 +627,53 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders>]> // This means that any variables that are escaping `self` need to be // shifted in by one so that they are still escaping. - let shifted_predicates = ty::fold::shift_vars(interner.tcx, self, 1); + let predicates = ty::fold::shift_vars(interner.tcx, self, 1); - let (predicates, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, shifted_predicates); let self_ty = interner.tcx.mk_ty(ty::Bound( // This is going to be wrapped in a binder ty::DebruijnIndex::from_usize(1), ty::BoundTy { var: ty::BoundVar::from_usize(0), kind: ty::BoundTyKind::Anon }, )); - let where_clauses = predicates.into_iter().map(|predicate| match predicate { - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => { - chalk_ir::Binders::new( + let where_clauses = predicates.into_iter().map(|predicate| { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, predicate); + match predicate { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => { + chalk_ir::Binders::new( + binders.clone(), + chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { + trait_id: chalk_ir::TraitId(def_id), + substitution: interner + .tcx + .mk_substs_trait(self_ty, substs) + .lower_into(interner), + }), + ) + } + ty::ExistentialPredicate::Projection(predicate) => chalk_ir::Binders::new( + binders.clone(), + chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { + alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { + associated_ty_id: chalk_ir::AssocTypeId(predicate.item_def_id), + substitution: interner + .tcx + .mk_substs_trait(self_ty, predicate.substs) + .lower_into(interner), + }), + ty: predicate.ty.lower_into(interner), + }), + ), + ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new( binders.clone(), chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { trait_id: chalk_ir::TraitId(def_id), substitution: interner .tcx - .mk_substs_trait(self_ty, substs) + .mk_substs_trait(self_ty, &[]) .lower_into(interner), }), - ) + ), } - ty::ExistentialPredicate::Projection(predicate) => chalk_ir::Binders::new( - binders.clone(), - chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { - alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id: chalk_ir::AssocTypeId(predicate.item_def_id), - substitution: interner - .tcx - .mk_substs_trait(self_ty, predicate.substs) - .lower_into(interner), - }), - ty: predicate.ty.lower_into(interner), - }), - ), - ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new( - binders.clone(), - chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { - trait_id: chalk_ir::TraitId(def_id), - substitution: interner.tcx.mk_substs_trait(self_ty, &[]).lower_into(interner), - }), - ), }); // Binder for the bound variable representing the concrete underlying type. diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 7888cb1b9f599..693cd236299a8 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1254,22 +1254,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) }); - // Calling `skip_binder` is okay because the predicates are re-bound. - let regular_trait_predicates = existential_trait_refs - .map(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref.skip_binder())); - let auto_trait_predicates = auto_traits - .into_iter() - .map(|trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())); + let regular_trait_predicates = existential_trait_refs.map(|trait_ref| { + trait_ref.map_bound(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref)) + }); + let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { + ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) + }); let mut v = regular_trait_predicates .chain(auto_trait_predicates) .chain( existential_projections - .map(|x| ty::ExistentialPredicate::Projection(x.skip_binder())), + .map(|x| x.map_bound(|x| ty::ExistentialPredicate::Projection(x))), ) .collect::>(); - v.sort_by(|a, b| a.stable_cmp(tcx, b)); + v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); v.dedup(); - let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter())); + let existential_predicates = tcx.mk_poly_existential_predicates(v.into_iter()); // Use explicitly-specified region bound. let region_bound = if !lifetime.is_elided() { @@ -2331,7 +2331,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn compute_object_lifetime_bound( &self, span: Span, - existential_predicates: ty::Binder<&'tcx ty::List>>, + existential_predicates: &'tcx ty::List>>, ) -> Option> // if None, use the default { let tcx = self.tcx(); diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 7ed2933c08bbf..369db87360b1e 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -619,8 +619,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)), // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _) => { - for pred in preds.skip_binder() { - match pred { + for pred in preds.iter() { + match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => { bound_spans.push((def_span(tr.def_id), msg.clone())) } @@ -673,9 +673,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .filter_map(|(pred, parent_pred)| { format_pred(*pred).map(|(p, self_ty)| match parent_pred { - None => format!("`{}`", p), + None => format!("`{}`", &p), Some(parent_pred) => match format_pred(*parent_pred) { - None => format!("`{}`", p), + None => format!("`{}`", &p), Some((parent_p, _)) => { collect_type_param_suggestions(self_ty, parent_pred, &p); format!("`{}`\nwhich is required by `{}`", p, parent_p) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 0fec2b70a855e..22e179af4a932 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -1355,66 +1355,65 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { /// /// Panics unless we `.can_merge()`. pub fn merge( - mut self, + self, track_edge_idx: Option>, ) -> Handle, K, V, marker::LeafOrInternal>, marker::Edge> { + let Handle { node: mut parent_node, idx: parent_idx, _marker } = self.parent; + let old_parent_len = parent_node.len(); let mut left_node = self.left_child; - let left_len = left_node.len(); + let old_left_len = left_node.len(); let right_node = self.right_child; let right_len = right_node.len(); + let new_left_len = old_left_len + 1 + right_len; - assert!(left_len + right_len < CAPACITY); + assert!(new_left_len <= CAPACITY); assert!(match track_edge_idx { None => true, - Some(LeftOrRight::Left(idx)) => idx <= left_len, + Some(LeftOrRight::Left(idx)) => idx <= old_left_len, Some(LeftOrRight::Right(idx)) => idx <= right_len, }); unsafe { - *left_node.reborrow_mut().into_len_mut() += right_len as u16 + 1; + *left_node.reborrow_mut().into_len_mut() = new_left_len as u16; - let parent_key = slice_remove( - self.parent.node.reborrow_mut().into_key_area_slice(), - self.parent.idx, - ); - left_node.reborrow_mut().into_key_area_mut_at(left_len).write(parent_key); + let parent_key = + slice_remove(parent_node.reborrow_mut().into_key_area_slice(), parent_idx); + left_node.reborrow_mut().into_key_area_mut_at(old_left_len).write(parent_key); ptr::copy_nonoverlapping( right_node.reborrow().key_area().as_ptr(), - left_node.reborrow_mut().into_key_area_slice().as_mut_ptr().add(left_len + 1), + left_node.reborrow_mut().into_key_area_slice().as_mut_ptr().add(old_left_len + 1), right_len, ); - let parent_val = slice_remove( - self.parent.node.reborrow_mut().into_val_area_slice(), - self.parent.idx, - ); - left_node.reborrow_mut().into_val_area_mut_at(left_len).write(parent_val); + let parent_val = + slice_remove(parent_node.reborrow_mut().into_val_area_slice(), parent_idx); + left_node.reborrow_mut().into_val_area_mut_at(old_left_len).write(parent_val); ptr::copy_nonoverlapping( right_node.reborrow().val_area().as_ptr(), - left_node.reborrow_mut().into_val_area_slice().as_mut_ptr().add(left_len + 1), + left_node.reborrow_mut().into_val_area_slice().as_mut_ptr().add(old_left_len + 1), right_len, ); - slice_remove( - &mut self.parent.node.reborrow_mut().into_edge_area_slice(), - self.parent.idx + 1, - ); - let parent_old_len = self.parent.node.len(); - self.parent.node.correct_childrens_parent_links(self.parent.idx + 1..parent_old_len); - *self.parent.node.reborrow_mut().into_len_mut() -= 1; + slice_remove(&mut parent_node.reborrow_mut().into_edge_area_slice(), parent_idx + 1); + parent_node.correct_childrens_parent_links(parent_idx + 1..old_parent_len); + *parent_node.reborrow_mut().into_len_mut() -= 1; - if self.parent.node.height > 1 { + if parent_node.height > 1 { // SAFETY: the height of the nodes being merged is one below the height // of the node of this edge, thus above zero, so they are internal. let mut left_node = left_node.reborrow_mut().cast_to_internal_unchecked(); let right_node = right_node.cast_to_internal_unchecked(); ptr::copy_nonoverlapping( right_node.reborrow().edge_area().as_ptr(), - left_node.reborrow_mut().into_edge_area_slice().as_mut_ptr().add(left_len + 1), + left_node + .reborrow_mut() + .into_edge_area_slice() + .as_mut_ptr() + .add(old_left_len + 1), right_len + 1, ); - left_node.correct_childrens_parent_links(left_len + 1..=left_len + 1 + right_len); + left_node.correct_childrens_parent_links(old_left_len + 1..new_left_len + 1); Global.deallocate(right_node.node.cast(), Layout::new::>()); } else { @@ -1424,7 +1423,7 @@ impl<'a, K: 'a, V: 'a> BalancingContext<'a, K, V> { let new_idx = match track_edge_idx { None => 0, Some(LeftOrRight::Left(idx)) => idx, - Some(LeftOrRight::Right(idx)) => left_len + 1 + idx, + Some(LeftOrRight::Right(idx)) => old_left_len + 1 + idx, }; Handle::new_edge(left_node, new_idx) } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index d8ce47ed77d1f..f63c3dd580408 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -679,7 +679,7 @@ impl BTreeSet { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn pop_first(&mut self) -> Option { - self.map.first_entry().map(|entry| entry.remove_entry().0) + self.map.pop_first().map(|kv| kv.0) } /// Removes the last value from the set and returns it, if any. @@ -701,7 +701,7 @@ impl BTreeSet { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn pop_last(&mut self) -> Option { - self.map.last_entry().map(|entry| entry.remove_entry().0) + self.map.pop_last().map(|kv| kv.0) } /// Adds a value to the set. diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 57807bc545390..9e54c15ea6a0b 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2793,8 +2793,12 @@ impl From> for VecDeque { let len = other.len(); // We need to extend the buf if it's not a power of two, too small - // or doesn't have at least one free space - if !buf.capacity().is_power_of_two() + // or doesn't have at least one free space. + // We check if `T` is a ZST in the first condition, + // because `usize::MAX` (the capacity returned by `capacity()` for ZST) + // is not a power of two and thus it'll always try + // to reserve more memory which will panic for ZST (rust-lang/rust#78532) + if (!buf.capacity().is_power_of_two() && mem::size_of::() != 0) || (buf.capacity() < (MINIMUM_CAPACITY + 1)) || (buf.capacity() == len) { diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 705f0d62fbb7a..0919b1325bceb 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1728,3 +1728,10 @@ fn test_zero_sized_push() { } } } + +#[test] +fn test_from_zero_sized_vec() { + let v = vec![(); 100]; + let queue = VecDeque::from(v); + assert_eq!(queue.len(), 100); +} diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index f752472c3ba80..0c459a820c6ea 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1236,7 +1236,7 @@ mod impls { impl PartialOrd for bool { #[inline] fn partial_cmp(&self, other: &bool) -> Option { - (*self as u8).partial_cmp(&(*other as u8)) + Some(self.cmp(other)) } } diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 41292b3d83841..94e0cbe223a95 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -285,6 +285,41 @@ warning: unclosed HTML tag `h1` warning: 2 warnings emitted ``` + +## invalid_rust_codeblock + +This lint **warns by default**. It detects Rust code blocks in documentation +examples that are invalid (e.g. empty, not parsable as Rust). For example: + +```rust +/// Empty code block, with and without Rust: +/// +/// ```rust +/// ``` +/// +/// Unclosed code block: +/// +/// ```rust +fn main() {} +``` + +Which will give: + +```text +warning: Rust code block is empty + --> src/lib.rs:3:5 + | +3 | /// ```rust + | _____^ +4 | | /// ``` + | |_______^ + +warning: Rust code block is empty + --> src/lib.rs:8:5 + | +8 | /// ```rust + | ^^^^^^^ +``` ## non_autolinks diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b2eeaf584bf20..e7d1193b275df 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -322,6 +322,7 @@ crate fn run_core( let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name; let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name; let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name; + let invalid_rust_codeblock = rustc_lint::builtin::INVALID_RUST_CODEBLOCK.name; let invalid_html_tags = rustc_lint::builtin::INVALID_HTML_TAGS.name; let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name; let non_autolinks = rustc_lint::builtin::NON_AUTOLINKS.name; @@ -337,6 +338,7 @@ crate fn run_core( private_doc_tests.to_owned(), no_crate_level_docs.to_owned(), invalid_codeblock_attributes_name.to_owned(), + invalid_rust_codeblock.to_owned(), invalid_html_tags.to_owned(), renamed_and_removed_lints.to_owned(), unknown_lints.to_owned(), diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 0c76dc571beee..323b140847148 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,6 +1,8 @@ use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler}; +use rustc_middle::lint::LintDiagnosticBuilder; use rustc_parse::parse_stream_from_source_str; +use rustc_session::lint; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{FileName, InnerSpan}; @@ -47,51 +49,76 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { .unwrap_or(false); let buffer = buffer.borrow(); - if buffer.has_errors || is_empty { - let mut diag = if let Some(sp) = - super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs) - { - let warning_message = if buffer.has_errors { + if !(buffer.has_errors || is_empty) { + // No errors in a non-empty program. + return; + } + + let local_id = match item.def_id.as_local() { + Some(id) => id, + // We don't need to check the syntax for other crates so returning + // without doing anything should not be a problem. + None => return, + }; + + let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id); + let mark_with_text = code_block.syntax.is_none() && code_block.is_fenced; + + // The span and whether it is precise or not. + let (sp, precise_span) = match super::source_span_for_markdown_range( + self.cx, + &dox, + &code_block.range, + &item.attrs, + ) { + Some(sp) => (sp, true), + None => (super::span_of_attrs(&item.attrs).unwrap_or(item.source.span()), false), + }; + + // lambda that will use the lint to start a new diagnostic and add + // a suggestion to it when needed. + let diag_builder = |lint: LintDiagnosticBuilder<'_>| { + let mut diag = if precise_span { + let msg = if buffer.has_errors { "could not parse code block as Rust code" } else { "Rust code block is empty" }; - let mut diag = self.cx.sess().struct_span_warn(sp, warning_message); - - if code_block.syntax.is_none() && code_block.is_fenced { - let sp = sp.from_inner(InnerSpan::new(0, 3)); + let mut diag = lint.build(msg); + if mark_with_text { diag.span_suggestion( - sp, + sp.from_inner(InnerSpan::new(0, 3)), "mark blocks that do not contain Rust code as text", String::from("```text"), Applicability::MachineApplicable, ); } - diag } else { - // We couldn't calculate the span of the markdown block that had the error, so our - // diagnostics are going to be a bit lacking. - let mut diag = self.cx.sess().struct_span_warn( - super::span_of_attrs(&item.attrs).unwrap_or(item.source.span()), - "doc comment contains an invalid Rust code block", - ); - - if code_block.syntax.is_none() && code_block.is_fenced { + let mut diag = lint.build("doc comment contains an invalid Rust code block"); + if mark_with_text { diag.help("mark blocks that do not contain Rust code as text: ```text"); } diag }; - // FIXME(#67563): Provide more context for these errors by displaying the spans inline. for message in buffer.messages.iter() { diag.note(&message); } - diag.emit(); - } + }; + + // Finally build and emit the completed diagnostic. + // All points of divergence have been handled earlier so this can be + // done the same way whether the span is precise or not. + self.cx.tcx.struct_span_lint_hir( + lint::builtin::INVALID_RUST_CODEBLOCK, + hir_id, + sp, + diag_builder, + ); } } diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr index 9a7a4d2101362..a55a0b1d90e24 100644 --- a/src/test/rustdoc-ui/invalid-syntax.stderr +++ b/src/test/rustdoc-ui/invalid-syntax.stderr @@ -7,6 +7,7 @@ LL | | /// \__________pkt->size___________/ \_result->size_/ \__pkt->si LL | | /// ``` | |_______^ | + = note: `#[warn(invalid_rust_codeblock)]` on by default = note: error from rustc: unknown start of token: \ = note: error from rustc: unknown start of token: \ = note: error from rustc: unknown start of token: \ diff --git a/src/test/ui/mir/issue-78496.rs b/src/test/ui/mir/issue-78496.rs new file mode 100644 index 0000000000000..1b0687cfac3f6 --- /dev/null +++ b/src/test/ui/mir/issue-78496.rs @@ -0,0 +1,16 @@ +// run-pass +// compile-flags: -Z mir-opt-level=2 -C opt-level=0 + +// example from #78496 +pub enum E<'a> { + Empty, + Some(&'a E<'a>), +} + +fn f(e: &E) -> u32 { + if let E::Some(E::Some(_)) = e { 1 } else { 2 } +} + +fn main() { + assert_eq!(f(&E::Empty), 2); +} diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 3a6b64c90e8f6..0deaee3a944a0 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -1449,8 +1449,8 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { false }, ty::Dynamic(binder, _) => { - for predicate in binder.skip_binder().iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate { + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() { return true; } diff --git a/src/tools/expand-yaml-anchors/src/main.rs b/src/tools/expand-yaml-anchors/src/main.rs index f7ff64036a1a9..f8cf18a9309ec 100644 --- a/src/tools/expand-yaml-anchors/src/main.rs +++ b/src/tools/expand-yaml-anchors/src/main.rs @@ -87,7 +87,8 @@ impl App { let content = std::fs::read_to_string(source) .with_context(|| format!("failed to read {}", self.path(source)))?; - let mut buf = HEADER_MESSAGE.replace("{source}", &self.path(source).to_string()); + let mut buf = + HEADER_MESSAGE.replace("{source}", &self.path(source).to_string().replace("\\", "/")); let documents = YamlLoader::load_from_str(&content) .with_context(|| format!("failed to parse {}", self.path(source)))?;