Auto merge of #134269 - matthiaskrgr:rollup-fkshwux, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #133900 (Advent of `tests/ui` (misc cleanups and improvements) [1/N])
 - #133937 (Keep track of parse errors in `mod`s and don't emit resolve errors for paths involving them)
 - #133938 (`rustc_mir_dataflow` cleanups, including some renamings)
 - #134058 (interpret: reduce usage of TypingEnv::fully_monomorphized)
 - #134130 (Stop using driver queries in the public API)
 - #134140 (Add AST support for unsafe binders)
 - #134229 (Fix typos in docs on provenance)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-12-13 23:09:16 +00:00
commit 4a204bebdf
119 changed files with 1341 additions and 639 deletions

View file

@ -1382,6 +1382,7 @@ impl Expr {
| ExprKind::Tup(_) | ExprKind::Tup(_)
| ExprKind::Type(..) | ExprKind::Type(..)
| ExprKind::Underscore | ExprKind::Underscore
| ExprKind::UnsafeBinderCast(..)
| ExprKind::While(..) | ExprKind::While(..)
| ExprKind::Err(_) | ExprKind::Err(_)
| ExprKind::Dummy => ExprPrecedence::Unambiguous, | ExprKind::Dummy => ExprPrecedence::Unambiguous,
@ -1509,7 +1510,13 @@ pub enum ExprKind {
/// `'label: for await? pat in iter { block }` /// `'label: for await? pat in iter { block }`
/// ///
/// This is desugared to a combination of `loop` and `match` expressions. /// 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`). /// Conditionless loop (can be exited with `break`, `continue`, or `return`).
/// ///
/// `'label: loop { block }` /// `'label: loop { block }`
@ -1614,6 +1621,8 @@ pub enum ExprKind {
/// A `format_args!()` expression. /// A `format_args!()` expression.
FormatArgs(P<FormatArgs>), FormatArgs(P<FormatArgs>),
UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>),
/// Placeholder for an expression that wasn't syntactically well formed in some way. /// Placeholder for an expression that wasn't syntactically well formed in some way.
Err(ErrorGuaranteed), 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 /// The explicit `Self` type in a "qualified path". The actual
/// path, including the trait and the associated item, is stored /// path, including the trait and the associated item, is stored
/// separately. `position` represents the index of the associated /// separately. `position` represents the index of the associated
@ -2223,6 +2242,12 @@ pub struct BareFnTy {
pub decl_span: Span, 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. /// The various kinds of type recognized by the compiler.
// //
// Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`. // 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), PinnedRef(Option<Lifetime>, MutTy),
/// A bare function (e.g., `fn(usize) -> bool`). /// A bare function (e.g., `fn(usize) -> bool`).
BareFn(P<BareFnTy>), BareFn(P<BareFnTy>),
/// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`).
UnsafeBinder(P<UnsafeBinderTy>),
/// The never type (`!`). /// The never type (`!`).
Never, Never,
/// A tuple (`(A, B, C, D,...)`). /// 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. /// 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 `}`, /// 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. /// 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. /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
Unloaded, Unloaded,
} }

View file

@ -558,6 +558,11 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
vis.visit_fn_decl(decl); vis.visit_fn_decl(decl);
vis.visit_span(decl_span); 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::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
TyKind::Paren(ty) => vis.visit_ty(ty), TyKind::Paren(ty) => vis.visit_ty(ty),
TyKind::Pat(ty, pat) => { TyKind::Pat(ty, pat) => {
@ -1212,7 +1217,12 @@ impl WalkItemKind for ItemKind {
ItemKind::Mod(safety, mod_kind) => { ItemKind::Mod(safety, mod_kind) => {
visit_safety(vis, safety); visit_safety(vis, safety);
match mod_kind { 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)); items.flat_map_in_place(|item| vis.flat_map_item(item));
vis.visit_span(inner_span); vis.visit_span(inner_span);
vis.visit_span(inject_use_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::TryBlock(body) => vis.visit_block(body),
ExprKind::Lit(_token) => {} ExprKind::Lit(_token) => {}
ExprKind::IncludedBytes(_bytes) => {} 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::Err(_guar) => {}
ExprKind::Dummy => {} ExprKind::Dummy => {}
} }

View file

@ -152,6 +152,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
| Underscore | Underscore
| Yeet(..) | Yeet(..)
| Yield(..) | Yield(..)
| UnsafeBinderCast(..)
| Err(..) | Err(..)
| Dummy => return false, | Dummy => return false,
} }
@ -232,6 +233,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
| Paren(_) | Paren(_)
| Try(_) | Try(_)
| Yeet(None) | Yeet(None)
| UnsafeBinderCast(..)
| Err(_) | Err(_)
| Dummy => break None, | Dummy => break None,
} }
@ -253,6 +255,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
ty = &mut_ty.ty; ty = &mut_ty.ty;
} }
ast::TyKind::UnsafeBinder(binder) => {
ty = &binder.inner_ty;
}
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output { ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
ast::FnRetTy::Default(_) => break None, ast::FnRetTy::Default(_) => break None,
ast::FnRetTy::Ty(ret) => ty = ret, ast::FnRetTy::Ty(ret) => ty = ret,

View file

@ -380,7 +380,7 @@ impl WalkItemKind for ItemKind {
try_visit!(visitor.visit_fn(kind, span, id)); try_visit!(visitor.visit_fn(kind, span, id));
} }
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind { 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); walk_list!(visitor, visit_item, items);
} }
ModKind::Unloaded => {} 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); walk_list!(visitor, visit_generic_param, generic_params);
try_visit!(visitor.visit_fn_decl(decl)); 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) => { TyKind::Path(maybe_qself, path) => {
try_visit!(visitor.visit_qself(maybe_qself)); try_visit!(visitor.visit_qself(maybe_qself));
try_visit!(visitor.visit_path(path, *id)); 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::TryBlock(body) => try_visit!(visitor.visit_block(body)),
ExprKind::Lit(_token) => {} ExprKind::Lit(_token) => {}
ExprKind::IncludedBytes(_bytes) => {} ExprKind::IncludedBytes(_bytes) => {}
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
try_visit!(visitor.visit_expr(expr));
visit_opt!(visitor, visit_ty, ty);
}
ExprKind::Err(_guar) => {} ExprKind::Err(_guar) => {}
ExprKind::Dummy => {} ExprKind::Dummy => {}
} }

View file

@ -379,6 +379,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
ExprKind::Err(guar) => hir::ExprKind::Err(*guar), 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 => { ExprKind::Dummy => {
span_bug!(e.span, "lowered ExprKind::Dummy") span_bug!(e.span, "lowered ExprKind::Dummy")
} }

View file

@ -238,7 +238,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}) })
} }
ItemKind::Mod(_, mod_kind) => match mod_kind { ItemKind::Mod(_, mod_kind) => match mod_kind {
ModKind::Loaded(items, _, spans) => { ModKind::Loaded(items, _, spans, _) => {
hir::ItemKind::Mod(self.lower_mod(items, spans)) hir::ItemKind::Mod(self.lower_mod(items, spans))
} }
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"), ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),

View file

@ -1228,6 +1228,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_names: self.lower_fn_params_to_names(&f.decl), 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::Never => hir::TyKind::Never,
TyKind::Tup(tys) => hir::TyKind::Tup( TyKind::Tup(tys) => hir::TyKind::Tup(
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))), self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),

View file

