diff options
119 files changed, 1337 insertions, 635 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 650525a2f52..f0099fa8adc 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1382,6 +1382,7 @@ impl Expr { | ExprKind::Tup(_) | ExprKind::Type(..) | ExprKind::Underscore + | ExprKind::UnsafeBinderCast(..) | ExprKind::While(..) | ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Unambiguous, @@ -1509,7 +1510,13 @@ pub enum ExprKind { /// `'label: for await? pat in iter { block }` /// /// This is desugared to a combination of `loop` and `match` expressions. - ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind }, + ForLoop { + pat: P<Pat>, + iter: P<Expr>, + body: P<Block>, + label: Option<Label>, + kind: ForLoopKind, + }, /// Conditionless loop (can be exited with `break`, `continue`, or `return`). /// /// `'label: loop { block }` @@ -1614,6 +1621,8 @@ pub enum ExprKind { /// A `format_args!()` expression. FormatArgs(P<FormatArgs>), + UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>), + /// Placeholder for an expression that wasn't syntactically well formed in some way. Err(ErrorGuaranteed), @@ -1652,6 +1661,16 @@ impl GenBlockKind { } } +/// Whether we're unwrapping or wrapping an unsafe binder +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Encodable, Decodable, HashStable_Generic)] +pub enum UnsafeBinderCastKind { + // e.g. `&i32` -> `unsafe<'a> &'a i32` + Wrap, + // e.g. `unsafe<'a> &'a i32` -> `&i32` + Unwrap, +} + /// The explicit `Self` type in a "qualified path". The actual /// path, including the trait and the associated item, is stored /// separately. `position` represents the index of the associated @@ -2223,6 +2242,12 @@ pub struct BareFnTy { pub decl_span: Span, } +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct UnsafeBinderTy { + pub generic_params: ThinVec<GenericParam>, + pub inner_ty: P<Ty>, +} + /// The various kinds of type recognized by the compiler. // // Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`. @@ -2242,6 +2267,8 @@ pub enum TyKind { PinnedRef(Option<Lifetime>, MutTy), /// A bare function (e.g., `fn(usize) -> bool`). BareFn(P<BareFnTy>), + /// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`). + UnsafeBinder(P<UnsafeBinderTy>), /// The never type (`!`). Never, /// A tuple (`(A, B, C, D,...)`). @@ -2877,7 +2904,7 @@ pub enum ModKind { /// or with definition outlined to a separate file `mod foo;` and already loaded from it. /// The inner span is from the first token past `{` to the last token until `}`, /// or from the first to the last token in the loaded file. - Loaded(ThinVec<P<Item>>, Inline, ModSpans), + Loaded(ThinVec<P<Item>>, Inline, ModSpans, Result<(), ErrorGuaranteed>), /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it. Unloaded, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 2c09059fe19..b44e2d9cace 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -558,6 +558,11 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) { vis.visit_fn_decl(decl); vis.visit_span(decl_span); } + TyKind::UnsafeBinder(binder) => { + let UnsafeBinderTy { generic_params, inner_ty } = binder.deref_mut(); + generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); + vis.visit_ty(inner_ty); + } TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)), TyKind::Paren(ty) => vis.visit_ty(ty), TyKind::Pat(ty, pat) => { @@ -1212,7 +1217,12 @@ impl WalkItemKind for ItemKind { ItemKind::Mod(safety, mod_kind) => { visit_safety(vis, safety); match mod_kind { - ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => { + ModKind::Loaded( + items, + _inline, + ModSpans { inner_span, inject_use_span }, + _, + ) => { items.flat_map_in_place(|item| vis.flat_map_item(item)); vis.visit_span(inner_span); vis.visit_span(inject_use_span); @@ -1775,6 +1785,12 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token ExprKind::TryBlock(body) => vis.visit_block(body), ExprKind::Lit(_token) => {} ExprKind::IncludedBytes(_bytes) => {} + ExprKind::UnsafeBinderCast(_kind, expr, ty) => { + vis.visit_expr(expr); + if let Some(ty) = ty { + vis.visit_ty(ty); + } + } ExprKind::Err(_guar) => {} ExprKind::Dummy => {} } diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index ae1ca36a3ba..64f2a98b8a6 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -152,6 +152,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool { | Underscore | Yeet(..) | Yield(..) + | UnsafeBinderCast(..) | Err(..) | Dummy => return false, } @@ -232,6 +233,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> { | Paren(_) | Try(_) | Yeet(None) + | UnsafeBinderCast(..) | Err(_) | Dummy => break None, } @@ -253,6 +255,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { ty = &mut_ty.ty; } + ast::TyKind::UnsafeBinder(binder) => { + ty = &binder.inner_ty; + } + ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output { ast::FnRetTy::Default(_) => break None, ast::FnRetTy::Ty(ret) => ty = ret, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index a7f7c37693a..22db4438e31 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -380,7 +380,7 @@ impl WalkItemKind for ItemKind { try_visit!(visitor.visit_fn(kind, span, id)); } ItemKind::Mod(_unsafety, mod_kind) => match mod_kind { - ModKind::Loaded(items, _inline, _inner_span) => { + ModKind::Loaded(items, _inline, _inner_span, _) => { walk_list!(visitor, visit_item, items); } ModKind::Unloaded => {} @@ -522,6 +522,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { walk_list!(visitor, visit_generic_param, generic_params); try_visit!(visitor.visit_fn_decl(decl)); } + TyKind::UnsafeBinder(binder) => { + walk_list!(visitor, visit_generic_param, &binder.generic_params); + try_visit!(visitor.visit_ty(&binder.inner_ty)); + } TyKind::Path(maybe_qself, path) => { try_visit!(visitor.visit_qself(maybe_qself)); try_visit!(visitor.visit_path(path, *id)); @@ -1226,6 +1230,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), ExprKind::Lit(_token) => {} ExprKind::IncludedBytes(_bytes) => {} + ExprKind::UnsafeBinderCast(_kind, expr, ty) => { + try_visit!(visitor.visit_expr(expr)); + visit_opt!(visitor, visit_ty, ty); + } ExprKind::Err(_guar) => {} ExprKind::Dummy => {} } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 2ad0ff3200e..32905806343 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -379,6 +379,14 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), ExprKind::Err(guar) => hir::ExprKind::Err(*guar), + ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast( + *kind, + self.lower_expr(expr), + ty.as_ref().map(|ty| { + self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast)) + }), + ), + ExprKind::Dummy => { span_bug!(e.span, "lowered ExprKind::Dummy") } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 7d6c41992eb..d63131eacb5 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -238,7 +238,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } ItemKind::Mod(_, mod_kind) => match mod_kind { - ModKind::Loaded(items, _, spans) => { + ModKind::Loaded(items, _, spans, _) => { hir::ItemKind::Mod(self.lower_mod(items, spans)) } ModKind::Unloaded => panic!("`mod` items should have been loaded by now"), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index bac3f974cca..3cbd3e1b637 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1228,6 +1228,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_names: self.lower_fn_params_to_names(&f.decl), })) } + TyKind::UnsafeBinder(f) => { + let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); + hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy { + generic_params, + inner_ty: self.lower_ty(&f.inner_ty, itctx), + })) + } TyKind::Never => hir::TyKind::Never, TyKind::Tup(tys) => hir::TyKind::Tup( self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))), diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 64e91c91e2c..290c2e52970 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1029,7 +1029,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" }); } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). - if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) + if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) && !attr::contains_name(&item.attrs, sym::path) { self.check_mod_file_item_asciionly(item.ident); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 61a710517ea..c10b3296497 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -560,6 +560,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); gate_all!(unsafe_fields, "`unsafe` fields are experimental"); + gate_all!(unsafe_binders, "unsafe binder types are experimental"); if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 49e4a559e73..04ffa2cffe3 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1198,6 +1198,14 @@ impl<'a> State<'a> { ast::TyKind::BareFn(f) => { self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params); } + ast::TyKind::UnsafeBinder(f) => { + self.ibox(INDENT_UNIT); + self.word("unsafe"); + self.print_generic_params(&f.generic_params); + self.nbsp(); + self.print_type(&f.inner_ty); + self.end(); + } ast::TyKind::Path(None, path) => { self.print_path(path, false, 0); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index c239cb249c3..dce76fb1e77 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -772,6 +772,25 @@ impl<'a> State<'a> { self.word_nbsp("try"); self.print_block_with_attrs(blk, attrs) } + ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => { + self.word("builtin # "); + match kind { + ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder"), + ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder"), + } + self.popen(); + self.ibox(0); + self.print_expr(expr, FixupContext::default()); + + if let Some(ty) = ty { + self.word(","); + self.space(); + self.print_type(ty); + } + + self.end(); + self.pclose(); + } ast::ExprKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 452038bc328..dc4eab766c9 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -8,7 +8,10 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; -use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; +use rustc_mir_dataflow::impls::{ + EverInitializedPlaces, EverInitializedPlacesDomain, MaybeUninitializedPlaces, + MaybeUninitializedPlacesDomain, +}; use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects}; use tracing::debug; @@ -24,7 +27,7 @@ pub(crate) struct Borrowck<'a, 'tcx> { } impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { - type Domain = BorrowckDomain<'a, 'tcx>; + type Domain = BorrowckDomain; const NAME: &'static str = "borrowck"; @@ -41,48 +44,48 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { unreachable!(); } - fn apply_before_statement_effect( + fn apply_early_statement_effect( &mut self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { - self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc); - self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc); - self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc); + self.borrows.apply_early_statement_effect(&mut state.borrows, stmt, loc); + self.uninits.apply_early_statement_effect(&mut state.uninits, stmt, loc); + self.ever_inits.apply_early_statement_effect(&mut state.ever_inits, stmt, loc); } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, ) { - self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc); - self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc); - self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc); + self.borrows.apply_primary_statement_effect(&mut state.borrows, stmt, loc); + self.uninits.apply_primary_statement_effect(&mut state.uninits, stmt, loc); + self.ever_inits.apply_primary_statement_effect(&mut state.ever_inits, stmt, loc); } - fn apply_before_terminator_effect( + fn apply_early_terminator_effect( &mut self, state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, ) { - self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc); - self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc); - self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc); + self.borrows.apply_early_terminator_effect(&mut state.borrows, term, loc); + self.uninits.apply_early_terminator_effect(&mut state.uninits, term, loc); + self.ever_inits.apply_early_terminator_effect(&mut state.ever_inits, term, loc); } - fn apply_terminator_effect<'mir>( + fn apply_primary_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, term: &'mir mir::Terminator<'tcx>, loc: Location, ) -> TerminatorEdges<'mir, 'tcx> { - self.borrows.apply_terminator_effect(&mut state.borrows, term, loc); - self.uninits.apply_terminator_effect(&mut state.uninits, term, loc); - self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc); + self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc); + self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc); + self.ever_inits.apply_primary_terminator_effect(&mut state.ever_inits, term, loc); // This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this // analysis doesn't use. @@ -110,14 +113,14 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } } -impl JoinSemiLattice for BorrowckDomain<'_, '_> { +impl JoinSemiLattice for BorrowckDomain { fn join(&mut self, _other: &Self) -> bool { // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. unreachable!(); } } -impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx> +impl<'tcx, C> DebugWithContext<C> for BorrowckDomain where C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>, { @@ -160,10 +163,10 @@ where /// The transient state of the dataflow analyses used by the borrow checker. #[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct BorrowckDomain<'a, 'tcx> { - pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain, - pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, - pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, +pub(crate) struct BorrowckDomain { + pub(crate) borrows: BorrowsDomain, + pub(crate) uninits: MaybeUninitializedPlacesDomain, + pub(crate) ever_inits: EverInitializedPlacesDomain, } rustc_index::newtype_index! { @@ -503,7 +506,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { /// That means they went out of a nonlexical scope fn kill_loans_out_of_scope_at_location( &self, - trans: &mut <Self as Analysis<'tcx>>::Domain, + state: &mut <Self as Analysis<'tcx>>::Domain, location: Location, ) { // NOTE: The state associated with a given `location` @@ -518,14 +521,14 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // region, then setting that gen-bit will override any // potential kill introduced here. if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { - trans.kill_all(indices.iter().copied()); + state.kill_all(indices.iter().copied()); } } /// Kill any borrows that conflict with `place`. fn kill_borrows_on_place( &self, - trans: &mut <Self as Analysis<'tcx>>::Domain, + state: &mut <Self as Analysis<'tcx>>::Domain, place: Place<'tcx>, ) { debug!("kill_borrows_on_place: place={:?}", place); @@ -543,7 +546,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { // `places_conflict` for every borrow. if place.projection.is_empty() { if !self.body.local_decls[place.local].is_ref_to_static() { - trans.kill_all(other_borrows_of_local); + state.kill_all(other_borrows_of_local); } return; } @@ -562,10 +565,12 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { ) }); - trans.kill_all(definitely_conflicting_borrows); + state.kill_all(definitely_conflicting_borrows); } } +type BorrowsDomain = BitSet<BorrowIndex>; + /// Forward dataflow computation of the set of borrows that are in scope at a particular location. /// - we gen the introduced loans /// - we kill loans on locals going out of (regular) scope @@ -574,7 +579,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { /// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of /// `a.b.c` when `a` is overwritten. impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { - type Domain = BitSet<BorrowIndex>; + type Domain = BorrowsDomain; const NAME: &'static str = "borrows"; @@ -588,18 +593,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { // function execution, so this method has no effect. } - fn apply_before_statement_effect( + fn apply_early_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { - self.kill_loans_out_of_scope_at_location(trans, location); + self.kill_loans_out_of_scope_at_location(state, location); } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, location: Location, ) { @@ -617,18 +622,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { panic!("could not find BorrowIndex for location {location:?}"); }); - trans.gen_(index); + state.gen_(index); } // Make sure there are no remaining borrows for variables // that are assigned over. - self.kill_borrows_on_place(trans, *lhs); + self.kill_borrows_on_place(state, *lhs); } mir::StatementKind::StorageDead(local) => { // Make sure there are no remaining borrows for locals that // are gone out of scope. - self.kill_borrows_on_place(trans, Place::from(*local)); + self.kill_borrows_on_place(state, Place::from(*local)); } mir::StatementKind::FakeRead(..) @@ -646,18 +651,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } } - fn apply_before_terminator_effect( + fn apply_early_terminator_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, location: Location, ) { - self.kill_loans_out_of_scope_at_location(trans, location); + self.kill_loans_out_of_scope_at_location(state, location); } - fn apply_terminator_effect<'mir>( + fn apply_primary_terminator_effect<'mir>( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, _location: Location, ) -> TerminatorEdges<'mir, 'tcx> { @@ -666,7 +671,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { if let mir::InlineAsmOperand::Out { place: Some(place), .. } | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op { - self.kill_borrows_on_place(trans, place); + self.kill_borrows_on_place(state, place); } } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d7db92da18f..18b7984e90d 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -43,7 +43,7 @@ use rustc_mir_dataflow::impls::{ use rustc_mir_dataflow::move_paths::{ InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex, }; -use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results}; +use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results}; use rustc_session::lint::builtin::UNUSED_MUT; use rustc_span::{Span, Symbol}; use smallvec::SmallVec; @@ -426,14 +426,14 @@ fn get_flow_results<'a, 'tcx>( ever_inits: ever_inits.analysis, }; - assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len()); - assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len()); - let entry_sets: EntrySets<'_, Borrowck<'_, '_>> = - itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets) + assert_eq!(borrows.entry_states.len(), uninits.entry_states.len()); + assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len()); + let entry_states: EntryStates<'_, Borrowck<'_, '_>> = + itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states) .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits }) .collect(); - Results { analysis, entry_sets } + Results { analysis, entry_states } } pub(crate) struct BorrowckInferCtxt<'tcx> { @@ -600,10 +600,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> { - fn visit_statement_before_primary_effect( + fn visit_after_early_statement_effect( &mut self, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, stmt: &'a Statement<'tcx>, location: Location, ) { @@ -674,10 +674,10 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt< } } - fn visit_terminator_before_primary_effect( + fn visit_after_early_terminator_effect( &mut self, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, term: &'a Terminator<'tcx>, loc: Location, ) { @@ -787,10 +787,10 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt< } } - fn visit_terminator_after_primary_effect( + fn visit_after_primary_terminator_effect( &mut self, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, term: &'a Terminator<'tcx>, loc: Location, ) { @@ -983,7 +983,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { place_span: (Place<'tcx>, Span), kind: (AccessDepth, ReadOrWrite), is_local_mutation_allowed: LocalMutationIsAllowed, - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, ) { let (sd, rw) = kind; @@ -1032,7 +1032,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { place_span: (Place<'tcx>, Span), sd: AccessDepth, rw: ReadOrWrite, - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, ) -> bool { let mut error_reported = false; @@ -1172,7 +1172,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, place_span: (Place<'tcx>, Span), kind: AccessDepth, - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, ) { // Write of P[i] or *P requires P init'd. self.check_if_assigned_path_is_moved(location, place_span, state); @@ -1190,7 +1190,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { &mut self, location: Location, (rvalue, span): (&'a Rvalue<'tcx>, Span), - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, ) { match rvalue { &Rvalue::Ref(_ /*rgn*/, bk, place) => { @@ -1448,7 +1448,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { &mut self, location: Location, (operand, span): (&'a Operand<'tcx>, Span), - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, ) { match *operand { Operand::Copy(place) => { @@ -1568,12 +1568,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } - fn check_activations( - &mut self, - location: Location, - span: Span, - state: &BorrowckDomain<'a, 'tcx>, - ) { + fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) { // Two-phase borrow support: For each activation that is newly // generated at this statement, check if it interferes with // another borrow. @@ -1731,7 +1726,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, ) { let maybe_uninits = &state.uninits; @@ -1836,7 +1831,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, ) { let maybe_uninits = &state.uninits; @@ -1935,7 +1930,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { &mut self, location: Location, (place, span): (Place<'tcx>, Span), - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, ) { debug!("check_if_assigned_path_is_moved place: {:?}", place); @@ -2001,7 +1996,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, base: PlaceRef<'tcx>, span: Span, - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, ) { // rust-lang/rust#21232: Until Rust allows reads from the // initialized parts of partially initialized structs, we @@ -2092,7 +2087,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (place, span): (Place<'tcx>, Span), kind: ReadOrWrite, is_local_mutation_allowed: LocalMutationIsAllowed, - state: &BorrowckDomain<'a, 'tcx>, + state: &BorrowckDomain, location: Location, ) -> bool { debug!( @@ -2206,18 +2201,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } - fn is_local_ever_initialized( - &self, - local: Local, - state: &BorrowckDomain<'a, 'tcx>, - ) -> Option<InitIndex> { + fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> { let mpi = self.move_data.rev_lookup.find_local(local)?; let ii = &self.move_data.init_path_map[mpi]; ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied() } /// Adds the place into the used mutable variables set - fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain<'a, 'tcx>) { + fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) { match root_place { RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { // If the local may have been initialized, and it is now currently being diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 70fa4d00c0f..eb07975d8af 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -323,7 +323,8 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::While(_, _, _) | ExprKind::Yeet(_) | ExprKind::Become(_) - | ExprKind::Yield(_) => {} + | ExprKind::Yield(_) + | ExprKind::UnsafeBinderCast(..) => {} } } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index b2048c534a4..e7ff65e08f9 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -141,8 +141,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { // We don't want to recurse into anything other than mods, since // mods or tests inside of functions will break things - if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) = - item.kind + if let ast::ItemKind::Mod( + _, + ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }, _), + ) = item.kind { let prev_tests = mem::take(&mut self.tests); walk_item_kind( diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 0f9a460ca1b..763c37a41af 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -329,7 +329,7 @@ where self.transfer_function(state).initialize_state(); } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, @@ -338,7 +338,7 @@ where self.transfer_function(state).visit_statement(statement, location); } - fn apply_terminator_effect<'mir>( + fn apply_primary_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 56325eaa1be..23683851799 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -249,10 +249,9 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { // For panic_fmt, call const_panic_fmt instead. let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); - // FIXME(@lcnr): why does this use an empty env if we've got a `param_env` right here. let new_instance = ty::Instance::expect_resolve( *self.tcx, - ty::TypingEnv::fully_monomorphized(), + self.typing_env(), const_def_id, instance.args, self.cur_span(), diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 0157e6c2125..2db6322ba06 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -297,6 +297,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self { + // Can use any typing env, since `bool` is always monomorphic. let layout = tcx .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool)) .unwrap(); @@ -305,17 +306,18 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self { + // Can use any typing env, since `Ordering` is always monomorphic. let ty = tcx.ty_ordering_enum(None); let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap(); Self::from_scalar(Scalar::from_i8(c as i8), layout) } - pub fn from_pair(a: Self, b: Self, tcx: TyCtxt<'tcx>) -> Self { - let layout = tcx + pub fn from_pair(a: Self, b: Self, cx: &(impl HasTypingEnv<'tcx> + HasTyCtxt<'tcx>)) -> Self { + let layout = cx + .tcx() .layout_of( - ty::TypingEnv::fully_monomorphized() - .as_query_input(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])), + cx.typing_env().as_query_input(Ty::new_tup(cx.tcx(), &[a.layout.ty, b.layout.ty])), ) .unwrap(); Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout) diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 1fa5dcbd24f..8b7b78c7129 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -222,7 +222,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let res = ImmTy::from_scalar_int(result, left.layout); return interp_ok(if with_overflow { let overflow = ImmTy::from_bool(overflow, *self.tcx); - ImmTy::from_pair(res, overflow, *self.tcx) + ImmTy::from_pair(res, overflow, self) } else { res }); @@ -279,7 +279,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let res = ImmTy::from_scalar_int(result, left.layout); if with_overflow { let overflow = ImmTy::from_bool(overflow, *self.tcx); - ImmTy::from_pair(res, overflow, *self.tcx) + ImmTy::from_pair(res, overflow, self) } else { res } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 2e01c385a66..fe4e822ce0d 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -45,7 +45,7 @@ use rustc_errors::registry::Registry; use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown}; use rustc_feature::find_gated_cfg; use rustc_interface::util::{self, get_codegen_backend}; -use rustc_interface::{Linker, Queries, interface, passes}; +use rustc_interface::{Linker, interface, passes}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; @@ -158,13 +158,10 @@ pub trait Callbacks { /// Called after parsing the crate root. Submodules are not yet parsed when /// this callback is called. Return value instructs the compiler whether to /// continue the compilation afterwards (defaults to `Compilation::Continue`) - #[deprecated = "This callback will likely be removed or stop giving access \ - to the TyCtxt in the future. Use either the after_expansion \ - or the after_analysis callback instead."] - fn after_crate_root_parsing<'tcx>( + fn after_crate_root_parsing( &mut self, _compiler: &interface::Compiler, - _queries: &'tcx Queries<'tcx>, + _queries: &ast::Crate, ) -> Compilation { Compilation::Continue } @@ -173,7 +170,7 @@ pub trait Callbacks { fn after_expansion<'tcx>( &mut self, _compiler: &interface::Compiler, - _queries: &'tcx Queries<'tcx>, + _tcx: TyCtxt<'tcx>, ) -> Compilation { Compilation::Continue } @@ -416,8 +413,9 @@ fn run_compiler( return early_exit(); } - #[allow(deprecated)] - if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop { + if callbacks.after_crate_root_parsing(compiler, &*queries.parse().borrow()) + == Compilation::Stop + { return early_exit(); } @@ -425,18 +423,18 @@ fn run_compiler( return early_exit(); } - // Make sure name resolution and macro expansion is run. - queries.global_ctxt().enter(|tcx| tcx.resolver_for_lowering()); + queries.global_ctxt().enter(|tcx| { + // Make sure name resolution and macro expansion is run. + let _ = tcx.resolver_for_lowering(); - if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir { - queries.global_ctxt().enter(|tcxt| dump_feature_usage_metrics(tcxt, metrics_dir)); - } + if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir { + dump_feature_usage_metrics(tcx, metrics_dir); + } - if callbacks.after_expansion(compiler, queries) == Compilation::Stop { - return early_exit(); - } + if callbacks.after_expansion(compiler, tcx) == Compilation::Stop { + return early_exit(); + } - queries.global_ctxt().enter(|tcx| { passes::write_dep_info(tcx); if sess.opts.output_types.contains_key(&OutputType::DepInfo) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 6a6496f9827..690e080fbfc 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -723,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { item_inner.kind, ItemKind::Mod( _, - ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _), + ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _, _), ) ) => { @@ -889,7 +889,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn visit_item(&mut self, item: &'ast ast::Item) { match &item.kind { ItemKind::Mod(_, mod_kind) - if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) => + if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) => { feature_err( self.sess, @@ -1195,7 +1195,7 @@ impl InvocationCollectorNode for P<ast::Item> { let ecx = &mut collector.cx; let (file_path, dir_path, dir_ownership) = match mod_kind { - ModKind::Loaded(_, inline, _) => { + ModKind::Loaded(_, inline, _, _) => { // Inline `mod foo { ... }`, but we still need to push directories. let (dir_path, dir_ownership) = mod_dir_path( ecx.sess, @@ -1217,15 +1217,21 @@ impl InvocationCollectorNode for P<ast::Item> { ModKind::Unloaded => { // We have an outline `mod foo;` so we need to parse the file. let old_attrs_len = attrs.len(); - let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } = - parse_external_mod( - ecx.sess, - ident, - span, - &ecx.current_expansion.module, - ecx.current_expansion.dir_ownership, - &mut attrs, - ); + let ParsedExternalMod { + items, + spans, + file_path, + dir_path, + dir_ownership, + had_parse_error, + } = parse_external_mod( + ecx.sess, + ident, + span, + &ecx.current_expansion.module, + ecx.current_expansion.dir_ownership, + &mut attrs, + ); if let Some(lint_store) = ecx.lint_store { lint_store.pre_expansion_lint( @@ -1239,7 +1245,7 @@ impl InvocationCollectorNode for P<ast::Item> { ); } - *mod_kind = ModKind::Loaded(items, Inline::No, spans); + *mod_kind = ModKind::Loaded(items, Inline::No, spans, had_parse_error); node.attrs = attrs; if node.attrs.len() > old_attrs_len { // If we loaded an out-of-line module and added some inner attributes, diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 614f52bbd28..85ea42e78ad 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -37,6 +37,7 @@ pub(crate) struct ParsedExternalMod { pub file_path: PathBuf, pub dir_path: PathBuf, pub dir_ownership: DirOwnership, + pub had_parse_error: Result<(), ErrorGuaranteed>, } pub enum ModError<'a> { @@ -74,14 +75,17 @@ pub(crate) fn parse_external_mod( attrs.extend(inner_attrs); (items, inner_span, mp.file_path) }; + // (1) ...instead, we return a dummy module. - let (items, spans, file_path) = - result.map_err(|err| err.report(sess, span)).unwrap_or_default(); + let ((items, spans, file_path), had_parse_error) = match result { + Err(err) => (Default::default(), Err(err.report(sess, span))), + Ok(result) => (result, Ok(())), + }; // Extract the directory path for submodules of the module. let dir_path = file_path.parent().unwrap_or(&file_path).to_owned(); - ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } + ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership, had_parse_error } } pub(crate) fn mod_dir_path( diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e7abe2e0362..8fa75eac9db 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -636,6 +636,8 @@ declare_features! ( /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (unstable, type_changing_struct_update, "1.58.0", Some(86555)), + /// Allows using `unsafe<'a> &'a T` unsafe binder types. + (incomplete, unsafe_binders, "CURRENT_RUSTC_VERSION", Some(130516)), /// Allows declaring fields `unsafe`. (incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)), /// Allows const generic parameters to be defined with types that diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 8cf18c2b912..c7d83760b78 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -8,7 +8,7 @@ use rustc_ast::{ }; pub use rustc_ast::{ BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, - ImplPolarity, IsAuto, Movability, Mutability, UnOp, + ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind, }; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; @@ -1740,6 +1740,7 @@ impl Expr<'_> { | ExprKind::Struct(..) | ExprKind::Tup(_) | ExprKind::Type(..) + | ExprKind::UnsafeBinderCast(..) | ExprKind::Err(_) => ExprPrecedence::Unambiguous, ExprKind::DropTemps(ref expr, ..) => expr.precedence(), @@ -1769,6 +1770,9 @@ impl Expr<'_> { // https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from), + // Unsafe binder cast preserves place-ness of the sub-expression. + ExprKind::UnsafeBinderCast(_, e, _) => e.is_place_expr(allow_projections_from), + ExprKind::Unary(UnOp::Deref, _) => true, ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => { @@ -1850,7 +1854,8 @@ impl Expr<'_> { | ExprKind::Field(base, _) | ExprKind::Index(base, _, _) | ExprKind::AddrOf(.., base) - | ExprKind::Cast(base, _) => { + | ExprKind::Cast(base, _) + | ExprKind::UnsafeBinderCast(_, base, _) => { // This isn't exactly true for `Index` and all `Unary`, but we are using this // method exclusively for diagnostics and there's a *cultural* pressure against // them being used only for its side-effects. @@ -2144,6 +2149,10 @@ pub enum ExprKind<'hir> { /// A suspension point for coroutines (i.e., `yield <expr>`). Yield(&'hir Expr<'hir>, YieldSource), + /// Operators which can be used to interconvert `unsafe` binder types. + /// e.g. `unsafe<'a> &'a i32` <=> `&i32`. + UnsafeBinderCast(UnsafeBinderCastKind, &'hir Expr<'hir>, Option<&'hir Ty<'hir>>), + /// A placeholder for an expression that wasn't syntactically well formed in some way. Err(rustc_span::ErrorGuaranteed), } @@ -2781,6 +2790,12 @@ pub struct BareFnTy<'hir> { } #[derive(Debug, Clone, Copy, HashStable_Generic)] +pub struct UnsafeBinderTy<'hir> { + pub generic_params: &'hir [GenericParam<'hir>], + pub inner_ty: &'hir Ty<'hir>, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct OpaqueTy<'hir> { pub hir_id: HirId, pub def_id: LocalDefId, @@ -2878,6 +2893,8 @@ pub enum TyKind<'hir> { Ref(&'hir Lifetime, MutTy<'hir>), /// A bare function (e.g., `fn(usize) -> bool`). BareFn(&'hir BareFnTy<'hir>), + /// An unsafe binder type (e.g. `unsafe<'a> Foo<'a>`). + UnsafeBinder(&'hir UnsafeBinderTy<'hir>), /// The never type (`!`). Never, /// A tuple (`(A, B, C, D, ...)`). diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 8dbfefffee4..482940eb5ca 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -857,6 +857,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::Yield(ref subexpression, _) => { try_visit!(visitor.visit_expr(subexpression)); } + ExprKind::UnsafeBinderCast(_kind, expr, ty) => { + try_visit!(visitor.visit_expr(expr)); + visit_opt!(visitor, visit_ty, ty); + } ExprKind::Lit(_) | ExprKind::Err(_) => {} } V::Result::output() @@ -886,6 +890,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul walk_list!(visitor, visit_generic_param, function_declaration.generic_params); try_visit!(visitor.visit_fn_decl(function_declaration.decl)); } + TyKind::UnsafeBinder(ref unsafe_binder) => { + walk_list!(visitor, visit_generic_param, unsafe_binder.generic_params); + try_visit!(visitor.visit_ty(unsafe_binder.inner_ty)); + } TyKind::Path(ref qpath) => { try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span)); } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 1d9114b0ef3..f52d4f42eca 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -470,6 +470,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S self.outer_index.shift_out(1); res } + hir::TyKind::UnsafeBinder(_) => { + self.outer_index.shift_in(1); + let res = intravisit::walk_ty(self, ty); + self.outer_index.shift_out(1); + res + } _ => intravisit::walk_ty(self, ty), } } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 74f381d2661..923d2b1fe67 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -781,6 +781,36 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { intravisit::walk_ty(this, ty); }); } + hir::TyKind::UnsafeBinder(binder) => { + let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = + binder + .generic_params + .iter() + .enumerate() + .map(|(late_bound_idx, param)| { + ( + (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)), + late_arg_as_bound_arg(self.tcx, param), + ) + }) + .unzip(); + + deny_non_region_late_bound(self.tcx, &mut bound_vars, "function pointer types"); + + self.record_late_bound_vars(ty.hir_id, binders); + let scope = Scope::Binder { + hir_id: ty.hir_id, + bound_vars, + s: self.scope, + scope_type: BinderScopeType::Normal, + where_bound_origin: None, + }; + self.with(scope, |this| { + // a bare fn has no bounds, so everything + // contained within is scoped within its binder. + intravisit::walk_ty(this, ty); + }); + } hir::TyKind::TraitObject(bounds, lifetime, _) => { debug!(?bounds, ?lifetime, "TraitObject"); let scope = Scope::TraitRefBoundary { s: self.scope }; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 7683c87168b..1bdbde30037 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2312,6 +2312,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)), ) } + hir::TyKind::UnsafeBinder(_binder) => { + let guar = self + .dcx() + .struct_span_err(hir_ty.span, "unsafe binders are not yet implemented") + .emit(); + Ty::new_error(tcx, guar) + } hir::TyKind::TraitObject(bounds, lifetime, repr) => { if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) { // Don't continue with type analysis if the `dyn` keyword is missing diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 20ba9ae2632..a17b6321ce8 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -288,6 +288,9 @@ impl<'a> State<'a> { hir::TyKind::BareFn(f) => { self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names); } + hir::TyKind::UnsafeBinder(unsafe_binder) => { + self.print_unsafe_binder(unsafe_binder); + } hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"), hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false), hir::TyKind::TraitObject(bounds, lifetime, syntax) => { @@ -339,6 +342,15 @@ impl<'a> State<'a> { self.end() } + fn print_unsafe_binder(&mut self, unsafe_binder: &hir::UnsafeBinderTy<'_>) { + self.ibox(INDENT_UNIT); + self.word("unsafe"); + self.print_generic_params(unsafe_binder.generic_params); + self.nbsp(); + self.print_type(unsafe_binder.inner_ty); + self.end(); + } + fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); @@ -1530,6 +1542,19 @@ impl<'a> State<'a> { self.word(")"); } + hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => { + match kind { + hir::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("), + hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("), + } + self.print_expr(expr); + if let Some(ty) = ty { + self.word(","); + self.space(); + self.print_type(ty); + } + self.word(")"); + } hir::ExprKind::Yield(expr, _) => { self.word_space("yield"); self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 56903865277..65345048bfc 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -329,6 +329,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Assignment does call `drop_in_place`, though, but its safety // requirements are not the same. ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false, + + // Place-preserving expressions only constitute reads if their + // parent expression constitutes a read. + ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) => { + self.expr_guaranteed_to_constitute_read_for_never(expr) + } + ExprKind::Assign(lhs, _, _) => { // Only the LHS does not constitute a read expr.hir_id != lhs.hir_id @@ -353,7 +360,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ExprKind::Binary(_, _, _) | ExprKind::Unary(_, _) | ExprKind::Cast(_, _) - | ExprKind::Type(_, _) | ExprKind::DropTemps(_) | ExprKind::If(_, _, _) | ExprKind::Closure(_) @@ -564,7 +570,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_index(base, idx, expr, brackets_span) } ExprKind::Yield(value, _) => self.check_expr_yield(value, expr), - hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar), + ExprKind::UnsafeBinderCast(kind, expr, ty) => { + self.check_expr_unsafe_binder_cast(kind, expr, ty, expected) + } + ExprKind::Err(guar) => Ty::new_error(tcx, guar), } } @@ -1634,6 +1643,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_expr_unsafe_binder_cast( + &self, + _kind: hir::UnsafeBinderCastKind, + expr: &'tcx hir::Expr<'tcx>, + _hir_ty: Option<&'tcx hir::Ty<'tcx>>, + _expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let guar = + self.dcx().struct_span_err(expr.span, "unsafe binders are not yet implemented").emit(); + Ty::new_error(self.tcx, guar) + } + fn check_expr_array( &self, args: &'tcx [hir::Expr<'tcx>], diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 27ec2e9e0d4..ecbae6ac72f 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -341,6 +341,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.walk_expr(subexpr)?; } + hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => { + self.walk_expr(subexpr)?; + } + hir::ExprKind::Unary(hir::UnOp::Deref, base) => { // *base self.walk_expr(base)?; @@ -1360,7 +1364,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.cat_res(expr.hir_id, expr.span, expr_ty, res) } + // both type ascription and unsafe binder casts don't affect + // the place-ness of the subexpression. hir::ExprKind::Type(e, _) => self.cat_expr(e), + hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e), hir::ExprKind::AddrOf(..) | hir::ExprKind::Call(..) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 62f35333015..430bc7db077 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1125,6 +1125,18 @@ pub(crate) fn start_codegen<'tcx>( } } + // This must run after monomorphization so that all generic types + // have been instantiated. + if tcx.sess.opts.unstable_opts.print_type_sizes { + tcx.sess.code_stats.print_type_sizes(); + } + + if tcx.sess.opts.unstable_opts.print_vtable_sizes { + let crate_name = tcx.crate_name(LOCAL_CRATE); + + tcx.sess.code_stats.print_vtable_sizes(crate_name); + } + codegen } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 7e3a1332630..bb2ad3b3dd0 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -127,18 +127,6 @@ impl Linker { ) -> Linker { let ongoing_codegen = passes::start_codegen(codegen_backend, tcx); - // This must run after monomorphization so that all generic types - // have been instantiated. - if tcx.sess.opts.unstable_opts.print_type_sizes { - tcx.sess.code_stats.print_type_sizes(); - } - - if tcx.sess.opts.unstable_opts.print_vtable_sizes { - let crate_name = tcx.crate_name(LOCAL_CRATE); - - tcx.sess.code_stats.print_vtable_sizes(crate_name); - } - Linker { dep_graph: tcx.dep_graph.clone(), output_filenames: Arc::clone(tcx.output_filenames(())), diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 093cc16fb4c..3543784bc72 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -3038,7 +3038,7 @@ impl EarlyLintPass for SpecialModuleName { for item in &krate.items { if let ast::ItemKind::Mod( _, - ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _), + ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _, _), ) = item.kind { if item.attrs.iter().any(|a| a.has_name(sym::path)) { diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 7e298a9a63c..10769b57a76 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -192,6 +192,8 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { | ExprKind::DropTemps(..) | ExprKind::Let(..) => false, + ExprKind::UnsafeBinderCast(..) => false, + // Not applicable ExprKind::Type(..) | ExprKind::Err(..) => false, } diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 2db229ed133..1402129195f 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -422,6 +422,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> { hir::ExprKind::Unary(_, expr) | hir::ExprKind::Cast(expr, _) | hir::ExprKind::Type(expr, _) + | hir::ExprKind::UnsafeBinderCast(_, expr, _) | hir::ExprKind::Yield(expr, _) | hir::ExprKind::AddrOf(_, _, expr) | hir::ExprKind::Match(expr, _, _) diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index c8675660e0f..f4135d8dbc6 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -44,16 +44,16 @@ pub struct DynamicQuery<'tcx, C: QueryCache> { pub format_value: fn(&C::Value) -> String, } -pub struct QuerySystemFns<'tcx> { +pub struct QuerySystemFns { pub engine: QueryEngine, pub local_providers: Providers, pub extern_providers: ExternProviders, - pub encode_query_results: fn( + pub encode_query_results: for<'tcx> fn( tcx: TyCtxt<'tcx>, encoder: &mut CacheEncoder<'_, 'tcx>, query_result_index: &mut EncodedDepNodeIndex, ), - pub try_mark_green: fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool, + pub try_mark_green: for<'tcx> fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool, } pub struct QuerySystem<'tcx> { @@ -68,7 +68,7 @@ pub struct QuerySystem<'tcx> { /// This is `None` if we are not incremental compilation mode pub on_disk_cache: Option<OnDiskCache>, - pub fns: QuerySystemFns<'tcx>, + pub fns: QuerySystemFns, pub jobs: AtomicU64, } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index d75f01dfba0..3cbf1e2055c 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -915,6 +915,11 @@ impl<'tcx> Cx<'tcx> { } } } + + hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => { + unreachable!("unsafe binders are not yet implemented") + } + hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) }, hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) }, hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) }, diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 4a9bcdaddb3..89ff93d9943 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -179,15 +179,15 @@ where /// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is /// applied. /// - /// The "before" effect at the target location *will be* applied. + /// The "early" effect at the target location *will be* applied. pub fn seek_before_primary_effect(&mut self, target: Location) { - self.seek_after(target, Effect::Before) + self.seek_after(target, Effect::Early) } /// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is /// applied. /// - /// The "before" effect at the target location will be applied as well. + /// The "early" effect at the target location will be applied as well. pub fn seek_after_primary_effect(&mut self, target: Location) { self.seek_after(target, Effect::Primary) } @@ -222,12 +222,12 @@ where #[rustfmt::skip] let next_effect = if A::Direction::IS_FORWARD { self.pos.curr_effect_index.map_or_else( - || Effect::Before.at_index(0), + || Effect::Early.at_index(0), EffectIndex::next_in_forward_order, ) } else { self.pos.curr_effect_index.map_or_else( - || Effect::Before.at_index(block_data.statements.len()), + || Effect::Early.at_index(block_data.statements.len()), EffectIndex::next_in_backward_order, ) }; diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 566a6b09b2b..9d943ebe327 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -66,12 +66,12 @@ impl Direction for Backward { { let terminator = block_data.terminator(); let location = Location { block, statement_index: block_data.statements.len() }; - analysis.apply_before_terminator_effect(state, terminator, location); - analysis.apply_terminator_effect(state, terminator, location); + analysis.apply_early_terminator_effect(state, terminator, location); + analysis.apply_primary_terminator_effect(state, terminator, location); for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { let location = Location { block, statement_index }; - analysis.apply_before_statement_effect(state, statement, location); - analysis.apply_statement_effect(state, statement, location); + analysis.apply_early_statement_effect(state, statement, location); + analysis.apply_primary_statement_effect(state, statement, location); } let exit_state = state; @@ -159,14 +159,14 @@ impl Direction for Backward { let location = Location { block, statement_index: from.statement_index }; let terminator = block_data.terminator(); - if from.effect == Effect::Before { - analysis.apply_before_terminator_effect(state, terminator, location); - if to == Effect::Before.at_index(terminator_index) { + if from.effect == Effect::Early { + analysis.apply_early_terminator_effect(state, terminator, location); + if to == Effect::Early.at_index(terminator_index) { return; } } - analysis.apply_terminator_effect(state, terminator, location); + analysis.apply_primary_terminator_effect(state, terminator, location); if to == Effect::Primary.at_index(terminator_index) { return; } @@ -180,7 +180,7 @@ impl Direction for Backward { let location = Location { block, statement_index: from.statement_index }; let statement = &block_data.statements[from.statement_index]; - analysis.apply_statement_effect(state, statement, location); + analysis.apply_primary_statement_effect(state, statement, location); if to == Effect::Primary.at_index(from.statement_index) { return; } @@ -188,7 +188,7 @@ impl Direction for Backward { from.statement_index - 1 } - Effect::Before => from.statement_index, + Effect::Early => from.statement_index, }; // Handle all statements between `first_unapplied_idx` and `to.statement_index`. @@ -196,21 +196,21 @@ impl Direction for Backward { for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) { let location = Location { block, statement_index }; let statement = &block_data.statements[statement_index]; - analysis.apply_before_statement_effect(state, statement, location); - analysis.apply_statement_effect(state, statement, location); + analysis.apply_early_statement_effect(state, statement, location); + analysis.apply_primary_statement_effect(state, statement, location); } // Handle the statement at `to`. let location = Location { block, statement_index: to.statement_index }; let statement = &block_data.statements[to.statement_index]; - analysis.apply_before_statement_effect(state, statement, location); + analysis.apply_early_statement_effect(state, statement, location); - if to.effect == Effect::Before { + if to.effect == Effect::Early { return; } - analysis.apply_statement_effect(state, statement, location); + analysis.apply_primary_statement_effect(state, statement, location); } fn visit_results_in_block<'mir, 'tcx, A>( @@ -228,17 +228,17 @@ impl Direction for Backward { let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); - results.analysis.apply_before_terminator_effect(state, term, loc); - vis.visit_terminator_before_primary_effect(results, state, term, loc); - results.analysis.apply_terminator_effect(state, term, loc); - vis.visit_terminator_after_primary_effect(results, state, term, loc); + results.analysis.apply_early_terminator_effect(state, term, loc); + vis.visit_after_early_terminator_effect(results, state, term, loc); + results.analysis.apply_primary_terminator_effect(state, term, loc); + vis.visit_after_primary_terminator_effect(results, state, term, loc); for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() { let loc = Location { block, statement_index }; - results.analysis.apply_before_statement_effect(state, stmt, loc); - vis.visit_statement_before_primary_effect(results, state, stmt, loc); - results.analysis.apply_statement_effect(state, stmt, loc); - vis.visit_statement_after_primary_effect(results, state, stmt, loc); + results.analysis.apply_early_statement_effect(state, stmt, loc); + vis.visit_after_early_statement_effect(results, state, stmt, loc); + results.analysis.apply_primary_statement_effect(state, stmt, loc); + vis.visit_after_primary_statement_effect(results, state, stmt, loc); } vis.visit_block_start(state); @@ -294,13 +294,13 @@ impl Direction for Forward { { for (statement_index, statement) in block_data.statements.iter().enumerate() { let location = Location { block, statement_index }; - analysis.apply_before_statement_effect(state, statement, location); - analysis.apply_statement_effect(state, statement, location); + analysis.apply_early_statement_effect(state, statement, location); + analysis.apply_primary_statement_effect(state, statement, location); } let terminator = block_data.terminator(); let location = Location { block, statement_index: block_data.statements.len() }; - analysis.apply_before_terminator_effect(state, terminator, location); - let edges = analysis.apply_terminator_effect(state, terminator, location); + analysis.apply_early_terminator_effect(state, terminator, location); + let edges = analysis.apply_primary_terminator_effect(state, terminator, location); let exit_state = state; match edges { @@ -368,21 +368,21 @@ impl Direction for Forward { // after effect, do so now and start the loop below from the next statement. let first_unapplied_index = match from.effect { - Effect::Before => from.statement_index, + Effect::Early => from.statement_index, Effect::Primary if from.statement_index == terminator_index => { debug_assert_eq!(from, to); let location = Location { block, statement_index: terminator_index }; let terminator = block_data.terminator(); - analysis.apply_terminator_effect(state, terminator, location); + analysis.apply_primary_terminator_effect(state, terminator, location); return; } Effect::Primary => { let location = Location { block, statement_index: from.statement_index }; let statement = &block_data.statements[from.statement_index]; - analysis.apply_statement_effect(state, statement, location); + analysis.apply_primary_statement_effect(state, statement, location); // If we only needed to apply the after effect of the statement at `idx`, we are // done. @@ -399,8 +399,8 @@ impl Direction for Forward { for statement_index in first_unapplied_index..to.statement_index { let location = Location { block, statement_index }; let statement = &block_data.statements[statement_index]; - analysis.apply_before_statement_effect(state, statement, location); - analysis.apply_statement_effect(state, statement, location); + analysis.apply_early_statement_effect(state, statement, location); + analysis.apply_primary_statement_effect(state, statement, location); } // Handle the statement or terminator at `to`. @@ -408,17 +408,17 @@ impl Direction for Forward { let location = Location { block, statement_index: to.statement_index }; if to.statement_index == terminator_index { let terminator = block_data.terminator(); - analysis.apply_before_terminator_effect(state, terminator, location); + analysis.apply_early_terminator_effect(state, terminator, location); if to.effect == Effect::Primary { - analysis.apply_terminator_effect(state, terminator, location); + analysis.apply_primary_terminator_effect(state, terminator, location); } } else { let statement = &block_data.statements[to.statement_index]; - analysis.apply_before_statement_effect(state, statement, location); + analysis.apply_early_statement_effect(state, statement, location); if to.effect == Effect::Primary { - analysis.apply_statement_effect(state, statement, location); + analysis.apply_primary_statement_effect(state, statement, location); } } } @@ -438,18 +438,18 @@ impl Direction for Forward { for (statement_index, stmt) in block_data.statements.iter().enumerate() { let loc = Location { block, statement_index }; - results.analysis.apply_before_statement_effect(state, stmt, loc); - vis.visit_statement_before_primary_effect(results, state, stmt, loc); - results.analysis.apply_statement_effect(state, stmt, loc); - vis.visit_statement_after_primary_effect(results, state, stmt, loc); + results.analysis.apply_early_statement_effect(state, stmt, loc); + vis.visit_after_early_statement_effect(results, state, stmt, loc); + results.analysis.apply_primary_statement_effect(state, stmt, loc); + vis.visit_after_primary_statement_effect(results, state, stmt, loc); } let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); - results.analysis.apply_before_terminator_effect(state, term, loc); - vis.visit_terminator_before_primary_effect(results, state, term, loc); - results.analysis.apply_terminator_effect(state, term, loc); - vis.visit_terminator_after_primary_effect(results, state, term, loc); + results.analysis.apply_early_terminator_effect(state, term, loc); + vis.visit_after_early_terminator_effect(results, state, term, loc); + results.analysis.apply_primary_terminator_effect(state, term, loc); + vis.visit_after_primary_terminator_effect(results, state, term, loc); vis.visit_block_end(state); } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index f844e8fbe03..5b2b128e035 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -724,7 +724,7 @@ where } } - fn visit_statement_before_primary_effect( + fn visit_after_early_statement_effect( &mut self, results: &mut Results<'tcx, A>, state: &A::Domain, @@ -737,7 +737,7 @@ where } } - fn visit_statement_after_primary_effect( + fn visit_after_primary_statement_effect( &mut self, results: &mut Results<'tcx, A>, state: &A::Domain, @@ -748,7 +748,7 @@ where self.prev_state.clone_from(state) } - fn visit_terminator_before_primary_effect( + fn visit_after_early_terminator_effect( &mut self, results: &mut Results<'tcx, A>, state: &A::Domain, @@ -761,7 +761,7 @@ where } } - fn visit_terminator_after_primary_effect( + fn visit_after_primary_terminator_effect( &mut self, results: &mut Results<'tcx, A>, state: &A::Domain, diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index e063eaf74bd..cb8159ce37b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -38,10 +38,8 @@ //! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram //! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set -use std::iter; - +use rustc_index::Idx; use rustc_index::bit_set::{BitSet, MixedBitSet}; -use rustc_index::{Idx, IndexVec}; use crate::framework::BitSetExt; @@ -70,53 +68,6 @@ pub trait HasTop { const TOP: Self; } -/// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom: -/// -/// ```text -/// true -/// | -/// false -/// ``` -impl JoinSemiLattice for bool { - fn join(&mut self, other: &Self) -> bool { - if let (false, true) = (*self, *other) { - *self = true; - return true; - } - - false - } -} - -impl HasBottom for bool { - const BOTTOM: Self = false; - - fn is_bottom(&self) -> bool { - !self - } -} - -impl HasTop for bool { - const TOP: Self = true; -} - -/// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation -/// of the least upper bounds of each element of the tuple (or list). -/// -/// In other words: -/// (A₀, A₁, ..., Aₙ) ∨ (B₀, B₁, ..., Bₙ) = (A₀∨B₀, A₁∨B₁, ..., Aₙ∨Bₙ) -impl<I: Idx, T: JoinSemiLattice> JoinSemiLattice for IndexVec<I, T> { - fn join(&mut self, other: &Self) -> bool { - assert_eq!(self.len(), other.len()); - - let mut changed = false; - for (a, b) in iter::zip(self, other) { - changed |= a.join(b); - } - changed - } -} - /// A `BitSet` represents the lattice formed by the powerset of all possible values of /// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices, /// one for each possible value of `T`. @@ -197,18 +148,6 @@ impl<T> MaybeReachable<T> { } } -impl<T> HasBottom for MaybeReachable<T> { - const BOTTOM: Self = MaybeReachable::Unreachable; - - fn is_bottom(&self) -> bool { - matches!(self, Self::Unreachable) - } -} - -impl<T: HasTop> HasTop for MaybeReachable<T> { - const TOP: Self = MaybeReachable::Reachable(T::TOP); -} - impl<S> MaybeReachable<S> { /// Return whether the current state contains the given element. If the state is unreachable, /// it does no contain anything. diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 7f5a68e884e..41df5fae0de 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -56,7 +56,7 @@ mod visitor; pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; -pub use self::results::{EntrySets, Results}; +pub use self::results::{EntryStates, Results}; pub use self::visitor::{ResultsVisitor, visit_results}; /// Analysis domains are all bitsets of various kinds. This trait holds @@ -122,8 +122,23 @@ pub trait Analysis<'tcx> { // `resume`). It's not obvious how to handle `yield` points in coroutines, however. fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain); + /// Updates the current dataflow state with an "early" effect, i.e. one + /// that occurs immediately before the given statement. + /// + /// This method is useful if the consumer of the results of this analysis only needs to observe + /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule, + /// analyses should not implement this without also implementing + /// `apply_primary_statement_effect`. + fn apply_early_statement_effect( + &mut self, + _state: &mut Self::Domain, + _statement: &mir::Statement<'tcx>, + _location: Location, + ) { + } + /// Updates the current dataflow state with the effect of evaluating a statement. - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, @@ -131,15 +146,16 @@ pub trait Analysis<'tcx> { ); /// Updates the current dataflow state with an effect that occurs immediately *before* the - /// given statement. + /// given terminator. /// - /// This method is useful if the consumer of the results of this analysis only needs to observe - /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule, - /// analyses should not implement this without also implementing `apply_statement_effect`. - fn apply_before_statement_effect( + /// This method is useful if the consumer of the results of this analysis needs only to observe + /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule, + /// analyses should not implement this without also implementing + /// `apply_primary_terminator_effect`. + fn apply_early_terminator_effect( &mut self, _state: &mut Self::Domain, - _statement: &mir::Statement<'tcx>, + _terminator: &mir::Terminator<'tcx>, _location: Location, ) { } @@ -150,7 +166,7 @@ pub trait Analysis<'tcx> { /// in this function. That should go in `apply_call_return_effect`. For example, in the /// `InitializedPlaces` analyses, the return place for a function call is not marked as /// initialized here. - fn apply_terminator_effect<'mir>( + fn apply_primary_terminator_effect<'mir>( &mut self, _state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, @@ -159,27 +175,13 @@ pub trait Analysis<'tcx> { terminator.edges() } - /// Updates the current dataflow state with an effect that occurs immediately *before* the - /// given terminator. - /// - /// This method is useful if the consumer of the results of this analysis needs only to observe - /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule, - /// analyses should not implement this without also implementing `apply_terminator_effect`. - fn apply_before_terminator_effect( - &mut self, - _state: &mut Self::Domain, - _terminator: &mir::Terminator<'tcx>, - _location: Location, - ) { - } - /* Edge-specific effects */ /// Updates the current dataflow state with the effect of a successful return from a `Call` /// terminator. /// - /// This is separate from `apply_terminator_effect` to properly track state across unwind - /// edges. + /// This is separate from `apply_primary_terminator_effect` to properly track state across + /// unwind edges. fn apply_call_return_effect( &mut self, _state: &mut Self::Domain, @@ -234,11 +236,12 @@ pub trait Analysis<'tcx> { Self: Sized, Self::Domain: DebugWithContext<Self>, { - let mut entry_sets = + let mut entry_states = IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); - self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); + self.initialize_start_block(body, &mut entry_states[mir::START_BLOCK]); - if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) { + if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body) + { bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); } @@ -262,9 +265,9 @@ pub trait Analysis<'tcx> { let mut state = self.bottom_value(body); while let Some(bb) = dirty_queue.pop() { // Set the state to the entry state of the block. - // This is equivalent to `state = entry_sets[bb].clone()`, + // This is equivalent to `state = entry_states[bb].clone()`, // but it saves an allocation, thus improving compile times. - state.clone_from(&entry_sets[bb]); + state.clone_from(&entry_states[bb]); Self::Direction::apply_effects_in_block( &mut self, @@ -273,7 +276,7 @@ pub trait Analysis<'tcx> { bb, &body[bb], |target: BasicBlock, state: &Self::Domain| { - let set_changed = entry_sets[target].join(state); + let set_changed = entry_states[target].join(state); if set_changed { dirty_queue.insert(target); } @@ -281,7 +284,7 @@ pub trait Analysis<'tcx> { ); } - let mut results = Results { analysis: self, entry_sets }; + let mut results = Results { analysis: self, entry_states }; if tcx.sess.opts.unstable_opts.dump_mir_dataflow { let res = write_graphviz_results(tcx, body, &mut results, pass_name); @@ -358,11 +361,10 @@ impl<T, S: GenKill<T>> GenKill<T> for MaybeReachable<S> { // NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] enum Effect { - /// The "before" effect (e.g., `apply_before_statement_effect`) for a statement (or - /// terminator). - Before, + /// The "early" effect (e.g., `apply_early_statement_effect`) for a statement/terminator. + Early, - /// The "primary" effect (e.g., `apply_statement_effect`) for a statement (or terminator). + /// The "primary" effect (e.g., `apply_primary_statement_effect`) for a statement/terminator. Primary, } @@ -381,15 +383,15 @@ pub struct EffectIndex { impl EffectIndex { fn next_in_forward_order(self) -> Self { match self.effect { - Effect::Before => Effect::Primary.at_index(self.statement_index), - Effect::Primary => Effect::Before.at_index(self.statement_index + 1), + Effect::Early => Effect::Primary.at_index(self.statement_index), + Effect::Primary => Effect::Early.at_index(self.statement_index + 1), } } fn next_in_backward_order(self) -> Self { match self.effect { - Effect::Before => Effect::Primary.at_index(self.statement_index), - Effect::Primary => Effect::Before.at_index(self.statement_index - 1), + Effect::Early => Effect::Primary.at_index(self.statement_index), + Effect::Primary => Effect::Early.at_index(self.statement_index - 1), } } diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs index a7dbd99b8ab..8e2c3afddb3 100644 --- a/compiler/rustc_mir_dataflow/src/framework/results.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::{BasicBlock, Body, traversal}; use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results}; use crate::framework::cursor::ResultsHandle; -pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>; +pub type EntryStates<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>; /// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the /// entry of each basic block. Domain values in other parts of the block are recomputed on the fly @@ -17,7 +17,7 @@ where A: Analysis<'tcx>, { pub analysis: A, - pub entry_sets: EntrySets<'tcx, A>, + pub entry_states: EntryStates<'tcx, A>, } impl<'tcx, A> Results<'tcx, A> @@ -40,7 +40,7 @@ where /// Gets the dataflow state for the given block. pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain { - &self.entry_sets[block] + &self.entry_states[block] } pub fn visit_with<'mir>( diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 14fb6dfb50c..8e7d4ab0fa3 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -73,7 +73,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { /// /// The `102` in the block's entry set is derived from the basic block index and ensures that the /// expected state is unique across all basic blocks. Remember, it is generated by -/// `mock_entry_sets`, not from actually running `MockAnalysis` to fixpoint. +/// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint. struct MockAnalysis<'tcx, D> { body: &'tcx mir::Body<'tcx>, dir: PhantomData<D>, @@ -90,7 +90,7 @@ impl<D: Direction> MockAnalysis<'_, D> { ret } - fn mock_entry_sets(&self) -> IndexVec<BasicBlock, BitSet<usize>> { + fn mock_entry_states(&self) -> IndexVec<BasicBlock, BitSet<usize>> { let empty = self.bottom_value(self.body); let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks); @@ -104,7 +104,7 @@ impl<D: Direction> MockAnalysis<'_, D> { /// Returns the index that should be added to the dataflow state at the given target. fn effect(&self, loc: EffectIndex) -> usize { let idx = match loc.effect { - Effect::Before => loc.statement_index * 2, + Effect::Early => loc.statement_index * 2, Effect::Primary => loc.statement_index * 2 + 1, }; @@ -128,14 +128,14 @@ impl<D: Direction> MockAnalysis<'_, D> { let target = match target { SeekTarget::BlockEntry { .. } => return ret, - SeekTarget::Before(loc) => Effect::Before.at_index(loc.statement_index), + SeekTarget::Early(loc) => Effect::Early.at_index(loc.statement_index), SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index), }; let mut pos = if D::IS_FORWARD { - Effect::Before.at_index(0) + Effect::Early.at_index(0) } else { - Effect::Before.at_index(self.body[block].statements.len()) + Effect::Early.at_index(self.body[block].statements.len()) }; loop { @@ -168,52 +168,52 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint"); } - fn apply_statement_effect( + fn apply_early_statement_effect( &mut self, state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { - let idx = self.effect(Effect::Primary.at_index(location.statement_index)); + let idx = self.effect(Effect::Early.at_index(location.statement_index)); assert!(state.insert(idx)); } - fn apply_before_statement_effect( + fn apply_primary_statement_effect( &mut self, state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { - let idx = self.effect(Effect::Before.at_index(location.statement_index)); + let idx = self.effect(Effect::Primary.at_index(location.statement_index)); assert!(state.insert(idx)); } - fn apply_terminator_effect<'mir>( + fn apply_early_terminator_effect( &mut self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + _terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { - let idx = self.effect(Effect::Primary.at_index(location.statement_index)); + ) { + let idx = self.effect(Effect::Early.at_index(location.statement_index)); assert!(state.insert(idx)); - terminator.edges() } - fn apply_before_terminator_effect( + fn apply_primary_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, - _terminator: &mir::Terminator<'tcx>, + terminator: &'mir mir::Terminator<'tcx>, location: Location, - ) { - let idx = self.effect(Effect::Before.at_index(location.statement_index)); + ) -> TerminatorEdges<'mir, 'tcx> { + let idx = self.effect(Effect::Primary.at_index(location.statement_index)); assert!(state.insert(idx)); + terminator.edges() } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum SeekTarget { BlockEntry(BasicBlock), - Before(Location), + Early(Location), After(Location), } @@ -223,7 +223,7 @@ impl SeekTarget { match *self { BlockEntry(block) => block, - Before(loc) | After(loc) => loc.block, + Early(loc) | After(loc) => loc.block, } } @@ -235,7 +235,7 @@ impl SeekTarget { .map(move |(i, kind)| { let loc = Location { block, statement_index: i }; match kind { - 0 => SeekTarget::Before(loc), + 0 => SeekTarget::Early(loc), 1 => SeekTarget::After(loc), _ => unreachable!(), } @@ -249,7 +249,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) { let body = analysis.body; let mut cursor = - Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body); + Results { entry_states: analysis.mock_entry_states(), analysis }.into_results_cursor(body); cursor.allow_unreachable(); @@ -262,7 +262,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) { match targ { BlockEntry(block) => cursor.seek_to_block_entry(block), - Before(loc) => cursor.seek_before_primary_effect(loc), + Early(loc) => cursor.seek_before_primary_effect(loc), After(loc) => cursor.seek_after_primary_effect(loc), } diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index bde41974d47..d18e9fa33f0 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -35,9 +35,9 @@ where { fn visit_block_start(&mut self, _state: &A::Domain) {} - /// Called with the `before_statement_effect` of the given statement applied to `state` but not - /// its `statement_effect`. - fn visit_statement_before_primary_effect( + /// // njn: grep for "before", "primary", etc. + /// Called after the "early" effect of the given statement is applied to `state`. + fn visit_after_early_statement_effect( &mut self, _results: &mut Results<'tcx, A>, _state: &A::Domain, @@ -46,9 +46,8 @@ where ) { } - /// Called with both the `before_statement_effect` and the `statement_effect` of the given - /// statement applied to `state`. - fn visit_statement_after_primary_effect( + /// Called after the "primary" effect of the given statement is applied to `state`. + fn visit_after_primary_statement_effect( &mut self, _results: &mut Results<'tcx, A>, _state: &A::Domain, @@ -57,9 +56,8 @@ where ) { } - /// Called with the `before_terminator_effect` of the given terminator applied to `state` but - /// not its `terminator_effect`. - fn visit_terminator_before_primary_effect( + /// Called after the "early" effect of the given terminator is applied to `state`. + fn visit_after_early_terminator_effect( &mut self, _results: &mut Results<'tcx, A>, _state: &A::Domain, @@ -68,11 +66,10 @@ where ) { } - /// Called with both the `before_terminator_effect` and the `terminator_effect` of the given - /// terminator applied to `state`. + /// Called after the "primary" effect of the given terminator is applied to `state`. /// /// The `call_return_effect` (if one exists) will *not* be applied to `state`. - fn visit_terminator_after_primary_effect( + fn visit_after_primary_terminator_effect( &mut self, _results: &mut Results<'tcx, A>, _state: &A::Domain, diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index cec654cac72..568d8a5acaf 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -33,22 +33,22 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { // No locals are aliased on function entry } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, statement: &Statement<'tcx>, location: Location, ) { - Self::transfer_function(trans).visit_statement(statement, location); + Self::transfer_function(state).visit_statement(statement, location); } - fn apply_terminator_effect<'mir>( + fn apply_primary_terminator_effect<'mir>( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, ) -> TerminatorEdges<'mir, 'tcx> { - Self::transfer_function(trans).visit_terminator(terminator, location); + Self::transfer_function(state).visit_terminator(terminator, location); terminator.edges() } } diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 91677657602..fb02408e17d 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -70,7 +70,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { pub fn is_unwind_dead( &self, place: mir::Place<'tcx>, - state: &MaybeReachable<MixedBitSet<MovePathIndex>>, + state: &<Self as Analysis<'tcx>>::Domain, ) -> bool { if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) { let mut maybe_live = false; @@ -218,26 +218,26 @@ impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> { impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut <Self as Analysis<'tcx>>::Domain, + state: &mut <Self as Analysis<'tcx>>::Domain, path: MovePathIndex, - state: DropFlagState, + dfstate: DropFlagState, ) { - match state { - DropFlagState::Absent => trans.kill(path), - DropFlagState::Present => trans.gen_(path), + match dfstate { + DropFlagState::Absent => state.kill(path), + DropFlagState::Present => state.gen_(path), } } } impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> { fn update_bits( - trans: &mut <Self as Analysis<'tcx>>::Domain, + state: &mut <Self as Analysis<'tcx>>::Domain, path: MovePathIndex, - state: DropFlagState, + dfstate: DropFlagState, ) { - match state { - DropFlagState::Absent => trans.gen_(path), - DropFlagState::Present => trans.kill(path), + match dfstate { + DropFlagState::Absent => state.gen_(path), + DropFlagState::Present => state.kill(path), } } } @@ -263,14 +263,14 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { }); } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { - Self::update_bits(trans, path, s) + Self::update_bits(state, path, s) }); // Mark all places as "maybe init" if they are mutably borrowed. See #90752. @@ -282,12 +282,12 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref()) { on_all_children_bits(self.move_data(), mpi, |child| { - trans.gen_(child); + state.gen_(child); }) } } - fn apply_terminator_effect<'mir>( + fn apply_primary_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, @@ -309,7 +309,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { fn apply_call_return_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, ) { @@ -320,7 +320,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(place.as_ref()), |mpi| { - trans.gen_(mpi); + state.gen_(mpi); }, ); }); @@ -345,7 +345,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { }; let mut discriminants = enum_def.discriminants(self.tcx); - edge_effects.apply(|trans, edge| { + edge_effects.apply(|state, edge| { let Some(value) = edge.value else { return; }; @@ -363,25 +363,27 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { self.move_data(), enum_place, variant, - |mpi| trans.kill(mpi), + |mpi| state.kill(mpi), ); }); } } +/// There can be many more `MovePathIndex` than there are locals in a MIR body. +/// We use a mixed bitset to avoid paying too high a memory footprint. +pub type MaybeUninitializedPlacesDomain = MixedBitSet<MovePathIndex>; + impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { - /// There can be many more `MovePathIndex` than there are locals in a MIR body. - /// We use a mixed bitset to avoid paying too high a memory footprint. - type Domain = MixedBitSet<MovePathIndex>; + type Domain = MaybeUninitializedPlacesDomain; const NAME: &'static str = "maybe_uninit"; fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { - // bottom = initialized (start_block_effect counters this at outset) + // bottom = initialized (`initialize_start_block` overwrites this on first entry) MixedBitSet::new_empty(self.move_data().move_paths.len()) } - // sets on_entry bits for Arg places + // sets state bits for Arg places fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { // set all bits to 1 (uninit) before gathering counter-evidence state.insert_all(); @@ -392,28 +394,28 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { }); } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { - Self::update_bits(trans, path, s) + Self::update_bits(state, path, s) }); // Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a // mutable borrow occurs. Places cannot become uninitialized through a mutable reference. } - fn apply_terminator_effect<'mir>( + fn apply_primary_terminator_effect<'mir>( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, ) -> TerminatorEdges<'mir, 'tcx> { drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { - Self::update_bits(trans, path, s) + Self::update_bits(state, path, s) }); if self.skip_unreachable_unwind.contains(location.block) { let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() }; @@ -426,7 +428,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { fn apply_call_return_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, ) { @@ -437,7 +439,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { self.move_data(), self.move_data().rev_lookup.find(place.as_ref()), |mpi| { - trans.kill(mpi); + state.kill(mpi); }, ); }); @@ -466,7 +468,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { }; let mut discriminants = enum_def.discriminants(self.tcx); - edge_effects.apply(|trans, edge| { + edge_effects.apply(|state, edge| { let Some(value) = edge.value else { return; }; @@ -484,16 +486,18 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { self.move_data(), enum_place, variant, - |mpi| trans.gen_(mpi), + |mpi| state.gen_(mpi), ); }); } } +/// There can be many more `InitIndex` than there are locals in a MIR body. +/// We use a mixed bitset to avoid paying too high a memory footprint. +pub type EverInitializedPlacesDomain = MixedBitSet<InitIndex>; + impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { - /// There can be many more `InitIndex` than there are locals in a MIR body. - /// We use a mixed bitset to avoid paying too high a memory footprint. - type Domain = MixedBitSet<InitIndex>; + type Domain = EverInitializedPlacesDomain; const NAME: &'static str = "ever_init"; @@ -508,10 +512,10 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { } } - #[instrument(skip(self, trans), level = "debug")] - fn apply_statement_effect( + #[instrument(skip(self, state), level = "debug")] + fn apply_primary_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, location: Location, ) { @@ -521,7 +525,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { let rev_lookup = &move_data.rev_lookup; debug!("initializes move_indexes {:?}", init_loc_map[location]); - trans.gen_all(init_loc_map[location].iter().copied()); + state.gen_all(init_loc_map[location].iter().copied()); if let mir::StatementKind::StorageDead(local) = stmt.kind { // End inits for StorageDead, so that an immutable variable can @@ -531,15 +535,15 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { "clears the ever initialized status of {:?}", init_path_map[move_path_index] ); - trans.kill_all(init_path_map[move_path_index].iter().copied()); + state.kill_all(init_path_map[move_path_index].iter().copied()); } } } - #[instrument(skip(self, trans, terminator), level = "debug")] - fn apply_terminator_effect<'mir>( + #[instrument(skip(self, state, terminator), level = "debug")] + fn apply_primary_terminator_effect<'mir>( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, ) -> TerminatorEdges<'mir, 'tcx> { @@ -548,7 +552,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { let init_loc_map = &move_data.init_loc_map; debug!(?term); debug!("initializes move_indexes {:?}", init_loc_map[location]); - trans.gen_all( + state.gen_all( init_loc_map[location] .iter() .filter(|init_index| { @@ -561,7 +565,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { fn apply_call_return_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, block: mir::BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, ) { @@ -570,7 +574,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { let call_loc = self.body.terminator_loc(block); for init_index in &init_loc_map[call_loc] { - trans.gen_(*init_index); + state.gen_(*init_index); } } } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index fd7254a0210..b2050a6adf9 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -40,33 +40,33 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { // No variables are live until we observe a use } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { - TransferFunction(trans).visit_statement(statement, location); + TransferFunction(state).visit_statement(statement, location); } - fn apply_terminator_effect<'mir>( + fn apply_primary_terminator_effect<'mir>( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, ) -> TerminatorEdges<'mir, 'tcx> { - TransferFunction(trans).visit_terminator(terminator, location); + TransferFunction(state).visit_terminator(terminator, location); terminator.edges() } fn apply_call_return_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, ) { if let CallReturnPlaces::Yield(resume_place) = return_places { - YieldResumeEffect(trans).visit_place( + YieldResumeEffect(state).visit_place( &resume_place, PlaceContext::MutatingUse(MutatingUseContext::Yield), Location::START, @@ -74,7 +74,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { } else { return_places.for_each(|place| { if let Some(local) = place.as_local() { - trans.kill(local); + state.kill(local); } }); } @@ -137,10 +137,10 @@ enum DefUse { } impl DefUse { - fn apply(trans: &mut BitSet<Local>, place: Place<'_>, context: PlaceContext) { + fn apply(state: &mut BitSet<Local>, place: Place<'_>, context: PlaceContext) { match DefUse::for_place(place, context) { - Some(DefUse::Def) => trans.kill(place.local), - Some(DefUse::Use) => trans.gen_(place.local), + Some(DefUse::Def) => state.kill(place.local), + Some(DefUse::Use) => state.gen_(place.local), None => {} } } @@ -232,9 +232,9 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { // No variables are live until we observe a use } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { @@ -258,34 +258,34 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { }; if let Some(destination) = destination { if !destination.is_indirect() - && !trans.contains(destination.local) + && !state.contains(destination.local) && !self.always_live.contains(destination.local) { // This store is dead return; } } - TransferFunction(trans).visit_statement(statement, location); + TransferFunction(state).visit_statement(statement, location); } - fn apply_terminator_effect<'mir>( + fn apply_primary_terminator_effect<'mir>( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, ) -> TerminatorEdges<'mir, 'tcx> { - TransferFunction(trans).visit_terminator(terminator, location); + TransferFunction(state).visit_terminator(terminator, location); terminator.edges() } fn apply_call_return_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, ) { if let CallReturnPlaces::Yield(resume_place) = return_places { - YieldResumeEffect(trans).visit_place( + YieldResumeEffect(state).visit_place( &resume_place, PlaceContext::MutatingUse(MutatingUseContext::Yield), Location::START, @@ -293,7 +293,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { } else { return_places.for_each(|place| { if let Some(local) = place.as_local() { - trans.remove(local); + state.remove(local); } }); } diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index d69a8019c8d..3f29b819a6d 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -5,7 +5,8 @@ mod storage_liveness; pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals}; pub use self::initialized::{ - EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, + EverInitializedPlaces, EverInitializedPlacesDomain, MaybeInitializedPlaces, + MaybeUninitializedPlaces, MaybeUninitializedPlacesDomain, }; pub use self::liveness::{ MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction, diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 1aae06d79d3..65b480d3a5e 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -44,23 +44,23 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> { BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) { - on_entry.union(&*self.always_live_locals); + fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { + state.union(&*self.always_live_locals); for arg in body.args_iter() { - on_entry.insert(arg); + state.insert(arg); } } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, stmt: &Statement<'tcx>, _: Location, ) { match stmt.kind { - StatementKind::StorageLive(l) => trans.gen_(l), - StatementKind::StorageDead(l) => trans.kill(l), + StatementKind::StorageLive(l) => state.gen_(l), + StatementKind::StorageDead(l) => state.kill(l), _ => (), } } @@ -86,25 +86,25 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> { BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) { + fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size()); // Do not iterate on return place and args, as they are trivially always live. for local in body.vars_and_temps_iter() { if !self.always_live_locals.contains(local) { - on_entry.insert(local); + state.insert(local); } } } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, stmt: &Statement<'tcx>, _: Location, ) { match stmt.kind { - StatementKind::StorageLive(l) => trans.kill(l), - StatementKind::StorageDead(l) => trans.gen_(l), + StatementKind::StorageLive(l) => state.kill(l), + StatementKind::StorageDead(l) => state.gen_(l), _ => (), } } @@ -134,31 +134,31 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { BitSet::new_empty(body.local_decls.len()) } - fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) { + fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { // The resume argument is live on function entry (we don't care about // the `self` argument) for arg in body.args_iter().skip(1) { - on_entry.insert(arg); + state.insert(arg); } } - fn apply_before_statement_effect( + fn apply_early_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, stmt: &Statement<'tcx>, loc: Location, ) { // If a place is borrowed in a statement, it needs storage for that statement. - MaybeBorrowedLocals::transfer_function(trans).visit_statement(stmt, loc); + MaybeBorrowedLocals::transfer_function(state).visit_statement(stmt, loc); match &stmt.kind { - StatementKind::StorageDead(l) => trans.kill(*l), + StatementKind::StorageDead(l) => state.kill(*l), // If a place is assigned to in a statement, it needs storage for that statement. StatementKind::Assign(box (place, _)) | StatementKind::SetDiscriminant { box place, .. } | StatementKind::Deinit(box place) => { - trans.gen_(place.local); + state.gen_(place.local); } // Nothing to do for these. Match exhaustively so this fails to compile when new @@ -176,29 +176,29 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, _: &Statement<'tcx>, loc: Location, ) { // If we move from a place then it only stops needing storage *after* // that statement. - self.check_for_move(trans, loc); + self.check_for_move(state, loc); } - fn apply_before_terminator_effect( + fn apply_early_terminator_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, terminator: &Terminator<'tcx>, loc: Location, ) { // If a place is borrowed in a terminator, it needs storage for that terminator. - MaybeBorrowedLocals::transfer_function(trans).visit_terminator(terminator, loc); + MaybeBorrowedLocals::transfer_function(state).visit_terminator(terminator, loc); match &terminator.kind { TerminatorKind::Call { destination, .. } => { - trans.gen_(destination.local); + state.gen_(destination.local); } // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for @@ -213,7 +213,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { InlineAsmOperand::Out { place, .. } | InlineAsmOperand::InOut { out_place: place, .. } => { if let Some(place) = place { - trans.gen_(place.local); + state.gen_(place.local); } } InlineAsmOperand::In { .. } @@ -242,9 +242,9 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } } - fn apply_terminator_effect<'t>( + fn apply_primary_terminator_effect<'t>( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, terminator: &'t Terminator<'tcx>, loc: Location, ) -> TerminatorEdges<'t, 'tcx> { @@ -254,12 +254,12 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { // Since `propagate_call_unwind` doesn't exist, we have to kill the // destination here, and then gen it again in `call_return_effect`. TerminatorKind::Call { destination, .. } => { - trans.kill(destination.local); + state.kill(destination.local); } // The same applies to InlineAsm outputs. TerminatorKind::InlineAsm { ref operands, .. } => { - CallReturnPlaces::InlineAsm(operands).for_each(|place| trans.kill(place.local)); + CallReturnPlaces::InlineAsm(operands).for_each(|place| state.kill(place.local)); } // Nothing to do for these. Match exhaustively so this fails to compile when new @@ -279,32 +279,32 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { | TerminatorKind::Unreachable => {} } - self.check_for_move(trans, loc); + self.check_for_move(state, loc); terminator.edges() } fn apply_call_return_effect( &mut self, - trans: &mut Self::Domain, + state: &mut Self::Domain, _block: BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, ) { - return_places.for_each(|place| trans.gen_(place.local)); + return_places.for_each(|place| state.gen_(place.local)); } } impl<'tcx> MaybeRequiresStorage<'_, 'tcx> { /// Kill locals that are fully moved and have not been borrowed. - fn check_for_move(&mut self, trans: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) { + fn check_for_move(&mut self, state: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) { let body = self.borrowed_locals.body(); - let mut visitor = MoveVisitor { trans, borrowed_locals: &mut self.borrowed_locals }; + let mut visitor = MoveVisitor { state, borrowed_locals: &mut self.borrowed_locals }; visitor.visit_location(body, loc); } } struct MoveVisitor<'a, 'mir, 'tcx> { borrowed_locals: &'a mut BorrowedLocalsResults<'mir, 'tcx>, - trans: &'a mut BitSet<Local>, + state: &'a mut BitSet<Local>, } impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> { @@ -312,7 +312,7 @@ impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> { if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { self.borrowed_locals.seek_before_primary_effect(loc); if !self.borrowed_locals.get().contains(local) { - self.trans.kill(local); + self.state.kill(local); } } } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 2248972cecc..85255db5d9a 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -18,7 +18,7 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - Analysis, Backward, Direction, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable, + Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice, visit_results, }; diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 10f1e009855..74209da876a 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -125,7 +125,7 @@ where A: Analysis<'tcx, Domain = BitSet<N>>, N: Idx, { - fn visit_statement_after_primary_effect( + fn visit_after_primary_statement_effect( &mut self, _results: &mut Results<'tcx, A>, state: &A::Domain, @@ -139,7 +139,7 @@ where }); } - fn visit_terminator_after_primary_effect( + fn visit_after_primary_terminator_effect( &mut self, _results: &mut Results<'tcx, A>, state: &A::Domain, diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 34ef8afdde3..85cf8ca2104 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -1,6 +1,5 @@ use rustc_ast::MetaItem; use rustc_hir::def_id::DefId; -use rustc_index::bit_set::BitSet; use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; @@ -254,7 +253,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals { &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - state: &BitSet<Local>, + state: &Self::Domain, call: PeekCall, ) { info!(?place, "peek_at"); diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index ed8678de1eb..9328870c7ae 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -67,7 +67,7 @@ impl<V: Clone> Clone for StateData<V> { } } -impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for StateData<V> { +impl<V: JoinSemiLattice + Clone> JoinSemiLattice for StateData<V> { fn join(&mut self, other: &Self) -> bool { let mut changed = false; #[allow(rustc::potential_query_instability)] @@ -342,7 +342,7 @@ impl<V: Clone + HasBottom> State<V> { } } -impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for State<V> { +impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> { fn join(&mut self, other: &Self) -> bool { match (&mut *self, other) { (_, State::Unreachable) => false, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 858752a3f01..31d5245fb5c 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -878,7 +878,7 @@ struct StorageConflictVisitor<'a, 'tcx> { impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>> for StorageConflictVisitor<'a, 'tcx> { - fn visit_statement_before_primary_effect( + fn visit_after_early_statement_effect( &mut self, _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, state: &BitSet<Local>, @@ -888,7 +888,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>> self.apply_state(state, loc); } - fn visit_terminator_before_primary_effect( + fn visit_after_early_terminator_effect( &mut self, _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, state: &BitSet<Local>, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index b94c925b1db..711cf2edc46 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -106,7 +106,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } - fn apply_statement_effect( + fn apply_primary_statement_effect( &mut self, state: &mut Self::Domain, statement: &Statement<'tcx>, @@ -117,7 +117,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } - fn apply_terminator_effect<'mir>( + fn apply_primary_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, @@ -224,7 +224,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } /// The effect of a successful function call return should not be - /// applied here, see [`Analysis::apply_terminator_effect`]. + /// applied here, see [`Analysis::apply_primary_terminator_effect`]. fn handle_terminator<'mir>( &self, terminator: &'mir Terminator<'tcx>, @@ -954,7 +954,7 @@ fn try_write_constant<'tcx>( impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> { #[instrument(level = "trace", skip(self, results, statement))] - fn visit_statement_before_primary_effect( + fn visit_after_early_statement_effect( &mut self, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &State<FlatSet<Scalar>>, @@ -976,7 +976,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collect } #[instrument(level = "trace", skip(self, results, statement))] - fn visit_statement_after_primary_effect( + fn visit_after_primary_statement_effect( &mut self, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &State<FlatSet<Scalar>>, @@ -1001,7 +1001,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collect } } - fn visit_terminator_before_primary_effect( + fn visit_after_early_terminator_effect( &mut self, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &State<FlatSet<Scalar>>, diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 0c0f3b61977..3ebc9113725 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -127,7 +127,7 @@ impl InitializationData<'_, '_> { self.uninits.seek_before_primary_effect(loc); } - fn maybe_live_dead(&self, path: MovePathIndex) -> (bool, bool) { + fn maybe_init_uninit(&self, path: MovePathIndex) -> (bool, bool) { (self.inits.get().contains(path), self.uninits.get().contains(path)) } } @@ -153,23 +153,23 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self), ret)] fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle { - let ((maybe_live, maybe_dead), multipart) = match mode { - DropFlagMode::Shallow => (self.init_data.maybe_live_dead(path), false), + let ((maybe_init, maybe_uninit), multipart) = match mode { + DropFlagMode::Shallow => (self.init_data.maybe_init_uninit(path), false), DropFlagMode::Deep => { - let mut some_live = false; - let mut some_dead = false; + let mut some_maybe_init = false; + let mut some_maybe_uninit = false; let mut children_count = 0; on_all_children_bits(self.move_data(), path, |child| { - let (live, dead) = self.init_data.maybe_live_dead(child); - debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead)); - some_live |= live; - some_dead |= dead; + let (maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(child); + debug!("elaborate_drop: state({:?}) = {:?}", child, (maybe_init, maybe_uninit)); + some_maybe_init |= maybe_init; + some_maybe_uninit |= maybe_uninit; children_count += 1; }); - ((some_live, some_dead), children_count != 1) + ((some_maybe_init, some_maybe_uninit), children_count != 1) } }; - match (maybe_live, maybe_dead, multipart) { + match (maybe_init, maybe_uninit, multipart) { (false, _, _) => DropStyle::Dead, (true, false, _) => DropStyle::Static, (true, true, false) => DropStyle::Conditional, @@ -283,15 +283,15 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { LookupResult::Exact(path) => { self.init_data.seek_before(self.body.terminator_loc(bb)); on_all_children_bits(self.move_data(), path, |child| { - let (maybe_live, maybe_dead) = self.init_data.maybe_live_dead(child); + let (maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(child); debug!( "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", child, place, path, - (maybe_live, maybe_dead) + (maybe_init, maybe_uninit) ); - if maybe_live && maybe_dead { + if maybe_init && maybe_uninit { self.create_drop_flag(child, terminator.source_info.span) } }); @@ -303,8 +303,8 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> { } self.init_data.seek_before(self.body.terminator_loc(bb)); - let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); - if maybe_dead { + let (_maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(parent); + if maybe_uninit { self.tcx.dcx().span_delayed_bug( terminator.source_info.span, format!( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 44f42e5fbf2..a2136399b0c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -15,7 +15,7 @@ use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::{ self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall, - MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, + MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -1931,6 +1931,12 @@ impl<'a> Parser<'a> { Ok(match ident.name { sym::offset_of => Some(this.parse_expr_offset_of(lo)?), sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?), + sym::wrap_binder => { + Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?) + } + sym::unwrap_binder => { + Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?) + } _ => None, }) }) @@ -2006,6 +2012,17 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span, ExprKind::Type(expr, ty))) } + pub(crate) fn parse_expr_unsafe_binder_cast( + &mut self, + lo: Span, + kind: UnsafeBinderCastKind, + ) -> PResult<'a, P<Expr>> { + let expr = self.parse_expr()?; + let ty = if self.eat(&TokenKind::Comma) { Some(self.parse_ty()?) } else { None }; + let span = lo.to(self.token.span); + Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty))) + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. @@ -4016,7 +4033,9 @@ impl MutVisitor for CondChecker<'_> { mut_visit::walk_expr(self, e); self.forbid_let_reason = forbid_let_reason; } - ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => { + ExprKind::Cast(ref mut op, _) + | ExprKind::Type(ref mut op, _) + | ExprKind::UnsafeBinderCast(_, ref mut op, _) => { let forbid_let_reason = self.forbid_let_reason; self.forbid_let_reason = Some(OtherForbidden); self.visit_expr(op); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 58b4bf8980b..e27fc963eb9 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -45,7 +45,7 @@ impl<'a> Parser<'a> { let (inner_attrs, items, inner_span) = self.parse_mod(&token::CloseDelim(Delimiter::Brace))?; attrs.extend(inner_attrs); - ModKind::Loaded(items, Inline::Yes, inner_span) + ModKind::Loaded(items, Inline::Yes, inner_span, Ok(())) }; Ok((id, ItemKind::Mod(safety, mod_kind))) } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 8cff23c2e32..f696074e66a 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -5,7 +5,7 @@ use rustc_ast::{ self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, - TyKind, + TyKind, UnsafeBinderTy, }; use rustc_errors::{Applicability, PResult}; use rustc_span::symbol::{Ident, kw, sym}; @@ -348,6 +348,10 @@ impl<'a> Parser<'a> { TyKind::Err(guar) } } + } else if self.check_keyword(kw::Unsafe) + && self.look_ahead(1, |tok| matches!(tok.kind, token::Lt)) + { + self.parse_unsafe_binder_ty()? } else { let msg = format!("expected type, found {}", super::token_descr(&self.token)); let mut err = self.dcx().struct_span_err(lo, msg); @@ -369,6 +373,19 @@ impl<'a> Parser<'a> { if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) } } + fn parse_unsafe_binder_ty(&mut self) -> PResult<'a, TyKind> { + let lo = self.token.span; + assert!(self.eat_keyword(kw::Unsafe)); + self.expect_lt()?; + let generic_params = self.parse_generic_params()?; + self.expect_gt()?; + let inner_ty = self.parse_ty()?; + let span = lo.to(self.prev_token.span); + self.psess.gated_spans.gate(sym::unsafe_binders, span); + + Ok(TyKind::UnsafeBinder(P(UnsafeBinderTy { generic_params, inner_ty }))) + } + /// Parses either: /// - `(TYPE)`, a parenthesized type. /// - `(TYPE,)`, a tuple with a single field of type TYPE. diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 76edb51c0bc..164cbc69595 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -315,9 +315,40 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_expr(&mut self, e: &'v hir::Expr<'v>) { record_variants!((self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind), [ - ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, DropTemps, - Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, Path, AddrOf, - Break, Continue, Ret, Become, InlineAsm, OffsetOf, Struct, Repeat, Yield, Err + ConstBlock, + Array, + Call, + MethodCall, + Tup, + Binary, + Unary, + Lit, + Cast, + Type, + DropTemps, + Let, + If, + Loop, + Match, + Closure, + Block, + Assign, + AssignOp, + Field, + Index, + Path, + AddrOf, + Break, + Continue, + Ret, + Become, + InlineAsm, + OffsetOf, + Struct, + Repeat, + Yield, + UnsafeBinderCast, + Err ]); hir_visit::walk_expr(self, e) } @@ -335,6 +366,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Ptr, Ref, BareFn, + UnsafeBinder, Never, Tup, Path, @@ -571,7 +603,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, - Become, IncludedBytes, Gen, Err, Dummy + Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy ] ); ast_visit::walk_expr(self, e) @@ -585,6 +617,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Ref, PinnedRef, BareFn, + UnsafeBinder, Never, Tup, Path, diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 09cbb648f9b..034f7308c4a 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -447,6 +447,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::InlineAsm(..) | hir::ExprKind::OffsetOf(..) | hir::ExprKind::Type(..) + | hir::ExprKind::UnsafeBinderCast(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {} @@ -1051,6 +1052,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::AddrOf(_, _, ref e) | hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Type(ref e, _) + | hir::ExprKind::UnsafeBinderCast(_, ref e, _) | hir::ExprKind::DropTemps(ref e) | hir::ExprKind::Unary(_, ref e) | hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(e, succ), @@ -1443,6 +1445,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) | hir::ExprKind::Type(..) + | hir::ExprKind::UnsafeBinderCast(..) | hir::ExprKind::Err(_) => {} } } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index b2f8d7dadff..766a9e1bdad 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -186,6 +186,7 @@ impl CheckInlineAssembly { | ExprKind::Lit(..) | ExprKind::Cast(..) | ExprKind::Type(..) + | ExprKind::UnsafeBinderCast(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::If(..) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 293cee500bb..924b8afa329 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -770,7 +770,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ); } - ItemKind::Mod(..) => { + ItemKind::Mod(.., ref mod_kind) => { let module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, ident.name), @@ -781,6 +781,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); + if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { + self.r.mods_with_parse_errors.insert(def_id); + } + // Descend into the module. self.parent_scope.module = module; } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 4c76617a391..368eb3c26c7 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -3056,7 +3056,7 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { fn visit_item(&mut self, item: &'tcx ast::Item) { if self.target_module == item.id { - if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind { + if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind { let inject = mod_spans.inject_use_span; if is_span_suitable_for_use_injection(inject) { self.first_legal_span = Some(inject); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 466e190028a..5906a682f3e 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1428,6 +1428,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_import: Option<Import<'ra>>, ) -> PathResult<'ra> { let mut module = None; + let mut module_had_parse_errors = false; let mut allow_super = true; let mut second_binding = None; @@ -1471,9 +1472,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { continue; } } - return PathResult::failed(ident, false, finalize.is_some(), module, || { - ("there are too many leading `super` keywords".to_string(), None) - }); + return PathResult::failed( + ident, + false, + finalize.is_some(), + module_had_parse_errors, + module, + || ("there are too many leading `super` keywords".to_string(), None), + ); } if segment_idx == 0 { if name == kw::SelfLower { @@ -1511,19 +1517,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Report special messages for path segment keywords in wrong positions. if ident.is_path_segment_keyword() && segment_idx != 0 { - return PathResult::failed(ident, false, finalize.is_some(), module, || { - let name_str = if name == kw::PathRoot { - "crate root".to_string() - } else { - format!("`{name}`") - }; - let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot { - format!("global paths cannot start with {name_str}") - } else { - format!("{name_str} in paths can only be used in start position") - }; - (label, None) - }); + return PathResult::failed( + ident, + false, + finalize.is_some(), + module_had_parse_errors, + module, + || { + let name_str = if name == kw::PathRoot { + "crate root".to_string() + } else { + format!("`{name}`") + }; + let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot { + format!("global paths cannot start with {name_str}") + } else { + format!("{name_str} in paths can only be used in start position") + }; + (label, None) + }, + ); } let binding = if let Some(module) = module { @@ -1589,6 +1602,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); if let Some(next_module) = binding.module() { + if self.mods_with_parse_errors.contains(&next_module.def_id()) { + module_had_parse_errors = true; + } module = Some(ModuleOrUniformRoot::Module(next_module)); record_segment_res(self, res); } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { @@ -1614,6 +1630,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, is_last, finalize.is_some(), + module_had_parse_errors, module, || { let label = format!( @@ -1637,19 +1654,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - return PathResult::failed(ident, is_last, finalize.is_some(), module, || { - self.report_path_resolution_error( - path, - opt_ns, - parent_scope, - ribs, - ignore_binding, - ignore_import, - module, - segment_idx, - ident, - ) - }); + return PathResult::failed( + ident, + is_last, + finalize.is_some(), + module_had_parse_errors, + module, + || { + self.report_path_resolution_error( + path, + opt_ns, + parent_scope, + ribs, + ignore_binding, + ignore_import, + module, + segment_idx, + ident, + ) + }, + ); } } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 51fbcb8ebb8..2ed3f4d2c4f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -670,9 +670,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn throw_unresolved_import_error( &mut self, - errors: Vec<(Import<'_>, UnresolvedImportError)>, + mut errors: Vec<(Import<'_>, UnresolvedImportError)>, glob_error: bool, ) { + errors.retain(|(_import, err)| match err.module { + // Skip `use` errors for `use foo::Bar;` if `foo.rs` has unrecovered parse errors. + Some(def_id) if self.mods_with_parse_errors.contains(&def_id) => false, + _ => true, + }); if errors.is_empty() { return; } @@ -898,6 +903,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { label, suggestion, module, + error_implied_by_parse_error: _, } => { if no_ambiguity { assert!(import.imported_module.get().is_none()); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 789d74876f7..bde11428d40 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -887,6 +887,28 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r }, ) } + TyKind::UnsafeBinder(unsafe_binder) => { + // FIXME(unsafe_binder): Better span + let span = ty.span; + self.with_generic_param_rib( + &unsafe_binder.generic_params, + RibKind::Normal, + LifetimeRibKind::Generics { + binder: ty.id, + kind: LifetimeBinderKind::BareFnType, + span, + }, + |this| { + this.visit_generic_params(&unsafe_binder.generic_params, false); + this.with_lifetime_rib( + // We don't allow anonymous `unsafe &'_ ()` binders, + // although I guess we could. + LifetimeRibKind::AnonymousReportError, + |this| this.visit_ty(&unsafe_binder.inner_ty), + ); + }, + ) + } TyKind::Array(element_ty, length) => { self.visit_ty(element_ty); self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No)); @@ -4395,6 +4417,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => { PartialRes::new(module.res().unwrap()) } + // A part of this path references a `mod` that had a parse error. To avoid resolution + // errors for each reference to that module, we don't emit an error for them until the + // `mod` is fixed. this can have a significant cascade effect. + PathResult::Failed { error_implied_by_parse_error: true, .. } => { + PartialRes::new(Res::Err) + } // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we // don't report an error right away, but try to fallback to a primitive type. // So, we are still able to successfully resolve something like @@ -4443,6 +4471,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { suggestion, module, segment_name, + error_implied_by_parse_error: _, } => { return Err(respan(span, ResolutionError::FailedToResolve { segment: Some(segment_name), diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ca4adce37ce..94adfcd3b91 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -450,6 +450,7 @@ enum PathResult<'ra> { module: Option<ModuleOrUniformRoot<'ra>>, /// The segment name of target segment_name: Symbol, + error_implied_by_parse_error: bool, }, } @@ -458,6 +459,7 @@ impl<'ra> PathResult<'ra> { ident: Ident, is_error_from_last_segment: bool, finalize: bool, + error_implied_by_parse_error: bool, module: Option<ModuleOrUniformRoot<'ra>>, label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>), ) -> PathResult<'ra> { @@ -470,6 +472,7 @@ impl<'ra> PathResult<'ra> { suggestion, is_error_from_last_segment, module, + error_implied_by_parse_error, } } } @@ -1198,6 +1201,8 @@ pub struct Resolver<'ra, 'tcx> { /// This is the `Span` where an `extern crate foo;` suggestion would be inserted, if `foo` /// could be a crate that wasn't imported. For diagnostics use only. current_crate_outer_attr_insert_span: Span, + + mods_with_parse_errors: FxHashSet<DefId>, } /// This provides memory for the rest of the crate. The `'ra` lifetime that is @@ -1543,6 +1548,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { impl_unexpanded_invocations: Default::default(), impl_binding_keys: Default::default(), current_crate_outer_attr_insert_span, + mods_with_parse_errors: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 0b4d0e04c29..669a9c2428f 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -166,7 +166,7 @@ fn soft_custom_inner_attributes_gate(path: &ast::Path, invoc: &Invocation) -> bo [seg1, seg2] if seg1.ident.name == sym::rustfmt && seg2.ident.name == sym::skip => { if let InvocationKind::Attr { item, .. } = &invoc.kind { if let Annotatable::Item(item) = item { - if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _)) = item.kind { + if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _, _)) = item.kind { return true; } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 082d9742c40..e3708896ba9 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2105,6 +2105,7 @@ symbols! { unreachable_macro, unrestricted_attribute_tokens, unsafe_attributes, + unsafe_binders, unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_cell_raw_get, @@ -2128,6 +2129,7 @@ symbols! { unwind_attributes, unwind_safe_trait, unwrap, + unwrap_binder, unwrap_or, use_extern_macros, use_nested_groups, @@ -2186,6 +2188,7 @@ symbols! { windows, windows_subsystem, with_negative_coherence, + wrap_binder, wrapping_add, wrapping_div, wrapping_mul, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index fde6887c5ab..d45cb01910f 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -354,6 +354,8 @@ pub mod random; pub mod range; pub mod result; pub mod sync; +#[unstable(feature = "unsafe_binders", issue = "130516")] +pub mod unsafe_binder; pub mod fmt; pub mod hash; diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index bc4c4e168a3..51ab2054b3b 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -200,7 +200,7 @@ //! //! But it *is* still sound to: //! -//! * Create a pointer without provenance from just an address (see [`ptr::dangling`]). Such a +//! * Create a pointer without provenance from just an address (see [`without_provenance`]). Such a //! pointer cannot be used for memory accesses (except for zero-sized accesses). This can still be //! useful for sentinel values like `null` *or* to represent a tagged pointer that will never be //! dereferenceable. In general, it is always sound for an integer to pretend to be a pointer "for @@ -314,8 +314,8 @@ //! } //! ``` //! -//! (Yes, if you've been using AtomicUsize for pointers in concurrent datastructures, you should -//! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers, +//! (Yes, if you've been using [`AtomicUsize`] for pointers in concurrent datastructures, you should +//! be using [`AtomicPtr`] instead. If that messes up the way you atomically manipulate pointers, //! we would like to know why, and what needs to be done to fix it.) //! //! Situations where a valid pointer *must* be created from just an address, such as baremetal code @@ -381,7 +381,8 @@ //! [`with_addr`]: pointer::with_addr //! [`map_addr`]: pointer::map_addr //! [`addr`]: pointer::addr -//! [`ptr::dangling`]: core::ptr::dangling +//! [`AtomicUsize`]: crate::sync::atomic::AtomicUsize +//! [`AtomicPtr`]: crate::sync::atomic::AtomicPtr //! [`expose_provenance`]: pointer::expose_provenance //! [`with_exposed_provenance`]: with_exposed_provenance //! [Miri]: https://github.com/rust-lang/miri diff --git a/library/core/src/unsafe_binder.rs b/library/core/src/unsafe_binder.rs new file mode 100644 index 00000000000..98f53e07d9d --- /dev/null +++ b/library/core/src/unsafe_binder.rs @@ -0,0 +1,25 @@ +//! Operators used to turn types into unsafe binders and back. + +/// Unwrap an unsafe binder into its underlying type. +#[allow_internal_unstable(builtin_syntax)] +#[unstable(feature = "unsafe_binders", issue = "130516")] +pub macro unwrap_binder { + ($expr:expr) => { + builtin # unwrap_binder ( $expr ) + }, + ($expr:expr ; $ty:ty) => { + builtin # unwrap_binder ( $expr, $ty ) + }, +} + +/// Wrap a type into an unsafe binder. +#[allow_internal_unstable(builtin_syntax)] +#[unstable(feature = "unsafe_binders", issue = "130516")] +pub macro wrap_binder { + ($expr:expr) => { + builtin # wrap_binder ( $expr ) + }, + ($expr:expr ; $ty:ty) => { + builtin # wrap_binder ( $expr, $ty ) + }, +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 047f5b0c4c5..1cbf51463ea 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -544,6 +544,8 @@ pub use core::u64; #[stable(feature = "i128", since = "1.26.0")] #[allow(deprecated, deprecated_in_future)] pub use core::u128; +#[unstable(feature = "unsafe_binders", issue = "130516")] +pub use core::unsafe_binder; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated, deprecated_in_future)] pub use core::usize; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 50dfe0a1b56..a201a9bbfed 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1841,6 +1841,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))), // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer, + TyKind::UnsafeBinder(..) => { + unimplemented!("unsafe binders are not supported yet") + } } } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index c300f7cd665..bd4ce7ab922 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -819,6 +819,7 @@ impl TyCoercionStability { | TyKind::TraitObject(..) | TyKind::InferDelegation(..) | TyKind::Err(_) => Self::Reborrow, + TyKind::UnsafeBinder(..) => Self::None, }; } } diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs index ed27e38ef2d..1dac7b971f9 100644 --- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs +++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs @@ -63,7 +63,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]); impl EarlyLintPass for DuplicateMod { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans)) = &item.kind + if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans, _)) = &item.kind && let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span) && let Some(local_path) = real.into_local_path() && let Ok(absolute_path) = local_path.canonicalize() diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs index ffc76366983..dfea40db182 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs @@ -163,7 +163,7 @@ impl Visitor<'_> for NestingVisitor<'_, '_> { } match &item.kind { - ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _)) => { + ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _, _)) => { self.nest_level += 1; if !self.check_indent(item.span, item.id) { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index ed9879de13b..b679fdfadc3 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -156,7 +156,8 @@ fn never_loop_expr<'tcx>( | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Repeat(e, _) - | ExprKind::DropTemps(e) => never_loop_expr(cx, e, local_labels, main_loop_id), + | ExprKind::DropTemps(e) + | ExprKind::UnsafeBinderCast(_, e, _) => never_loop_expr(cx, e, local_labels, main_loop_id), ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id), ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id), ExprKind::MethodCall(_, receiver, es, _) => { diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 311ed427cb9..521bf6a5fed 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -623,6 +623,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("DropTemps({expr})"); self.expr(expr); }, + ExprKind::UnsafeBinderCast(..) => { + unimplemented!("unsafe binders are not implemented yet"); + } } } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 620a9b56eb5..12074dd16e6 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -379,7 +379,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { (Mod(lu, lmk), Mod(ru, rmk)) => { lu == ru && match (lmk, rmk) { - (ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) => { + (ModKind::Loaded(litems, linline, _, _), ModKind::Loaded(ritems, rinline, _, _)) => { linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind)) }, (ModKind::Unloaded, ModKind::Unloaded) => true, diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 7f0363ac942..b5bb174e737 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -303,7 +303,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS | ExprKind::AddrOf(..) | ExprKind::Repeat(..) | ExprKind::Block(Block { stmts: [], .. }, _) - | ExprKind::OffsetOf(..) => (), + | ExprKind::OffsetOf(..) + | ExprKind::UnsafeBinderCast(..) => (), // Assignment might be to a local defined earlier, so don't eagerly evaluate. // Blocks with multiple statements might be expensive, so don't eagerly evaluate. diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index e318ad8671c..279025b9bf9 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -370,6 +370,10 @@ impl HirEqInterExpr<'_, '_, '_> { && self.eq_expr(l_receiver, r_receiver) && self.eq_exprs(l_args, r_args) }, + (&ExprKind::UnsafeBinderCast(lkind, le, None), &ExprKind::UnsafeBinderCast(rkind, re, None)) => + lkind == rkind && self.eq_expr(le, re), + (&ExprKind::UnsafeBinderCast(lkind, le, Some(lt)), &ExprKind::UnsafeBinderCast(rkind, re, Some(rt))) => + lkind == rkind && self.eq_expr(le, re) && self.eq_ty(lt, rt), (&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => { self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name) }, @@ -424,6 +428,7 @@ impl HirEqInterExpr<'_, '_, '_> { | &ExprKind::Type(..) | &ExprKind::Unary(..) | &ExprKind::Yield(..) + | &ExprKind::UnsafeBinderCast(..) // --- Special cases that do not have a positive branch. @@ -1032,6 +1037,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { std::mem::discriminant(&lop).hash(&mut self.s); self.hash_expr(le); }, + ExprKind::UnsafeBinderCast(kind, expr, ty) => { + std::mem::discriminant(&kind).hash(&mut self.s); + self.hash_expr(expr); + if let Some(ty) = ty { + self.hash_ty(ty); + } + } ExprKind::Err(_) => {}, } } @@ -1241,6 +1253,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { TyKind::Typeof(anon_const) => { self.hash_body(anon_const.body); }, + TyKind::UnsafeBinder(binder) => { + self.hash_ty(binder.inner_ty); + } TyKind::Err(_) | TyKind::Infer | TyKind::Never diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 25ebe879192..088abd7c479 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -151,7 +151,8 @@ impl<'a> Sugg<'a> { | ExprKind::Become(..) | ExprKind::Struct(..) | ExprKind::Tup(..) - | ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)), + | ExprKind::Err(_) + | ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)), ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet), ExprKind::Assign(lhs, rhs, _) => { Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span)) @@ -226,7 +227,8 @@ impl<'a> Sugg<'a> { | ast::ExprKind::While(..) | ast::ExprKind::Await(..) | ast::ExprKind::Err(_) - | ast::ExprKind::Dummy => Sugg::NonParen(snippet(expr.span)), + | ast::ExprKind::Dummy + | ast::ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(snippet(expr.span)), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 351e619d7b1..ff58c6358ba 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -694,6 +694,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( | ExprKind::Continue(_) | ExprKind::InlineAsm(_) | ExprKind::OffsetOf(..) + | ExprKind::UnsafeBinderCast(..) | ExprKind::Err(_) => (), } ControlFlow::Continue(()) diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 77c9818b66b..16b7e7aa709 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -413,7 +413,8 @@ pub(crate) fn format_expr( ast::ExprKind::FormatArgs(..) | ast::ExprKind::Type(..) | ast::ExprKind::IncludedBytes(..) - | ast::ExprKind::OffsetOf(..) => { + | ast::ExprKind::OffsetOf(..) + | ast::ExprKind::UnsafeBinderCast(..) => { // These don't normally occur in the AST because macros aren't expanded. However, // rustfmt tries to parse macro arguments when formatting macros, so it's not totally // impossible for rustfmt to come across one of these nodes when formatting a file. diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 18932587f1f..c3debc2f4f0 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -3597,7 +3597,7 @@ pub(crate) fn rewrite_extern_crate( pub(crate) fn is_mod_decl(item: &ast::Item) -> bool { !matches!( item.kind, - ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _)) + ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _)) ) } diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs index 493b04f16c6..a40ee7f66a9 100644 --- a/src/tools/rustfmt/src/modules.rs +++ b/src/tools/rustfmt/src/modules.rs @@ -316,12 +316,11 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { self.directory = directory; } match (sub_mod.ast_mod_kind, sub_mod.items) { - (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => { + (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _, _))), _) => { self.visit_mod_from_ast(items) } - (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => { - self.visit_mod_outside_ast(items) - } + (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _, _))), _) + | (_, Cow::Owned(items)) => self.visit_mod_outside_ast(items), (_, _) => Ok(()), } } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index dd4a788c002..f8b713117f4 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1016,6 +1016,31 @@ impl Rewrite for ast::Ty { let pat = pat.rewrite_result(context, shape)?; Ok(format!("{ty} is {pat}")) } + ast::TyKind::UnsafeBinder(ref binder) => { + let mut result = String::new(); + if let Some(ref lifetime_str) = + rewrite_bound_params(context, shape, &binder.generic_params) + { + result.push_str("unsafe<"); + result.push_str(lifetime_str); + result.push_str("> "); + } + + let inner_ty_shape = if context.use_block_indent() { + shape + .offset_left(result.len()) + .max_width_error(shape.width, self.span())? + } else { + shape + .visual_indent(result.len()) + .sub_width(result.len()) + .max_width_error(shape.width, self.span())? + }; + + let rewrite = binder.inner_ty.rewrite_result(context, inner_ty_shape)?; + result.push_str(&rewrite); + Ok(result) + } } } } diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 0ca34a79491..ba4a4c045f1 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -504,6 +504,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::InlineAsm(..) | ast::ExprKind::OffsetOf(..) + | ast::ExprKind::UnsafeBinderCast(..) | ast::ExprKind::Let(..) | ast::ExprKind::Path(..) | ast::ExprKind::Range(..) diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 9b116b620b7..805e13b7803 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -927,7 +927,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let ident_str = rewrite_ident(&self.get_context(), ident).to_owned(); self.push_str(&ident_str); - if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans) = mod_kind { + if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans, _) = mod_kind { let ast::ModSpans { inner_span, inject_use_span: _, diff --git a/src/tools/rustfmt/tests/source/unsafe-binders.rs b/src/tools/rustfmt/tests/source/unsafe-binders.rs new file mode 100644 index 00000000000..ccf7c8bb9af --- /dev/null +++ b/src/tools/rustfmt/tests/source/unsafe-binders.rs @@ -0,0 +1,11 @@ +fn foo() -> unsafe<'a> +&'a () {} + +struct Foo { + x: unsafe<'a> +&'a (), +} + +struct Bar(unsafe<'a> &'a ()); + +impl Trait for unsafe<'a> &'a () {} diff --git a/src/tools/rustfmt/tests/target/unsafe-binders.rs b/src/tools/rustfmt/tests/target/unsafe-binders.rs new file mode 100644 index 00000000000..9d308f4a894 --- /dev/null +++ b/src/tools/rustfmt/tests/target/unsafe-binders.rs @@ -0,0 +1,9 @@ +fn foo() -> unsafe<'a> &'a () {} + +struct Foo { + x: unsafe<'a> &'a (), +} + +struct Bar(unsafe<'a> &'a ()); + +impl Trait for unsafe<'a> &'a () {} diff --git a/tests/ui/alias-uninit-value.rs b/tests/ui/alias-uninit-value.rs deleted file mode 100644 index 0084a98e627..00000000000 --- a/tests/ui/alias-uninit-value.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ run-pass - -#![allow(non_camel_case_types)] -#![allow(dead_code)] - - - -// Regression test for issue #374 - - -enum sty { ty_nil, } - -struct RawT {struct_: sty, cname: Option<String>, hash: usize} - -fn mk_raw_ty(st: sty, cname: Option<String>) -> RawT { - return RawT {struct_: st, cname: cname, hash: 0}; -} - -pub fn main() { mk_raw_ty(sty::ty_nil, None::<String>); } diff --git a/tests/ui/allow-non-lint-warnings.rs b/tests/ui/allow-non-lint-warnings.rs deleted file mode 100644 index f8f5a78ebff..00000000000 --- a/tests/ui/allow-non-lint-warnings.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ compile-flags: -Awarnings -//@ check-pass - -#[derive()] -#[derive(Copy, Clone)] -pub struct Foo; - -pub fn main() {} diff --git a/tests/ui/artificial-block.rs b/tests/ui/artificial-block.rs deleted file mode 100644 index 037163b4174..00000000000 --- a/tests/ui/artificial-block.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ run-pass - -fn f() -> isize { { return 3; } } - -pub fn main() { assert_eq!(f(), 3); } diff --git a/tests/ui/as-precedence.rs b/tests/ui/as-precedence.rs deleted file mode 100644 index 5021a3b677f..00000000000 --- a/tests/ui/as-precedence.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass - -#[allow(unused_parens)] -fn main() { - assert_eq!(3 as usize * 3, 9); - assert_eq!(3 as (usize) * 3, 9); - assert_eq!(3 as (usize) / 3, 1); - assert_eq!(3 as usize + 3, 6); - assert_eq!(3 as (usize) + 3, 6); -} diff --git a/tests/ui/codegen/alias-uninit-value.rs b/tests/ui/codegen/alias-uninit-value.rs new file mode 100644 index 00000000000..a8aa94caaf2 --- /dev/null +++ b/tests/ui/codegen/alias-uninit-value.rs @@ -0,0 +1,26 @@ +//! Regression test for issue #374, where previously rustc performed conditional jumps or moves that +//! incorrectly depended on uninitialized values. +//! +//! Issue: <https://github.com/rust-lang/rust/issues/374>. + +//@ run-pass + +#![allow(dead_code)] + +enum TyS { + Nil, +} + +struct RawT { + struct_: TyS, + cname: Option<String>, + hash: usize, +} + +fn mk_raw_ty(st: TyS, cname: Option<String>) -> RawT { + return RawT { struct_: st, cname: cname, hash: 0 }; +} + +pub fn main() { + mk_raw_ty(TyS::Nil, None::<String>); +} diff --git a/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs b/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs new file mode 100644 index 00000000000..40b9e6536f5 --- /dev/null +++ b/tests/ui/diagnostic-flags/allow-non-lint-warnings.rs @@ -0,0 +1,27 @@ +// ignore-tidy-linelength +//! Check that `-A warnings` cli flag applies to non-lint warnings as well. +//! +//! This test tries to exercise that by checking that the "relaxing a default bound only does +//! something for `?Sized`; all other traits are not bound by default" non-lint warning (normally +//! warn-by-default) is suppressed if the `-A warnings` cli flag is passed. +//! +//! Take special note that `warnings` is a special pseudo lint group in relationship to non-lint +//! warnings, which is somewhat special. This test does not exercise other `-A <other_lint_group>` +//! that check that they are working in the same way, only `warnings` specifically. +//! +//! # Relevant context +//! +//! - Original impl PR: <https://github.com/rust-lang/rust/pull/21248>. +//! - RFC 507 "Release channels": +//! <https://github.com/rust-lang/rfcs/blob/c017755b9bfa0421570d92ba38082302e0f3ad4f/text/0507-release-channels.md>. +#![crate_type = "lib"] + +//@ revisions: without_flag with_flag + +//@[with_flag] compile-flags: -Awarnings + +//@ check-pass + +pub trait Trait {} +pub fn f<T: ?Trait>() {} +//[without_flag]~^ WARN relaxing a default bound only does something for `?Sized`; all other traits are not bound by default diff --git a/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr b/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr new file mode 100644 index 00000000000..b037847c70f --- /dev/null +++ b/tests/ui/diagnostic-flags/allow-non-lint-warnings.without_flag.stderr @@ -0,0 +1,8 @@ +warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default + --> $DIR/allow-non-lint-warnings.rs:26:13 + | +LL | pub fn f<T: ?Trait>() {} + | ^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/feature-gates/feature-gate-unsafe-binders.rs b/tests/ui/feature-gates/feature-gate-unsafe-binders.rs new file mode 100644 index 00000000000..a2997ced4fa --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe-binders.rs @@ -0,0 +1,7 @@ +#[cfg(any())] +fn test() { + let x: unsafe<> (); + //~^ ERROR unsafe binder types are experimental +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unsafe-binders.stderr b/tests/ui/feature-gates/feature-gate-unsafe-binders.stderr new file mode 100644 index 00000000000..93997d6c14a --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe-binders.stderr @@ -0,0 +1,13 @@ +error[E0658]: unsafe binder types are experimental + --> $DIR/feature-gate-unsafe-binders.rs:3:12 + | +LL | let x: unsafe<> (); + | ^^^^^^^^^^^ + | + = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information + = help: add `#![feature(unsafe_binders)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/anonymous-higher-ranked-lifetime.rs b/tests/ui/higher-ranked/anonymous-higher-ranked-lifetime.rs index 898fe22fa23..8d8d0e71067 100644 --- a/tests/ui/anonymous-higher-ranked-lifetime.rs +++ b/tests/ui/higher-ranked/anonymous-higher-ranked-lifetime.rs @@ -1,3 +1,9 @@ +//! Diagnostics test to check that higher-ranked lifetimes are properly named when being pretty +//! printed in diagnostics. +//! +//! Issue: <https://github.com/rust-lang/rust/issues/44887> +//! PR: <https://github.com/rust-lang/rust/pull/44888> + fn main() { f1(|_: (), _: ()| {}); //~ ERROR type mismatch f2(|_: (), _: ()| {}); //~ ERROR type mismatch diff --git a/tests/ui/anonymous-higher-ranked-lifetime.stderr b/tests/ui/higher-ranked/anonymous-higher-ranked-lifetime.stderr index c28d856ad55..7e0cdba6ff2 100644 --- a/tests/ui/anonymous-higher-ranked-lifetime.stderr +++ b/tests/ui/higher-ranked/anonymous-higher-ranked-lifetime.stderr @@ -1,5 +1,5 @@ error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 | LL | f1(|_: (), _: ()| {}); | ^^^--------------^^^^ @@ -10,7 +10,7 @@ LL | f1(|_: (), _: ()| {}); = note: expected closure signature `for<'a, 'b> fn(&'a (), &'b ()) -> _` found closure signature `fn((), ()) -> _` note: required by a bound in `f1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:16:25 + --> $DIR/anonymous-higher-ranked-lifetime.rs:22:25 | LL | fn f1<F>(_: F) where F: Fn(&(), &()) {} | ^^^^^^^^^^^^ required by this bound in `f1` @@ -20,7 +20,7 @@ LL | f1(|_: &(), _: &()| {}); | + + error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5 | LL | f2(|_: (), _: ()| {}); | ^^^--------------^^^^ @@ -31,7 +31,7 @@ LL | f2(|_: (), _: ()| {}); = note: expected closure signature `for<'a, 'b> fn(&'a (), &'b ()) -> _` found closure signature `fn((), ()) -> _` note: required by a bound in `f2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:17:25 + --> $DIR/anonymous-higher-ranked-lifetime.rs:23:25 | LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f2` @@ -41,7 +41,7 @@ LL | f2(|_: &(), _: &()| {}); | + + error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 | LL | f3(|_: (), _: ()| {}); | ^^^--------------^^^^ @@ -52,7 +52,7 @@ LL | f3(|_: (), _: ()| {}); = note: expected closure signature `for<'a> fn(&(), &'a ()) -> _` found closure signature `fn((), ()) -> _` note: required by a bound in `f3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:18:29 + --> $DIR/anonymous-higher-ranked-lifetime.rs:24:29 | LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} | ^^^^^^^^^^^^^^^ required by this bound in `f3` @@ -62,7 +62,7 @@ LL | f3(|_: &(), _: &()| {}); | + + error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5 | LL | f4(|_: (), _: ()| {}); | ^^^--------------^^^^ @@ -73,7 +73,7 @@ LL | f4(|_: (), _: ()| {}); = note: expected closure signature `for<'a, 'r> fn(&'a (), &'r ()) -> _` found closure signature `fn((), ()) -> _` note: required by a bound in `f4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:19:25 + --> $DIR/anonymous-higher-ranked-lifetime.rs:25:25 | LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f4` @@ -83,7 +83,7 @@ LL | f4(|_: &(), _: &()| {}); | + + error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 | LL | f5(|_: (), _: ()| {}); | ^^^--------------^^^^ @@ -94,7 +94,7 @@ LL | f5(|_: (), _: ()| {}); = note: expected closure signature `for<'r> fn(&'r (), &'r ()) -> _` found closure signature `fn((), ()) -> _` note: required by a bound in `f5` - --> $DIR/anonymous-higher-ranked-lifetime.rs:20:25 + --> $DIR/anonymous-higher-ranked-lifetime.rs:26:25 | LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `f5` @@ -104,7 +104,7 @@ LL | f5(|_: &(), _: &()| {}); | + + error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:13:5 | LL | g1(|_: (), _: ()| {}); | ^^^--------------^^^^ @@ -115,7 +115,7 @@ LL | g1(|_: (), _: ()| {}); = note: expected closure signature `for<'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _` found closure signature `fn((), ()) -> _` note: required by a bound in `g1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:23:25 + --> $DIR/anonymous-higher-ranked-lifetime.rs:29:25 | LL | fn g1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g1` @@ -125,7 +125,7 @@ LL | g1(|_: &(), _: ()| {}); | + error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 | LL | g2(|_: (), _: ()| {}); | ^^^--------------^^^^ @@ -136,7 +136,7 @@ LL | g2(|_: (), _: ()| {}); = note: expected closure signature `for<'a> fn(&'a (), for<'a> fn(&'a ())) -> _` found closure signature `fn((), ()) -> _` note: required by a bound in `g2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:24:25 + --> $DIR/anonymous-higher-ranked-lifetime.rs:30:25 | LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {} | ^^^^^^^^^^^^^^^^ required by this bound in `g2` @@ -146,7 +146,7 @@ LL | g2(|_: &(), _: ()| {}); | + error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:15:5 | LL | g3(|_: (), _: ()| {}); | ^^^--------------^^^^ @@ -157,7 +157,7 @@ LL | g3(|_: (), _: ()| {}); = note: expected closure signature `for<'s> fn(&'s (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>) -> _` found closure signature `fn((), ()) -> _` note: required by a bound in `g3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:25:25 + --> $DIR/anonymous-higher-ranked-lifetime.rs:31:25 | LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<dyn Fn(&())>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g3` @@ -167,7 +167,7 @@ LL | g3(|_: &(), _: ()| {}); | + error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 | LL | g4(|_: (), _: ()| {}); | ^^^--------------^^^^ @@ -178,7 +178,7 @@ LL | g4(|_: (), _: ()| {}); = note: expected closure signature `for<'a> fn(&'a (), for<'r> fn(&'r ())) -> _` found closure signature `fn((), ()) -> _` note: required by a bound in `g4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:26:25 + --> $DIR/anonymous-higher-ranked-lifetime.rs:32:25 | LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `g4` @@ -188,7 +188,7 @@ LL | g4(|_: &(), _: ()| {}); | + error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:17:5 | LL | h1(|_: (), _: (), _: (), _: ()| {}); | ^^^----------------------------^^^^ @@ -199,7 +199,7 @@ LL | h1(|_: (), _: (), _: (), _: ()| {}); = note: expected closure signature `for<'a, 'b> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>, &'b (), for<'a, 'b> fn(&'a (), &'b ())) -> _` found closure signature `fn((), (), (), ()) -> _` note: required by a bound in `h1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:29:25 + --> $DIR/anonymous-higher-ranked-lifetime.rs:35:25 | LL | fn h1<F>(_: F) where F: Fn(&(), Box<dyn Fn(&())>, &(), fn(&(), &())) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h1` @@ -209,7 +209,7 @@ LL | h1(|_: &(), _: (), _: &(), _: ()| {}); | + + error[E0631]: type mismatch in closure arguments - --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 + --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 | LL | h2(|_: (), _: (), _: (), _: ()| {}); | ^^^----------------------------^^^^ @@ -220,7 +220,7 @@ LL | h2(|_: (), _: (), _: (), _: ()| {}); = note: expected closure signature `for<'a, 't0> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>, &'t0 (), for<'a, 'b> fn(&'a (), &'b ())) -> _` found closure signature `fn((), (), (), ()) -> _` note: required by a bound in `h2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:30:25 + --> $DIR/anonymous-higher-ranked-lifetime.rs:36:25 | LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<dyn Fn(&())>, &'t0 (), fn(&(), &())) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `h2` diff --git a/tests/ui/parser/as-precedence.rs b/tests/ui/parser/as-precedence.rs new file mode 100644 index 00000000000..ca8328adb0e --- /dev/null +++ b/tests/ui/parser/as-precedence.rs @@ -0,0 +1,18 @@ +//! Parser precedence test to help with [RFC 87 "Trait Bounds with Plus"][rfc-87], to check the +//! precedence of the `as` operator in relation to some arithmetic bin-ops and parentheses. +//! +//! Editor's note: this test seems quite incomplete compared to what's possible nowadays. Maybe +//! there's another set of tests whose coverage overshadows this test? +//! +//! [rfc-87]: https://rust-lang.github.io/rfcs/0087-trait-bounds-with-plus.html + +//@ run-pass + +#[allow(unused_parens)] +fn main() { + assert_eq!(3 as usize * 3, 9); + assert_eq!(3 as (usize) * 3, 9); + assert_eq!(3 as (usize) / 3, 1); + assert_eq!(3 as usize + 3, 6); + assert_eq!(3 as (usize) + 3, 6); +} diff --git a/tests/ui/parser/circular_modules_main.stderr b/tests/ui/parser/circular_modules_main.stderr index 2de70789358..e1780fe9fd9 100644 --- a/tests/ui/parser/circular_modules_main.stderr +++ b/tests/ui/parser/circular_modules_main.stderr @@ -4,22 +4,5 @@ error: circular modules: $DIR/circular_modules_main.rs -> $DIR/circular_modules_ LL | mod circular_modules_main; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0425]: cannot find function `hi_str` in module `circular_modules_main` - --> $DIR/circular_modules_hello.rs:7:43 - | -LL | println!("{}", circular_modules_main::hi_str()); - | ^^^^^^ not found in `circular_modules_main` - | -help: consider importing this function - | -LL + use hi_str; - | -help: if you import `hi_str`, refer to it directly - | -LL - println!("{}", circular_modules_main::hi_str()); -LL + println!("{}", hi_str()); - | - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/reachable/artificial-block.rs b/tests/ui/reachable/artificial-block.rs new file mode 100644 index 00000000000..6d73ba1a972 --- /dev/null +++ b/tests/ui/reachable/artificial-block.rs @@ -0,0 +1,30 @@ +//! Check that we don't get compile errors on unreachable code after the `{ return 3; }` artificial +//! block below. This test is run-pass to also exercise the codegen, but it might be possible to +//! reduce to build-pass or even check-pass. +//! +//! This test was introduced as part of commit `a833f152baa17460e8414355e832d30d5161f8e8` which +//! removes an "artificial block". See also commit `3d738e9e0634a4cd6239d1317bd7dad53be68dc8` for +//! more elaboration, reproduced below (this is outdated for *today*'s rustc as of 2024-12-10, but +//! is helpful to understand the original intention): +//! +//! > Return a fresh, unreachable context after ret, break, and cont +//! > +//! > This ensures we don't get compile errors on unreachable code (see +//! > test/run-pass/artificial-block.rs for an example of sane code that wasn't compiling). In the +//! > future, we might want to warn about non-trivial code appearing in an unreachable context, +//! > and/or avoid generating unreachable code altogether (though I'm sure LLVM will weed it out as +//! > well). +//! +//! Since then, `ret` became `return`, `int` became `isize` and `assert` became a macro. + +//@ run-pass + +fn f() -> isize { + { + return 3; + } +} + +fn main() { + assert_eq!(f(), 3); +} diff --git a/tests/ui/resolve/parse-error-resolve.rs b/tests/ui/resolve/parse-error-resolve.rs new file mode 100644 index 00000000000..1e0772648af --- /dev/null +++ b/tests/ui/resolve/parse-error-resolve.rs @@ -0,0 +1,7 @@ +mod parse_error; +use parse_error::Canonical; // ok, `parse_error.rs` had parse errors + +fn main() { + let _ = "" + 1; //~ ERROR E0369 + parse_error::Canonical.foo(); // ok, `parse_error.rs` had parse errors +} diff --git a/tests/ui/resolve/parse-error-resolve.stderr b/tests/ui/resolve/parse-error-resolve.stderr new file mode 100644 index 00000000000..30475aa0ee6 --- /dev/null +++ b/tests/ui/resolve/parse-error-resolve.stderr @@ -0,0 +1,22 @@ +error: expected one of `+`, `,`, `::`, `=`, or `>`, found `From` + --> $DIR/parse_error.rs:2:46 + | +LL | impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical { + | ^^^^ expected one of `+`, `,`, `::`, `=`, or `>` + | +help: you might have meant to end the type parameters here + | +LL | impl<S: Into<std::borrow::Cow<'static, str>>> From<S> for Canonical { + | + + +error[E0369]: cannot add `{integer}` to `&str` + --> $DIR/parse-error-resolve.rs:5:16 + | +LL | let _ = "" + 1; + | -- ^ - {integer} + | | + | &str + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/resolve/parse_error.rs b/tests/ui/resolve/parse_error.rs new file mode 100644 index 00000000000..4cd025e1edf --- /dev/null +++ b/tests/ui/resolve/parse_error.rs @@ -0,0 +1,5 @@ +struct Canonical; +impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical { //~ ERROR expected + fn foo() {} +} +fn bar() {} diff --git a/tests/ui/resolve/parse_error.stderr b/tests/ui/resolve/parse_error.stderr new file mode 100644 index 00000000000..f764f08875f --- /dev/null +++ b/tests/ui/resolve/parse_error.stderr @@ -0,0 +1,13 @@ +error: expected one of `+`, `,`, `::`, `=`, or `>`, found `From` + --> $DIR/parse_error.rs:2:46 + | +LL | impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical { + | ^^^^ expected one of `+`, `,`, `::`, `=`, or `>` + | +help: you might have meant to end the type parameters here + | +LL | impl<S: Into<std::borrow::Cow<'static, str>>> From<S> for Canonical { + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/unsafe-binders/expr.rs b/tests/ui/unsafe-binders/expr.rs new file mode 100644 index 00000000000..d8c4c2df2cd --- /dev/null +++ b/tests/ui/unsafe-binders/expr.rs @@ -0,0 +1,13 @@ +#![feature(unsafe_binders)] +//~^ WARN the feature `unsafe_binders` is incomplete + +use std::unsafe_binder::{wrap_binder, unwrap_binder}; + +fn main() { + let x = 1; + let binder: unsafe<'a> &'a i32 = wrap_binder!(x); + //~^ ERROR unsafe binders are not yet implemented + //~| ERROR unsafe binders are not yet implemented + let rx = *unwrap_binder!(binder); + //~^ ERROR unsafe binders are not yet implemented +} diff --git a/tests/ui/unsafe-binders/expr.stderr b/tests/ui/unsafe-binders/expr.stderr new file mode 100644 index 00000000000..26fae1958b0 --- /dev/null +++ b/tests/ui/unsafe-binders/expr.stderr @@ -0,0 +1,29 @@ +warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/expr.rs:1:12 + | +LL | #![feature(unsafe_binders)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: unsafe binders are not yet implemented + --> $DIR/expr.rs:8:17 + | +LL | let binder: unsafe<'a> &'a i32 = wrap_binder!(x); + | ^^^^^^^^^^^^^^^^^^ + +error: unsafe binders are not yet implemented + --> $DIR/expr.rs:8:51 + | +LL | let binder: unsafe<'a> &'a i32 = wrap_binder!(x); + | ^ + +error: unsafe binders are not yet implemented + --> $DIR/expr.rs:11:30 + | +LL | let rx = *unwrap_binder!(binder); + | ^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted + diff --git a/tests/ui/unsafe-binders/lifetime-resolution.rs b/tests/ui/unsafe-binders/lifetime-resolution.rs new file mode 100644 index 00000000000..aebed9599d4 --- /dev/null +++ b/tests/ui/unsafe-binders/lifetime-resolution.rs @@ -0,0 +1,19 @@ +#![feature(unsafe_binders)] +//~^ WARN the feature `unsafe_binders` is incomplete + +fn foo<'a>() { + let good: unsafe<'b> &'a &'b (); + //~^ ERROR unsafe binders are not yet implemented + + let missing: unsafe<> &'missing (); + //~^ ERROR unsafe binders are not yet implemented + //~| ERROR use of undeclared lifetime name `'missing` + + fn inner<'b>() { + let outer: unsafe<> &'a &'b (); + //~^ ERROR unsafe binders are not yet implemented + //~| can't use generic parameters from outer item + } +} + +fn main() {} diff --git a/tests/ui/unsafe-binders/lifetime-resolution.stderr b/tests/ui/unsafe-binders/lifetime-resolution.stderr new file mode 100644 index 00000000000..7a8ce929df1 --- /dev/null +++ b/tests/ui/unsafe-binders/lifetime-resolution.stderr @@ -0,0 +1,65 @@ +error[E0261]: use of undeclared lifetime name `'missing` + --> $DIR/lifetime-resolution.rs:8:28 + | +LL | let missing: unsafe<> &'missing (); + | ^^^^^^^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'missing` lifetime + | +LL | let missing: unsafe<'missing, > &'missing (); + | +++++++++ +help: consider introducing lifetime `'missing` here + | +LL | fn foo<'missing, 'a>() { + | +++++++++ + +error[E0401]: can't use generic parameters from outer item + --> $DIR/lifetime-resolution.rs:13:30 + | +LL | fn foo<'a>() { + | -- lifetime parameter from outer item +... +LL | let outer: unsafe<> &'a &'b (); + | ^^ use of generic parameter from outer item + | +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | let outer: unsafe<'a, > &'a &'b (); + | +++ +help: consider introducing lifetime `'a` here + | +LL | fn inner<'a, 'b>() { + | +++ + +warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/lifetime-resolution.rs:1:12 + | +LL | #![feature(unsafe_binders)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: unsafe binders are not yet implemented + --> $DIR/lifetime-resolution.rs:5:15 + | +LL | let good: unsafe<'b> &'a &'b (); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: unsafe binders are not yet implemented + --> $DIR/lifetime-resolution.rs:8:18 + | +LL | let missing: unsafe<> &'missing (); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: unsafe binders are not yet implemented + --> $DIR/lifetime-resolution.rs:13:20 + | +LL | let outer: unsafe<> &'a &'b (); + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0261, E0401. +For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/unsafe-binders/simple.rs b/tests/ui/unsafe-binders/simple.rs new file mode 100644 index 00000000000..cebff2cbfb8 --- /dev/null +++ b/tests/ui/unsafe-binders/simple.rs @@ -0,0 +1,7 @@ +#![feature(unsafe_binders)] +//~^ WARN the feature `unsafe_binders` is incomplete + +fn main() { + let x: unsafe<'a> &'a (); + //~^ ERROR unsafe binders are not yet implemented +} diff --git a/tests/ui/unsafe-binders/simple.stderr b/tests/ui/unsafe-binders/simple.stderr new file mode 100644 index 00000000000..a21dbd00b4c --- /dev/null +++ b/tests/ui/unsafe-binders/simple.stderr @@ -0,0 +1,17 @@ +warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/simple.rs:1:12 + | +LL | #![feature(unsafe_binders)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: unsafe binders are not yet implemented + --> $DIR/simple.rs:5:12 + | +LL | let x: unsafe<'a> &'a (); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error; 1 warning emitted + |