@ -1029,7 +1029,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" }); self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
} }
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). // 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) && !attr::contains_name(&item.attrs, sym::path)
{ {
self.check_mod_file_item_asciionly(item.ident); self.check_mod_file_item_asciionly(item.ident);

View file

@ -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!(return_type_notation, "return type notation is experimental");
gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
gate_all!(unsafe_fields, "`unsafe` fields are experimental"); gate_all!(unsafe_fields, "`unsafe` fields are experimental");
gate_all!(unsafe_binders, "unsafe binder types are experimental");
if !visitor.features.never_patterns() { if !visitor.features.never_patterns() {
if let Some(spans) = spans.get(&sym::never_patterns) { if let Some(spans) = spans.get(&sym::never_patterns) {

View file

@ -1198,6 +1198,14 @@ impl<'a> State<'a> {
ast::TyKind::BareFn(f) => { ast::TyKind::BareFn(f) => {
self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params); 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) => { ast::TyKind::Path(None, path) => {
self.print_path(path, false, 0); self.print_path(path, false, 0);
} }

View file

@ -772,6 +772,25 @@ impl<'a> State<'a> {
self.word_nbsp("try"); self.word_nbsp("try");
self.print_block_with_attrs(blk, attrs) 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(_) => { ast::ExprKind::Err(_) => {
self.popen(); self.popen();
self.word("/*ERROR*/"); self.word("/*ERROR*/");

View file

@ -8,7 +8,10 @@ use rustc_middle::mir::{
}; };
use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_mir_dataflow::fmt::DebugWithContext; 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 rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
use tracing::debug; use tracing::debug;
@ -24,7 +27,7 @@ pub(crate) struct Borrowck<'a, 'tcx> {
} }
impl<'a, 'tcx> Analysis<'tcx> for 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"; const NAME: &'static str = "borrowck";
@ -41,48 +44,48 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
unreachable!(); unreachable!();
} }
fn apply_before_statement_effect( fn apply_early_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>, stmt: &mir::Statement<'tcx>,
loc: Location, loc: Location,
) { ) {
self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc); self.borrows.apply_early_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc); self.uninits.apply_early_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, 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, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>, stmt: &mir::Statement<'tcx>,
loc: Location, loc: Location,
) { ) {
self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc); self.borrows.apply_primary_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc); self.uninits.apply_primary_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.apply_statement_effect(&mut state.ever_inits, 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, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
term: &mir::Terminator<'tcx>, term: &mir::Terminator<'tcx>,
loc: Location, loc: Location,
) { ) {
self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc); self.borrows.apply_early_terminator_effect(&mut state.borrows, term, loc);
self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc); self.uninits.apply_early_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, 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, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
term: &'mir mir::Terminator<'tcx>, term: &'mir mir::Terminator<'tcx>,
loc: Location, loc: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
self.borrows.apply_terminator_effect(&mut state.borrows, term, loc); self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc);
self.uninits.apply_terminator_effect(&mut state.uninits, term, loc); self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.apply_terminator_effect(&mut state.ever_inits, 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 // This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
// analysis doesn't use. // 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 { fn join(&mut self, _other: &Self) -> bool {
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
unreachable!(); unreachable!();
} }
} }
impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx> impl<'tcx, C> DebugWithContext<C> for BorrowckDomain
where where
C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>, 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. /// The transient state of the dataflow analyses used by the borrow checker.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct BorrowckDomain<'a, 'tcx> { pub(crate) struct BorrowckDomain {
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain, pub(crate) borrows: BorrowsDomain,
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, pub(crate) uninits: MaybeUninitializedPlacesDomain,
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, pub(crate) ever_inits: EverInitializedPlacesDomain,
} }
rustc_index::newtype_index! { rustc_index::newtype_index! {
@ -503,7 +506,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
/// That means they went out of a nonlexical scope /// That means they went out of a nonlexical scope
fn kill_loans_out_of_scope_at_location( fn kill_loans_out_of_scope_at_location(
&self, &self,
trans: &mut <Self as Analysis<'tcx>>::Domain, state: &mut <Self as Analysis<'tcx>>::Domain,
location: Location, location: Location,
) { ) {
// NOTE: The state associated with a given `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 // region, then setting that gen-bit will override any
// potential kill introduced here. // potential kill introduced here.
if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) { 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`. /// Kill any borrows that conflict with `place`.
fn kill_borrows_on_place( fn kill_borrows_on_place(
&self, &self,
trans: &mut <Self as Analysis<'tcx>>::Domain, state: &mut <Self as Analysis<'tcx>>::Domain,
place: Place<'tcx>, place: Place<'tcx>,
) { ) {
debug!("kill_borrows_on_place: place={:?}", place); debug!("kill_borrows_on_place: place={:?}", place);
@ -543,7 +546,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
// `places_conflict` for every borrow. // `places_conflict` for every borrow.
if place.projection.is_empty() { if place.projection.is_empty() {
if !self.body.local_decls[place.local].is_ref_to_static() { 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; 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. /// Forward dataflow computation of the set of borrows that are in scope at a particular location.
/// - we gen the introduced loans /// - we gen the introduced loans
/// - we kill loans on locals going out of (regular) scope /// - 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 /// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of
/// `a.b.c` when `a` is overwritten. /// `a.b.c` when `a` is overwritten.
impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
type Domain = BitSet<BorrowIndex>; type Domain = BorrowsDomain;
const NAME: &'static str = "borrows"; 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. // function execution, so this method has no effect.
} }
fn apply_before_statement_effect( fn apply_early_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>, _statement: &mir::Statement<'tcx>,
location: Location, 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>, stmt: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
@ -617,18 +622,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
panic!("could not find BorrowIndex for location {location:?}"); panic!("could not find BorrowIndex for location {location:?}");
}); });
trans.gen_(index); state.gen_(index);
} }
// Make sure there are no remaining borrows for variables // Make sure there are no remaining borrows for variables
// that are assigned over. // that are assigned over.
self.kill_borrows_on_place(trans, *lhs); self.kill_borrows_on_place(state, *lhs);
} }
mir::StatementKind::StorageDead(local) => { mir::StatementKind::StorageDead(local) => {
// Make sure there are no remaining borrows for locals that // Make sure there are no remaining borrows for locals that
// are gone out of scope. // 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(..) 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>, _terminator: &mir::Terminator<'tcx>,
location: Location, 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
_location: Location, _location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> 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), .. } if let mir::InlineAsmOperand::Out { place: Some(place), .. }
| mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op | mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op
{ {
self.kill_borrows_on_place(trans, place); self.kill_borrows_on_place(state, place);
} }
} }
} }

View file

@ -43,7 +43,7 @@ use rustc_mir_dataflow::impls::{
use rustc_mir_dataflow::move_paths::{ use rustc_mir_dataflow::move_paths::{
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex, 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_session::lint::builtin::UNUSED_MUT;
use rustc_span::{Span, Symbol}; use rustc_span::{Span, Symbol};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -426,14 +426,14 @@ fn get_flow_results<'a, 'tcx>(
ever_inits: ever_inits.analysis, ever_inits: ever_inits.analysis,
}; };
assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len()); assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len()); assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
let entry_sets: EntrySets<'_, Borrowck<'_, '_>> = let entry_states: EntryStates<'_, Borrowck<'_, '_>> =
itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets) itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits }) .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
.collect(); .collect();
Results { analysis, entry_sets } Results { analysis, entry_states }
} }
pub(crate) struct BorrowckInferCtxt<'tcx> { pub(crate) struct BorrowckInferCtxt<'tcx> {
@ -600,10 +600,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
// 3. assignments do not affect things loaned out as immutable // 3. assignments do not affect things loaned out as immutable
// 4. moves do not affect things loaned out in any way // 4. moves do not affect things loaned out in any way
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> { 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, &mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
stmt: &'a Statement<'tcx>, stmt: &'a Statement<'tcx>,
location: Location, 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, &mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
term: &'a Terminator<'tcx>, term: &'a Terminator<'tcx>,
loc: Location, 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, &mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
term: &'a Terminator<'tcx>, term: &'a Terminator<'tcx>,
loc: Location, loc: Location,
) { ) {
@ -983,7 +983,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
place_span: (Place<'tcx>, Span), place_span: (Place<'tcx>, Span),
kind: (AccessDepth, ReadOrWrite), kind: (AccessDepth, ReadOrWrite),
is_local_mutation_allowed: LocalMutationIsAllowed, is_local_mutation_allowed: LocalMutationIsAllowed,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
let (sd, rw) = kind; let (sd, rw) = kind;
@ -1032,7 +1032,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
place_span: (Place<'tcx>, Span), place_span: (Place<'tcx>, Span),
sd: AccessDepth, sd: AccessDepth,
rw: ReadOrWrite, rw: ReadOrWrite,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) -> bool { ) -> bool {
let mut error_reported = false; let mut error_reported = false;
@ -1172,7 +1172,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
location: Location, location: Location,
place_span: (Place<'tcx>, Span), place_span: (Place<'tcx>, Span),
kind: AccessDepth, kind: AccessDepth,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
// Write of P[i] or *P requires P init'd. // Write of P[i] or *P requires P init'd.
self.check_if_assigned_path_is_moved(location, place_span, state); self.check_if_assigned_path_is_moved(location, place_span, state);
@ -1190,7 +1190,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
&mut self, &mut self,
location: Location, location: Location,
(rvalue, span): (&'a Rvalue<'tcx>, Span), (rvalue, span): (&'a Rvalue<'tcx>, Span),
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
match rvalue { match rvalue {
&Rvalue::Ref(_ /*rgn*/, bk, place) => { &Rvalue::Ref(_ /*rgn*/, bk, place) => {
@ -1448,7 +1448,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
&mut self, &mut self,
location: Location, location: Location,
(operand, span): (&'a Operand<'tcx>, Span), (operand, span): (&'a Operand<'tcx>, Span),
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
match *operand { match *operand {
Operand::Copy(place) => { Operand::Copy(place) => {
@ -1568,12 +1568,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
} }
} }
fn check_activations( fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
&mut self,
location: Location,
span: Span,
state: &BorrowckDomain<'a, 'tcx>,
) {
// Two-phase borrow support: For each activation that is newly // Two-phase borrow support: For each activation that is newly
// generated at this statement, check if it interferes with // generated at this statement, check if it interferes with
// another borrow. // another borrow.
@ -1731,7 +1726,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
location: Location, location: Location,
desired_action: InitializationRequiringAction, desired_action: InitializationRequiringAction,
place_span: (PlaceRef<'tcx>, Span), place_span: (PlaceRef<'tcx>, Span),
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
let maybe_uninits = &state.uninits; let maybe_uninits = &state.uninits;
@ -1836,7 +1831,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
location: Location, location: Location,
desired_action: InitializationRequiringAction, desired_action: InitializationRequiringAction,
place_span: (PlaceRef<'tcx>, Span), place_span: (PlaceRef<'tcx>, Span),
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
let maybe_uninits = &state.uninits; let maybe_uninits = &state.uninits;
@ -1935,7 +1930,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
&mut self, &mut self,
location: Location, location: Location,
(place, span): (Place<'tcx>, Span), (place, span): (Place<'tcx>, Span),
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
debug!("check_if_assigned_path_is_moved place: {:?}", place); debug!("check_if_assigned_path_is_moved place: {:?}", place);
@ -2001,7 +1996,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
location: Location, location: Location,
base: PlaceRef<'tcx>, base: PlaceRef<'tcx>,
span: Span, span: Span,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
) { ) {
// rust-lang/rust#21232: Until Rust allows reads from the // rust-lang/rust#21232: Until Rust allows reads from the
// initialized parts of partially initialized structs, we // initialized parts of partially initialized structs, we
@ -2092,7 +2087,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
(place, span): (Place<'tcx>, Span), (place, span): (Place<'tcx>, Span),
kind: ReadOrWrite, kind: ReadOrWrite,
is_local_mutation_allowed: LocalMutationIsAllowed, is_local_mutation_allowed: LocalMutationIsAllowed,
state: &BorrowckDomain<'a, 'tcx>, state: &BorrowckDomain,
location: Location, location: Location,
) -> bool { ) -> bool {
debug!( debug!(
@ -2206,18 +2201,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
} }
} }
fn is_local_ever_initialized( fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
&self,
local: Local,
state: &BorrowckDomain<'a, 'tcx>,
) -> Option<InitIndex> {
let mpi = self.move_data.rev_lookup.find_local(local)?; let mpi = self.move_data.rev_lookup.find_local(local)?;
let ii = &self.move_data.init_path_map[mpi]; let ii = &self.move_data.init_path_map[mpi];
ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied() ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
} }
/// Adds the place into the used mutable variables set /// 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 { match root_place {
RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
// If the local may have been initialized, and it is now currently being // If the local may have been initialized, and it is now currently being

View file

@ -323,7 +323,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
| ExprKind::While(_, _, _) | ExprKind::While(_, _, _)
| ExprKind::Yeet(_) | ExprKind::Yeet(_)
| ExprKind::Become(_) | ExprKind::Become(_)
| ExprKind::Yield(_) => {} | ExprKind::Yield(_)
| ExprKind::UnsafeBinderCast(..) => {}
} }
} }

View file

@ -141,8 +141,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
// We don't want to recurse into anything other than mods, since // We don't want to recurse into anything other than mods, since
// mods or tests inside of functions will break things // mods or tests inside of functions will break things
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) = if let ast::ItemKind::Mod(
item.kind _,
ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }, _),
) = item.kind
{ {
let prev_tests = mem::take(&mut self.tests); let prev_tests = mem::take(&mut self.tests);
walk_item_kind( walk_item_kind(

View file

@ -329,7 +329,7 @@ where
self.transfer_function(state).initialize_state(); self.transfer_function(state).initialize_state();
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
statement: &mir::Statement<'tcx>, statement: &mir::Statement<'tcx>,
@ -338,7 +338,7 @@ where
self.transfer_function(state).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, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,

View file

@ -249,10 +249,9 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
} else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) {
// For panic_fmt, call const_panic_fmt instead. // For panic_fmt, call const_panic_fmt instead.
let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); 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( let new_instance = ty::Instance::expect_resolve(
*self.tcx, *self.tcx,
ty::TypingEnv::fully_monomorphized(), self.typing_env(),
const_def_id, const_def_id,
instance.args, instance.args,
self.cur_span(), self.cur_span(),

View file

@ -297,6 +297,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
#[inline] #[inline]
pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self { pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
// Can use any typing env, since `bool` is always monomorphic.
let layout = tcx let layout = tcx
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool)) .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool))
.unwrap(); .unwrap();
@ -305,17 +306,18 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
#[inline] #[inline]
pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self { 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 ty = tcx.ty_ordering_enum(None);
let layout = let layout =
tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap(); tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap();
Self::from_scalar(Scalar::from_i8(c as i8), layout) Self::from_scalar(Scalar::from_i8(c as i8), layout)
} }
pub fn from_pair(a: Self, b: Self, tcx: TyCtxt<'tcx>) -> Self { pub fn from_pair(a: Self, b: Self, cx: &(impl HasTypingEnv<'tcx> + HasTyCtxt<'tcx>)) -> Self {
let layout = tcx let layout = cx
.tcx()
.layout_of( .layout_of(
ty::TypingEnv::fully_monomorphized() cx.typing_env().as_query_input(Ty::new_tup(cx.tcx(), &[a.layout.ty, b.layout.ty])),
.as_query_input(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
) )
.unwrap(); .unwrap();
Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout) Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout)

View file

@ -222,7 +222,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let res = ImmTy::from_scalar_int(result, left.layout); let res = ImmTy::from_scalar_int(result, left.layout);
return interp_ok(if with_overflow { return interp_ok(if with_overflow {
let overflow = ImmTy::from_bool(overflow, *self.tcx); let overflow = ImmTy::from_bool(overflow, *self.tcx);
ImmTy::from_pair(res, overflow, *self.tcx) ImmTy::from_pair(res, overflow, self)
} else { } else {
res res
}); });
@ -279,7 +279,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let res = ImmTy::from_scalar_int(result, left.layout); let res = ImmTy::from_scalar_int(result, left.layout);
if with_overflow { if with_overflow {
let overflow = ImmTy::from_bool(overflow, *self.tcx); let overflow = ImmTy::from_bool(overflow, *self.tcx);
ImmTy::from_pair(res, overflow, *self.tcx) ImmTy::from_pair(res, overflow, self)
} else { } else {
res res
} }

View file

@ -45,7 +45,7 @@ use rustc_errors::registry::Registry;
use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown}; use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown};
use rustc_feature::find_gated_cfg; use rustc_feature::find_gated_cfg;
use rustc_interface::util::{self, get_codegen_backend}; 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_lint::unerased_lint_store;
use rustc_metadata::creader::MetadataLoader; use rustc_metadata::creader::MetadataLoader;
use rustc_metadata::locator; use rustc_metadata::locator;
@ -158,13 +158,10 @@ pub trait Callbacks {
/// Called after parsing the crate root. Submodules are not yet parsed when /// Called after parsing the crate root. Submodules are not yet parsed when
/// this callback is called. Return value instructs the compiler whether to /// this callback is called. Return value instructs the compiler whether to
/// continue the compilation afterwards (defaults to `Compilation::Continue`) /// continue the compilation afterwards (defaults to `Compilation::Continue`)
#[deprecated = "This callback will likely be removed or stop giving access \ fn after_crate_root_parsing(
to the TyCtxt in the future. Use either the after_expansion \
or the after_analysis callback instead."]
fn after_crate_root_parsing<'tcx>(
&mut self, &mut self,
_compiler: &interface::Compiler, _compiler: &interface::Compiler,
_queries: &'tcx Queries<'tcx>, _queries: &ast::Crate,
) -> Compilation { ) -> Compilation {
Compilation::Continue Compilation::Continue
} }
@ -173,7 +170,7 @@ pub trait Callbacks {
fn after_expansion<'tcx>( fn after_expansion<'tcx>(
&mut self, &mut self,
_compiler: &interface::Compiler, _compiler: &interface::Compiler,
_queries: &'tcx Queries<'tcx>, _tcx: TyCtxt<'tcx>,
) -> Compilation { ) -> Compilation {
Compilation::Continue Compilation::Continue
} }
@ -416,8 +413,9 @@ fn run_compiler(
return early_exit(); return early_exit();
} }
#[allow(deprecated)] if callbacks.after_crate_root_parsing(compiler, &*queries.parse().borrow())
if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop { == Compilation::Stop
{
return early_exit(); return early_exit();
} }
@ -425,18 +423,18 @@ fn run_compiler(
return early_exit(); return early_exit();
} }
queries.global_ctxt().enter(|tcx| {
// Make sure name resolution and macro expansion is run. // Make sure name resolution and macro expansion is run.
queries.global_ctxt().enter(|tcx| tcx.resolver_for_lowering()); let _ = tcx.resolver_for_lowering();
if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir { if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
queries.global_ctxt().enter(|tcxt| dump_feature_usage_metrics(tcxt, metrics_dir)); dump_feature_usage_metrics(tcx, metrics_dir);
} }
if callbacks.after_expansion(compiler, queries) == Compilation::Stop { if callbacks.after_expansion(compiler, tcx) == Compilation::Stop {
return early_exit(); return early_exit();
} }
queries.global_ctxt().enter(|tcx| {
passes::write_dep_info(tcx); passes::write_dep_info(tcx);
if sess.opts.output_types.contains_key(&OutputType::DepInfo) if sess.opts.output_types.contains_key(&OutputType::DepInfo)

View file

@ -723,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
item_inner.kind, item_inner.kind,
ItemKind::Mod( 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) { fn visit_item(&mut self, item: &'ast ast::Item) {
match &item.kind { match &item.kind {
ItemKind::Mod(_, mod_kind) ItemKind::Mod(_, mod_kind)
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) => if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) =>
{ {
feature_err( feature_err(
self.sess, self.sess,
@ -1195,7 +1195,7 @@ impl InvocationCollectorNode for P<ast::Item> {
let ecx = &mut collector.cx; let ecx = &mut collector.cx;
let (file_path, dir_path, dir_ownership) = match mod_kind { 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. // Inline `mod foo { ... }`, but we still need to push directories.
let (dir_path, dir_ownership) = mod_dir_path( let (dir_path, dir_ownership) = mod_dir_path(
ecx.sess, ecx.sess,
@ -1217,8 +1217,14 @@ impl InvocationCollectorNode for P<ast::Item> {
ModKind::Unloaded => { ModKind::Unloaded => {
// We have an outline `mod foo;` so we need to parse the file. // We have an outline `mod foo;` so we need to parse the file.
let old_attrs_len = attrs.len(); let old_attrs_len = attrs.len();
let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } = let ParsedExternalMod {
parse_external_mod( items,
spans,
file_path,
dir_path,
dir_ownership,
had_parse_error,
} = parse_external_mod(
ecx.sess, ecx.sess,
ident, ident,
span, span,
@ -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; node.attrs = attrs;
if node.attrs.len() > old_attrs_len { if node.attrs.len() > old_attrs_len {
// If we loaded an out-of-line module and added some inner attributes, // If we loaded an out-of-line module and added some inner attributes,

View file

@ -37,6 +37,7 @@ pub(crate) struct ParsedExternalMod {
pub file_path: PathBuf, pub file_path: PathBuf,
pub dir_path: PathBuf, pub dir_path: PathBuf,
pub dir_ownership: DirOwnership, pub dir_ownership: DirOwnership,
pub had_parse_error: Result<(), ErrorGuaranteed>,
} }
pub enum ModError<'a> { pub enum ModError<'a> {
@ -74,14 +75,17 @@ pub(crate) fn parse_external_mod(
attrs.extend(inner_attrs); attrs.extend(inner_attrs);
(items, inner_span, mp.file_path) (items, inner_span, mp.file_path)
}; };
// (1) ...instead, we return a dummy module. // (1) ...instead, we return a dummy module.
let (items, spans, file_path) = let ((items, spans, file_path), had_parse_error) = match result {
result.map_err(|err| err.report(sess, span)).unwrap_or_default(); Err(err) => (Default::default(), Err(err.report(sess, span))),
Ok(result) => (result, Ok(())),
};
// Extract the directory path for submodules of the module. // Extract the directory path for submodules of the module.
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned(); 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( pub(crate) fn mod_dir_path(

View file

@ -636,6 +636,8 @@ declare_features! (
/// Allows creation of instances of a struct by moving fields that have /// Allows creation of instances of a struct by moving fields that have
/// not changed from prior instances of the same struct (RFC #2528) /// not changed from prior instances of the same struct (RFC #2528)
(unstable, type_changing_struct_update, "1.58.0", Some(86555)), (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`. /// Allows declaring fields `unsafe`.
(incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)), (incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)),
/// Allows const generic parameters to be defined with types that /// Allows const generic parameters to be defined with types that

View file

@ -8,7 +8,7 @@ use rustc_ast::{
}; };
pub use rustc_ast::{ pub use rustc_ast::{
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, 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::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::sorted_map::SortedMap;
@ -1740,6 +1740,7 @@ impl Expr<'_> {
| ExprKind::Struct(..) | ExprKind::Struct(..)
| ExprKind::Tup(_) | ExprKind::Tup(_)
| ExprKind::Type(..) | ExprKind::Type(..)
| ExprKind::UnsafeBinderCast(..)
| ExprKind::Err(_) => ExprPrecedence::Unambiguous, | ExprKind::Err(_) => ExprPrecedence::Unambiguous,
ExprKind::DropTemps(ref expr, ..) => expr.precedence(), 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 // 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), 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::Unary(UnOp::Deref, _) => true,
ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => { ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
@ -1850,7 +1854,8 @@ impl Expr<'_> {
| ExprKind::Field(base, _) | ExprKind::Field(base, _)
| ExprKind::Index(base, _, _) | ExprKind::Index(base, _, _)
| ExprKind::AddrOf(.., 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 // 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 // method exclusively for diagnostics and there's a *cultural* pressure against
// them being used only for its side-effects. // 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>`). /// A suspension point for coroutines (i.e., `yield <expr>`).
Yield(&'hir Expr<'hir>, YieldSource), 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. /// A placeholder for an expression that wasn't syntactically well formed in some way.
Err(rustc_span::ErrorGuaranteed), Err(rustc_span::ErrorGuaranteed),
} }
@ -2780,6 +2789,12 @@ pub struct BareFnTy<'hir> {
pub param_names: &'hir [Ident], pub param_names: &'hir [Ident],
} }
#[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)] #[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct OpaqueTy<'hir> { pub struct OpaqueTy<'hir> {
pub hir_id: HirId, pub hir_id: HirId,
@ -2878,6 +2893,8 @@ pub enum TyKind<'hir> {
Ref(&'hir Lifetime, MutTy<'hir>), Ref(&'hir Lifetime, MutTy<'hir>),
/// A bare function (e.g., `fn(usize) -> bool`). /// A bare function (e.g., `fn(usize) -> bool`).
BareFn(&'hir BareFnTy<'hir>), BareFn(&'hir BareFnTy<'hir>),
/// An unsafe binder type (e.g. `unsafe<'a> Foo<'a>`).
UnsafeBinder(&'hir UnsafeBinderTy<'hir>),
/// The never type (`!`). /// The never type (`!`).
Never, Never,
/// A tuple (`(A, B, C, D, ...)`). /// A tuple (`(A, B, C, D, ...)`).

View file

@ -857,6 +857,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
ExprKind::Yield(ref subexpression, _) => { ExprKind::Yield(ref subexpression, _) => {
try_visit!(visitor.visit_expr(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(_) => {} ExprKind::Lit(_) | ExprKind::Err(_) => {}
} }
V::Result::output() 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); walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
try_visit!(visitor.visit_fn_decl(function_declaration.decl)); 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) => { TyKind::Path(ref qpath) => {
try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span)); try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
} }

View file

@ -470,6 +470,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
self.outer_index.shift_out(1); self.outer_index.shift_out(1);
res 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), _ => intravisit::walk_ty(self, ty),
} }
} }

View file

@ -781,6 +781,36 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
intravisit::walk_ty(this, ty); 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, _) => { hir::TyKind::TraitObject(bounds, lifetime, _) => {
debug!(?bounds, ?lifetime, "TraitObject"); debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope }; let scope = Scope::TraitRefBoundary { s: self.scope };

View file

@ -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)), 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) => { hir::TyKind::TraitObject(bounds, lifetime, repr) => {
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) { 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 // Don't continue with type analysis if the `dyn` keyword is missing

View file

@ -288,6 +288,9 @@ impl<'a> State<'a> {
hir::TyKind::BareFn(f) => { hir::TyKind::BareFn(f) => {
self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names); 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::OpaqueDef(..) => self.word("/*impl Trait*/"),
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false), hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
hir::TyKind::TraitObject(bounds, lifetime, syntax) => { hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
@ -339,6 +342,15 @@ impl<'a> State<'a> {
self.end() 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<'_>) { fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
self.hardbreak_if_not_bol(); self.hardbreak_if_not_bol();
self.maybe_print_comment(item.span.lo()); self.maybe_print_comment(item.span.lo());
@ -1530,6 +1542,19 @@ impl<'a> State<'a> {
self.word(")"); 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, _) => { hir::ExprKind::Yield(expr, _) => {
self.word_space("yield"); self.word_space("yield");
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump); self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);

View file

@ -329,6 +329,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Assignment does call `drop_in_place`, though, but its safety // Assignment does call `drop_in_place`, though, but its safety
// requirements are not the same. // requirements are not the same.
ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false, 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, _, _) => { ExprKind::Assign(lhs, _, _) => {
// Only the LHS does not constitute a read // Only the LHS does not constitute a read
expr.hir_id != lhs.hir_id expr.hir_id != lhs.hir_id
@ -353,7 +360,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ExprKind::Binary(_, _, _) | ExprKind::Binary(_, _, _)
| ExprKind::Unary(_, _) | ExprKind::Unary(_, _)
| ExprKind::Cast(_, _) | ExprKind::Cast(_, _)
| ExprKind::Type(_, _)
| ExprKind::DropTemps(_) | ExprKind::DropTemps(_)
| ExprKind::If(_, _, _) | ExprKind::If(_, _, _)
| ExprKind::Closure(_) | ExprKind::Closure(_)
@ -564,7 +570,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_index(base, idx, expr, brackets_span) self.check_expr_index(base, idx, expr, brackets_span)
} }
ExprKind::Yield(value, _) => self.check_expr_yield(value, expr), 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( fn check_expr_array(
&self, &self,
args: &'tcx [hir::Expr<'tcx>], args: &'tcx [hir::Expr<'tcx>],

View file

@ -341,6 +341,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
self.walk_expr(subexpr)?; self.walk_expr(subexpr)?;
} }
hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => {
self.walk_expr(subexpr)?;
}
hir::ExprKind::Unary(hir::UnOp::Deref, base) => { hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
// *base // *base
self.walk_expr(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) 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::Type(e, _) => self.cat_expr(e),
hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
hir::ExprKind::AddrOf(..) hir::ExprKind::AddrOf(..)
| hir::ExprKind::Call(..) | hir::ExprKind::Call(..)

View file

@ -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 codegen
} }

View file

@ -127,18 +127,6 @@ impl Linker {
) -> Linker { ) -> Linker {
let ongoing_codegen = passes::start_codegen(codegen_backend, tcx); 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 { Linker {
dep_graph: tcx.dep_graph.clone(), dep_graph: tcx.dep_graph.clone(),
output_filenames: Arc::clone(tcx.output_filenames(())), output_filenames: Arc::clone(tcx.output_filenames(())),

View file

@ -3038,7 +3038,7 @@ impl EarlyLintPass for SpecialModuleName {
for item in &krate.items { for item in &krate.items {
if let ast::ItemKind::Mod( 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 ) = item.kind
{ {
if item.attrs.iter().any(|a| a.has_name(sym::path)) { if item.attrs.iter().any(|a| a.has_name(sym::path)) {

View file

@ -192,6 +192,8 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
| ExprKind::DropTemps(..) | ExprKind::DropTemps(..)
| ExprKind::Let(..) => false, | ExprKind::Let(..) => false,
ExprKind::UnsafeBinderCast(..) => false,
// Not applicable // Not applicable
ExprKind::Type(..) | ExprKind::Err(..) => false, ExprKind::Type(..) | ExprKind::Err(..) => false,
} }

View file

@ -422,6 +422,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
hir::ExprKind::Unary(_, expr) hir::ExprKind::Unary(_, expr)
| hir::ExprKind::Cast(expr, _) | hir::ExprKind::Cast(expr, _)
| hir::ExprKind::Type(expr, _) | hir::ExprKind::Type(expr, _)
| hir::ExprKind::UnsafeBinderCast(_, expr, _)
| hir::ExprKind::Yield(expr, _) | hir::ExprKind::Yield(expr, _)
| hir::ExprKind::AddrOf(_, _, expr) | hir::ExprKind::AddrOf(_, _, expr)
| hir::ExprKind::Match(expr, _, _) | hir::ExprKind::Match(expr, _, _)

View file

@ -44,16 +44,16 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
pub format_value: fn(&C::Value) -> String, pub format_value: fn(&C::Value) -> String,
} }
pub struct QuerySystemFns<'tcx> { pub struct QuerySystemFns {
pub engine: QueryEngine, pub engine: QueryEngine,
pub local_providers: Providers, pub local_providers: Providers,
pub extern_providers: ExternProviders, pub extern_providers: ExternProviders,
pub encode_query_results: fn( pub encode_query_results: for<'tcx> fn(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
encoder: &mut CacheEncoder<'_, 'tcx>, encoder: &mut CacheEncoder<'_, 'tcx>,
query_result_index: &mut EncodedDepNodeIndex, 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> { pub struct QuerySystem<'tcx> {
@ -68,7 +68,7 @@ pub struct QuerySystem<'tcx> {
/// This is `None` if we are not incremental compilation mode /// This is `None` if we are not incremental compilation mode
pub on_disk_cache: Option<OnDiskCache>, pub on_disk_cache: Option<OnDiskCache>,
pub fns: QuerySystemFns<'tcx>, pub fns: QuerySystemFns,
pub jobs: AtomicU64, pub jobs: AtomicU64,
} }

View file

@ -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::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) }, hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) },
hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) }, hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },

View file

@ -179,15 +179,15 @@ where
/// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is /// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is
/// applied. /// 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) { 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 /// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is
/// applied. /// 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) { pub fn seek_after_primary_effect(&mut self, target: Location) {
self.seek_after(target, Effect::Primary) self.seek_after(target, Effect::Primary)
} }
@ -222,12 +222,12 @@ where
#[rustfmt::skip] #[rustfmt::skip]
let next_effect = if A::Direction::IS_FORWARD { let next_effect = if A::Direction::IS_FORWARD {
self.pos.curr_effect_index.map_or_else( self.pos.curr_effect_index.map_or_else(
|| Effect::Before.at_index(0), || Effect::Early.at_index(0),
EffectIndex::next_in_forward_order, EffectIndex::next_in_forward_order,
) )
} else { } else {
self.pos.curr_effect_index.map_or_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, EffectIndex::next_in_backward_order,
) )
}; };

View file

@ -66,12 +66,12 @@ impl Direction for Backward {
{ {
let terminator = block_data.terminator(); let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() }; let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location); analysis.apply_early_terminator_effect(state, terminator, location);
analysis.apply_terminator_effect(state, terminator, location); analysis.apply_primary_terminator_effect(state, terminator, location);
for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
let location = Location { block, statement_index }; let location = Location { block, statement_index };
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
let exit_state = state; let exit_state = state;
@ -159,14 +159,14 @@ impl Direction for Backward {
let location = Location { block, statement_index: from.statement_index }; let location = Location { block, statement_index: from.statement_index };
let terminator = block_data.terminator(); let terminator = block_data.terminator();
if from.effect == Effect::Before { if from.effect == Effect::Early {
analysis.apply_before_terminator_effect(state, terminator, location); analysis.apply_early_terminator_effect(state, terminator, location);
if to == Effect::Before.at_index(terminator_index) { if to == Effect::Early.at_index(terminator_index) {
return; return;
} }
} }
analysis.apply_terminator_effect(state, terminator, location); analysis.apply_primary_terminator_effect(state, terminator, location);
if to == Effect::Primary.at_index(terminator_index) { if to == Effect::Primary.at_index(terminator_index) {
return; return;
} }
@ -180,7 +180,7 @@ impl Direction for Backward {
let location = Location { block, statement_index: from.statement_index }; let location = Location { block, statement_index: from.statement_index };
let statement = &block_data.statements[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) { if to == Effect::Primary.at_index(from.statement_index) {
return; return;
} }
@ -188,7 +188,7 @@ impl Direction for Backward {
from.statement_index - 1 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`. // 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) { for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) {
let location = Location { block, statement_index }; let location = Location { block, statement_index };
let statement = &block_data.statements[statement_index]; let statement = &block_data.statements[statement_index];
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
// Handle the statement at `to`. // Handle the statement at `to`.
let location = Location { block, statement_index: to.statement_index }; let location = Location { block, statement_index: to.statement_index };
let statement = &block_data.statements[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; return;
} }
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
fn visit_results_in_block<'mir, 'tcx, A>( 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 loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator(); let term = block_data.terminator();
results.analysis.apply_before_terminator_effect(state, term, loc); results.analysis.apply_early_terminator_effect(state, term, loc);
vis.visit_terminator_before_primary_effect(results, state, term, loc); vis.visit_after_early_terminator_effect(results, state, term, loc);
results.analysis.apply_terminator_effect(state, term, loc); results.analysis.apply_primary_terminator_effect(state, term, loc);
vis.visit_terminator_after_primary_effect(results, state, term, loc); vis.visit_after_primary_terminator_effect(results, state, term, loc);
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() { for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
let loc = Location { block, statement_index }; let loc = Location { block, statement_index };
results.analysis.apply_before_statement_effect(state, stmt, loc); results.analysis.apply_early_statement_effect(state, stmt, loc);
vis.visit_statement_before_primary_effect(results, state, stmt, loc); vis.visit_after_early_statement_effect(results, state, stmt, loc);
results.analysis.apply_statement_effect(state, stmt, loc); results.analysis.apply_primary_statement_effect(state, stmt, loc);
vis.visit_statement_after_primary_effect(results, state, stmt, loc); vis.visit_after_primary_statement_effect(results, state, stmt, loc);
} }
vis.visit_block_start(state); vis.visit_block_start(state);
@ -294,13 +294,13 @@ impl Direction for Forward {
{ {
for (statement_index, statement) in block_data.statements.iter().enumerate() { for (statement_index, statement) in block_data.statements.iter().enumerate() {
let location = Location { block, statement_index }; let location = Location { block, statement_index };
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
let terminator = block_data.terminator(); let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() }; let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location); analysis.apply_early_terminator_effect(state, terminator, location);
let edges = analysis.apply_terminator_effect(state, terminator, location); let edges = analysis.apply_primary_terminator_effect(state, terminator, location);
let exit_state = state; let exit_state = state;
match edges { match edges {
@ -368,21 +368,21 @@ impl Direction for Forward {
// after effect, do so now and start the loop below from the next statement. // after effect, do so now and start the loop below from the next statement.
let first_unapplied_index = match from.effect { 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 => { Effect::Primary if from.statement_index == terminator_index => {
debug_assert_eq!(from, to); debug_assert_eq!(from, to);
let location = Location { block, statement_index: terminator_index }; let location = Location { block, statement_index: terminator_index };
let terminator = block_data.terminator(); let terminator = block_data.terminator();
analysis.apply_terminator_effect(state, terminator, location); analysis.apply_primary_terminator_effect(state, terminator, location);
return; return;
} }
Effect::Primary => { Effect::Primary => {
let location = Location { block, statement_index: from.statement_index }; let location = Location { block, statement_index: from.statement_index };
let statement = &block_data.statements[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 // If we only needed to apply the after effect of the statement at `idx`, we are
// done. // done.
@ -399,8 +399,8 @@ impl Direction for Forward {
for statement_index in first_unapplied_index..to.statement_index { for statement_index in first_unapplied_index..to.statement_index {
let location = Location { block, statement_index }; let location = Location { block, statement_index };
let statement = &block_data.statements[statement_index]; let statement = &block_data.statements[statement_index];
analysis.apply_before_statement_effect(state, statement, location); analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location); analysis.apply_primary_statement_effect(state, statement, location);
} }
// Handle the statement or terminator at `to`. // Handle the statement or terminator at `to`.
@ -408,17 +408,17 @@ impl Direction for Forward {
let location = Location { block, statement_index: to.statement_index }; let location = Location { block, statement_index: to.statement_index };
if to.statement_index == terminator_index { if to.statement_index == terminator_index {
let terminator = block_data.terminator(); 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 { if to.effect == Effect::Primary {
analysis.apply_terminator_effect(state, terminator, location); analysis.apply_primary_terminator_effect(state, terminator, location);
} }
} else { } else {
let statement = &block_data.statements[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::Primary { 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() { for (statement_index, stmt) in block_data.statements.iter().enumerate() {
let loc = Location { block, statement_index }; let loc = Location { block, statement_index };
results.analysis.apply_before_statement_effect(state, stmt, loc); results.analysis.apply_early_statement_effect(state, stmt, loc);
vis.visit_statement_before_primary_effect(results, state, stmt, loc); vis.visit_after_early_statement_effect(results, state, stmt, loc);
results.analysis.apply_statement_effect(state, stmt, loc); results.analysis.apply_primary_statement_effect(state, stmt, loc);
vis.visit_statement_after_primary_effect(results, state, stmt, loc); vis.visit_after_primary_statement_effect(results, state, stmt, loc);
} }
let loc = Location { block, statement_index: block_data.statements.len() }; let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator(); let term = block_data.terminator();
results.analysis.apply_before_terminator_effect(state, term, loc); results.analysis.apply_early_terminator_effect(state, term, loc);
vis.visit_terminator_before_primary_effect(results, state, term, loc); vis.visit_after_early_terminator_effect(results, state, term, loc);
results.analysis.apply_terminator_effect(state, term, loc); results.analysis.apply_primary_terminator_effect(state, term, loc);
vis.visit_terminator_after_primary_effect(results, state, term, loc); vis.visit_after_primary_terminator_effect(results, state, term, loc);
vis.visit_block_end(state); vis.visit_block_end(state);
} }

View file

@ -724,7 +724,7 @@ where
} }
} }
fn visit_statement_before_primary_effect( fn visit_after_early_statement_effect(
&mut self, &mut self,
results: &mut Results<'tcx, A>, results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,
@ -737,7 +737,7 @@ where
} }
} }
fn visit_statement_after_primary_effect( fn visit_after_primary_statement_effect(
&mut self, &mut self,
results: &mut Results<'tcx, A>, results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,
@ -748,7 +748,7 @@ where
self.prev_state.clone_from(state) self.prev_state.clone_from(state)
} }
fn visit_terminator_before_primary_effect( fn visit_after_early_terminator_effect(
&mut self, &mut self,
results: &mut Results<'tcx, A>, results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,
@ -761,7 +761,7 @@ where
} }
} }
fn visit_terminator_after_primary_effect( fn visit_after_primary_terminator_effect(
&mut self, &mut self,
results: &mut Results<'tcx, A>, results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,

View file

@ -38,10 +38,8 @@
//! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram //! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram
//! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set //! [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::bit_set::{BitSet, MixedBitSet};
use rustc_index::{Idx, IndexVec};
use crate::framework::BitSetExt; use crate::framework::BitSetExt;
@ -70,53 +68,6 @@ pub trait HasTop {
const TOP: Self; 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 /// 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, /// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices,
/// one for each possible value of `T`. /// 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> { impl<S> MaybeReachable<S> {
/// Return whether the current state contains the given element. If the state is unreachable, /// Return whether the current state contains the given element. If the state is unreachable,
/// it does no contain anything. /// it does no contain anything.

View file

@ -56,7 +56,7 @@ mod visitor;
pub use self::cursor::ResultsCursor; pub use self::cursor::ResultsCursor;
pub use self::direction::{Backward, Direction, Forward}; pub use self::direction::{Backward, Direction, Forward};
pub use self::lattice::{JoinSemiLattice, MaybeReachable}; 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}; pub use self::visitor::{ResultsVisitor, visit_results};
/// Analysis domains are all bitsets of various kinds. This trait holds /// 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. // `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); 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. /// Updates the current dataflow state with the effect of evaluating a statement.
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
statement: &mir::Statement<'tcx>, 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 /// 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 /// This method is useful if the consumer of the results of this analysis needs only to observe
/// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule, /// *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_statement_effect`. /// analyses should not implement this without also implementing
fn apply_before_statement_effect( /// `apply_primary_terminator_effect`.
fn apply_early_terminator_effect(
&mut self, &mut self,
_state: &mut Self::Domain, _state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>, _terminator: &mir::Terminator<'tcx>,
_location: Location, _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 /// 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 /// `InitializedPlaces` analyses, the return place for a function call is not marked as
/// initialized here. /// initialized here.
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
_state: &mut Self::Domain, _state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
@ -159,27 +175,13 @@ pub trait Analysis<'tcx> {
terminator.edges() 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 */ /* Edge-specific effects */
/// Updates the current dataflow state with the effect of a successful return from a `Call` /// Updates the current dataflow state with the effect of a successful return from a `Call`
/// terminator. /// terminator.
/// ///
/// This is separate from `apply_terminator_effect` to properly track state across unwind /// This is separate from `apply_primary_terminator_effect` to properly track state across
/// edges. /// unwind edges.
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
_state: &mut Self::Domain, _state: &mut Self::Domain,
@ -234,11 +236,12 @@ pub trait Analysis<'tcx> {
Self: Sized, Self: Sized,
Self::Domain: DebugWithContext<Self>, Self::Domain: DebugWithContext<Self>,
{ {
let mut entry_sets = let mut entry_states =
IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); 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"); 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); let mut state = self.bottom_value(body);
while let Some(bb) = dirty_queue.pop() { while let Some(bb) = dirty_queue.pop() {
// Set the state to the entry state of the block. // 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. // 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( Self::Direction::apply_effects_in_block(
&mut self, &mut self,
@ -273,7 +276,7 @@ pub trait Analysis<'tcx> {
bb, bb,
&body[bb], &body[bb],
|target: BasicBlock, state: &Self::Domain| { |target: BasicBlock, state: &Self::Domain| {
let set_changed = entry_sets[target].join(state); let set_changed = entry_states[target].join(state);
if set_changed { if set_changed {
dirty_queue.insert(target); 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 { if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
let res = write_graphviz_results(tcx, body, &mut results, pass_name); 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. // NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Effect { enum Effect {
/// The "before" effect (e.g., `apply_before_statement_effect`) for a statement (or /// The "early" effect (e.g., `apply_early_statement_effect`) for a statement/terminator.
/// terminator). Early,
Before,
/// 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, Primary,
} }
@ -381,15 +383,15 @@ pub struct EffectIndex {
impl EffectIndex { impl EffectIndex {
fn next_in_forward_order(self) -> Self { fn next_in_forward_order(self) -> Self {
match self.effect { match self.effect {
Effect::Before => Effect::Primary.at_index(self.statement_index), Effect::Early => Effect::Primary.at_index(self.statement_index),
Effect::Primary => Effect::Before.at_index(self.statement_index + 1), Effect::Primary => Effect::Early.at_index(self.statement_index + 1),
} }
} }
fn next_in_backward_order(self) -> Self { fn next_in_backward_order(self) -> Self {
match self.effect { match self.effect {
Effect::Before => Effect::Primary.at_index(self.statement_index), Effect::Early => Effect::Primary.at_index(self.statement_index),
Effect::Primary => Effect::Before.at_index(self.statement_index - 1), Effect::Primary => Effect::Early.at_index(self.statement_index - 1),
} }
} }

View file

@ -6,7 +6,7 @@ use rustc_middle::mir::{BasicBlock, Body, traversal};
use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results}; use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results};
use crate::framework::cursor::ResultsHandle; 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 /// 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 /// 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>, A: Analysis<'tcx>,
{ {
pub analysis: A, pub analysis: A,
pub entry_sets: EntrySets<'tcx, A>, pub entry_states: EntryStates<'tcx, A>,
} }
impl<'tcx, A> Results<'tcx, A> impl<'tcx, A> Results<'tcx, A>
@ -40,7 +40,7 @@ where
/// Gets the dataflow state for the given block. /// Gets the dataflow state for the given block.
pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain { pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
&self.entry_sets[block] &self.entry_states[block]
} }
pub fn visit_with<'mir>( pub fn visit_with<'mir>(

View file

@ -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 /// 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 /// 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> { struct MockAnalysis<'tcx, D> {
body: &'tcx mir::Body<'tcx>, body: &'tcx mir::Body<'tcx>,
dir: PhantomData<D>, dir: PhantomData<D>,
@ -90,7 +90,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
ret 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 empty = self.bottom_value(self.body);
let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks); 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. /// Returns the index that should be added to the dataflow state at the given target.
fn effect(&self, loc: EffectIndex) -> usize { fn effect(&self, loc: EffectIndex) -> usize {
let idx = match loc.effect { let idx = match loc.effect {
Effect::Before => loc.statement_index * 2, Effect::Early => loc.statement_index * 2,
Effect::Primary => loc.statement_index * 2 + 1, Effect::Primary => loc.statement_index * 2 + 1,
}; };
@ -128,14 +128,14 @@ impl<D: Direction> MockAnalysis<'_, D> {
let target = match target { let target = match target {
SeekTarget::BlockEntry { .. } => return ret, 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), SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index),
}; };
let mut pos = if D::IS_FORWARD { let mut pos = if D::IS_FORWARD {
Effect::Before.at_index(0) Effect::Early.at_index(0)
} else { } else {
Effect::Before.at_index(self.body[block].statements.len()) Effect::Early.at_index(self.body[block].statements.len())
}; };
loop { loop {
@ -168,7 +168,17 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint"); 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::Early.at_index(location.statement_index));
assert!(state.insert(idx));
}
fn apply_primary_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>, _statement: &mir::Statement<'tcx>,
@ -178,17 +188,17 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
assert!(state.insert(idx)); assert!(state.insert(idx));
} }
fn apply_before_statement_effect( fn apply_early_terminator_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>, _terminator: &mir::Terminator<'tcx>,
location: Location, location: Location,
) { ) {
let idx = self.effect(Effect::Before.at_index(location.statement_index)); let idx = self.effect(Effect::Early.at_index(location.statement_index));
assert!(state.insert(idx)); assert!(state.insert(idx));
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
@ -198,22 +208,12 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
assert!(state.insert(idx)); assert!(state.insert(idx));
terminator.edges() terminator.edges()
} }
fn apply_before_terminator_effect(
&mut self,
state: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
location: Location,
) {
let idx = self.effect(Effect::Before.at_index(location.statement_index));
assert!(state.insert(idx));
}
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum SeekTarget { enum SeekTarget {
BlockEntry(BasicBlock), BlockEntry(BasicBlock),
Before(Location), Early(Location),
After(Location), After(Location),
} }
@ -223,7 +223,7 @@ impl SeekTarget {
match *self { match *self {
BlockEntry(block) => block, 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)| { .map(move |(i, kind)| {
let loc = Location { block, statement_index: i }; let loc = Location { block, statement_index: i };
match kind { match kind {
0 => SeekTarget::Before(loc), 0 => SeekTarget::Early(loc),
1 => SeekTarget::After(loc), 1 => SeekTarget::After(loc),
_ => unreachable!(), _ => unreachable!(),
} }
@ -249,7 +249,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
let body = analysis.body; let body = analysis.body;
let mut cursor = 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(); cursor.allow_unreachable();
@ -262,7 +262,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
match targ { match targ {
BlockEntry(block) => cursor.seek_to_block_entry(block), 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), After(loc) => cursor.seek_after_primary_effect(loc),
} }

View file

@ -35,9 +35,9 @@ where
{ {
fn visit_block_start(&mut self, _state: &A::Domain) {} fn visit_block_start(&mut self, _state: &A::Domain) {}
/// Called with the `before_statement_effect` of the given statement applied to `state` but not /// // njn: grep for "before", "primary", etc.
/// its `statement_effect`. /// Called after the "early" effect of the given statement is applied to `state`.
fn visit_statement_before_primary_effect( fn visit_after_early_statement_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
_state: &A::Domain, _state: &A::Domain,
@ -46,9 +46,8 @@ where
) { ) {
} }
/// Called with both the `before_statement_effect` and the `statement_effect` of the given /// Called after the "primary" effect of the given statement is applied to `state`.
/// statement applied to `state`. fn visit_after_primary_statement_effect(
fn visit_statement_after_primary_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
_state: &A::Domain, _state: &A::Domain,
@ -57,9 +56,8 @@ where
) { ) {
} }
/// Called with the `before_terminator_effect` of the given terminator applied to `state` but /// Called after the "early" effect of the given terminator is applied to `state`.
/// not its `terminator_effect`. fn visit_after_early_terminator_effect(
fn visit_terminator_before_primary_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
_state: &A::Domain, _state: &A::Domain,
@ -68,11 +66,10 @@ where
) { ) {
} }
/// Called with both the `before_terminator_effect` and the `terminator_effect` of the given /// Called after the "primary" effect of the given terminator is applied to `state`.
/// terminator applied to `state`.
/// ///
/// The `call_return_effect` (if one exists) will *not* be 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, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
_state: &A::Domain, _state: &A::Domain,

View file

@ -33,22 +33,22 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
// No locals are aliased on function entry // No locals are aliased on function entry
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
statement: &Statement<'tcx>, statement: &Statement<'tcx>,
location: Location, 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir Terminator<'tcx>, terminator: &'mir Terminator<'tcx>,
location: Location, location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
Self::transfer_function(trans).visit_terminator(terminator, location); Self::transfer_function(state).visit_terminator(terminator, location);
terminator.edges() terminator.edges()
} }
} }

View file

@ -70,7 +70,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
pub fn is_unwind_dead( pub fn is_unwind_dead(
&self, &self,
place: mir::Place<'tcx>, place: mir::Place<'tcx>,
state: &MaybeReachable<MixedBitSet<MovePathIndex>>, state: &<Self as Analysis<'tcx>>::Domain,
) -> bool { ) -> bool {
if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) { if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) {
let mut maybe_live = false; let mut maybe_live = false;
@ -218,26 +218,26 @@ impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> {
impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
fn update_bits( fn update_bits(
trans: &mut <Self as Analysis<'tcx>>::Domain, state: &mut <Self as Analysis<'tcx>>::Domain,
path: MovePathIndex, path: MovePathIndex,
state: DropFlagState, dfstate: DropFlagState,
) { ) {
match state { match dfstate {
DropFlagState::Absent => trans.kill(path), DropFlagState::Absent => state.kill(path),
DropFlagState::Present => trans.gen_(path), DropFlagState::Present => state.gen_(path),
} }
} }
} }
impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> { impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> {
fn update_bits( fn update_bits(
trans: &mut <Self as Analysis<'tcx>>::Domain, state: &mut <Self as Analysis<'tcx>>::Domain,
path: MovePathIndex, path: MovePathIndex,
state: DropFlagState, dfstate: DropFlagState,
) { ) {
match state { match dfstate {
DropFlagState::Absent => trans.gen_(path), DropFlagState::Absent => state.gen_(path),
DropFlagState::Present => trans.kill(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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
statement: &mir::Statement<'tcx>, statement: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { 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. // 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()) && let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref())
{ {
on_all_children_bits(self.move_data(), mpi, |child| { 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, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
@ -309,7 +309,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_block: mir::BasicBlock, _block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>, return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
@ -320,7 +320,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
self.move_data(), self.move_data(),
self.move_data().rev_lookup.find(place.as_ref()), self.move_data().rev_lookup.find(place.as_ref()),
|mpi| { |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); let mut discriminants = enum_def.discriminants(self.tcx);
edge_effects.apply(|trans, edge| { edge_effects.apply(|state, edge| {
let Some(value) = edge.value else { let Some(value) = edge.value else {
return; return;
}; };
@ -363,25 +363,27 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
self.move_data(), self.move_data(),
enum_place, enum_place,
variant, variant,
|mpi| trans.kill(mpi), |mpi| state.kill(mpi),
); );
}); });
} }
} }
impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
/// There can be many more `MovePathIndex` than there are locals in a MIR body. /// 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. /// We use a mixed bitset to avoid paying too high a memory footprint.
type Domain = MixedBitSet<MovePathIndex>; pub type MaybeUninitializedPlacesDomain = MixedBitSet<MovePathIndex>;
impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
type Domain = MaybeUninitializedPlacesDomain;
const NAME: &'static str = "maybe_uninit"; const NAME: &'static str = "maybe_uninit";
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { 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()) 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) { fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
// set all bits to 1 (uninit) before gathering counter-evidence // set all bits to 1 (uninit) before gathering counter-evidence
state.insert_all(); 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>, _statement: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { 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 // 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. // mutable borrow occurs. Places cannot become uninitialized through a mutable reference.
} }
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
location: Location, location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { 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) { if self.skip_unreachable_unwind.contains(location.block) {
let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() }; 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( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_block: mir::BasicBlock, _block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>, return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
@ -437,7 +439,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
self.move_data(), self.move_data(),
self.move_data().rev_lookup.find(place.as_ref()), self.move_data().rev_lookup.find(place.as_ref()),
|mpi| { |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); let mut discriminants = enum_def.discriminants(self.tcx);
edge_effects.apply(|trans, edge| { edge_effects.apply(|state, edge| {
let Some(value) = edge.value else { let Some(value) = edge.value else {
return; return;
}; };
@ -484,16 +486,18 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
self.move_data(), self.move_data(),
enum_place, enum_place,
variant, variant,
|mpi| trans.gen_(mpi), |mpi| state.gen_(mpi),
); );
}); });
} }
} }
impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
/// There can be many more `InitIndex` than there are locals in a MIR body. /// 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. /// We use a mixed bitset to avoid paying too high a memory footprint.
type Domain = MixedBitSet<InitIndex>; pub type EverInitializedPlacesDomain = MixedBitSet<InitIndex>;
impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
type Domain = EverInitializedPlacesDomain;
const NAME: &'static str = "ever_init"; const NAME: &'static str = "ever_init";
@ -508,10 +512,10 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
} }
} }
#[instrument(skip(self, trans), level = "debug")] #[instrument(skip(self, state), level = "debug")]
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>, stmt: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
@ -521,7 +525,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
let rev_lookup = &move_data.rev_lookup; let rev_lookup = &move_data.rev_lookup;
debug!("initializes move_indexes {:?}", init_loc_map[location]); 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 { if let mir::StatementKind::StorageDead(local) = stmt.kind {
// End inits for StorageDead, so that an immutable variable can // 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 {:?}", "clears the ever initialized status of {:?}",
init_path_map[move_path_index] 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")] #[instrument(skip(self, state, terminator), level = "debug")]
fn apply_terminator_effect<'mir>( fn apply_primary_terminator_effect<'mir>(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
location: Location, location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
@ -548,7 +552,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
let init_loc_map = &move_data.init_loc_map; let init_loc_map = &move_data.init_loc_map;
debug!(?term); debug!(?term);
debug!("initializes move_indexes {:?}", init_loc_map[location]); debug!("initializes move_indexes {:?}", init_loc_map[location]);
trans.gen_all( state.gen_all(
init_loc_map[location] init_loc_map[location]
.iter() .iter()
.filter(|init_index| { .filter(|init_index| {
@ -561,7 +565,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
block: mir::BasicBlock, block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>, _return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
@ -570,7 +574,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
let call_loc = self.body.terminator_loc(block); let call_loc = self.body.terminator_loc(block);
for init_index in &init_loc_map[call_loc] { for init_index in &init_loc_map[call_loc] {
trans.gen_(*init_index); state.gen_(*init_index);
} }
} }
} }

View file

@ -40,33 +40,33 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
// No variables are live until we observe a use // No variables are live until we observe a use
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
statement: &mir::Statement<'tcx>, statement: &mir::Statement<'tcx>,
location: Location, 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
location: Location, location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
TransferFunction(trans).visit_terminator(terminator, location); TransferFunction(state).visit_terminator(terminator, location);
terminator.edges() terminator.edges()
} }
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_block: mir::BasicBlock, _block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>, return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
if let CallReturnPlaces::Yield(resume_place) = return_places { if let CallReturnPlaces::Yield(resume_place) = return_places {
YieldResumeEffect(trans).visit_place( YieldResumeEffect(state).visit_place(
&resume_place, &resume_place,
PlaceContext::MutatingUse(MutatingUseContext::Yield), PlaceContext::MutatingUse(MutatingUseContext::Yield),
Location::START, Location::START,
@ -74,7 +74,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
} else { } else {
return_places.for_each(|place| { return_places.for_each(|place| {
if let Some(local) = place.as_local() { if let Some(local) = place.as_local() {
trans.kill(local); state.kill(local);
} }
}); });
} }
@ -137,10 +137,10 @@ enum DefUse {
} }
impl 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) { match DefUse::for_place(place, context) {
Some(DefUse::Def) => trans.kill(place.local), Some(DefUse::Def) => state.kill(place.local),
Some(DefUse::Use) => trans.gen_(place.local), Some(DefUse::Use) => state.gen_(place.local),
None => {} None => {}
} }
} }
@ -232,9 +232,9 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
// No variables are live until we observe a use // No variables are live until we observe a use
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
statement: &mir::Statement<'tcx>, statement: &mir::Statement<'tcx>,
location: Location, location: Location,
) { ) {
@ -258,34 +258,34 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
}; };
if let Some(destination) = destination { if let Some(destination) = destination {
if !destination.is_indirect() if !destination.is_indirect()
&& !trans.contains(destination.local) && !state.contains(destination.local)
&& !self.always_live.contains(destination.local) && !self.always_live.contains(destination.local)
{ {
// This store is dead // This store is dead
return; 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>, terminator: &'mir mir::Terminator<'tcx>,
location: Location, location: Location,
) -> TerminatorEdges<'mir, 'tcx> { ) -> TerminatorEdges<'mir, 'tcx> {
TransferFunction(trans).visit_terminator(terminator, location); TransferFunction(state).visit_terminator(terminator, location);
terminator.edges() terminator.edges()
} }
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_block: mir::BasicBlock, _block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>, return_places: CallReturnPlaces<'_, 'tcx>,
) { ) {
if let CallReturnPlaces::Yield(resume_place) = return_places { if let CallReturnPlaces::Yield(resume_place) = return_places {
YieldResumeEffect(trans).visit_place( YieldResumeEffect(state).visit_place(
&resume_place, &resume_place,
PlaceContext::MutatingUse(MutatingUseContext::Yield), PlaceContext::MutatingUse(MutatingUseContext::Yield),
Location::START, Location::START,
@ -293,7 +293,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
} else { } else {
return_places.for_each(|place| { return_places.for_each(|place| {
if let Some(local) = place.as_local() { if let Some(local) = place.as_local() {
trans.remove(local); state.remove(local);
} }
}); });
} }

View file

@ -5,7 +5,8 @@ mod storage_liveness;
pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals}; pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals};
pub use self::initialized::{ pub use self::initialized::{
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, EverInitializedPlaces, EverInitializedPlacesDomain, MaybeInitializedPlaces,
MaybeUninitializedPlaces, MaybeUninitializedPlacesDomain,
}; };
pub use self::liveness::{ pub use self::liveness::{
MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction, MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,

View file

@ -44,23 +44,23 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> {
BitSet::new_empty(body.local_decls.len()) 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) {
on_entry.union(&*self.always_live_locals); state.union(&*self.always_live_locals);
for arg in body.args_iter() { for arg in body.args_iter() {
on_entry.insert(arg); state.insert(arg);
} }
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
stmt: &Statement<'tcx>, stmt: &Statement<'tcx>,
_: Location, _: Location,
) { ) {
match stmt.kind { match stmt.kind {
StatementKind::StorageLive(l) => trans.gen_(l), StatementKind::StorageLive(l) => state.gen_(l),
StatementKind::StorageDead(l) => trans.kill(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()) 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()); 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. // Do not iterate on return place and args, as they are trivially always live.
for local in body.vars_and_temps_iter() { for local in body.vars_and_temps_iter() {
if !self.always_live_locals.contains(local) { 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
stmt: &Statement<'tcx>, stmt: &Statement<'tcx>,
_: Location, _: Location,
) { ) {
match stmt.kind { match stmt.kind {
StatementKind::StorageLive(l) => trans.kill(l), StatementKind::StorageLive(l) => state.kill(l),
StatementKind::StorageDead(l) => trans.gen_(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()) 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 resume argument is live on function entry (we don't care about
// the `self` argument) // the `self` argument)
for arg in body.args_iter().skip(1) { 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
stmt: &Statement<'tcx>, stmt: &Statement<'tcx>,
loc: Location, loc: Location,
) { ) {
// If a place is borrowed in a statement, it needs storage for that statement. // 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 { 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. // If a place is assigned to in a statement, it needs storage for that statement.
StatementKind::Assign(box (place, _)) StatementKind::Assign(box (place, _))
| StatementKind::SetDiscriminant { box place, .. } | StatementKind::SetDiscriminant { box place, .. }
| StatementKind::Deinit(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 // 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_: &Statement<'tcx>, _: &Statement<'tcx>,
loc: Location, loc: Location,
) { ) {
// If we move from a place then it only stops needing storage *after* // If we move from a place then it only stops needing storage *after*
// that statement. // 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &Terminator<'tcx>, terminator: &Terminator<'tcx>,
loc: Location, loc: Location,
) { ) {
// If a place is borrowed in a terminator, it needs storage for that terminator. // 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 { match &terminator.kind {
TerminatorKind::Call { destination, .. } => { 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 // 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::Out { place, .. }
| InlineAsmOperand::InOut { out_place: place, .. } => { | InlineAsmOperand::InOut { out_place: place, .. } => {
if let Some(place) = place { if let Some(place) = place {
trans.gen_(place.local); state.gen_(place.local);
} }
} }
InlineAsmOperand::In { .. } 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, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'t Terminator<'tcx>, terminator: &'t Terminator<'tcx>,
loc: Location, loc: Location,
) -> TerminatorEdges<'t, 'tcx> { ) -> 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 // Since `propagate_call_unwind` doesn't exist, we have to kill the
// destination here, and then gen it again in `call_return_effect`. // destination here, and then gen it again in `call_return_effect`.
TerminatorKind::Call { destination, .. } => { TerminatorKind::Call { destination, .. } => {
trans.kill(destination.local); state.kill(destination.local);
} }
// The same applies to InlineAsm outputs. // The same applies to InlineAsm outputs.
TerminatorKind::InlineAsm { ref operands, .. } => { 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 // 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 => {} | TerminatorKind::Unreachable => {}
} }
self.check_for_move(trans, loc); self.check_for_move(state, loc);
terminator.edges() terminator.edges()
} }
fn apply_call_return_effect( fn apply_call_return_effect(
&mut self, &mut self,
trans: &mut Self::Domain, state: &mut Self::Domain,
_block: BasicBlock, _block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>, 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> { impl<'tcx> MaybeRequiresStorage<'_, 'tcx> {
/// Kill locals that are fully moved and have not been borrowed. /// 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 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); visitor.visit_location(body, loc);
} }
} }
struct MoveVisitor<'a, 'mir, 'tcx> { struct MoveVisitor<'a, 'mir, 'tcx> {
borrowed_locals: &'a mut BorrowedLocalsResults<'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> { impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
@ -312,7 +312,7 @@ impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
self.borrowed_locals.seek_before_primary_effect(loc); self.borrowed_locals.seek_before_primary_effect(loc);
if !self.borrowed_locals.get().contains(local) { if !self.borrowed_locals.get().contains(local) {
self.trans.kill(local); self.state.kill(local);
} }
} }
} }

View file

@ -18,7 +18,7 @@ pub use self::drop_flag_effects::{
move_path_children_matching, on_all_children_bits, on_lookup_result_bits, move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
}; };
pub use self::framework::{ 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, Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
visit_results, visit_results,
}; };

View file

@ -125,7 +125,7 @@ where
A: Analysis<'tcx, Domain = BitSet<N>>, A: Analysis<'tcx, Domain = BitSet<N>>,
N: Idx, N: Idx,
{ {
fn visit_statement_after_primary_effect( fn visit_after_primary_statement_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,
@ -139,7 +139,7 @@ where
}); });
} }
fn visit_terminator_after_primary_effect( fn visit_after_primary_terminator_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, A>, _results: &mut Results<'tcx, A>,
state: &A::Domain, state: &A::Domain,

View file

@ -1,6 +1,5 @@
use rustc_ast::MetaItem; use rustc_ast::MetaItem;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::mir::{self, Body, Local, Location};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span; use rustc_span::Span;
@ -254,7 +253,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
&self, &self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
place: mir::Place<'tcx>, place: mir::Place<'tcx>,
state: &BitSet<Local>, state: &Self::Domain,
call: PeekCall, call: PeekCall,
) { ) {
info!(?place, "peek_at"); info!(?place, "peek_at");

View file

@ -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 { fn join(&mut self, other: &Self) -> bool {
let mut changed = false; let mut changed = false;
#[allow(rustc::potential_query_instability)] #[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 { fn join(&mut self, other: &Self) -> bool {
match (&mut *self, other) { match (&mut *self, other) {
(_, State::Unreachable) => false, (_, State::Unreachable) => false,

View file

@ -878,7 +878,7 @@ struct StorageConflictVisitor<'a, 'tcx> {
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>> impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
for StorageConflictVisitor<'a, 'tcx> for StorageConflictVisitor<'a, 'tcx>
{ {
fn visit_statement_before_primary_effect( fn visit_after_early_statement_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
state: &BitSet<Local>, state: &BitSet<Local>,
@ -888,7 +888,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
self.apply_state(state, loc); self.apply_state(state, loc);
} }
fn visit_terminator_before_primary_effect( fn visit_after_early_terminator_effect(
&mut self, &mut self,
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
state: &BitSet<Local>, state: &BitSet<Local>,

View file

@ -106,7 +106,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
} }
} }
fn apply_statement_effect( fn apply_primary_statement_effect(
&mut self, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
statement: &Statement<'tcx>, 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, &mut self,
state: &mut Self::Domain, state: &mut Self::Domain,
terminator: &'mir Terminator<'tcx>, 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 /// 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>( fn handle_terminator<'mir>(
&self, &self,
terminator: &'mir Terminator<'tcx>, terminator: &'mir Terminator<'tcx>,
@ -954,7 +954,7 @@ fn try_write_constant<'tcx>(
impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> { impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
#[instrument(level = "trace", skip(self, results, statement))] #[instrument(level = "trace", skip(self, results, statement))]
fn visit_statement_before_primary_effect( fn visit_after_early_statement_effect(
&mut self, &mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &State<FlatSet<Scalar>>, 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))] #[instrument(level = "trace", skip(self, results, statement))]
fn visit_statement_after_primary_effect( fn visit_after_primary_statement_effect(
&mut self, &mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &State<FlatSet<Scalar>>, 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, &mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &State<FlatSet<Scalar>>, state: &State<FlatSet<Scalar>>,

View file

@ -127,7 +127,7 @@ impl InitializationData<'_, '_> {
self.uninits.seek_before_primary_effect(loc); 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)) (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)] #[instrument(level = "debug", skip(self), ret)]
fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle { fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle {
let ((maybe_live, maybe_dead), multipart) = match mode { let ((maybe_init, maybe_uninit), multipart) = match mode {
DropFlagMode::Shallow => (self.init_data.maybe_live_dead(path), false), DropFlagMode::Shallow => (self.init_data.maybe_init_uninit(path), false),
DropFlagMode::Deep => { DropFlagMode::Deep => {
let mut some_live = false; let mut some_maybe_init = false;
let mut some_dead = false; let mut some_maybe_uninit = false;
let mut children_count = 0; let mut children_count = 0;
on_all_children_bits(self.move_data(), path, |child| { on_all_children_bits(self.move_data(), path, |child| {
let (live, dead) = self.init_data.maybe_live_dead(child); let (maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(child);
debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead)); debug!("elaborate_drop: state({:?}) = {:?}", child, (maybe_init, maybe_uninit));
some_live |= live; some_maybe_init |= maybe_init;
some_dead |= dead; some_maybe_uninit |= maybe_uninit;
children_count += 1; 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, (false, _, _) => DropStyle::Dead,
(true, false, _) => DropStyle::Static, (true, false, _) => DropStyle::Static,
(true, true, false) => DropStyle::Conditional, (true, true, false) => DropStyle::Conditional,
@ -283,15 +283,15 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
LookupResult::Exact(path) => { LookupResult::Exact(path) => {
self.init_data.seek_before(self.body.terminator_loc(bb)); self.init_data.seek_before(self.body.terminator_loc(bb));
on_all_children_bits(self.move_data(), path, |child| { 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!( debug!(
"collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
child, child,
place, place,
path, 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) 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)); self.init_data.seek_before(self.body.terminator_loc(bb));
let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); let (_maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(parent);
if maybe_dead { if maybe_uninit {
self.tcx.dcx().span_delayed_bug( self.tcx.dcx().span_delayed_bug(
terminator.source_info.span, terminator.source_info.span,
format!( format!(

View file

@ -15,7 +15,7 @@ use rustc_ast::visit::{Visitor, walk_expr};
use rustc_ast::{ use rustc_ast::{
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall, 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_ast_pretty::pprust;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
@ -1931,6 +1931,12 @@ impl<'a> Parser<'a> {
Ok(match ident.name { Ok(match ident.name {
sym::offset_of => Some(this.parse_expr_offset_of(lo)?), sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
sym::type_ascribe => Some(this.parse_expr_type_ascribe(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, _ => None,
}) })
}) })
@ -2006,6 +2012,17 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(span, ExprKind::Type(expr, ty))) 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. /// 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, /// 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. /// 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); mut_visit::walk_expr(self, e);
self.forbid_let_reason = forbid_let_reason; 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; let forbid_let_reason = self.forbid_let_reason;
self.forbid_let_reason = Some(OtherForbidden); self.forbid_let_reason = Some(OtherForbidden);
self.visit_expr(op); self.visit_expr(op);

View file

@ -45,7 +45,7 @@ impl<'a> Parser<'a> {
let (inner_attrs, items, inner_span) = let (inner_attrs, items, inner_span) =
self.parse_mod(&token::CloseDelim(Delimiter::Brace))?; self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
attrs.extend(inner_attrs); 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))) Ok((id, ItemKind::Mod(safety, mod_kind)))
} }

View file

@ -5,7 +5,7 @@ use rustc_ast::{
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy, self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability,
Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
TyKind, TyKind, UnsafeBinderTy,
}; };
use rustc_errors::{Applicability, PResult}; use rustc_errors::{Applicability, PResult};
use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::symbol::{Ident, kw, sym};
@ -348,6 +348,10 @@ impl<'a> Parser<'a> {
TyKind::Err(guar) 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 { } else {
let msg = format!("expected type, found {}", super::token_descr(&self.token)); let msg = format!("expected type, found {}", super::token_descr(&self.token));
let mut err = self.dcx().struct_span_err(lo, msg); 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) } 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: /// Parses either:
/// - `(TYPE)`, a parenthesized type. /// - `(TYPE)`, a parenthesized type.
/// - `(TYPE,)`, a tuple with a single field of type TYPE. /// - `(TYPE,)`, a tuple with a single field of type TYPE.

View file

@ -315,9 +315,40 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
fn visit_expr(&mut self, e: &'v hir::Expr<'v>) { fn visit_expr(&mut self, e: &'v hir::Expr<'v>) {
record_variants!((self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind), [ record_variants!((self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind), [
ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, DropTemps, ConstBlock,
Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, Path, AddrOf, Array,
Break, Continue, Ret, Become, InlineAsm, OffsetOf, Struct, Repeat, Yield, Err 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) hir_visit::walk_expr(self, e)
} }
@ -335,6 +366,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
Ptr, Ptr,
Ref, Ref,
BareFn, BareFn,
UnsafeBinder,
Never, Never,
Tup, Tup,
Path, Path,
@ -571,7 +603,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign, If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign,
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, 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) ast_visit::walk_expr(self, e)
@ -585,6 +617,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
Ref, Ref,
PinnedRef, PinnedRef,
BareFn, BareFn,
UnsafeBinder,
Never, Never,
Tup, Tup,
Path, Path,

View file

@ -447,6 +447,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
| hir::ExprKind::InlineAsm(..) | hir::ExprKind::InlineAsm(..)
| hir::ExprKind::OffsetOf(..) | hir::ExprKind::OffsetOf(..)
| hir::ExprKind::Type(..) | hir::ExprKind::Type(..)
| hir::ExprKind::UnsafeBinderCast(..)
| hir::ExprKind::Err(_) | hir::ExprKind::Err(_)
| hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
| hir::ExprKind::Path(hir::QPath::LangItem(..)) => {} | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {}
@ -1051,6 +1052,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprKind::AddrOf(_, _, ref e) hir::ExprKind::AddrOf(_, _, ref e)
| hir::ExprKind::Cast(ref e, _) | hir::ExprKind::Cast(ref e, _)
| hir::ExprKind::Type(ref e, _) | hir::ExprKind::Type(ref e, _)
| hir::ExprKind::UnsafeBinderCast(_, ref e, _)
| hir::ExprKind::DropTemps(ref e) | hir::ExprKind::DropTemps(ref e)
| hir::ExprKind::Unary(_, ref e) | hir::ExprKind::Unary(_, ref e)
| hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(e, succ), | 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::Path(_)
| hir::ExprKind::Yield(..) | hir::ExprKind::Yield(..)
| hir::ExprKind::Type(..) | hir::ExprKind::Type(..)
| hir::ExprKind::UnsafeBinderCast(..)
| hir::ExprKind::Err(_) => {} | hir::ExprKind::Err(_) => {}
} }
} }

View file

@ -186,6 +186,7 @@ impl CheckInlineAssembly {
| ExprKind::Lit(..) | ExprKind::Lit(..)
| ExprKind::Cast(..) | ExprKind::Cast(..)
| ExprKind::Type(..) | ExprKind::Type(..)
| ExprKind::UnsafeBinderCast(..)
| ExprKind::Loop(..) | ExprKind::Loop(..)
| ExprKind::Match(..) | ExprKind::Match(..)
| ExprKind::If(..) | ExprKind::If(..)

View file

@ -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( let module = self.r.new_module(
Some(parent), Some(parent),
ModuleKind::Def(def_kind, def_id, ident.name), 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)); 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. // Descend into the module.
self.parent_scope.module = module; self.parent_scope.module = module;
} }

View file

@ -3056,7 +3056,7 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
fn visit_item(&mut self, item: &'tcx ast::Item) { fn visit_item(&mut self, item: &'tcx ast::Item) {
if self.target_module == item.id { 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; let inject = mod_spans.inject_use_span;
if is_span_suitable_for_use_injection(inject) { if is_span_suitable_for_use_injection(inject) {
self.first_legal_span = Some(inject); self.first_legal_span = Some(inject);

View file

@ -1428,6 +1428,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ignore_import: Option<Import<'ra>>, ignore_import: Option<Import<'ra>>,
) -> PathResult<'ra> { ) -> PathResult<'ra> {
let mut module = None; let mut module = None;
let mut module_had_parse_errors = false;
let mut allow_super = true; let mut allow_super = true;
let mut second_binding = None; let mut second_binding = None;
@ -1471,9 +1472,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
continue; continue;
} }
} }
return PathResult::failed(ident, false, finalize.is_some(), module, || { return PathResult::failed(
("there are too many leading `super` keywords".to_string(), None) 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 segment_idx == 0 {
if name == kw::SelfLower { if name == kw::SelfLower {
@ -1511,7 +1517,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// Report special messages for path segment keywords in wrong positions. // Report special messages for path segment keywords in wrong positions.
if ident.is_path_segment_keyword() && segment_idx != 0 { if ident.is_path_segment_keyword() && segment_idx != 0 {
return PathResult::failed(ident, false, finalize.is_some(), module, || { return PathResult::failed(
ident,
false,
finalize.is_some(),
module_had_parse_errors,
module,
|| {
let name_str = if name == kw::PathRoot { let name_str = if name == kw::PathRoot {
"crate root".to_string() "crate root".to_string()
} else { } else {
@ -1523,7 +1535,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
format!("{name_str} in paths can only be used in start position") format!("{name_str} in paths can only be used in start position")
}; };
(label, None) (label, None)
}); },
);
} }
let binding = if let Some(module) = module { 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); let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
if let Some(next_module) = binding.module() { 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)); module = Some(ModuleOrUniformRoot::Module(next_module));
record_segment_res(self, res); record_segment_res(self, res);
} else if res == Res::ToolMod && !is_last && opt_ns.is_some() { } else if res == Res::ToolMod && !is_last && opt_ns.is_some() {
@ -1614,6 +1630,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ident, ident,
is_last, is_last,
finalize.is_some(), finalize.is_some(),
module_had_parse_errors,
module, module,
|| { || {
let label = format!( let label = format!(
@ -1637,7 +1654,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
} }
} }
return PathResult::failed(ident, is_last, finalize.is_some(), module, || { return PathResult::failed(
ident,
is_last,
finalize.is_some(),
module_had_parse_errors,
module,
|| {
self.report_path_resolution_error( self.report_path_resolution_error(
path, path,
opt_ns, opt_ns,
@ -1649,7 +1672,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
segment_idx, segment_idx,
ident, ident,
) )
}); },
);
} }
} }
} }

View file

@ -670,9 +670,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
fn throw_unresolved_import_error( fn throw_unresolved_import_error(
&mut self, &mut self,
errors: Vec<(Import<'_>, UnresolvedImportError)>, mut errors: Vec<(Import<'_>, UnresolvedImportError)>,
glob_error: bool, 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() { if errors.is_empty() {
return; return;
} }
@ -898,6 +903,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
label, label,
suggestion, suggestion,
module, module,
error_implied_by_parse_error: _,
} => { } => {
if no_ambiguity { if no_ambiguity {
assert!(import.imported_module.get().is_none()); assert!(import.imported_module.get().is_none());

View file

@ -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) => { TyKind::Array(element_ty, length) => {
self.visit_ty(element_ty); self.visit_ty(element_ty);
self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No)); 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() => { PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
PartialRes::new(module.res().unwrap()) 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 // 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. // 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 // 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, suggestion,
module, module,
segment_name, segment_name,
error_implied_by_parse_error: _,
} => { } => {
return Err(respan(span, ResolutionError::FailedToResolve { return Err(respan(span, ResolutionError::FailedToResolve {
segment: Some(segment_name), segment: Some(segment_name),

View file

@ -450,6 +450,7 @@ enum PathResult<'ra> {
module: Option<ModuleOrUniformRoot<'ra>>, module: Option<ModuleOrUniformRoot<'ra>>,
/// The segment name of target /// The segment name of target
segment_name: Symbol, segment_name: Symbol,
error_implied_by_parse_error: bool,
}, },
} }
@ -458,6 +459,7 @@ impl<'ra> PathResult<'ra> {
ident: Ident, ident: Ident,
is_error_from_last_segment: bool, is_error_from_last_segment: bool,
finalize: bool, finalize: bool,
error_implied_by_parse_error: bool,
module: Option<ModuleOrUniformRoot<'ra>>, module: Option<ModuleOrUniformRoot<'ra>>,
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>), label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
) -> PathResult<'ra> { ) -> PathResult<'ra> {
@ -470,6 +472,7 @@ impl<'ra> PathResult<'ra> {
suggestion, suggestion,
is_error_from_last_segment, is_error_from_last_segment,
module, 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` /// 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. /// could be a crate that wasn't imported. For diagnostics use only.
current_crate_outer_attr_insert_span: Span, 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 /// 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_unexpanded_invocations: Default::default(),
impl_binding_keys: Default::default(), impl_binding_keys: Default::default(),
current_crate_outer_attr_insert_span, current_crate_outer_attr_insert_span,
mods_with_parse_errors: Default::default(),
}; };
let root_parent_scope = ParentScope::module(graph_root, &resolver); let root_parent_scope = ParentScope::module(graph_root, &resolver);

View file

@ -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 => { [seg1, seg2] if seg1.ident.name == sym::rustfmt && seg2.ident.name == sym::skip => {
if let InvocationKind::Attr { item, .. } = &invoc.kind { if let InvocationKind::Attr { item, .. } = &invoc.kind {
if let Annotatable::Item(item) = item { 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; return true;
} }
} }

View file

@ -2105,6 +2105,7 @@ symbols! {
unreachable_macro, unreachable_macro,
unrestricted_attribute_tokens, unrestricted_attribute_tokens,
unsafe_attributes, unsafe_attributes,
unsafe_binders,
unsafe_block_in_unsafe_fn, unsafe_block_in_unsafe_fn,
unsafe_cell, unsafe_cell,
unsafe_cell_raw_get, unsafe_cell_raw_get,
@ -2128,6 +2129,7 @@ symbols! {
unwind_attributes, unwind_attributes,
unwind_safe_trait, unwind_safe_trait,
unwrap, unwrap,
unwrap_binder,
unwrap_or, unwrap_or,
use_extern_macros, use_extern_macros,
use_nested_groups, use_nested_groups,
@ -2186,6 +2188,7 @@ symbols! {
windows, windows,
windows_subsystem, windows_subsystem,
with_negative_coherence, with_negative_coherence,
wrap_binder,
wrapping_add, wrapping_add,
wrapping_div, wrapping_div,
wrapping_mul, wrapping_mul,

View file

@ -354,6 +354,8 @@ pub mod random;
pub mod range; pub mod range;
pub mod result; pub mod result;
pub mod sync; pub mod sync;
#[unstable(feature = "unsafe_binders", issue = "130516")]
pub mod unsafe_binder;
pub mod fmt; pub mod fmt;
pub mod hash; pub mod hash;

View file

@ -200,7 +200,7 @@
//! //!
//! But it *is* still sound to: //! 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 //! 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 //! 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 //! 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 //! (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, //! 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.) //! 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 //! 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 //! [`with_addr`]: pointer::with_addr
//! [`map_addr`]: pointer::map_addr //! [`map_addr`]: pointer::map_addr
//! [`addr`]: pointer::addr //! [`addr`]: pointer::addr
//! [`ptr::dangling`]: core::ptr::dangling //! [`AtomicUsize`]: crate::sync::atomic::AtomicUsize
//! [`AtomicPtr`]: crate::sync::atomic::AtomicPtr
//! [`expose_provenance`]: pointer::expose_provenance //! [`expose_provenance`]: pointer::expose_provenance
//! [`with_exposed_provenance`]: with_exposed_provenance //! [`with_exposed_provenance`]: with_exposed_provenance
//! [Miri]: https://github.com/rust-lang/miri //! [Miri]: https://github.com/rust-lang/miri

View file

@ -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 )
},
}

View file

@ -544,6 +544,8 @@ pub use core::u64;
#[stable(feature = "i128", since = "1.26.0")] #[stable(feature = "i128", since = "1.26.0")]
#[allow(deprecated, deprecated_in_future)] #[allow(deprecated, deprecated_in_future)]
pub use core::u128; pub use core::u128;
#[unstable(feature = "unsafe_binders", issue = "130516")]
pub use core::unsafe_binder;
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated, deprecated_in_future)] #[allow(deprecated, deprecated_in_future)]
pub use core::usize; pub use core::usize;

View file

@ -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))), TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer, TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
TyKind::UnsafeBinder(..) => {
unimplemented!("unsafe binders are not supported yet")
}
} }
} }

View file

@ -819,6 +819,7 @@ impl TyCoercionStability {
| TyKind::TraitObject(..) | TyKind::TraitObject(..)
| TyKind::InferDelegation(..) | TyKind::InferDelegation(..)
| TyKind::Err(_) => Self::Reborrow, | TyKind::Err(_) => Self::Reborrow,
TyKind::UnsafeBinder(..) => Self::None,
}; };
} }
} }

View file

@ -63,7 +63,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]);
impl EarlyLintPass for DuplicateMod { impl EarlyLintPass for DuplicateMod {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { 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 FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span)
&& let Some(local_path) = real.into_local_path() && let Some(local_path) = real.into_local_path()
&& let Ok(absolute_path) = local_path.canonicalize() && let Ok(absolute_path) = local_path.canonicalize()

View file

@ -163,7 +163,7 @@ impl Visitor<'_> for NestingVisitor<'_, '_> {
} }
match &item.kind { 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; self.nest_level += 1;
if !self.check_indent(item.span, item.id) { if !self.check_indent(item.span, item.id) {

View file

@ -156,7 +156,8 @@ fn never_loop_expr<'tcx>(
| ExprKind::Field(e, _) | ExprKind::Field(e, _)
| ExprKind::AddrOf(_, _, e) | ExprKind::AddrOf(_, _, e)
| ExprKind::Repeat(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::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::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
ExprKind::MethodCall(_, receiver, es, _) => { ExprKind::MethodCall(_, receiver, es, _) => {

View file

@ -623,6 +623,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
kind!("DropTemps({expr})"); kind!("DropTemps({expr})");
self.expr(expr); self.expr(expr);
}, },
ExprKind::UnsafeBinderCast(..) => {
unimplemented!("unsafe binders are not implemented yet");
}
} }
} }

View file

@ -379,7 +379,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
(Mod(lu, lmk), Mod(ru, rmk)) => { (Mod(lu, lmk), Mod(ru, rmk)) => {
lu == ru lu == ru
&& match (lmk, rmk) { && 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)) linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind))
}, },
(ModKind::Unloaded, ModKind::Unloaded) => true, (ModKind::Unloaded, ModKind::Unloaded) => true,

View file

@ -303,7 +303,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
| ExprKind::AddrOf(..) | ExprKind::AddrOf(..)
| ExprKind::Repeat(..) | ExprKind::Repeat(..)
| ExprKind::Block(Block { stmts: [], .. }, _) | ExprKind::Block(Block { stmts: [], .. }, _)
| ExprKind::OffsetOf(..) => (), | ExprKind::OffsetOf(..)
| ExprKind::UnsafeBinderCast(..) => (),
// Assignment might be to a local defined earlier, so don't eagerly evaluate. // 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. // Blocks with multiple statements might be expensive, so don't eagerly evaluate.

View file

@ -370,6 +370,10 @@ impl HirEqInterExpr<'_, '_, '_> {
&& self.eq_expr(l_receiver, r_receiver) && self.eq_expr(l_receiver, r_receiver)
&& self.eq_exprs(l_args, r_args) && 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)) => { (&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) 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::Type(..)
| &ExprKind::Unary(..) | &ExprKind::Unary(..)
| &ExprKind::Yield(..) | &ExprKind::Yield(..)
| &ExprKind::UnsafeBinderCast(..)
// --- Special cases that do not have a positive branch. // --- 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); std::mem::discriminant(&lop).hash(&mut self.s);
self.hash_expr(le); 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(_) => {}, ExprKind::Err(_) => {},
} }
} }
@ -1241,6 +1253,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
TyKind::Typeof(anon_const) => { TyKind::Typeof(anon_const) => {
self.hash_body(anon_const.body); self.hash_body(anon_const.body);
}, },
TyKind::UnsafeBinder(binder) => {
self.hash_ty(binder.inner_ty);
}
TyKind::Err(_) TyKind::Err(_)
| TyKind::Infer | TyKind::Infer
| TyKind::Never | TyKind::Never

View file

@ -151,7 +151,8 @@ impl<'a> Sugg<'a> {
| ExprKind::Become(..) | ExprKind::Become(..)
| ExprKind::Struct(..) | ExprKind::Struct(..)
| ExprKind::Tup(..) | 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::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
ExprKind::Assign(lhs, rhs, _) => { ExprKind::Assign(lhs, rhs, _) => {
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span)) 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::While(..)
| ast::ExprKind::Await(..) | ast::ExprKind::Await(..)
| ast::ExprKind::Err(_) | 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( ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
AssocOp::DotDot, AssocOp::DotDot,
lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)),

View file

@ -694,6 +694,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
| ExprKind::Continue(_) | ExprKind::Continue(_)
| ExprKind::InlineAsm(_) | ExprKind::InlineAsm(_)
| ExprKind::OffsetOf(..) | ExprKind::OffsetOf(..)
| ExprKind::UnsafeBinderCast(..)
| ExprKind::Err(_) => (), | ExprKind::Err(_) => (),
} }
ControlFlow::Continue(()) ControlFlow::Continue(())

View file

@ -413,7 +413,8 @@ pub(crate) fn format_expr(
ast::ExprKind::FormatArgs(..) ast::ExprKind::FormatArgs(..)
| ast::ExprKind::Type(..) | ast::ExprKind::Type(..)
| ast::ExprKind::IncludedBytes(..) | 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, // 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 // 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. // impossible for rustfmt to come across one of these nodes when formatting a file.

View file

@ -3597,7 +3597,7 @@ pub(crate) fn rewrite_extern_crate(
pub(crate) fn is_mod_decl(item: &ast::Item) -> bool { pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
!matches!( !matches!(
item.kind, item.kind,
ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _)) ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _))
) )
} }

View file

@ -316,12 +316,11 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> {
self.directory = directory; self.directory = directory;
} }
match (sub_mod.ast_mod_kind, sub_mod.items) { 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) self.visit_mod_from_ast(items)
} }
(Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => { (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _, _))), _)
self.visit_mod_outside_ast(items) | (_, Cow::Owned(items)) => self.visit_mod_outside_ast(items),
}
(_, _) => Ok(()), (_, _) => Ok(()),
} }
} }

View file

@ -1016,6 +1016,31 @@ impl Rewrite for ast::Ty {
let pat = pat.rewrite_result(context, shape)?; let pat = pat.rewrite_result(context, shape)?;
Ok(format!("{ty} is {pat}")) 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)
}
} }
} }
} }

View file

@ -504,6 +504,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
| ast::ExprKind::IncludedBytes(..) | ast::ExprKind::IncludedBytes(..)
| ast::ExprKind::InlineAsm(..) | ast::ExprKind::InlineAsm(..)
| ast::ExprKind::OffsetOf(..) | ast::ExprKind::OffsetOf(..)
| ast::ExprKind::UnsafeBinderCast(..)
| ast::ExprKind::Let(..) | ast::ExprKind::Let(..)
| ast::ExprKind::Path(..) | ast::ExprKind::Path(..)
| ast::ExprKind::Range(..) | ast::ExprKind::Range(..)

View file

@ -927,7 +927,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
let ident_str = rewrite_ident(&self.get_context(), ident).to_owned(); let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
self.push_str(&ident_str); 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 { let ast::ModSpans {
inner_span, inner_span,
inject_use_span: _, inject_use_span: _,

View file

@ -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 () {}

View file

@ -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 () {}

View file

@ -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>); }

View file

@ -1,8 +0,0 @@
//@ compile-flags: -Awarnings
//@ check-pass
#[derive()]
#[derive(Copy, Clone)]
pub struct Foo;
pub fn main() {}

View file

@ -1,5 +0,0 @@
//@ run-pass
fn f() -> isize { { return 3; } }
pub fn main() { assert_eq!(f(), 3); }

View file

@ -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);
}

View file

@ -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>);
}

Some files were not shown because too many files have changed in this diff Show more