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:
commit
4a204bebdf
119 changed files with 1341 additions and 639 deletions
|
@ -1382,6 +1382,7 @@ impl Expr {
|
|||
| ExprKind::Tup(_)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::Underscore
|
||||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::While(..)
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
|
||||
|
@ -1509,7 +1510,13 @@ pub enum ExprKind {
|
|||
/// `'label: for await? pat in iter { block }`
|
||||
///
|
||||
/// This is desugared to a combination of `loop` and `match` expressions.
|
||||
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
|
||||
ForLoop {
|
||||
pat: P<Pat>,
|
||||
iter: P<Expr>,
|
||||
body: P<Block>,
|
||||
label: Option<Label>,
|
||||
kind: ForLoopKind,
|
||||
},
|
||||
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
|
||||
///
|
||||
/// `'label: loop { block }`
|
||||
|
@ -1614,6 +1621,8 @@ pub enum ExprKind {
|
|||
/// A `format_args!()` expression.
|
||||
FormatArgs(P<FormatArgs>),
|
||||
|
||||
UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>),
|
||||
|
||||
/// Placeholder for an expression that wasn't syntactically well formed in some way.
|
||||
Err(ErrorGuaranteed),
|
||||
|
||||
|
@ -1652,6 +1661,16 @@ impl GenBlockKind {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether we're unwrapping or wrapping an unsafe binder
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum UnsafeBinderCastKind {
|
||||
// e.g. `&i32` -> `unsafe<'a> &'a i32`
|
||||
Wrap,
|
||||
// e.g. `unsafe<'a> &'a i32` -> `&i32`
|
||||
Unwrap,
|
||||
}
|
||||
|
||||
/// The explicit `Self` type in a "qualified path". The actual
|
||||
/// path, including the trait and the associated item, is stored
|
||||
/// separately. `position` represents the index of the associated
|
||||
|
@ -2223,6 +2242,12 @@ pub struct BareFnTy {
|
|||
pub decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct UnsafeBinderTy {
|
||||
pub generic_params: ThinVec<GenericParam>,
|
||||
pub inner_ty: P<Ty>,
|
||||
}
|
||||
|
||||
/// The various kinds of type recognized by the compiler.
|
||||
//
|
||||
// Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`.
|
||||
|
@ -2242,6 +2267,8 @@ pub enum TyKind {
|
|||
PinnedRef(Option<Lifetime>, MutTy),
|
||||
/// A bare function (e.g., `fn(usize) -> bool`).
|
||||
BareFn(P<BareFnTy>),
|
||||
/// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`).
|
||||
UnsafeBinder(P<UnsafeBinderTy>),
|
||||
/// The never type (`!`).
|
||||
Never,
|
||||
/// A tuple (`(A, B, C, D,...)`).
|
||||
|
@ -2877,7 +2904,7 @@ pub enum ModKind {
|
|||
/// or with definition outlined to a separate file `mod foo;` and already loaded from it.
|
||||
/// The inner span is from the first token past `{` to the last token until `}`,
|
||||
/// or from the first to the last token in the loaded file.
|
||||
Loaded(ThinVec<P<Item>>, Inline, ModSpans),
|
||||
Loaded(ThinVec<P<Item>>, Inline, ModSpans, Result<(), ErrorGuaranteed>),
|
||||
/// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
|
||||
Unloaded,
|
||||
}
|
||||
|
|
|
@ -558,6 +558,11 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
|
|||
vis.visit_fn_decl(decl);
|
||||
vis.visit_span(decl_span);
|
||||
}
|
||||
TyKind::UnsafeBinder(binder) => {
|
||||
let UnsafeBinderTy { generic_params, inner_ty } = binder.deref_mut();
|
||||
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
vis.visit_ty(inner_ty);
|
||||
}
|
||||
TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
|
||||
TyKind::Paren(ty) => vis.visit_ty(ty),
|
||||
TyKind::Pat(ty, pat) => {
|
||||
|
@ -1212,7 +1217,12 @@ impl WalkItemKind for ItemKind {
|
|||
ItemKind::Mod(safety, mod_kind) => {
|
||||
visit_safety(vis, safety);
|
||||
match mod_kind {
|
||||
ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => {
|
||||
ModKind::Loaded(
|
||||
items,
|
||||
_inline,
|
||||
ModSpans { inner_span, inject_use_span },
|
||||
_,
|
||||
) => {
|
||||
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
||||
vis.visit_span(inner_span);
|
||||
vis.visit_span(inject_use_span);
|
||||
|
@ -1775,6 +1785,12 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
|
|||
ExprKind::TryBlock(body) => vis.visit_block(body),
|
||||
ExprKind::Lit(_token) => {}
|
||||
ExprKind::IncludedBytes(_bytes) => {}
|
||||
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||
vis.visit_expr(expr);
|
||||
if let Some(ty) = ty {
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
}
|
||||
ExprKind::Err(_guar) => {}
|
||||
ExprKind::Dummy => {}
|
||||
}
|
||||
|
|
|
@ -152,6 +152,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
|
|||
| Underscore
|
||||
| Yeet(..)
|
||||
| Yield(..)
|
||||
| UnsafeBinderCast(..)
|
||||
| Err(..)
|
||||
| Dummy => return false,
|
||||
}
|
||||
|
@ -232,6 +233,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
|
|||
| Paren(_)
|
||||
| Try(_)
|
||||
| Yeet(None)
|
||||
| UnsafeBinderCast(..)
|
||||
| Err(_)
|
||||
| Dummy => break None,
|
||||
}
|
||||
|
@ -253,6 +255,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
|
|||
ty = &mut_ty.ty;
|
||||
}
|
||||
|
||||
ast::TyKind::UnsafeBinder(binder) => {
|
||||
ty = &binder.inner_ty;
|
||||
}
|
||||
|
||||
ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
|
||||
ast::FnRetTy::Default(_) => break None,
|
||||
ast::FnRetTy::Ty(ret) => ty = ret,
|
||||
|
|
|
@ -380,7 +380,7 @@ impl WalkItemKind for ItemKind {
|
|||
try_visit!(visitor.visit_fn(kind, span, id));
|
||||
}
|
||||
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
||||
ModKind::Loaded(items, _inline, _inner_span) => {
|
||||
ModKind::Loaded(items, _inline, _inner_span, _) => {
|
||||
walk_list!(visitor, visit_item, items);
|
||||
}
|
||||
ModKind::Unloaded => {}
|
||||
|
@ -522,6 +522,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
|
|||
walk_list!(visitor, visit_generic_param, generic_params);
|
||||
try_visit!(visitor.visit_fn_decl(decl));
|
||||
}
|
||||
TyKind::UnsafeBinder(binder) => {
|
||||
walk_list!(visitor, visit_generic_param, &binder.generic_params);
|
||||
try_visit!(visitor.visit_ty(&binder.inner_ty));
|
||||
}
|
||||
TyKind::Path(maybe_qself, path) => {
|
||||
try_visit!(visitor.visit_qself(maybe_qself));
|
||||
try_visit!(visitor.visit_path(path, *id));
|
||||
|
@ -1226,6 +1230,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
|||
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
|
||||
ExprKind::Lit(_token) => {}
|
||||
ExprKind::IncludedBytes(_bytes) => {}
|
||||
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||
try_visit!(visitor.visit_expr(expr));
|
||||
visit_opt!(visitor, visit_ty, ty);
|
||||
}
|
||||
ExprKind::Err(_guar) => {}
|
||||
ExprKind::Dummy => {}
|
||||
}
|
||||
|
|
|
@ -379,6 +379,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||
ExprKind::Err(guar) => hir::ExprKind::Err(*guar),
|
||||
|
||||
ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
|
||||
*kind,
|
||||
self.lower_expr(expr),
|
||||
ty.as_ref().map(|ty| {
|
||||
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
|
||||
}),
|
||||
),
|
||||
|
||||
ExprKind::Dummy => {
|
||||
span_bug!(e.span, "lowered ExprKind::Dummy")
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
})
|
||||
}
|
||||
ItemKind::Mod(_, mod_kind) => match mod_kind {
|
||||
ModKind::Loaded(items, _, spans) => {
|
||||
ModKind::Loaded(items, _, spans, _) => {
|
||||
hir::ItemKind::Mod(self.lower_mod(items, spans))
|
||||
}
|
||||
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
|
||||
|
|
|
@ -1228,6 +1228,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
param_names: self.lower_fn_params_to_names(&f.decl),
|
||||
}))
|
||||
}
|
||||
TyKind::UnsafeBinder(f) => {
|
||||
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
|
||||
hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy {
|
||||
generic_params,
|
||||
inner_ty: self.lower_ty(&f.inner_ty, itctx),
|
||||
}))
|
||||
}
|
||||
TyKind::Never => hir::TyKind::Never,
|
||||
TyKind::Tup(tys) => hir::TyKind::Tup(
|
||||
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
|
||||
|
|
|
@ -1029,7 +1029,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
|
||||
}
|
||||
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _))
|
||||
&& !attr::contains_name(&item.attrs, sym::path)
|
||||
{
|
||||
self.check_mod_file_item_asciionly(item.ident);
|
||||
|
|
|
@ -560,6 +560,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(return_type_notation, "return type notation is experimental");
|
||||
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
|
||||
gate_all!(unsafe_fields, "`unsafe` fields are experimental");
|
||||
gate_all!(unsafe_binders, "unsafe binder types are experimental");
|
||||
|
||||
if !visitor.features.never_patterns() {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
|
|
@ -1198,6 +1198,14 @@ impl<'a> State<'a> {
|
|||
ast::TyKind::BareFn(f) => {
|
||||
self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params);
|
||||
}
|
||||
ast::TyKind::UnsafeBinder(f) => {
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.word("unsafe");
|
||||
self.print_generic_params(&f.generic_params);
|
||||
self.nbsp();
|
||||
self.print_type(&f.inner_ty);
|
||||
self.end();
|
||||
}
|
||||
ast::TyKind::Path(None, path) => {
|
||||
self.print_path(path, false, 0);
|
||||
}
|
||||
|
|
|
@ -772,6 +772,25 @@ impl<'a> State<'a> {
|
|||
self.word_nbsp("try");
|
||||
self.print_block_with_attrs(blk, attrs)
|
||||
}
|
||||
ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||
self.word("builtin # ");
|
||||
match kind {
|
||||
ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder"),
|
||||
ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder"),
|
||||
}
|
||||
self.popen();
|
||||
self.ibox(0);
|
||||
self.print_expr(expr, FixupContext::default());
|
||||
|
||||
if let Some(ty) = ty {
|
||||
self.word(",");
|
||||
self.space();
|
||||
self.print_type(ty);
|
||||
}
|
||||
|
||||
self.end();
|
||||
self.pclose();
|
||||
}
|
||||
ast::ExprKind::Err(_) => {
|
||||
self.popen();
|
||||
self.word("/*ERROR*/");
|
||||
|
|
|
@ -8,7 +8,10 @@ use rustc_middle::mir::{
|
|||
};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::fmt::DebugWithContext;
|
||||
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
|
||||
use rustc_mir_dataflow::impls::{
|
||||
EverInitializedPlaces, EverInitializedPlacesDomain, MaybeUninitializedPlaces,
|
||||
MaybeUninitializedPlacesDomain,
|
||||
};
|
||||
use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
|
||||
use tracing::debug;
|
||||
|
||||
|
@ -24,7 +27,7 @@ pub(crate) struct Borrowck<'a, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
||||
type Domain = BorrowckDomain<'a, 'tcx>;
|
||||
type Domain = BorrowckDomain;
|
||||
|
||||
const NAME: &'static str = "borrowck";
|
||||
|
||||
|
@ -41,48 +44,48 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
|||
unreachable!();
|
||||
}
|
||||
|
||||
fn apply_before_statement_effect(
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
self.borrows.apply_early_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.apply_early_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.apply_early_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
self.borrows.apply_primary_statement_effect(&mut state.borrows, stmt, loc);
|
||||
self.uninits.apply_primary_statement_effect(&mut state.uninits, stmt, loc);
|
||||
self.ever_inits.apply_primary_statement_effect(&mut state.ever_inits, stmt, loc);
|
||||
}
|
||||
|
||||
fn apply_before_terminator_effect(
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
self.borrows.apply_early_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.apply_early_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.apply_early_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
term: &'mir mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
self.borrows.apply_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.apply_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc);
|
||||
self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc);
|
||||
self.ever_inits.apply_primary_terminator_effect(&mut state.ever_inits, term, loc);
|
||||
|
||||
// This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
|
||||
// analysis doesn't use.
|
||||
|
@ -110,14 +113,14 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl JoinSemiLattice for BorrowckDomain<'_, '_> {
|
||||
impl JoinSemiLattice for BorrowckDomain {
|
||||
fn join(&mut self, _other: &Self) -> bool {
|
||||
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx>
|
||||
impl<'tcx, C> DebugWithContext<C> for BorrowckDomain
|
||||
where
|
||||
C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>,
|
||||
{
|
||||
|
@ -160,10 +163,10 @@ where
|
|||
|
||||
/// The transient state of the dataflow analyses used by the borrow checker.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct BorrowckDomain<'a, 'tcx> {
|
||||
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||
pub(crate) struct BorrowckDomain {
|
||||
pub(crate) borrows: BorrowsDomain,
|
||||
pub(crate) uninits: MaybeUninitializedPlacesDomain,
|
||||
pub(crate) ever_inits: EverInitializedPlacesDomain,
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
|
@ -503,7 +506,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
/// That means they went out of a nonlexical scope
|
||||
fn kill_loans_out_of_scope_at_location(
|
||||
&self,
|
||||
trans: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
state: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
location: Location,
|
||||
) {
|
||||
// NOTE: The state associated with a given `location`
|
||||
|
@ -518,14 +521,14 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
// region, then setting that gen-bit will override any
|
||||
// potential kill introduced here.
|
||||
if let Some(indices) = self.borrows_out_of_scope_at_location.get(&location) {
|
||||
trans.kill_all(indices.iter().copied());
|
||||
state.kill_all(indices.iter().copied());
|
||||
}
|
||||
}
|
||||
|
||||
/// Kill any borrows that conflict with `place`.
|
||||
fn kill_borrows_on_place(
|
||||
&self,
|
||||
trans: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
state: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
place: Place<'tcx>,
|
||||
) {
|
||||
debug!("kill_borrows_on_place: place={:?}", place);
|
||||
|
@ -543,7 +546,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
// `places_conflict` for every borrow.
|
||||
if place.projection.is_empty() {
|
||||
if !self.body.local_decls[place.local].is_ref_to_static() {
|
||||
trans.kill_all(other_borrows_of_local);
|
||||
state.kill_all(other_borrows_of_local);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -562,10 +565,12 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
)
|
||||
});
|
||||
|
||||
trans.kill_all(definitely_conflicting_borrows);
|
||||
state.kill_all(definitely_conflicting_borrows);
|
||||
}
|
||||
}
|
||||
|
||||
type BorrowsDomain = BitSet<BorrowIndex>;
|
||||
|
||||
/// Forward dataflow computation of the set of borrows that are in scope at a particular location.
|
||||
/// - we gen the introduced loans
|
||||
/// - we kill loans on locals going out of (regular) scope
|
||||
|
@ -574,7 +579,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of
|
||||
/// `a.b.c` when `a` is overwritten.
|
||||
impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
||||
type Domain = BitSet<BorrowIndex>;
|
||||
type Domain = BorrowsDomain;
|
||||
|
||||
const NAME: &'static str = "borrows";
|
||||
|
||||
|
@ -588,18 +593,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
// function execution, so this method has no effect.
|
||||
}
|
||||
|
||||
fn apply_before_statement_effect(
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
self.kill_loans_out_of_scope_at_location(trans, location);
|
||||
self.kill_loans_out_of_scope_at_location(state, location);
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
|
@ -617,18 +622,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
panic!("could not find BorrowIndex for location {location:?}");
|
||||
});
|
||||
|
||||
trans.gen_(index);
|
||||
state.gen_(index);
|
||||
}
|
||||
|
||||
// Make sure there are no remaining borrows for variables
|
||||
// that are assigned over.
|
||||
self.kill_borrows_on_place(trans, *lhs);
|
||||
self.kill_borrows_on_place(state, *lhs);
|
||||
}
|
||||
|
||||
mir::StatementKind::StorageDead(local) => {
|
||||
// Make sure there are no remaining borrows for locals that
|
||||
// are gone out of scope.
|
||||
self.kill_borrows_on_place(trans, Place::from(*local));
|
||||
self.kill_borrows_on_place(state, Place::from(*local));
|
||||
}
|
||||
|
||||
mir::StatementKind::FakeRead(..)
|
||||
|
@ -646,18 +651,18 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn apply_before_terminator_effect(
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
self.kill_loans_out_of_scope_at_location(trans, location);
|
||||
self.kill_loans_out_of_scope_at_location(state, location);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
|
@ -666,7 +671,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
if let mir::InlineAsmOperand::Out { place: Some(place), .. }
|
||||
| mir::InlineAsmOperand::InOut { out_place: Some(place), .. } = *op
|
||||
{
|
||||
self.kill_borrows_on_place(trans, place);
|
||||
self.kill_borrows_on_place(state, place);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ use rustc_mir_dataflow::impls::{
|
|||
use rustc_mir_dataflow::move_paths::{
|
||||
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
|
||||
};
|
||||
use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results};
|
||||
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
|
||||
use rustc_session::lint::builtin::UNUSED_MUT;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
|
@ -426,14 +426,14 @@ fn get_flow_results<'a, 'tcx>(
|
|||
ever_inits: ever_inits.analysis,
|
||||
};
|
||||
|
||||
assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len());
|
||||
assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len());
|
||||
let entry_sets: EntrySets<'_, Borrowck<'_, '_>> =
|
||||
itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets)
|
||||
assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
|
||||
assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
|
||||
let entry_states: EntryStates<'_, Borrowck<'_, '_>> =
|
||||
itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
|
||||
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
|
||||
.collect();
|
||||
|
||||
Results { analysis, entry_sets }
|
||||
Results { analysis, entry_states }
|
||||
}
|
||||
|
||||
pub(crate) struct BorrowckInferCtxt<'tcx> {
|
||||
|
@ -600,10 +600,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
// 3. assignments do not affect things loaned out as immutable
|
||||
// 4. moves do not affect things loaned out in any way
|
||||
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||
fn visit_statement_before_primary_effect(
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
stmt: &'a Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
|
@ -674,10 +674,10 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_terminator_before_primary_effect(
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
term: &'a Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
|
@ -787,10 +787,10 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_terminator_after_primary_effect(
|
||||
fn visit_after_primary_terminator_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
term: &'a Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
|
@ -983,7 +983,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
place_span: (Place<'tcx>, Span),
|
||||
kind: (AccessDepth, ReadOrWrite),
|
||||
is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
let (sd, rw) = kind;
|
||||
|
||||
|
@ -1032,7 +1032,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
place_span: (Place<'tcx>, Span),
|
||||
sd: AccessDepth,
|
||||
rw: ReadOrWrite,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) -> bool {
|
||||
let mut error_reported = false;
|
||||
|
||||
|
@ -1172,7 +1172,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
location: Location,
|
||||
place_span: (Place<'tcx>, Span),
|
||||
kind: AccessDepth,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
// Write of P[i] or *P requires P init'd.
|
||||
self.check_if_assigned_path_is_moved(location, place_span, state);
|
||||
|
@ -1190,7 +1190,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
&mut self,
|
||||
location: Location,
|
||||
(rvalue, span): (&'a Rvalue<'tcx>, Span),
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
match rvalue {
|
||||
&Rvalue::Ref(_ /*rgn*/, bk, place) => {
|
||||
|
@ -1448,7 +1448,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
&mut self,
|
||||
location: Location,
|
||||
(operand, span): (&'a Operand<'tcx>, Span),
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
match *operand {
|
||||
Operand::Copy(place) => {
|
||||
|
@ -1568,12 +1568,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_activations(
|
||||
&mut self,
|
||||
location: Location,
|
||||
span: Span,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
) {
|
||||
fn check_activations(&mut self, location: Location, span: Span, state: &BorrowckDomain) {
|
||||
// Two-phase borrow support: For each activation that is newly
|
||||
// generated at this statement, check if it interferes with
|
||||
// another borrow.
|
||||
|
@ -1731,7 +1726,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
location: Location,
|
||||
desired_action: InitializationRequiringAction,
|
||||
place_span: (PlaceRef<'tcx>, Span),
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
let maybe_uninits = &state.uninits;
|
||||
|
||||
|
@ -1836,7 +1831,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
location: Location,
|
||||
desired_action: InitializationRequiringAction,
|
||||
place_span: (PlaceRef<'tcx>, Span),
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
let maybe_uninits = &state.uninits;
|
||||
|
||||
|
@ -1935,7 +1930,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
&mut self,
|
||||
location: Location,
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
debug!("check_if_assigned_path_is_moved place: {:?}", place);
|
||||
|
||||
|
@ -2001,7 +1996,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
location: Location,
|
||||
base: PlaceRef<'tcx>,
|
||||
span: Span,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
// rust-lang/rust#21232: Until Rust allows reads from the
|
||||
// initialized parts of partially initialized structs, we
|
||||
|
@ -2092,7 +2087,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
(place, span): (Place<'tcx>, Span),
|
||||
kind: ReadOrWrite,
|
||||
is_local_mutation_allowed: LocalMutationIsAllowed,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
state: &BorrowckDomain,
|
||||
location: Location,
|
||||
) -> bool {
|
||||
debug!(
|
||||
|
@ -2206,18 +2201,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_local_ever_initialized(
|
||||
&self,
|
||||
local: Local,
|
||||
state: &BorrowckDomain<'a, 'tcx>,
|
||||
) -> Option<InitIndex> {
|
||||
fn is_local_ever_initialized(&self, local: Local, state: &BorrowckDomain) -> Option<InitIndex> {
|
||||
let mpi = self.move_data.rev_lookup.find_local(local)?;
|
||||
let ii = &self.move_data.init_path_map[mpi];
|
||||
ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
|
||||
}
|
||||
|
||||
/// Adds the place into the used mutable variables set
|
||||
fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain<'a, 'tcx>) {
|
||||
fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain) {
|
||||
match root_place {
|
||||
RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
|
||||
// If the local may have been initialized, and it is now currently being
|
||||
|
|
|
@ -323,7 +323,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
| ExprKind::While(_, _, _)
|
||||
| ExprKind::Yeet(_)
|
||||
| ExprKind::Become(_)
|
||||
| ExprKind::Yield(_) => {}
|
||||
| ExprKind::Yield(_)
|
||||
| ExprKind::UnsafeBinderCast(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,8 +141,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
|||
|
||||
// We don't want to recurse into anything other than mods, since
|
||||
// mods or tests inside of functions will break things
|
||||
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. })) =
|
||||
item.kind
|
||||
if let ast::ItemKind::Mod(
|
||||
_,
|
||||
ModKind::Loaded(.., ast::ModSpans { inner_span: span, .. }, _),
|
||||
) = item.kind
|
||||
{
|
||||
let prev_tests = mem::take(&mut self.tests);
|
||||
walk_item_kind(
|
||||
|
|
|
@ -329,7 +329,7 @@ where
|
|||
self.transfer_function(state).initialize_state();
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
|
@ -338,7 +338,7 @@ where
|
|||
self.transfer_function(state).visit_statement(statement, location);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
|
|
|
@ -249,10 +249,9 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
|
|||
} else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) {
|
||||
// For panic_fmt, call const_panic_fmt instead.
|
||||
let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None);
|
||||
// FIXME(@lcnr): why does this use an empty env if we've got a `param_env` right here.
|
||||
let new_instance = ty::Instance::expect_resolve(
|
||||
*self.tcx,
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
self.typing_env(),
|
||||
const_def_id,
|
||||
instance.args,
|
||||
self.cur_span(),
|
||||
|
|
|
@ -297,6 +297,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
|||
|
||||
#[inline]
|
||||
pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
|
||||
// Can use any typing env, since `bool` is always monomorphic.
|
||||
let layout = tcx
|
||||
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tcx.types.bool))
|
||||
.unwrap();
|
||||
|
@ -305,17 +306,18 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
|||
|
||||
#[inline]
|
||||
pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
|
||||
// Can use any typing env, since `Ordering` is always monomorphic.
|
||||
let ty = tcx.ty_ordering_enum(None);
|
||||
let layout =
|
||||
tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap();
|
||||
Self::from_scalar(Scalar::from_i8(c as i8), layout)
|
||||
}
|
||||
|
||||
pub fn from_pair(a: Self, b: Self, tcx: TyCtxt<'tcx>) -> Self {
|
||||
let layout = tcx
|
||||
pub fn from_pair(a: Self, b: Self, cx: &(impl HasTypingEnv<'tcx> + HasTyCtxt<'tcx>)) -> Self {
|
||||
let layout = cx
|
||||
.tcx()
|
||||
.layout_of(
|
||||
ty::TypingEnv::fully_monomorphized()
|
||||
.as_query_input(Ty::new_tup(tcx, &[a.layout.ty, b.layout.ty])),
|
||||
cx.typing_env().as_query_input(Ty::new_tup(cx.tcx(), &[a.layout.ty, b.layout.ty])),
|
||||
)
|
||||
.unwrap();
|
||||
Self::from_scalar_pair(a.to_scalar(), b.to_scalar(), layout)
|
||||
|
|
|
@ -222,7 +222,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let res = ImmTy::from_scalar_int(result, left.layout);
|
||||
return interp_ok(if with_overflow {
|
||||
let overflow = ImmTy::from_bool(overflow, *self.tcx);
|
||||
ImmTy::from_pair(res, overflow, *self.tcx)
|
||||
ImmTy::from_pair(res, overflow, self)
|
||||
} else {
|
||||
res
|
||||
});
|
||||
|
@ -279,7 +279,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let res = ImmTy::from_scalar_int(result, left.layout);
|
||||
if with_overflow {
|
||||
let overflow = ImmTy::from_bool(overflow, *self.tcx);
|
||||
ImmTy::from_pair(res, overflow, *self.tcx)
|
||||
ImmTy::from_pair(res, overflow, self)
|
||||
} else {
|
||||
res
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ use rustc_errors::registry::Registry;
|
|||
use rustc_errors::{ColorConfig, DiagCtxt, ErrCode, FatalError, PResult, markdown};
|
||||
use rustc_feature::find_gated_cfg;
|
||||
use rustc_interface::util::{self, get_codegen_backend};
|
||||
use rustc_interface::{Linker, Queries, interface, passes};
|
||||
use rustc_interface::{Linker, interface, passes};
|
||||
use rustc_lint::unerased_lint_store;
|
||||
use rustc_metadata::creader::MetadataLoader;
|
||||
use rustc_metadata::locator;
|
||||
|
@ -158,13 +158,10 @@ pub trait Callbacks {
|
|||
/// Called after parsing the crate root. Submodules are not yet parsed when
|
||||
/// this callback is called. Return value instructs the compiler whether to
|
||||
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
|
||||
#[deprecated = "This callback will likely be removed or stop giving access \
|
||||
to the TyCtxt in the future. Use either the after_expansion \
|
||||
or the after_analysis callback instead."]
|
||||
fn after_crate_root_parsing<'tcx>(
|
||||
fn after_crate_root_parsing(
|
||||
&mut self,
|
||||
_compiler: &interface::Compiler,
|
||||
_queries: &'tcx Queries<'tcx>,
|
||||
_queries: &ast::Crate,
|
||||
) -> Compilation {
|
||||
Compilation::Continue
|
||||
}
|
||||
|
@ -173,7 +170,7 @@ pub trait Callbacks {
|
|||
fn after_expansion<'tcx>(
|
||||
&mut self,
|
||||
_compiler: &interface::Compiler,
|
||||
_queries: &'tcx Queries<'tcx>,
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> Compilation {
|
||||
Compilation::Continue
|
||||
}
|
||||
|
@ -416,8 +413,9 @@ fn run_compiler(
|
|||
return early_exit();
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop {
|
||||
if callbacks.after_crate_root_parsing(compiler, &*queries.parse().borrow())
|
||||
== Compilation::Stop
|
||||
{
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
|
@ -425,18 +423,18 @@ fn run_compiler(
|
|||
return early_exit();
|
||||
}
|
||||
|
||||
queries.global_ctxt().enter(|tcx| {
|
||||
// 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 {
|
||||
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();
|
||||
}
|
||||
|
||||
queries.global_ctxt().enter(|tcx| {
|
||||
passes::write_dep_info(tcx);
|
||||
|
||||
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
|
||||
|
|
|
@ -723,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
item_inner.kind,
|
||||
ItemKind::Mod(
|
||||
_,
|
||||
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _),
|
||||
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _, _),
|
||||
)
|
||||
) =>
|
||||
{
|
||||
|
@ -889,7 +889,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
fn visit_item(&mut self, item: &'ast ast::Item) {
|
||||
match &item.kind {
|
||||
ItemKind::Mod(_, mod_kind)
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
|
||||
if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _, _)) =>
|
||||
{
|
||||
feature_err(
|
||||
self.sess,
|
||||
|
@ -1195,7 +1195,7 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
|
||||
let ecx = &mut collector.cx;
|
||||
let (file_path, dir_path, dir_ownership) = match mod_kind {
|
||||
ModKind::Loaded(_, inline, _) => {
|
||||
ModKind::Loaded(_, inline, _, _) => {
|
||||
// Inline `mod foo { ... }`, but we still need to push directories.
|
||||
let (dir_path, dir_ownership) = mod_dir_path(
|
||||
ecx.sess,
|
||||
|
@ -1217,8 +1217,14 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
ModKind::Unloaded => {
|
||||
// We have an outline `mod foo;` so we need to parse the file.
|
||||
let old_attrs_len = attrs.len();
|
||||
let ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership } =
|
||||
parse_external_mod(
|
||||
let ParsedExternalMod {
|
||||
items,
|
||||
spans,
|
||||
file_path,
|
||||
dir_path,
|
||||
dir_ownership,
|
||||
had_parse_error,
|
||||
} = parse_external_mod(
|
||||
ecx.sess,
|
||||
ident,
|
||||
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;
|
||||
if node.attrs.len() > old_attrs_len {
|
||||
// If we loaded an out-of-line module and added some inner attributes,
|
||||
|
|
|
@ -37,6 +37,7 @@ pub(crate) struct ParsedExternalMod {
|
|||
pub file_path: PathBuf,
|
||||
pub dir_path: PathBuf,
|
||||
pub dir_ownership: DirOwnership,
|
||||
pub had_parse_error: Result<(), ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
pub enum ModError<'a> {
|
||||
|
@ -74,14 +75,17 @@ pub(crate) fn parse_external_mod(
|
|||
attrs.extend(inner_attrs);
|
||||
(items, inner_span, mp.file_path)
|
||||
};
|
||||
|
||||
// (1) ...instead, we return a dummy module.
|
||||
let (items, spans, file_path) =
|
||||
result.map_err(|err| err.report(sess, span)).unwrap_or_default();
|
||||
let ((items, spans, file_path), had_parse_error) = match result {
|
||||
Err(err) => (Default::default(), Err(err.report(sess, span))),
|
||||
Ok(result) => (result, Ok(())),
|
||||
};
|
||||
|
||||
// Extract the directory path for submodules of the module.
|
||||
let dir_path = file_path.parent().unwrap_or(&file_path).to_owned();
|
||||
|
||||
ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership }
|
||||
ParsedExternalMod { items, spans, file_path, dir_path, dir_ownership, had_parse_error }
|
||||
}
|
||||
|
||||
pub(crate) fn mod_dir_path(
|
||||
|
|
|
@ -636,6 +636,8 @@ declare_features! (
|
|||
/// Allows creation of instances of a struct by moving fields that have
|
||||
/// not changed from prior instances of the same struct (RFC #2528)
|
||||
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
|
||||
/// Allows using `unsafe<'a> &'a T` unsafe binder types.
|
||||
(incomplete, unsafe_binders, "CURRENT_RUSTC_VERSION", Some(130516)),
|
||||
/// Allows declaring fields `unsafe`.
|
||||
(incomplete, unsafe_fields, "CURRENT_RUSTC_VERSION", Some(132922)),
|
||||
/// Allows const generic parameters to be defined with types that
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_ast::{
|
|||
};
|
||||
pub use rustc_ast::{
|
||||
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
|
||||
ImplPolarity, IsAuto, Movability, Mutability, UnOp,
|
||||
ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind,
|
||||
};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
|
@ -1740,6 +1740,7 @@ impl Expr<'_> {
|
|||
| ExprKind::Struct(..)
|
||||
| ExprKind::Tup(_)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::Err(_) => ExprPrecedence::Unambiguous,
|
||||
|
||||
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
|
||||
|
@ -1769,6 +1770,9 @@ impl Expr<'_> {
|
|||
// https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
|
||||
ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from),
|
||||
|
||||
// Unsafe binder cast preserves place-ness of the sub-expression.
|
||||
ExprKind::UnsafeBinderCast(_, e, _) => e.is_place_expr(allow_projections_from),
|
||||
|
||||
ExprKind::Unary(UnOp::Deref, _) => true,
|
||||
|
||||
ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => {
|
||||
|
@ -1850,7 +1854,8 @@ impl Expr<'_> {
|
|||
| ExprKind::Field(base, _)
|
||||
| ExprKind::Index(base, _, _)
|
||||
| ExprKind::AddrOf(.., base)
|
||||
| ExprKind::Cast(base, _) => {
|
||||
| ExprKind::Cast(base, _)
|
||||
| ExprKind::UnsafeBinderCast(_, base, _) => {
|
||||
// This isn't exactly true for `Index` and all `Unary`, but we are using this
|
||||
// method exclusively for diagnostics and there's a *cultural* pressure against
|
||||
// them being used only for its side-effects.
|
||||
|
@ -2144,6 +2149,10 @@ pub enum ExprKind<'hir> {
|
|||
/// A suspension point for coroutines (i.e., `yield <expr>`).
|
||||
Yield(&'hir Expr<'hir>, YieldSource),
|
||||
|
||||
/// Operators which can be used to interconvert `unsafe` binder types.
|
||||
/// e.g. `unsafe<'a> &'a i32` <=> `&i32`.
|
||||
UnsafeBinderCast(UnsafeBinderCastKind, &'hir Expr<'hir>, Option<&'hir Ty<'hir>>),
|
||||
|
||||
/// A placeholder for an expression that wasn't syntactically well formed in some way.
|
||||
Err(rustc_span::ErrorGuaranteed),
|
||||
}
|
||||
|
@ -2780,6 +2789,12 @@ pub struct BareFnTy<'hir> {
|
|||
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)]
|
||||
pub struct OpaqueTy<'hir> {
|
||||
pub hir_id: HirId,
|
||||
|
@ -2878,6 +2893,8 @@ pub enum TyKind<'hir> {
|
|||
Ref(&'hir Lifetime, MutTy<'hir>),
|
||||
/// A bare function (e.g., `fn(usize) -> bool`).
|
||||
BareFn(&'hir BareFnTy<'hir>),
|
||||
/// An unsafe binder type (e.g. `unsafe<'a> Foo<'a>`).
|
||||
UnsafeBinder(&'hir UnsafeBinderTy<'hir>),
|
||||
/// The never type (`!`).
|
||||
Never,
|
||||
/// A tuple (`(A, B, C, D, ...)`).
|
||||
|
|
|
@ -857,6 +857,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
|||
ExprKind::Yield(ref subexpression, _) => {
|
||||
try_visit!(visitor.visit_expr(subexpression));
|
||||
}
|
||||
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||
try_visit!(visitor.visit_expr(expr));
|
||||
visit_opt!(visitor, visit_ty, ty);
|
||||
}
|
||||
ExprKind::Lit(_) | ExprKind::Err(_) => {}
|
||||
}
|
||||
V::Result::output()
|
||||
|
@ -886,6 +890,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
|
|||
walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
|
||||
try_visit!(visitor.visit_fn_decl(function_declaration.decl));
|
||||
}
|
||||
TyKind::UnsafeBinder(ref unsafe_binder) => {
|
||||
walk_list!(visitor, visit_generic_param, unsafe_binder.generic_params);
|
||||
try_visit!(visitor.visit_ty(unsafe_binder.inner_ty));
|
||||
}
|
||||
TyKind::Path(ref qpath) => {
|
||||
try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
|
||||
}
|
||||
|
|
|
@ -470,6 +470,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
self.outer_index.shift_out(1);
|
||||
res
|
||||
}
|
||||
hir::TyKind::UnsafeBinder(_) => {
|
||||
self.outer_index.shift_in(1);
|
||||
let res = intravisit::walk_ty(self, ty);
|
||||
self.outer_index.shift_out(1);
|
||||
res
|
||||
}
|
||||
_ => intravisit::walk_ty(self, ty),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -781,6 +781,36 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
intravisit::walk_ty(this, ty);
|
||||
});
|
||||
}
|
||||
hir::TyKind::UnsafeBinder(binder) => {
|
||||
let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
|
||||
binder
|
||||
.generic_params
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(late_bound_idx, param)| {
|
||||
(
|
||||
(param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
|
||||
late_arg_as_bound_arg(self.tcx, param),
|
||||
)
|
||||
})
|
||||
.unzip();
|
||||
|
||||
deny_non_region_late_bound(self.tcx, &mut bound_vars, "function pointer types");
|
||||
|
||||
self.record_late_bound_vars(ty.hir_id, binders);
|
||||
let scope = Scope::Binder {
|
||||
hir_id: ty.hir_id,
|
||||
bound_vars,
|
||||
s: self.scope,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |this| {
|
||||
// a bare fn has no bounds, so everything
|
||||
// contained within is scoped within its binder.
|
||||
intravisit::walk_ty(this, ty);
|
||||
});
|
||||
}
|
||||
hir::TyKind::TraitObject(bounds, lifetime, _) => {
|
||||
debug!(?bounds, ?lifetime, "TraitObject");
|
||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||
|
|
|
@ -2312,6 +2312,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)),
|
||||
)
|
||||
}
|
||||
hir::TyKind::UnsafeBinder(_binder) => {
|
||||
let guar = self
|
||||
.dcx()
|
||||
.struct_span_err(hir_ty.span, "unsafe binders are not yet implemented")
|
||||
.emit();
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
|
||||
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
|
||||
// Don't continue with type analysis if the `dyn` keyword is missing
|
||||
|
|
|
@ -288,6 +288,9 @@ impl<'a> State<'a> {
|
|||
hir::TyKind::BareFn(f) => {
|
||||
self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names);
|
||||
}
|
||||
hir::TyKind::UnsafeBinder(unsafe_binder) => {
|
||||
self.print_unsafe_binder(unsafe_binder);
|
||||
}
|
||||
hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
|
||||
hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
|
||||
hir::TyKind::TraitObject(bounds, lifetime, syntax) => {
|
||||
|
@ -339,6 +342,15 @@ impl<'a> State<'a> {
|
|||
self.end()
|
||||
}
|
||||
|
||||
fn print_unsafe_binder(&mut self, unsafe_binder: &hir::UnsafeBinderTy<'_>) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.word("unsafe");
|
||||
self.print_generic_params(unsafe_binder.generic_params);
|
||||
self.nbsp();
|
||||
self.print_type(unsafe_binder.inner_ty);
|
||||
self.end();
|
||||
}
|
||||
|
||||
fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
|
||||
self.hardbreak_if_not_bol();
|
||||
self.maybe_print_comment(item.span.lo());
|
||||
|
@ -1530,6 +1542,19 @@ impl<'a> State<'a> {
|
|||
|
||||
self.word(")");
|
||||
}
|
||||
hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||
match kind {
|
||||
hir::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("),
|
||||
hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("),
|
||||
}
|
||||
self.print_expr(expr);
|
||||
if let Some(ty) = ty {
|
||||
self.word(",");
|
||||
self.space();
|
||||
self.print_type(ty);
|
||||
}
|
||||
self.word(")");
|
||||
}
|
||||
hir::ExprKind::Yield(expr, _) => {
|
||||
self.word_space("yield");
|
||||
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Jump);
|
||||
|
|
|
@ -329,6 +329,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Assignment does call `drop_in_place`, though, but its safety
|
||||
// requirements are not the same.
|
||||
ExprKind::AddrOf(..) | hir::ExprKind::Field(..) => false,
|
||||
|
||||
// Place-preserving expressions only constitute reads if their
|
||||
// parent expression constitutes a read.
|
||||
ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) => {
|
||||
self.expr_guaranteed_to_constitute_read_for_never(expr)
|
||||
}
|
||||
|
||||
ExprKind::Assign(lhs, _, _) => {
|
||||
// Only the LHS does not constitute a read
|
||||
expr.hir_id != lhs.hir_id
|
||||
|
@ -353,7 +360,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| ExprKind::Binary(_, _, _)
|
||||
| ExprKind::Unary(_, _)
|
||||
| ExprKind::Cast(_, _)
|
||||
| ExprKind::Type(_, _)
|
||||
| ExprKind::DropTemps(_)
|
||||
| ExprKind::If(_, _, _)
|
||||
| ExprKind::Closure(_)
|
||||
|
@ -564,7 +570,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.check_expr_index(base, idx, expr, brackets_span)
|
||||
}
|
||||
ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
|
||||
hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
|
||||
ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||
self.check_expr_unsafe_binder_cast(kind, expr, ty, expected)
|
||||
}
|
||||
ExprKind::Err(guar) => Ty::new_error(tcx, guar),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1634,6 +1643,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_expr_unsafe_binder_cast(
|
||||
&self,
|
||||
_kind: hir::UnsafeBinderCastKind,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
_hir_ty: Option<&'tcx hir::Ty<'tcx>>,
|
||||
_expected: Expectation<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let guar =
|
||||
self.dcx().struct_span_err(expr.span, "unsafe binders are not yet implemented").emit();
|
||||
Ty::new_error(self.tcx, guar)
|
||||
}
|
||||
|
||||
fn check_expr_array(
|
||||
&self,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
|
|
|
@ -341,6 +341,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
self.walk_expr(subexpr)?;
|
||||
}
|
||||
|
||||
hir::ExprKind::UnsafeBinderCast(_, subexpr, _) => {
|
||||
self.walk_expr(subexpr)?;
|
||||
}
|
||||
|
||||
hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
|
||||
// *base
|
||||
self.walk_expr(base)?;
|
||||
|
@ -1360,7 +1364,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
self.cat_res(expr.hir_id, expr.span, expr_ty, res)
|
||||
}
|
||||
|
||||
// both type ascription and unsafe binder casts don't affect
|
||||
// the place-ness of the subexpression.
|
||||
hir::ExprKind::Type(e, _) => self.cat_expr(e),
|
||||
hir::ExprKind::UnsafeBinderCast(_, e, _) => self.cat_expr(e),
|
||||
|
||||
hir::ExprKind::AddrOf(..)
|
||||
| hir::ExprKind::Call(..)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -127,18 +127,6 @@ impl Linker {
|
|||
) -> Linker {
|
||||
let ongoing_codegen = passes::start_codegen(codegen_backend, tcx);
|
||||
|
||||
// This must run after monomorphization so that all generic types
|
||||
// have been instantiated.
|
||||
if tcx.sess.opts.unstable_opts.print_type_sizes {
|
||||
tcx.sess.code_stats.print_type_sizes();
|
||||
}
|
||||
|
||||
if tcx.sess.opts.unstable_opts.print_vtable_sizes {
|
||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
|
||||
tcx.sess.code_stats.print_vtable_sizes(crate_name);
|
||||
}
|
||||
|
||||
Linker {
|
||||
dep_graph: tcx.dep_graph.clone(),
|
||||
output_filenames: Arc::clone(tcx.output_filenames(())),
|
||||
|
|
|
@ -3038,7 +3038,7 @@ impl EarlyLintPass for SpecialModuleName {
|
|||
for item in &krate.items {
|
||||
if let ast::ItemKind::Mod(
|
||||
_,
|
||||
ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _),
|
||||
ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _, _),
|
||||
) = item.kind
|
||||
{
|
||||
if item.attrs.iter().any(|a| a.has_name(sym::path)) {
|
||||
|
|
|
@ -192,6 +192,8 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
|
|||
| ExprKind::DropTemps(..)
|
||||
| ExprKind::Let(..) => false,
|
||||
|
||||
ExprKind::UnsafeBinderCast(..) => false,
|
||||
|
||||
// Not applicable
|
||||
ExprKind::Type(..) | ExprKind::Err(..) => false,
|
||||
}
|
||||
|
|
|
@ -422,6 +422,7 @@ impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> {
|
|||
hir::ExprKind::Unary(_, expr)
|
||||
| hir::ExprKind::Cast(expr, _)
|
||||
| hir::ExprKind::Type(expr, _)
|
||||
| hir::ExprKind::UnsafeBinderCast(_, expr, _)
|
||||
| hir::ExprKind::Yield(expr, _)
|
||||
| hir::ExprKind::AddrOf(_, _, expr)
|
||||
| hir::ExprKind::Match(expr, _, _)
|
||||
|
|
|
@ -44,16 +44,16 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
|
|||
pub format_value: fn(&C::Value) -> String,
|
||||
}
|
||||
|
||||
pub struct QuerySystemFns<'tcx> {
|
||||
pub struct QuerySystemFns {
|
||||
pub engine: QueryEngine,
|
||||
pub local_providers: Providers,
|
||||
pub extern_providers: ExternProviders,
|
||||
pub encode_query_results: fn(
|
||||
pub encode_query_results: for<'tcx> fn(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
encoder: &mut CacheEncoder<'_, 'tcx>,
|
||||
query_result_index: &mut EncodedDepNodeIndex,
|
||||
),
|
||||
pub try_mark_green: fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool,
|
||||
pub try_mark_green: for<'tcx> fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool,
|
||||
}
|
||||
|
||||
pub struct QuerySystem<'tcx> {
|
||||
|
@ -68,7 +68,7 @@ pub struct QuerySystem<'tcx> {
|
|||
/// This is `None` if we are not incremental compilation mode
|
||||
pub on_disk_cache: Option<OnDiskCache>,
|
||||
|
||||
pub fns: QuerySystemFns<'tcx>,
|
||||
pub fns: QuerySystemFns,
|
||||
|
||||
pub jobs: AtomicU64,
|
||||
}
|
||||
|
|
|
@ -915,6 +915,11 @@ impl<'tcx> Cx<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => {
|
||||
unreachable!("unsafe binders are not yet implemented")
|
||||
}
|
||||
|
||||
hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },
|
||||
hir::ExprKind::Array(fields) => ExprKind::Array { fields: self.mirror_exprs(fields) },
|
||||
hir::ExprKind::Tup(fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) },
|
||||
|
|
|
@ -179,15 +179,15 @@ where
|
|||
/// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is
|
||||
/// applied.
|
||||
///
|
||||
/// The "before" effect at the target location *will be* applied.
|
||||
/// The "early" effect at the target location *will be* applied.
|
||||
pub fn seek_before_primary_effect(&mut self, target: Location) {
|
||||
self.seek_after(target, Effect::Before)
|
||||
self.seek_after(target, Effect::Early)
|
||||
}
|
||||
|
||||
/// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is
|
||||
/// applied.
|
||||
///
|
||||
/// The "before" effect at the target location will be applied as well.
|
||||
/// The "early" effect at the target location will be applied as well.
|
||||
pub fn seek_after_primary_effect(&mut self, target: Location) {
|
||||
self.seek_after(target, Effect::Primary)
|
||||
}
|
||||
|
@ -222,12 +222,12 @@ where
|
|||
#[rustfmt::skip]
|
||||
let next_effect = if A::Direction::IS_FORWARD {
|
||||
self.pos.curr_effect_index.map_or_else(
|
||||
|| Effect::Before.at_index(0),
|
||||
|| Effect::Early.at_index(0),
|
||||
EffectIndex::next_in_forward_order,
|
||||
)
|
||||
} else {
|
||||
self.pos.curr_effect_index.map_or_else(
|
||||
|| Effect::Before.at_index(block_data.statements.len()),
|
||||
|| Effect::Early.at_index(block_data.statements.len()),
|
||||
EffectIndex::next_in_backward_order,
|
||||
)
|
||||
};
|
||||
|
|
|
@ -66,12 +66,12 @@ impl Direction for Backward {
|
|||
{
|
||||
let terminator = block_data.terminator();
|
||||
let location = Location { block, statement_index: block_data.statements.len() };
|
||||
analysis.apply_before_terminator_effect(state, terminator, location);
|
||||
analysis.apply_terminator_effect(state, terminator, location);
|
||||
analysis.apply_early_terminator_effect(state, terminator, location);
|
||||
analysis.apply_primary_terminator_effect(state, terminator, location);
|
||||
for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
|
||||
let location = Location { block, statement_index };
|
||||
analysis.apply_before_statement_effect(state, statement, location);
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
analysis.apply_early_statement_effect(state, statement, location);
|
||||
analysis.apply_primary_statement_effect(state, statement, location);
|
||||
}
|
||||
|
||||
let exit_state = state;
|
||||
|
@ -159,14 +159,14 @@ impl Direction for Backward {
|
|||
let location = Location { block, statement_index: from.statement_index };
|
||||
let terminator = block_data.terminator();
|
||||
|
||||
if from.effect == Effect::Before {
|
||||
analysis.apply_before_terminator_effect(state, terminator, location);
|
||||
if to == Effect::Before.at_index(terminator_index) {
|
||||
if from.effect == Effect::Early {
|
||||
analysis.apply_early_terminator_effect(state, terminator, location);
|
||||
if to == Effect::Early.at_index(terminator_index) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
analysis.apply_terminator_effect(state, terminator, location);
|
||||
analysis.apply_primary_terminator_effect(state, terminator, location);
|
||||
if to == Effect::Primary.at_index(terminator_index) {
|
||||
return;
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ impl Direction for Backward {
|
|||
let location = Location { block, statement_index: from.statement_index };
|
||||
let statement = &block_data.statements[from.statement_index];
|
||||
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
analysis.apply_primary_statement_effect(state, statement, location);
|
||||
if to == Effect::Primary.at_index(from.statement_index) {
|
||||
return;
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ impl Direction for Backward {
|
|||
from.statement_index - 1
|
||||
}
|
||||
|
||||
Effect::Before => from.statement_index,
|
||||
Effect::Early => from.statement_index,
|
||||
};
|
||||
|
||||
// Handle all statements between `first_unapplied_idx` and `to.statement_index`.
|
||||
|
@ -196,21 +196,21 @@ impl Direction for Backward {
|
|||
for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) {
|
||||
let location = Location { block, statement_index };
|
||||
let statement = &block_data.statements[statement_index];
|
||||
analysis.apply_before_statement_effect(state, statement, location);
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
analysis.apply_early_statement_effect(state, statement, location);
|
||||
analysis.apply_primary_statement_effect(state, statement, location);
|
||||
}
|
||||
|
||||
// Handle the statement at `to`.
|
||||
|
||||
let location = Location { block, statement_index: to.statement_index };
|
||||
let statement = &block_data.statements[to.statement_index];
|
||||
analysis.apply_before_statement_effect(state, statement, location);
|
||||
analysis.apply_early_statement_effect(state, statement, location);
|
||||
|
||||
if to.effect == Effect::Before {
|
||||
if to.effect == Effect::Early {
|
||||
return;
|
||||
}
|
||||
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
analysis.apply_primary_statement_effect(state, statement, location);
|
||||
}
|
||||
|
||||
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||
|
@ -228,17 +228,17 @@ impl Direction for Backward {
|
|||
|
||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||
let term = block_data.terminator();
|
||||
results.analysis.apply_before_terminator_effect(state, term, loc);
|
||||
vis.visit_terminator_before_primary_effect(results, state, term, loc);
|
||||
results.analysis.apply_terminator_effect(state, term, loc);
|
||||
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
||||
results.analysis.apply_early_terminator_effect(state, term, loc);
|
||||
vis.visit_after_early_terminator_effect(results, state, term, loc);
|
||||
results.analysis.apply_primary_terminator_effect(state, term, loc);
|
||||
vis.visit_after_primary_terminator_effect(results, state, term, loc);
|
||||
|
||||
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
|
||||
let loc = Location { block, statement_index };
|
||||
results.analysis.apply_before_statement_effect(state, stmt, loc);
|
||||
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
|
||||
results.analysis.apply_statement_effect(state, stmt, loc);
|
||||
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
||||
results.analysis.apply_early_statement_effect(state, stmt, loc);
|
||||
vis.visit_after_early_statement_effect(results, state, stmt, loc);
|
||||
results.analysis.apply_primary_statement_effect(state, stmt, loc);
|
||||
vis.visit_after_primary_statement_effect(results, state, stmt, loc);
|
||||
}
|
||||
|
||||
vis.visit_block_start(state);
|
||||
|
@ -294,13 +294,13 @@ impl Direction for Forward {
|
|||
{
|
||||
for (statement_index, statement) in block_data.statements.iter().enumerate() {
|
||||
let location = Location { block, statement_index };
|
||||
analysis.apply_before_statement_effect(state, statement, location);
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
analysis.apply_early_statement_effect(state, statement, location);
|
||||
analysis.apply_primary_statement_effect(state, statement, location);
|
||||
}
|
||||
let terminator = block_data.terminator();
|
||||
let location = Location { block, statement_index: block_data.statements.len() };
|
||||
analysis.apply_before_terminator_effect(state, terminator, location);
|
||||
let edges = analysis.apply_terminator_effect(state, terminator, location);
|
||||
analysis.apply_early_terminator_effect(state, terminator, location);
|
||||
let edges = analysis.apply_primary_terminator_effect(state, terminator, location);
|
||||
|
||||
let exit_state = state;
|
||||
match edges {
|
||||
|
@ -368,21 +368,21 @@ impl Direction for Forward {
|
|||
// after effect, do so now and start the loop below from the next statement.
|
||||
|
||||
let first_unapplied_index = match from.effect {
|
||||
Effect::Before => from.statement_index,
|
||||
Effect::Early => from.statement_index,
|
||||
|
||||
Effect::Primary if from.statement_index == terminator_index => {
|
||||
debug_assert_eq!(from, to);
|
||||
|
||||
let location = Location { block, statement_index: terminator_index };
|
||||
let terminator = block_data.terminator();
|
||||
analysis.apply_terminator_effect(state, terminator, location);
|
||||
analysis.apply_primary_terminator_effect(state, terminator, location);
|
||||
return;
|
||||
}
|
||||
|
||||
Effect::Primary => {
|
||||
let location = Location { block, statement_index: from.statement_index };
|
||||
let statement = &block_data.statements[from.statement_index];
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
analysis.apply_primary_statement_effect(state, statement, location);
|
||||
|
||||
// If we only needed to apply the after effect of the statement at `idx`, we are
|
||||
// done.
|
||||
|
@ -399,8 +399,8 @@ impl Direction for Forward {
|
|||
for statement_index in first_unapplied_index..to.statement_index {
|
||||
let location = Location { block, statement_index };
|
||||
let statement = &block_data.statements[statement_index];
|
||||
analysis.apply_before_statement_effect(state, statement, location);
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
analysis.apply_early_statement_effect(state, statement, location);
|
||||
analysis.apply_primary_statement_effect(state, statement, location);
|
||||
}
|
||||
|
||||
// Handle the statement or terminator at `to`.
|
||||
|
@ -408,17 +408,17 @@ impl Direction for Forward {
|
|||
let location = Location { block, statement_index: to.statement_index };
|
||||
if to.statement_index == terminator_index {
|
||||
let terminator = block_data.terminator();
|
||||
analysis.apply_before_terminator_effect(state, terminator, location);
|
||||
analysis.apply_early_terminator_effect(state, terminator, location);
|
||||
|
||||
if to.effect == Effect::Primary {
|
||||
analysis.apply_terminator_effect(state, terminator, location);
|
||||
analysis.apply_primary_terminator_effect(state, terminator, location);
|
||||
}
|
||||
} else {
|
||||
let statement = &block_data.statements[to.statement_index];
|
||||
analysis.apply_before_statement_effect(state, statement, location);
|
||||
analysis.apply_early_statement_effect(state, statement, location);
|
||||
|
||||
if to.effect == Effect::Primary {
|
||||
analysis.apply_statement_effect(state, statement, location);
|
||||
analysis.apply_primary_statement_effect(state, statement, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -438,18 +438,18 @@ impl Direction for Forward {
|
|||
|
||||
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
|
||||
let loc = Location { block, statement_index };
|
||||
results.analysis.apply_before_statement_effect(state, stmt, loc);
|
||||
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
|
||||
results.analysis.apply_statement_effect(state, stmt, loc);
|
||||
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
||||
results.analysis.apply_early_statement_effect(state, stmt, loc);
|
||||
vis.visit_after_early_statement_effect(results, state, stmt, loc);
|
||||
results.analysis.apply_primary_statement_effect(state, stmt, loc);
|
||||
vis.visit_after_primary_statement_effect(results, state, stmt, loc);
|
||||
}
|
||||
|
||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||
let term = block_data.terminator();
|
||||
results.analysis.apply_before_terminator_effect(state, term, loc);
|
||||
vis.visit_terminator_before_primary_effect(results, state, term, loc);
|
||||
results.analysis.apply_terminator_effect(state, term, loc);
|
||||
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
||||
results.analysis.apply_early_terminator_effect(state, term, loc);
|
||||
vis.visit_after_early_terminator_effect(results, state, term, loc);
|
||||
results.analysis.apply_primary_terminator_effect(state, term, loc);
|
||||
vis.visit_after_primary_terminator_effect(results, state, term, loc);
|
||||
|
||||
vis.visit_block_end(state);
|
||||
}
|
||||
|
|
|
@ -724,7 +724,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_statement_before_primary_effect(
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, A>,
|
||||
state: &A::Domain,
|
||||
|
@ -737,7 +737,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_statement_after_primary_effect(
|
||||
fn visit_after_primary_statement_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, A>,
|
||||
state: &A::Domain,
|
||||
|
@ -748,7 +748,7 @@ where
|
|||
self.prev_state.clone_from(state)
|
||||
}
|
||||
|
||||
fn visit_terminator_before_primary_effect(
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, A>,
|
||||
state: &A::Domain,
|
||||
|
@ -761,7 +761,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_terminator_after_primary_effect(
|
||||
fn visit_after_primary_terminator_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, A>,
|
||||
state: &A::Domain,
|
||||
|
|
|
@ -38,10 +38,8 @@
|
|||
//! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram
|
||||
//! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set
|
||||
|
||||
use std::iter;
|
||||
|
||||
use rustc_index::Idx;
|
||||
use rustc_index::bit_set::{BitSet, MixedBitSet};
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
|
||||
use crate::framework::BitSetExt;
|
||||
|
||||
|
@ -70,53 +68,6 @@ pub trait HasTop {
|
|||
const TOP: Self;
|
||||
}
|
||||
|
||||
/// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom:
|
||||
///
|
||||
/// ```text
|
||||
/// true
|
||||
/// |
|
||||
/// false
|
||||
/// ```
|
||||
impl JoinSemiLattice for bool {
|
||||
fn join(&mut self, other: &Self) -> bool {
|
||||
if let (false, true) = (*self, *other) {
|
||||
*self = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl HasBottom for bool {
|
||||
const BOTTOM: Self = false;
|
||||
|
||||
fn is_bottom(&self) -> bool {
|
||||
!self
|
||||
}
|
||||
}
|
||||
|
||||
impl HasTop for bool {
|
||||
const TOP: Self = true;
|
||||
}
|
||||
|
||||
/// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation
|
||||
/// of the least upper bounds of each element of the tuple (or list).
|
||||
///
|
||||
/// In other words:
|
||||
/// (A₀, A₁, ..., Aₙ) ∨ (B₀, B₁, ..., Bₙ) = (A₀∨B₀, A₁∨B₁, ..., Aₙ∨Bₙ)
|
||||
impl<I: Idx, T: JoinSemiLattice> JoinSemiLattice for IndexVec<I, T> {
|
||||
fn join(&mut self, other: &Self) -> bool {
|
||||
assert_eq!(self.len(), other.len());
|
||||
|
||||
let mut changed = false;
|
||||
for (a, b) in iter::zip(self, other) {
|
||||
changed |= a.join(b);
|
||||
}
|
||||
changed
|
||||
}
|
||||
}
|
||||
|
||||
/// A `BitSet` represents the lattice formed by the powerset of all possible values of
|
||||
/// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices,
|
||||
/// one for each possible value of `T`.
|
||||
|
@ -197,18 +148,6 @@ impl<T> MaybeReachable<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> HasBottom for MaybeReachable<T> {
|
||||
const BOTTOM: Self = MaybeReachable::Unreachable;
|
||||
|
||||
fn is_bottom(&self) -> bool {
|
||||
matches!(self, Self::Unreachable)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HasTop> HasTop for MaybeReachable<T> {
|
||||
const TOP: Self = MaybeReachable::Reachable(T::TOP);
|
||||
}
|
||||
|
||||
impl<S> MaybeReachable<S> {
|
||||
/// Return whether the current state contains the given element. If the state is unreachable,
|
||||
/// it does no contain anything.
|
||||
|
|
|
@ -56,7 +56,7 @@ mod visitor;
|
|||
pub use self::cursor::ResultsCursor;
|
||||
pub use self::direction::{Backward, Direction, Forward};
|
||||
pub use self::lattice::{JoinSemiLattice, MaybeReachable};
|
||||
pub use self::results::{EntrySets, Results};
|
||||
pub use self::results::{EntryStates, Results};
|
||||
pub use self::visitor::{ResultsVisitor, visit_results};
|
||||
|
||||
/// Analysis domains are all bitsets of various kinds. This trait holds
|
||||
|
@ -122,8 +122,23 @@ pub trait Analysis<'tcx> {
|
|||
// `resume`). It's not obvious how to handle `yield` points in coroutines, however.
|
||||
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain);
|
||||
|
||||
/// Updates the current dataflow state with an "early" effect, i.e. one
|
||||
/// that occurs immediately before the given statement.
|
||||
///
|
||||
/// This method is useful if the consumer of the results of this analysis only needs to observe
|
||||
/// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
|
||||
/// analyses should not implement this without also implementing
|
||||
/// `apply_primary_statement_effect`.
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
_state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
}
|
||||
|
||||
/// Updates the current dataflow state with the effect of evaluating a statement.
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
|
@ -131,15 +146,16 @@ pub trait Analysis<'tcx> {
|
|||
);
|
||||
|
||||
/// Updates the current dataflow state with an effect that occurs immediately *before* the
|
||||
/// given statement.
|
||||
/// given terminator.
|
||||
///
|
||||
/// This method is useful if the consumer of the results of this analysis only needs to observe
|
||||
/// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
|
||||
/// analyses should not implement this without also implementing `apply_statement_effect`.
|
||||
fn apply_before_statement_effect(
|
||||
/// This method is useful if the consumer of the results of this analysis needs only to observe
|
||||
/// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
|
||||
/// analyses should not implement this without also implementing
|
||||
/// `apply_primary_terminator_effect`.
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
_state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
}
|
||||
|
@ -150,7 +166,7 @@ pub trait Analysis<'tcx> {
|
|||
/// in this function. That should go in `apply_call_return_effect`. For example, in the
|
||||
/// `InitializedPlaces` analyses, the return place for a function call is not marked as
|
||||
/// initialized here.
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
_state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
|
@ -159,27 +175,13 @@ pub trait Analysis<'tcx> {
|
|||
terminator.edges()
|
||||
}
|
||||
|
||||
/// Updates the current dataflow state with an effect that occurs immediately *before* the
|
||||
/// given terminator.
|
||||
///
|
||||
/// This method is useful if the consumer of the results of this analysis needs only to observe
|
||||
/// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
|
||||
/// analyses should not implement this without also implementing `apply_terminator_effect`.
|
||||
fn apply_before_terminator_effect(
|
||||
&mut self,
|
||||
_state: &mut Self::Domain,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
) {
|
||||
}
|
||||
|
||||
/* Edge-specific effects */
|
||||
|
||||
/// Updates the current dataflow state with the effect of a successful return from a `Call`
|
||||
/// terminator.
|
||||
///
|
||||
/// This is separate from `apply_terminator_effect` to properly track state across unwind
|
||||
/// edges.
|
||||
/// This is separate from `apply_primary_terminator_effect` to properly track state across
|
||||
/// unwind edges.
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
_state: &mut Self::Domain,
|
||||
|
@ -234,11 +236,12 @@ pub trait Analysis<'tcx> {
|
|||
Self: Sized,
|
||||
Self::Domain: DebugWithContext<Self>,
|
||||
{
|
||||
let mut entry_sets =
|
||||
let mut entry_states =
|
||||
IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
|
||||
self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
|
||||
self.initialize_start_block(body, &mut entry_states[mir::START_BLOCK]);
|
||||
|
||||
if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) {
|
||||
if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body)
|
||||
{
|
||||
bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
|
||||
}
|
||||
|
||||
|
@ -262,9 +265,9 @@ pub trait Analysis<'tcx> {
|
|||
let mut state = self.bottom_value(body);
|
||||
while let Some(bb) = dirty_queue.pop() {
|
||||
// Set the state to the entry state of the block.
|
||||
// This is equivalent to `state = entry_sets[bb].clone()`,
|
||||
// This is equivalent to `state = entry_states[bb].clone()`,
|
||||
// but it saves an allocation, thus improving compile times.
|
||||
state.clone_from(&entry_sets[bb]);
|
||||
state.clone_from(&entry_states[bb]);
|
||||
|
||||
Self::Direction::apply_effects_in_block(
|
||||
&mut self,
|
||||
|
@ -273,7 +276,7 @@ pub trait Analysis<'tcx> {
|
|||
bb,
|
||||
&body[bb],
|
||||
|target: BasicBlock, state: &Self::Domain| {
|
||||
let set_changed = entry_sets[target].join(state);
|
||||
let set_changed = entry_states[target].join(state);
|
||||
if set_changed {
|
||||
dirty_queue.insert(target);
|
||||
}
|
||||
|
@ -281,7 +284,7 @@ pub trait Analysis<'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
let mut results = Results { analysis: self, entry_sets };
|
||||
let mut results = Results { analysis: self, entry_states };
|
||||
|
||||
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
|
||||
let res = write_graphviz_results(tcx, body, &mut results, pass_name);
|
||||
|
@ -358,11 +361,10 @@ impl<T, S: GenKill<T>> GenKill<T> for MaybeReachable<S> {
|
|||
// NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
enum Effect {
|
||||
/// The "before" effect (e.g., `apply_before_statement_effect`) for a statement (or
|
||||
/// terminator).
|
||||
Before,
|
||||
/// The "early" effect (e.g., `apply_early_statement_effect`) for a statement/terminator.
|
||||
Early,
|
||||
|
||||
/// The "primary" effect (e.g., `apply_statement_effect`) for a statement (or terminator).
|
||||
/// The "primary" effect (e.g., `apply_primary_statement_effect`) for a statement/terminator.
|
||||
Primary,
|
||||
}
|
||||
|
||||
|
@ -381,15 +383,15 @@ pub struct EffectIndex {
|
|||
impl EffectIndex {
|
||||
fn next_in_forward_order(self) -> Self {
|
||||
match self.effect {
|
||||
Effect::Before => Effect::Primary.at_index(self.statement_index),
|
||||
Effect::Primary => Effect::Before.at_index(self.statement_index + 1),
|
||||
Effect::Early => Effect::Primary.at_index(self.statement_index),
|
||||
Effect::Primary => Effect::Early.at_index(self.statement_index + 1),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_in_backward_order(self) -> Self {
|
||||
match self.effect {
|
||||
Effect::Before => Effect::Primary.at_index(self.statement_index),
|
||||
Effect::Primary => Effect::Before.at_index(self.statement_index - 1),
|
||||
Effect::Early => Effect::Primary.at_index(self.statement_index),
|
||||
Effect::Primary => Effect::Early.at_index(self.statement_index - 1),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use rustc_middle::mir::{BasicBlock, Body, traversal};
|
|||
use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results};
|
||||
use crate::framework::cursor::ResultsHandle;
|
||||
|
||||
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
|
||||
pub type EntryStates<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
|
||||
|
||||
/// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the
|
||||
/// entry of each basic block. Domain values in other parts of the block are recomputed on the fly
|
||||
|
@ -17,7 +17,7 @@ where
|
|||
A: Analysis<'tcx>,
|
||||
{
|
||||
pub analysis: A,
|
||||
pub entry_sets: EntrySets<'tcx, A>,
|
||||
pub entry_states: EntryStates<'tcx, A>,
|
||||
}
|
||||
|
||||
impl<'tcx, A> Results<'tcx, A>
|
||||
|
@ -40,7 +40,7 @@ where
|
|||
|
||||
/// Gets the dataflow state for the given block.
|
||||
pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
|
||||
&self.entry_sets[block]
|
||||
&self.entry_states[block]
|
||||
}
|
||||
|
||||
pub fn visit_with<'mir>(
|
||||
|
|
|
@ -73,7 +73,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
|
|||
///
|
||||
/// The `102` in the block's entry set is derived from the basic block index and ensures that the
|
||||
/// expected state is unique across all basic blocks. Remember, it is generated by
|
||||
/// `mock_entry_sets`, not from actually running `MockAnalysis` to fixpoint.
|
||||
/// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint.
|
||||
struct MockAnalysis<'tcx, D> {
|
||||
body: &'tcx mir::Body<'tcx>,
|
||||
dir: PhantomData<D>,
|
||||
|
@ -90,7 +90,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
|
|||
ret
|
||||
}
|
||||
|
||||
fn mock_entry_sets(&self) -> IndexVec<BasicBlock, BitSet<usize>> {
|
||||
fn mock_entry_states(&self) -> IndexVec<BasicBlock, BitSet<usize>> {
|
||||
let empty = self.bottom_value(self.body);
|
||||
let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks);
|
||||
|
||||
|
@ -104,7 +104,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
|
|||
/// Returns the index that should be added to the dataflow state at the given target.
|
||||
fn effect(&self, loc: EffectIndex) -> usize {
|
||||
let idx = match loc.effect {
|
||||
Effect::Before => loc.statement_index * 2,
|
||||
Effect::Early => loc.statement_index * 2,
|
||||
Effect::Primary => loc.statement_index * 2 + 1,
|
||||
};
|
||||
|
||||
|
@ -128,14 +128,14 @@ impl<D: Direction> MockAnalysis<'_, D> {
|
|||
|
||||
let target = match target {
|
||||
SeekTarget::BlockEntry { .. } => return ret,
|
||||
SeekTarget::Before(loc) => Effect::Before.at_index(loc.statement_index),
|
||||
SeekTarget::Early(loc) => Effect::Early.at_index(loc.statement_index),
|
||||
SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index),
|
||||
};
|
||||
|
||||
let mut pos = if D::IS_FORWARD {
|
||||
Effect::Before.at_index(0)
|
||||
Effect::Early.at_index(0)
|
||||
} else {
|
||||
Effect::Before.at_index(self.body[block].statements.len())
|
||||
Effect::Early.at_index(self.body[block].statements.len())
|
||||
};
|
||||
|
||||
loop {
|
||||
|
@ -168,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");
|
||||
}
|
||||
|
||||
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,
|
||||
state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
|
@ -178,17 +188,17 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
|||
assert!(state.insert(idx));
|
||||
}
|
||||
|
||||
fn apply_before_statement_effect(
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
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));
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
|
@ -198,22 +208,12 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
|
|||
assert!(state.insert(idx));
|
||||
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)]
|
||||
enum SeekTarget {
|
||||
BlockEntry(BasicBlock),
|
||||
Before(Location),
|
||||
Early(Location),
|
||||
After(Location),
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,7 @@ impl SeekTarget {
|
|||
|
||||
match *self {
|
||||
BlockEntry(block) => block,
|
||||
Before(loc) | After(loc) => loc.block,
|
||||
Early(loc) | After(loc) => loc.block,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ impl SeekTarget {
|
|||
.map(move |(i, kind)| {
|
||||
let loc = Location { block, statement_index: i };
|
||||
match kind {
|
||||
0 => SeekTarget::Before(loc),
|
||||
0 => SeekTarget::Early(loc),
|
||||
1 => SeekTarget::After(loc),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
|
|||
let body = analysis.body;
|
||||
|
||||
let mut cursor =
|
||||
Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
|
||||
Results { entry_states: analysis.mock_entry_states(), analysis }.into_results_cursor(body);
|
||||
|
||||
cursor.allow_unreachable();
|
||||
|
||||
|
@ -262,7 +262,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
|
|||
|
||||
match targ {
|
||||
BlockEntry(block) => cursor.seek_to_block_entry(block),
|
||||
Before(loc) => cursor.seek_before_primary_effect(loc),
|
||||
Early(loc) => cursor.seek_before_primary_effect(loc),
|
||||
After(loc) => cursor.seek_after_primary_effect(loc),
|
||||
}
|
||||
|
||||
|
|
|
@ -35,9 +35,9 @@ where
|
|||
{
|
||||
fn visit_block_start(&mut self, _state: &A::Domain) {}
|
||||
|
||||
/// Called with the `before_statement_effect` of the given statement applied to `state` but not
|
||||
/// its `statement_effect`.
|
||||
fn visit_statement_before_primary_effect(
|
||||
/// // njn: grep for "before", "primary", etc.
|
||||
/// Called after the "early" effect of the given statement is applied to `state`.
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
_state: &A::Domain,
|
||||
|
@ -46,9 +46,8 @@ where
|
|||
) {
|
||||
}
|
||||
|
||||
/// Called with both the `before_statement_effect` and the `statement_effect` of the given
|
||||
/// statement applied to `state`.
|
||||
fn visit_statement_after_primary_effect(
|
||||
/// Called after the "primary" effect of the given statement is applied to `state`.
|
||||
fn visit_after_primary_statement_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
_state: &A::Domain,
|
||||
|
@ -57,9 +56,8 @@ where
|
|||
) {
|
||||
}
|
||||
|
||||
/// Called with the `before_terminator_effect` of the given terminator applied to `state` but
|
||||
/// not its `terminator_effect`.
|
||||
fn visit_terminator_before_primary_effect(
|
||||
/// Called after the "early" effect of the given terminator is applied to `state`.
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
_state: &A::Domain,
|
||||
|
@ -68,11 +66,10 @@ where
|
|||
) {
|
||||
}
|
||||
|
||||
/// Called with both the `before_terminator_effect` and the `terminator_effect` of the given
|
||||
/// terminator applied to `state`.
|
||||
/// Called after the "primary" effect of the given terminator is applied to `state`.
|
||||
///
|
||||
/// The `call_return_effect` (if one exists) will *not* be applied to `state`.
|
||||
fn visit_terminator_after_primary_effect(
|
||||
fn visit_after_primary_terminator_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
_state: &A::Domain,
|
||||
|
|
|
@ -33,22 +33,22 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
|
|||
// No locals are aliased on function entry
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
statement: &Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
Self::transfer_function(trans).visit_statement(statement, location);
|
||||
Self::transfer_function(state).visit_statement(statement, location);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir Terminator<'tcx>,
|
||||
location: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
Self::transfer_function(trans).visit_terminator(terminator, location);
|
||||
Self::transfer_function(state).visit_terminator(terminator, location);
|
||||
terminator.edges()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
|
|||
pub fn is_unwind_dead(
|
||||
&self,
|
||||
place: mir::Place<'tcx>,
|
||||
state: &MaybeReachable<MixedBitSet<MovePathIndex>>,
|
||||
state: &<Self as Analysis<'tcx>>::Domain,
|
||||
) -> bool {
|
||||
if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) {
|
||||
let mut maybe_live = false;
|
||||
|
@ -218,26 +218,26 @@ impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
|
||||
fn update_bits(
|
||||
trans: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
state: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
path: MovePathIndex,
|
||||
state: DropFlagState,
|
||||
dfstate: DropFlagState,
|
||||
) {
|
||||
match state {
|
||||
DropFlagState::Absent => trans.kill(path),
|
||||
DropFlagState::Present => trans.gen_(path),
|
||||
match dfstate {
|
||||
DropFlagState::Absent => state.kill(path),
|
||||
DropFlagState::Present => state.gen_(path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> {
|
||||
fn update_bits(
|
||||
trans: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
state: &mut <Self as Analysis<'tcx>>::Domain,
|
||||
path: MovePathIndex,
|
||||
state: DropFlagState,
|
||||
dfstate: DropFlagState,
|
||||
) {
|
||||
match state {
|
||||
DropFlagState::Absent => trans.gen_(path),
|
||||
DropFlagState::Present => trans.kill(path),
|
||||
match dfstate {
|
||||
DropFlagState::Absent => state.gen_(path),
|
||||
DropFlagState::Present => state.kill(path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -263,14 +263,14 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
|
||||
Self::update_bits(trans, path, s)
|
||||
Self::update_bits(state, path, s)
|
||||
});
|
||||
|
||||
// Mark all places as "maybe init" if they are mutably borrowed. See #90752.
|
||||
|
@ -282,12 +282,12 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
&& let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref())
|
||||
{
|
||||
on_all_children_bits(self.move_data(), mpi, |child| {
|
||||
trans.gen_(child);
|
||||
state.gen_(child);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
|
@ -309,7 +309,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_block: mir::BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
) {
|
||||
|
@ -320,7 +320,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
self.move_data(),
|
||||
self.move_data().rev_lookup.find(place.as_ref()),
|
||||
|mpi| {
|
||||
trans.gen_(mpi);
|
||||
state.gen_(mpi);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -345,7 +345,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
};
|
||||
|
||||
let mut discriminants = enum_def.discriminants(self.tcx);
|
||||
edge_effects.apply(|trans, edge| {
|
||||
edge_effects.apply(|state, edge| {
|
||||
let Some(value) = edge.value else {
|
||||
return;
|
||||
};
|
||||
|
@ -363,25 +363,27 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
|
|||
self.move_data(),
|
||||
enum_place,
|
||||
variant,
|
||||
|mpi| trans.kill(mpi),
|
||||
|mpi| state.kill(mpi),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
||||
/// There can be many more `MovePathIndex` than there are locals in a MIR body.
|
||||
/// We use a mixed bitset to avoid paying too high a memory footprint.
|
||||
type Domain = MixedBitSet<MovePathIndex>;
|
||||
pub type MaybeUninitializedPlacesDomain = MixedBitSet<MovePathIndex>;
|
||||
|
||||
impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
||||
type Domain = MaybeUninitializedPlacesDomain;
|
||||
|
||||
const NAME: &'static str = "maybe_uninit";
|
||||
|
||||
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
|
||||
// bottom = initialized (start_block_effect counters this at outset)
|
||||
// bottom = initialized (`initialize_start_block` overwrites this on first entry)
|
||||
MixedBitSet::new_empty(self.move_data().move_paths.len())
|
||||
}
|
||||
|
||||
// sets on_entry bits for Arg places
|
||||
// sets state bits for Arg places
|
||||
fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
|
||||
// set all bits to 1 (uninit) before gathering counter-evidence
|
||||
state.insert_all();
|
||||
|
@ -392,28 +394,28 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
|
||||
Self::update_bits(trans, path, s)
|
||||
Self::update_bits(state, path, s)
|
||||
});
|
||||
|
||||
// Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a
|
||||
// mutable borrow occurs. Places cannot become uninitialized through a mutable reference.
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
|
||||
Self::update_bits(trans, path, s)
|
||||
Self::update_bits(state, path, s)
|
||||
});
|
||||
if self.skip_unreachable_unwind.contains(location.block) {
|
||||
let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() };
|
||||
|
@ -426,7 +428,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_block: mir::BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
) {
|
||||
|
@ -437,7 +439,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
self.move_data(),
|
||||
self.move_data().rev_lookup.find(place.as_ref()),
|
||||
|mpi| {
|
||||
trans.kill(mpi);
|
||||
state.kill(mpi);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -466,7 +468,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
};
|
||||
|
||||
let mut discriminants = enum_def.discriminants(self.tcx);
|
||||
edge_effects.apply(|trans, edge| {
|
||||
edge_effects.apply(|state, edge| {
|
||||
let Some(value) = edge.value else {
|
||||
return;
|
||||
};
|
||||
|
@ -484,16 +486,18 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
|
|||
self.move_data(),
|
||||
enum_place,
|
||||
variant,
|
||||
|mpi| trans.gen_(mpi),
|
||||
|mpi| state.gen_(mpi),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
||||
/// There can be many more `InitIndex` than there are locals in a MIR body.
|
||||
/// We use a mixed bitset to avoid paying too high a memory footprint.
|
||||
type Domain = MixedBitSet<InitIndex>;
|
||||
pub type EverInitializedPlacesDomain = MixedBitSet<InitIndex>;
|
||||
|
||||
impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
||||
type Domain = EverInitializedPlacesDomain;
|
||||
|
||||
const NAME: &'static str = "ever_init";
|
||||
|
||||
|
@ -508,10 +512,10 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self, trans), level = "debug")]
|
||||
fn apply_statement_effect(
|
||||
#[instrument(skip(self, state), level = "debug")]
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
|
@ -521,7 +525,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
|||
let rev_lookup = &move_data.rev_lookup;
|
||||
|
||||
debug!("initializes move_indexes {:?}", init_loc_map[location]);
|
||||
trans.gen_all(init_loc_map[location].iter().copied());
|
||||
state.gen_all(init_loc_map[location].iter().copied());
|
||||
|
||||
if let mir::StatementKind::StorageDead(local) = stmt.kind {
|
||||
// End inits for StorageDead, so that an immutable variable can
|
||||
|
@ -531,15 +535,15 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
|||
"clears the ever initialized status of {:?}",
|
||||
init_path_map[move_path_index]
|
||||
);
|
||||
trans.kill_all(init_path_map[move_path_index].iter().copied());
|
||||
state.kill_all(init_path_map[move_path_index].iter().copied());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self, trans, terminator), level = "debug")]
|
||||
fn apply_terminator_effect<'mir>(
|
||||
#[instrument(skip(self, state, terminator), level = "debug")]
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
|
@ -548,7 +552,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
|||
let init_loc_map = &move_data.init_loc_map;
|
||||
debug!(?term);
|
||||
debug!("initializes move_indexes {:?}", init_loc_map[location]);
|
||||
trans.gen_all(
|
||||
state.gen_all(
|
||||
init_loc_map[location]
|
||||
.iter()
|
||||
.filter(|init_index| {
|
||||
|
@ -561,7 +565,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
|||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
block: mir::BasicBlock,
|
||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
) {
|
||||
|
@ -570,7 +574,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
|
|||
|
||||
let call_loc = self.body.terminator_loc(block);
|
||||
for init_index in &init_loc_map[call_loc] {
|
||||
trans.gen_(*init_index);
|
||||
state.gen_(*init_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,33 +40,33 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
|
|||
// No variables are live until we observe a use
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
TransferFunction(trans).visit_statement(statement, location);
|
||||
TransferFunction(state).visit_statement(statement, location);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
TransferFunction(trans).visit_terminator(terminator, location);
|
||||
TransferFunction(state).visit_terminator(terminator, location);
|
||||
terminator.edges()
|
||||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_block: mir::BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
) {
|
||||
if let CallReturnPlaces::Yield(resume_place) = return_places {
|
||||
YieldResumeEffect(trans).visit_place(
|
||||
YieldResumeEffect(state).visit_place(
|
||||
&resume_place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Yield),
|
||||
Location::START,
|
||||
|
@ -74,7 +74,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
|
|||
} else {
|
||||
return_places.for_each(|place| {
|
||||
if let Some(local) = place.as_local() {
|
||||
trans.kill(local);
|
||||
state.kill(local);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -137,10 +137,10 @@ enum DefUse {
|
|||
}
|
||||
|
||||
impl DefUse {
|
||||
fn apply(trans: &mut BitSet<Local>, place: Place<'_>, context: PlaceContext) {
|
||||
fn apply(state: &mut BitSet<Local>, place: Place<'_>, context: PlaceContext) {
|
||||
match DefUse::for_place(place, context) {
|
||||
Some(DefUse::Def) => trans.kill(place.local),
|
||||
Some(DefUse::Use) => trans.gen_(place.local),
|
||||
Some(DefUse::Def) => state.kill(place.local),
|
||||
Some(DefUse::Use) => state.gen_(place.local),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
@ -232,9 +232,9 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
|||
// No variables are live until we observe a use
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
|
@ -258,34 +258,34 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
|||
};
|
||||
if let Some(destination) = destination {
|
||||
if !destination.is_indirect()
|
||||
&& !trans.contains(destination.local)
|
||||
&& !state.contains(destination.local)
|
||||
&& !self.always_live.contains(destination.local)
|
||||
{
|
||||
// This store is dead
|
||||
return;
|
||||
}
|
||||
}
|
||||
TransferFunction(trans).visit_statement(statement, location);
|
||||
TransferFunction(state).visit_statement(statement, location);
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
) -> TerminatorEdges<'mir, 'tcx> {
|
||||
TransferFunction(trans).visit_terminator(terminator, location);
|
||||
TransferFunction(state).visit_terminator(terminator, location);
|
||||
terminator.edges()
|
||||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_block: mir::BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
) {
|
||||
if let CallReturnPlaces::Yield(resume_place) = return_places {
|
||||
YieldResumeEffect(trans).visit_place(
|
||||
YieldResumeEffect(state).visit_place(
|
||||
&resume_place,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Yield),
|
||||
Location::START,
|
||||
|
@ -293,7 +293,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
|||
} else {
|
||||
return_places.for_each(|place| {
|
||||
if let Some(local) = place.as_local() {
|
||||
trans.remove(local);
|
||||
state.remove(local);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@ mod storage_liveness;
|
|||
|
||||
pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals};
|
||||
pub use self::initialized::{
|
||||
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
|
||||
EverInitializedPlaces, EverInitializedPlacesDomain, MaybeInitializedPlaces,
|
||||
MaybeUninitializedPlaces, MaybeUninitializedPlacesDomain,
|
||||
};
|
||||
pub use self::liveness::{
|
||||
MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,
|
||||
|
|
|
@ -44,23 +44,23 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> {
|
|||
BitSet::new_empty(body.local_decls.len())
|
||||
}
|
||||
|
||||
fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) {
|
||||
on_entry.union(&*self.always_live_locals);
|
||||
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
|
||||
state.union(&*self.always_live_locals);
|
||||
|
||||
for arg in body.args_iter() {
|
||||
on_entry.insert(arg);
|
||||
state.insert(arg);
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &Statement<'tcx>,
|
||||
_: Location,
|
||||
) {
|
||||
match stmt.kind {
|
||||
StatementKind::StorageLive(l) => trans.gen_(l),
|
||||
StatementKind::StorageDead(l) => trans.kill(l),
|
||||
StatementKind::StorageLive(l) => state.gen_(l),
|
||||
StatementKind::StorageDead(l) => state.kill(l),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -86,25 +86,25 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> {
|
|||
BitSet::new_empty(body.local_decls.len())
|
||||
}
|
||||
|
||||
fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) {
|
||||
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
|
||||
assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size());
|
||||
// Do not iterate on return place and args, as they are trivially always live.
|
||||
for local in body.vars_and_temps_iter() {
|
||||
if !self.always_live_locals.contains(local) {
|
||||
on_entry.insert(local);
|
||||
state.insert(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &Statement<'tcx>,
|
||||
_: Location,
|
||||
) {
|
||||
match stmt.kind {
|
||||
StatementKind::StorageLive(l) => trans.kill(l),
|
||||
StatementKind::StorageDead(l) => trans.gen_(l),
|
||||
StatementKind::StorageLive(l) => state.kill(l),
|
||||
StatementKind::StorageDead(l) => state.gen_(l),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -134,31 +134,31 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
BitSet::new_empty(body.local_decls.len())
|
||||
}
|
||||
|
||||
fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) {
|
||||
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
|
||||
// The resume argument is live on function entry (we don't care about
|
||||
// the `self` argument)
|
||||
for arg in body.args_iter().skip(1) {
|
||||
on_entry.insert(arg);
|
||||
state.insert(arg);
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_before_statement_effect(
|
||||
fn apply_early_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
stmt: &Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
// If a place is borrowed in a statement, it needs storage for that statement.
|
||||
MaybeBorrowedLocals::transfer_function(trans).visit_statement(stmt, loc);
|
||||
MaybeBorrowedLocals::transfer_function(state).visit_statement(stmt, loc);
|
||||
|
||||
match &stmt.kind {
|
||||
StatementKind::StorageDead(l) => trans.kill(*l),
|
||||
StatementKind::StorageDead(l) => state.kill(*l),
|
||||
|
||||
// If a place is assigned to in a statement, it needs storage for that statement.
|
||||
StatementKind::Assign(box (place, _))
|
||||
| StatementKind::SetDiscriminant { box place, .. }
|
||||
| StatementKind::Deinit(box place) => {
|
||||
trans.gen_(place.local);
|
||||
state.gen_(place.local);
|
||||
}
|
||||
|
||||
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||
|
@ -176,29 +176,29 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_: &Statement<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
// If we move from a place then it only stops needing storage *after*
|
||||
// that statement.
|
||||
self.check_for_move(trans, loc);
|
||||
self.check_for_move(state, loc);
|
||||
}
|
||||
|
||||
fn apply_before_terminator_effect(
|
||||
fn apply_early_terminator_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) {
|
||||
// If a place is borrowed in a terminator, it needs storage for that terminator.
|
||||
MaybeBorrowedLocals::transfer_function(trans).visit_terminator(terminator, loc);
|
||||
MaybeBorrowedLocals::transfer_function(state).visit_terminator(terminator, loc);
|
||||
|
||||
match &terminator.kind {
|
||||
TerminatorKind::Call { destination, .. } => {
|
||||
trans.gen_(destination.local);
|
||||
state.gen_(destination.local);
|
||||
}
|
||||
|
||||
// Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for
|
||||
|
@ -213,7 +213,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
InlineAsmOperand::Out { place, .. }
|
||||
| InlineAsmOperand::InOut { out_place: place, .. } => {
|
||||
if let Some(place) = place {
|
||||
trans.gen_(place.local);
|
||||
state.gen_(place.local);
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::In { .. }
|
||||
|
@ -242,9 +242,9 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'t>(
|
||||
fn apply_primary_terminator_effect<'t>(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'t Terminator<'tcx>,
|
||||
loc: Location,
|
||||
) -> TerminatorEdges<'t, 'tcx> {
|
||||
|
@ -254,12 +254,12 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
// Since `propagate_call_unwind` doesn't exist, we have to kill the
|
||||
// destination here, and then gen it again in `call_return_effect`.
|
||||
TerminatorKind::Call { destination, .. } => {
|
||||
trans.kill(destination.local);
|
||||
state.kill(destination.local);
|
||||
}
|
||||
|
||||
// The same applies to InlineAsm outputs.
|
||||
TerminatorKind::InlineAsm { ref operands, .. } => {
|
||||
CallReturnPlaces::InlineAsm(operands).for_each(|place| trans.kill(place.local));
|
||||
CallReturnPlaces::InlineAsm(operands).for_each(|place| state.kill(place.local));
|
||||
}
|
||||
|
||||
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||
|
@ -279,32 +279,32 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
|
|||
| TerminatorKind::Unreachable => {}
|
||||
}
|
||||
|
||||
self.check_for_move(trans, loc);
|
||||
self.check_for_move(state, loc);
|
||||
terminator.edges()
|
||||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&mut self,
|
||||
trans: &mut Self::Domain,
|
||||
state: &mut Self::Domain,
|
||||
_block: BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
) {
|
||||
return_places.for_each(|place| trans.gen_(place.local));
|
||||
return_places.for_each(|place| state.gen_(place.local));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MaybeRequiresStorage<'_, 'tcx> {
|
||||
/// Kill locals that are fully moved and have not been borrowed.
|
||||
fn check_for_move(&mut self, trans: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
|
||||
fn check_for_move(&mut self, state: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
|
||||
let body = self.borrowed_locals.body();
|
||||
let mut visitor = MoveVisitor { trans, borrowed_locals: &mut self.borrowed_locals };
|
||||
let mut visitor = MoveVisitor { state, borrowed_locals: &mut self.borrowed_locals };
|
||||
visitor.visit_location(body, loc);
|
||||
}
|
||||
}
|
||||
|
||||
struct MoveVisitor<'a, 'mir, 'tcx> {
|
||||
borrowed_locals: &'a mut BorrowedLocalsResults<'mir, 'tcx>,
|
||||
trans: &'a mut BitSet<Local>,
|
||||
state: &'a mut BitSet<Local>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
|
||||
|
@ -312,7 +312,7 @@ impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
|
|||
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
|
||||
self.borrowed_locals.seek_before_primary_effect(loc);
|
||||
if !self.borrowed_locals.get().contains(local) {
|
||||
self.trans.kill(local);
|
||||
self.state.kill(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ pub use self::drop_flag_effects::{
|
|||
move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
|
||||
};
|
||||
pub use self::framework::{
|
||||
Analysis, Backward, Direction, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable,
|
||||
Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable,
|
||||
Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
|
||||
visit_results,
|
||||
};
|
||||
|
|
|
@ -125,7 +125,7 @@ where
|
|||
A: Analysis<'tcx, Domain = BitSet<N>>,
|
||||
N: Idx,
|
||||
{
|
||||
fn visit_statement_after_primary_effect(
|
||||
fn visit_after_primary_statement_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
state: &A::Domain,
|
||||
|
@ -139,7 +139,7 @@ where
|
|||
});
|
||||
}
|
||||
|
||||
fn visit_terminator_after_primary_effect(
|
||||
fn visit_after_primary_terminator_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, A>,
|
||||
state: &A::Domain,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use rustc_ast::MetaItem;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::{self, Body, Local, Location};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
@ -254,7 +253,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
|
|||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
place: mir::Place<'tcx>,
|
||||
state: &BitSet<Local>,
|
||||
state: &Self::Domain,
|
||||
call: PeekCall,
|
||||
) {
|
||||
info!(?place, "peek_at");
|
||||
|
|
|
@ -67,7 +67,7 @@ impl<V: Clone> Clone for StateData<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for StateData<V> {
|
||||
impl<V: JoinSemiLattice + Clone> JoinSemiLattice for StateData<V> {
|
||||
fn join(&mut self, other: &Self) -> bool {
|
||||
let mut changed = false;
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
|
@ -342,7 +342,7 @@ impl<V: Clone + HasBottom> State<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for State<V> {
|
||||
impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> {
|
||||
fn join(&mut self, other: &Self) -> bool {
|
||||
match (&mut *self, other) {
|
||||
(_, State::Unreachable) => false,
|
||||
|
|
|
@ -878,7 +878,7 @@ struct StorageConflictVisitor<'a, 'tcx> {
|
|||
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
|
||||
for StorageConflictVisitor<'a, 'tcx>
|
||||
{
|
||||
fn visit_statement_before_primary_effect(
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
|
||||
state: &BitSet<Local>,
|
||||
|
@ -888,7 +888,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
|
|||
self.apply_state(state, loc);
|
||||
}
|
||||
|
||||
fn visit_terminator_before_primary_effect(
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
|
||||
state: &BitSet<Local>,
|
||||
|
|
|
@ -106,7 +106,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn apply_statement_effect(
|
||||
fn apply_primary_statement_effect(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &Statement<'tcx>,
|
||||
|
@ -117,7 +117,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn apply_terminator_effect<'mir>(
|
||||
fn apply_primary_terminator_effect<'mir>(
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &'mir Terminator<'tcx>,
|
||||
|
@ -224,7 +224,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// The effect of a successful function call return should not be
|
||||
/// applied here, see [`Analysis::apply_terminator_effect`].
|
||||
/// applied here, see [`Analysis::apply_primary_terminator_effect`].
|
||||
fn handle_terminator<'mir>(
|
||||
&self,
|
||||
terminator: &'mir Terminator<'tcx>,
|
||||
|
@ -954,7 +954,7 @@ fn try_write_constant<'tcx>(
|
|||
|
||||
impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
|
||||
#[instrument(level = "trace", skip(self, results, statement))]
|
||||
fn visit_statement_before_primary_effect(
|
||||
fn visit_after_early_statement_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
||||
state: &State<FlatSet<Scalar>>,
|
||||
|
@ -976,7 +976,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collect
|
|||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, results, statement))]
|
||||
fn visit_statement_after_primary_effect(
|
||||
fn visit_after_primary_statement_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
||||
state: &State<FlatSet<Scalar>>,
|
||||
|
@ -1001,7 +1001,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collect
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_terminator_before_primary_effect(
|
||||
fn visit_after_early_terminator_effect(
|
||||
&mut self,
|
||||
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
||||
state: &State<FlatSet<Scalar>>,
|
||||
|
|
|
@ -127,7 +127,7 @@ impl InitializationData<'_, '_> {
|
|||
self.uninits.seek_before_primary_effect(loc);
|
||||
}
|
||||
|
||||
fn maybe_live_dead(&self, path: MovePathIndex) -> (bool, bool) {
|
||||
fn maybe_init_uninit(&self, path: MovePathIndex) -> (bool, bool) {
|
||||
(self.inits.get().contains(path), self.uninits.get().contains(path))
|
||||
}
|
||||
}
|
||||
|
@ -153,23 +153,23 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> {
|
|||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle {
|
||||
let ((maybe_live, maybe_dead), multipart) = match mode {
|
||||
DropFlagMode::Shallow => (self.init_data.maybe_live_dead(path), false),
|
||||
let ((maybe_init, maybe_uninit), multipart) = match mode {
|
||||
DropFlagMode::Shallow => (self.init_data.maybe_init_uninit(path), false),
|
||||
DropFlagMode::Deep => {
|
||||
let mut some_live = false;
|
||||
let mut some_dead = false;
|
||||
let mut some_maybe_init = false;
|
||||
let mut some_maybe_uninit = false;
|
||||
let mut children_count = 0;
|
||||
on_all_children_bits(self.move_data(), path, |child| {
|
||||
let (live, dead) = self.init_data.maybe_live_dead(child);
|
||||
debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead));
|
||||
some_live |= live;
|
||||
some_dead |= dead;
|
||||
let (maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(child);
|
||||
debug!("elaborate_drop: state({:?}) = {:?}", child, (maybe_init, maybe_uninit));
|
||||
some_maybe_init |= maybe_init;
|
||||
some_maybe_uninit |= maybe_uninit;
|
||||
children_count += 1;
|
||||
});
|
||||
((some_live, some_dead), children_count != 1)
|
||||
((some_maybe_init, some_maybe_uninit), children_count != 1)
|
||||
}
|
||||
};
|
||||
match (maybe_live, maybe_dead, multipart) {
|
||||
match (maybe_init, maybe_uninit, multipart) {
|
||||
(false, _, _) => DropStyle::Dead,
|
||||
(true, false, _) => DropStyle::Static,
|
||||
(true, true, false) => DropStyle::Conditional,
|
||||
|
@ -283,15 +283,15 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
|
|||
LookupResult::Exact(path) => {
|
||||
self.init_data.seek_before(self.body.terminator_loc(bb));
|
||||
on_all_children_bits(self.move_data(), path, |child| {
|
||||
let (maybe_live, maybe_dead) = self.init_data.maybe_live_dead(child);
|
||||
let (maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(child);
|
||||
debug!(
|
||||
"collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
|
||||
child,
|
||||
place,
|
||||
path,
|
||||
(maybe_live, maybe_dead)
|
||||
(maybe_init, maybe_uninit)
|
||||
);
|
||||
if maybe_live && maybe_dead {
|
||||
if maybe_init && maybe_uninit {
|
||||
self.create_drop_flag(child, terminator.source_info.span)
|
||||
}
|
||||
});
|
||||
|
@ -303,8 +303,8 @@ impl<'a, 'tcx> ElaborateDropsCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
self.init_data.seek_before(self.body.terminator_loc(bb));
|
||||
let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent);
|
||||
if maybe_dead {
|
||||
let (_maybe_init, maybe_uninit) = self.init_data.maybe_init_uninit(parent);
|
||||
if maybe_uninit {
|
||||
self.tcx.dcx().span_delayed_bug(
|
||||
terminator.source_info.span,
|
||||
format!(
|
||||
|
|
|
@ -15,7 +15,7 @@ use rustc_ast::visit::{Visitor, walk_expr};
|
|||
use rustc_ast::{
|
||||
self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy,
|
||||
ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall,
|
||||
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp,
|
||||
MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
|
@ -1931,6 +1931,12 @@ impl<'a> Parser<'a> {
|
|||
Ok(match ident.name {
|
||||
sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
|
||||
sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
|
||||
sym::wrap_binder => {
|
||||
Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)
|
||||
}
|
||||
sym::unwrap_binder => {
|
||||
Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
|
@ -2006,6 +2012,17 @@ impl<'a> Parser<'a> {
|
|||
Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
|
||||
}
|
||||
|
||||
pub(crate) fn parse_expr_unsafe_binder_cast(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
kind: UnsafeBinderCastKind,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
let expr = self.parse_expr()?;
|
||||
let ty = if self.eat(&TokenKind::Comma) { Some(self.parse_ty()?) } else { None };
|
||||
let span = lo.to(self.token.span);
|
||||
Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
|
||||
}
|
||||
|
||||
/// Returns a string literal if the next token is a string literal.
|
||||
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
|
||||
/// and returns `None` if the next token is not literal at all.
|
||||
|
@ -4016,7 +4033,9 @@ impl MutVisitor for CondChecker<'_> {
|
|||
mut_visit::walk_expr(self, e);
|
||||
self.forbid_let_reason = forbid_let_reason;
|
||||
}
|
||||
ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => {
|
||||
ExprKind::Cast(ref mut op, _)
|
||||
| ExprKind::Type(ref mut op, _)
|
||||
| ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
|
||||
let forbid_let_reason = self.forbid_let_reason;
|
||||
self.forbid_let_reason = Some(OtherForbidden);
|
||||
self.visit_expr(op);
|
||||
|
|
|
@ -45,7 +45,7 @@ impl<'a> Parser<'a> {
|
|||
let (inner_attrs, items, inner_span) =
|
||||
self.parse_mod(&token::CloseDelim(Delimiter::Brace))?;
|
||||
attrs.extend(inner_attrs);
|
||||
ModKind::Loaded(items, Inline::Yes, inner_span)
|
||||
ModKind::Loaded(items, Inline::Yes, inner_span, Ok(()))
|
||||
};
|
||||
Ok((id, ItemKind::Mod(safety, mod_kind)))
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc_ast::{
|
|||
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
|
||||
GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability,
|
||||
Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
|
||||
TyKind,
|
||||
TyKind, UnsafeBinderTy,
|
||||
};
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_span::symbol::{Ident, kw, sym};
|
||||
|
@ -348,6 +348,10 @@ impl<'a> Parser<'a> {
|
|||
TyKind::Err(guar)
|
||||
}
|
||||
}
|
||||
} else if self.check_keyword(kw::Unsafe)
|
||||
&& self.look_ahead(1, |tok| matches!(tok.kind, token::Lt))
|
||||
{
|
||||
self.parse_unsafe_binder_ty()?
|
||||
} else {
|
||||
let msg = format!("expected type, found {}", super::token_descr(&self.token));
|
||||
let mut err = self.dcx().struct_span_err(lo, msg);
|
||||
|
@ -369,6 +373,19 @@ impl<'a> Parser<'a> {
|
|||
if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
|
||||
}
|
||||
|
||||
fn parse_unsafe_binder_ty(&mut self) -> PResult<'a, TyKind> {
|
||||
let lo = self.token.span;
|
||||
assert!(self.eat_keyword(kw::Unsafe));
|
||||
self.expect_lt()?;
|
||||
let generic_params = self.parse_generic_params()?;
|
||||
self.expect_gt()?;
|
||||
let inner_ty = self.parse_ty()?;
|
||||
let span = lo.to(self.prev_token.span);
|
||||
self.psess.gated_spans.gate(sym::unsafe_binders, span);
|
||||
|
||||
Ok(TyKind::UnsafeBinder(P(UnsafeBinderTy { generic_params, inner_ty })))
|
||||
}
|
||||
|
||||
/// Parses either:
|
||||
/// - `(TYPE)`, a parenthesized type.
|
||||
/// - `(TYPE,)`, a tuple with a single field of type TYPE.
|
||||
|
|
|
@ -315,9 +315,40 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||
|
||||
fn visit_expr(&mut self, e: &'v hir::Expr<'v>) {
|
||||
record_variants!((self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind), [
|
||||
ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, DropTemps,
|
||||
Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index, Path, AddrOf,
|
||||
Break, Continue, Ret, Become, InlineAsm, OffsetOf, Struct, Repeat, Yield, Err
|
||||
ConstBlock,
|
||||
Array,
|
||||
Call,
|
||||
MethodCall,
|
||||
Tup,
|
||||
Binary,
|
||||
Unary,
|
||||
Lit,
|
||||
Cast,
|
||||
Type,
|
||||
DropTemps,
|
||||
Let,
|
||||
If,
|
||||
Loop,
|
||||
Match,
|
||||
Closure,
|
||||
Block,
|
||||
Assign,
|
||||
AssignOp,
|
||||
Field,
|
||||
Index,
|
||||
Path,
|
||||
AddrOf,
|
||||
Break,
|
||||
Continue,
|
||||
Ret,
|
||||
Become,
|
||||
InlineAsm,
|
||||
OffsetOf,
|
||||
Struct,
|
||||
Repeat,
|
||||
Yield,
|
||||
UnsafeBinderCast,
|
||||
Err
|
||||
]);
|
||||
hir_visit::walk_expr(self, e)
|
||||
}
|
||||
|
@ -335,6 +366,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||
Ptr,
|
||||
Ref,
|
||||
BareFn,
|
||||
UnsafeBinder,
|
||||
Never,
|
||||
Tup,
|
||||
Path,
|
||||
|
@ -571,7 +603,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
|||
If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign,
|
||||
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
|
||||
InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
|
||||
Become, IncludedBytes, Gen, Err, Dummy
|
||||
Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy
|
||||
]
|
||||
);
|
||||
ast_visit::walk_expr(self, e)
|
||||
|
@ -585,6 +617,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
|||
Ref,
|
||||
PinnedRef,
|
||||
BareFn,
|
||||
UnsafeBinder,
|
||||
Never,
|
||||
Tup,
|
||||
Path,
|
||||
|
|
|
@ -447,6 +447,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
|
|||
| hir::ExprKind::InlineAsm(..)
|
||||
| hir::ExprKind::OffsetOf(..)
|
||||
| hir::ExprKind::Type(..)
|
||||
| hir::ExprKind::UnsafeBinderCast(..)
|
||||
| hir::ExprKind::Err(_)
|
||||
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
|
||||
| hir::ExprKind::Path(hir::QPath::LangItem(..)) => {}
|
||||
|
@ -1051,6 +1052,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
hir::ExprKind::AddrOf(_, _, ref e)
|
||||
| hir::ExprKind::Cast(ref e, _)
|
||||
| hir::ExprKind::Type(ref e, _)
|
||||
| hir::ExprKind::UnsafeBinderCast(_, ref e, _)
|
||||
| hir::ExprKind::DropTemps(ref e)
|
||||
| hir::ExprKind::Unary(_, ref e)
|
||||
| hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(e, succ),
|
||||
|
@ -1443,6 +1445,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
|
|||
| hir::ExprKind::Path(_)
|
||||
| hir::ExprKind::Yield(..)
|
||||
| hir::ExprKind::Type(..)
|
||||
| hir::ExprKind::UnsafeBinderCast(..)
|
||||
| hir::ExprKind::Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,6 +186,7 @@ impl CheckInlineAssembly {
|
|||
| ExprKind::Lit(..)
|
||||
| ExprKind::Cast(..)
|
||||
| ExprKind::Type(..)
|
||||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Match(..)
|
||||
| ExprKind::If(..)
|
||||
|
|
|
@ -770,7 +770,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
ItemKind::Mod(..) => {
|
||||
ItemKind::Mod(.., ref mod_kind) => {
|
||||
let module = self.r.new_module(
|
||||
Some(parent),
|
||||
ModuleKind::Def(def_kind, def_id, ident.name),
|
||||
|
@ -781,6 +781,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
);
|
||||
self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion));
|
||||
|
||||
if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind {
|
||||
self.r.mods_with_parse_errors.insert(def_id);
|
||||
}
|
||||
|
||||
// Descend into the module.
|
||||
self.parent_scope.module = module;
|
||||
}
|
||||
|
|
|
@ -3056,7 +3056,7 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
|
|||
|
||||
fn visit_item(&mut self, item: &'tcx ast::Item) {
|
||||
if self.target_module == item.id {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans, _)) = &item.kind {
|
||||
let inject = mod_spans.inject_use_span;
|
||||
if is_span_suitable_for_use_injection(inject) {
|
||||
self.first_legal_span = Some(inject);
|
||||
|
|
|
@ -1428,6 +1428,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
ignore_import: Option<Import<'ra>>,
|
||||
) -> PathResult<'ra> {
|
||||
let mut module = None;
|
||||
let mut module_had_parse_errors = false;
|
||||
let mut allow_super = true;
|
||||
let mut second_binding = None;
|
||||
|
||||
|
@ -1471,9 +1472,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
return PathResult::failed(ident, false, finalize.is_some(), module, || {
|
||||
("there are too many leading `super` keywords".to_string(), None)
|
||||
});
|
||||
return PathResult::failed(
|
||||
ident,
|
||||
false,
|
||||
finalize.is_some(),
|
||||
module_had_parse_errors,
|
||||
module,
|
||||
|| ("there are too many leading `super` keywords".to_string(), None),
|
||||
);
|
||||
}
|
||||
if segment_idx == 0 {
|
||||
if name == kw::SelfLower {
|
||||
|
@ -1511,7 +1517,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
|
||||
// Report special messages for path segment keywords in wrong positions.
|
||||
if ident.is_path_segment_keyword() && segment_idx != 0 {
|
||||
return PathResult::failed(ident, false, finalize.is_some(), module, || {
|
||||
return PathResult::failed(
|
||||
ident,
|
||||
false,
|
||||
finalize.is_some(),
|
||||
module_had_parse_errors,
|
||||
module,
|
||||
|| {
|
||||
let name_str = if name == kw::PathRoot {
|
||||
"crate root".to_string()
|
||||
} else {
|
||||
|
@ -1523,7 +1535,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
format!("{name_str} in paths can only be used in start position")
|
||||
};
|
||||
(label, None)
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let binding = if let Some(module) = module {
|
||||
|
@ -1589,6 +1602,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
|
||||
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
|
||||
if let Some(next_module) = binding.module() {
|
||||
if self.mods_with_parse_errors.contains(&next_module.def_id()) {
|
||||
module_had_parse_errors = true;
|
||||
}
|
||||
module = Some(ModuleOrUniformRoot::Module(next_module));
|
||||
record_segment_res(self, res);
|
||||
} else if res == Res::ToolMod && !is_last && opt_ns.is_some() {
|
||||
|
@ -1614,6 +1630,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
ident,
|
||||
is_last,
|
||||
finalize.is_some(),
|
||||
module_had_parse_errors,
|
||||
module,
|
||||
|| {
|
||||
let label = format!(
|
||||
|
@ -1637,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(
|
||||
path,
|
||||
opt_ns,
|
||||
|
@ -1649,7 +1672,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
segment_idx,
|
||||
ident,
|
||||
)
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -670,9 +670,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
|
||||
fn throw_unresolved_import_error(
|
||||
&mut self,
|
||||
errors: Vec<(Import<'_>, UnresolvedImportError)>,
|
||||
mut errors: Vec<(Import<'_>, UnresolvedImportError)>,
|
||||
glob_error: bool,
|
||||
) {
|
||||
errors.retain(|(_import, err)| match err.module {
|
||||
// Skip `use` errors for `use foo::Bar;` if `foo.rs` has unrecovered parse errors.
|
||||
Some(def_id) if self.mods_with_parse_errors.contains(&def_id) => false,
|
||||
_ => true,
|
||||
});
|
||||
if errors.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
@ -898,6 +903,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
label,
|
||||
suggestion,
|
||||
module,
|
||||
error_implied_by_parse_error: _,
|
||||
} => {
|
||||
if no_ambiguity {
|
||||
assert!(import.imported_module.get().is_none());
|
||||
|
|
|
@ -887,6 +887,28 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
|
|||
},
|
||||
)
|
||||
}
|
||||
TyKind::UnsafeBinder(unsafe_binder) => {
|
||||
// FIXME(unsafe_binder): Better span
|
||||
let span = ty.span;
|
||||
self.with_generic_param_rib(
|
||||
&unsafe_binder.generic_params,
|
||||
RibKind::Normal,
|
||||
LifetimeRibKind::Generics {
|
||||
binder: ty.id,
|
||||
kind: LifetimeBinderKind::BareFnType,
|
||||
span,
|
||||
},
|
||||
|this| {
|
||||
this.visit_generic_params(&unsafe_binder.generic_params, false);
|
||||
this.with_lifetime_rib(
|
||||
// We don't allow anonymous `unsafe &'_ ()` binders,
|
||||
// although I guess we could.
|
||||
LifetimeRibKind::AnonymousReportError,
|
||||
|this| this.visit_ty(&unsafe_binder.inner_ty),
|
||||
);
|
||||
},
|
||||
)
|
||||
}
|
||||
TyKind::Array(element_ty, length) => {
|
||||
self.visit_ty(element_ty);
|
||||
self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No));
|
||||
|
@ -4395,6 +4417,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => {
|
||||
PartialRes::new(module.res().unwrap())
|
||||
}
|
||||
// A part of this path references a `mod` that had a parse error. To avoid resolution
|
||||
// errors for each reference to that module, we don't emit an error for them until the
|
||||
// `mod` is fixed. this can have a significant cascade effect.
|
||||
PathResult::Failed { error_implied_by_parse_error: true, .. } => {
|
||||
PartialRes::new(Res::Err)
|
||||
}
|
||||
// In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
|
||||
// don't report an error right away, but try to fallback to a primitive type.
|
||||
// So, we are still able to successfully resolve something like
|
||||
|
@ -4443,6 +4471,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
suggestion,
|
||||
module,
|
||||
segment_name,
|
||||
error_implied_by_parse_error: _,
|
||||
} => {
|
||||
return Err(respan(span, ResolutionError::FailedToResolve {
|
||||
segment: Some(segment_name),
|
||||
|
|
|
@ -450,6 +450,7 @@ enum PathResult<'ra> {
|
|||
module: Option<ModuleOrUniformRoot<'ra>>,
|
||||
/// The segment name of target
|
||||
segment_name: Symbol,
|
||||
error_implied_by_parse_error: bool,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -458,6 +459,7 @@ impl<'ra> PathResult<'ra> {
|
|||
ident: Ident,
|
||||
is_error_from_last_segment: bool,
|
||||
finalize: bool,
|
||||
error_implied_by_parse_error: bool,
|
||||
module: Option<ModuleOrUniformRoot<'ra>>,
|
||||
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
|
||||
) -> PathResult<'ra> {
|
||||
|
@ -470,6 +472,7 @@ impl<'ra> PathResult<'ra> {
|
|||
suggestion,
|
||||
is_error_from_last_segment,
|
||||
module,
|
||||
error_implied_by_parse_error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1198,6 +1201,8 @@ pub struct Resolver<'ra, 'tcx> {
|
|||
/// This is the `Span` where an `extern crate foo;` suggestion would be inserted, if `foo`
|
||||
/// could be a crate that wasn't imported. For diagnostics use only.
|
||||
current_crate_outer_attr_insert_span: Span,
|
||||
|
||||
mods_with_parse_errors: FxHashSet<DefId>,
|
||||
}
|
||||
|
||||
/// This provides memory for the rest of the crate. The `'ra` lifetime that is
|
||||
|
@ -1543,6 +1548,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
impl_unexpanded_invocations: Default::default(),
|
||||
impl_binding_keys: Default::default(),
|
||||
current_crate_outer_attr_insert_span,
|
||||
mods_with_parse_errors: Default::default(),
|
||||
};
|
||||
|
||||
let root_parent_scope = ParentScope::module(graph_root, &resolver);
|
||||
|
|
|
@ -166,7 +166,7 @@ fn soft_custom_inner_attributes_gate(path: &ast::Path, invoc: &Invocation) -> bo
|
|||
[seg1, seg2] if seg1.ident.name == sym::rustfmt && seg2.ident.name == sym::skip => {
|
||||
if let InvocationKind::Attr { item, .. } = &invoc.kind {
|
||||
if let Annotatable::Item(item) = item {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _)) = item.kind {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _, _)) = item.kind {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2105,6 +2105,7 @@ symbols! {
|
|||
unreachable_macro,
|
||||
unrestricted_attribute_tokens,
|
||||
unsafe_attributes,
|
||||
unsafe_binders,
|
||||
unsafe_block_in_unsafe_fn,
|
||||
unsafe_cell,
|
||||
unsafe_cell_raw_get,
|
||||
|
@ -2128,6 +2129,7 @@ symbols! {
|
|||
unwind_attributes,
|
||||
unwind_safe_trait,
|
||||
unwrap,
|
||||
unwrap_binder,
|
||||
unwrap_or,
|
||||
use_extern_macros,
|
||||
use_nested_groups,
|
||||
|
@ -2186,6 +2188,7 @@ symbols! {
|
|||
windows,
|
||||
windows_subsystem,
|
||||
with_negative_coherence,
|
||||
wrap_binder,
|
||||
wrapping_add,
|
||||
wrapping_div,
|
||||
wrapping_mul,
|
||||
|
|
|
@ -354,6 +354,8 @@ pub mod random;
|
|||
pub mod range;
|
||||
pub mod result;
|
||||
pub mod sync;
|
||||
#[unstable(feature = "unsafe_binders", issue = "130516")]
|
||||
pub mod unsafe_binder;
|
||||
|
||||
pub mod fmt;
|
||||
pub mod hash;
|
||||
|
|
|
@ -200,7 +200,7 @@
|
|||
//!
|
||||
//! But it *is* still sound to:
|
||||
//!
|
||||
//! * Create a pointer without provenance from just an address (see [`ptr::dangling`]). Such a
|
||||
//! * Create a pointer without provenance from just an address (see [`without_provenance`]). Such a
|
||||
//! pointer cannot be used for memory accesses (except for zero-sized accesses). This can still be
|
||||
//! useful for sentinel values like `null` *or* to represent a tagged pointer that will never be
|
||||
//! dereferenceable. In general, it is always sound for an integer to pretend to be a pointer "for
|
||||
|
@ -314,8 +314,8 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! (Yes, if you've been using AtomicUsize for pointers in concurrent datastructures, you should
|
||||
//! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers,
|
||||
//! (Yes, if you've been using [`AtomicUsize`] for pointers in concurrent datastructures, you should
|
||||
//! be using [`AtomicPtr`] instead. If that messes up the way you atomically manipulate pointers,
|
||||
//! we would like to know why, and what needs to be done to fix it.)
|
||||
//!
|
||||
//! Situations where a valid pointer *must* be created from just an address, such as baremetal code
|
||||
|
@ -381,7 +381,8 @@
|
|||
//! [`with_addr`]: pointer::with_addr
|
||||
//! [`map_addr`]: pointer::map_addr
|
||||
//! [`addr`]: pointer::addr
|
||||
//! [`ptr::dangling`]: core::ptr::dangling
|
||||
//! [`AtomicUsize`]: crate::sync::atomic::AtomicUsize
|
||||
//! [`AtomicPtr`]: crate::sync::atomic::AtomicPtr
|
||||
//! [`expose_provenance`]: pointer::expose_provenance
|
||||
//! [`with_exposed_provenance`]: with_exposed_provenance
|
||||
//! [Miri]: https://github.com/rust-lang/miri
|
||||
|
|
25
library/core/src/unsafe_binder.rs
Normal file
25
library/core/src/unsafe_binder.rs
Normal 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 )
|
||||
},
|
||||
}
|
|
@ -544,6 +544,8 @@ pub use core::u64;
|
|||
#[stable(feature = "i128", since = "1.26.0")]
|
||||
#[allow(deprecated, deprecated_in_future)]
|
||||
pub use core::u128;
|
||||
#[unstable(feature = "unsafe_binders", issue = "130516")]
|
||||
pub use core::unsafe_binder;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow(deprecated, deprecated_in_future)]
|
||||
pub use core::usize;
|
||||
|
|
|
@ -1841,6 +1841,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
|||
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
|
||||
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
|
||||
TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
|
||||
TyKind::UnsafeBinder(..) => {
|
||||
unimplemented!("unsafe binders are not supported yet")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -819,6 +819,7 @@ impl TyCoercionStability {
|
|||
| TyKind::TraitObject(..)
|
||||
| TyKind::InferDelegation(..)
|
||||
| TyKind::Err(_) => Self::Reborrow,
|
||||
TyKind::UnsafeBinder(..) => Self::None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ impl_lint_pass!(DuplicateMod => [DUPLICATE_MOD]);
|
|||
|
||||
impl EarlyLintPass for DuplicateMod {
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans)) = &item.kind
|
||||
if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, mod_spans, _)) = &item.kind
|
||||
&& let FileName::Real(real) = cx.sess().source_map().span_to_filename(mod_spans.inner_span)
|
||||
&& let Some(local_path) = real.into_local_path()
|
||||
&& let Ok(absolute_path) = local_path.canonicalize()
|
||||
|
|
|
@ -163,7 +163,7 @@ impl Visitor<'_> for NestingVisitor<'_, '_> {
|
|||
}
|
||||
|
||||
match &item.kind {
|
||||
ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _)) => {
|
||||
ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _, _)) => {
|
||||
self.nest_level += 1;
|
||||
|
||||
if !self.check_indent(item.span, item.id) {
|
||||
|
|
|
@ -156,7 +156,8 @@ fn never_loop_expr<'tcx>(
|
|||
| ExprKind::Field(e, _)
|
||||
| ExprKind::AddrOf(_, _, e)
|
||||
| ExprKind::Repeat(e, _)
|
||||
| ExprKind::DropTemps(e) => never_loop_expr(cx, e, local_labels, main_loop_id),
|
||||
| ExprKind::DropTemps(e)
|
||||
| ExprKind::UnsafeBinderCast(_, e, _) => never_loop_expr(cx, e, local_labels, main_loop_id),
|
||||
ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, local_labels, main_loop_id),
|
||||
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, es.iter(), local_labels, main_loop_id),
|
||||
ExprKind::MethodCall(_, receiver, es, _) => {
|
||||
|
|
|
@ -623,6 +623,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
kind!("DropTemps({expr})");
|
||||
self.expr(expr);
|
||||
},
|
||||
ExprKind::UnsafeBinderCast(..) => {
|
||||
unimplemented!("unsafe binders are not implemented yet");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -379,7 +379,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
(Mod(lu, lmk), Mod(ru, rmk)) => {
|
||||
lu == ru
|
||||
&& match (lmk, rmk) {
|
||||
(ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) => {
|
||||
(ModKind::Loaded(litems, linline, _, _), ModKind::Loaded(ritems, rinline, _, _)) => {
|
||||
linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind))
|
||||
},
|
||||
(ModKind::Unloaded, ModKind::Unloaded) => true,
|
||||
|
|
|
@ -303,7 +303,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
|
|||
| ExprKind::AddrOf(..)
|
||||
| ExprKind::Repeat(..)
|
||||
| ExprKind::Block(Block { stmts: [], .. }, _)
|
||||
| ExprKind::OffsetOf(..) => (),
|
||||
| ExprKind::OffsetOf(..)
|
||||
| ExprKind::UnsafeBinderCast(..) => (),
|
||||
|
||||
// Assignment might be to a local defined earlier, so don't eagerly evaluate.
|
||||
// Blocks with multiple statements might be expensive, so don't eagerly evaluate.
|
||||
|
|
|
@ -370,6 +370,10 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
&& self.eq_expr(l_receiver, r_receiver)
|
||||
&& self.eq_exprs(l_args, r_args)
|
||||
},
|
||||
(&ExprKind::UnsafeBinderCast(lkind, le, None), &ExprKind::UnsafeBinderCast(rkind, re, None)) =>
|
||||
lkind == rkind && self.eq_expr(le, re),
|
||||
(&ExprKind::UnsafeBinderCast(lkind, le, Some(lt)), &ExprKind::UnsafeBinderCast(rkind, re, Some(rt))) =>
|
||||
lkind == rkind && self.eq_expr(le, re) && self.eq_ty(lt, rt),
|
||||
(&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => {
|
||||
self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name)
|
||||
},
|
||||
|
@ -424,6 +428,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
| &ExprKind::Type(..)
|
||||
| &ExprKind::Unary(..)
|
||||
| &ExprKind::Yield(..)
|
||||
| &ExprKind::UnsafeBinderCast(..)
|
||||
|
||||
// --- Special cases that do not have a positive branch.
|
||||
|
||||
|
@ -1032,6 +1037,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
std::mem::discriminant(&lop).hash(&mut self.s);
|
||||
self.hash_expr(le);
|
||||
},
|
||||
ExprKind::UnsafeBinderCast(kind, expr, ty) => {
|
||||
std::mem::discriminant(&kind).hash(&mut self.s);
|
||||
self.hash_expr(expr);
|
||||
if let Some(ty) = ty {
|
||||
self.hash_ty(ty);
|
||||
}
|
||||
}
|
||||
ExprKind::Err(_) => {},
|
||||
}
|
||||
}
|
||||
|
@ -1241,6 +1253,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
TyKind::Typeof(anon_const) => {
|
||||
self.hash_body(anon_const.body);
|
||||
},
|
||||
TyKind::UnsafeBinder(binder) => {
|
||||
self.hash_ty(binder.inner_ty);
|
||||
}
|
||||
TyKind::Err(_)
|
||||
| TyKind::Infer
|
||||
| TyKind::Never
|
||||
|
|
|
@ -151,7 +151,8 @@ impl<'a> Sugg<'a> {
|
|||
| ExprKind::Become(..)
|
||||
| ExprKind::Struct(..)
|
||||
| ExprKind::Tup(..)
|
||||
| ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)),
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)),
|
||||
ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
|
||||
ExprKind::Assign(lhs, rhs, _) => {
|
||||
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
|
||||
|
@ -226,7 +227,8 @@ impl<'a> Sugg<'a> {
|
|||
| ast::ExprKind::While(..)
|
||||
| ast::ExprKind::Await(..)
|
||||
| ast::ExprKind::Err(_)
|
||||
| ast::ExprKind::Dummy => Sugg::NonParen(snippet(expr.span)),
|
||||
| ast::ExprKind::Dummy
|
||||
| ast::ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(snippet(expr.span)),
|
||||
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
|
||||
AssocOp::DotDot,
|
||||
lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)),
|
||||
|
|
|
@ -694,6 +694,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
|
|||
| ExprKind::Continue(_)
|
||||
| ExprKind::InlineAsm(_)
|
||||
| ExprKind::OffsetOf(..)
|
||||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::Err(_) => (),
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
|
|
|
@ -413,7 +413,8 @@ pub(crate) fn format_expr(
|
|||
ast::ExprKind::FormatArgs(..)
|
||||
| ast::ExprKind::Type(..)
|
||||
| ast::ExprKind::IncludedBytes(..)
|
||||
| ast::ExprKind::OffsetOf(..) => {
|
||||
| ast::ExprKind::OffsetOf(..)
|
||||
| ast::ExprKind::UnsafeBinderCast(..) => {
|
||||
// These don't normally occur in the AST because macros aren't expanded. However,
|
||||
// rustfmt tries to parse macro arguments when formatting macros, so it's not totally
|
||||
// impossible for rustfmt to come across one of these nodes when formatting a file.
|
||||
|
|
|
@ -3597,7 +3597,7 @@ pub(crate) fn rewrite_extern_crate(
|
|||
pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
|
||||
!matches!(
|
||||
item.kind,
|
||||
ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _))
|
||||
ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -316,12 +316,11 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> {
|
|||
self.directory = directory;
|
||||
}
|
||||
match (sub_mod.ast_mod_kind, sub_mod.items) {
|
||||
(Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => {
|
||||
(Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _, _))), _) => {
|
||||
self.visit_mod_from_ast(items)
|
||||
}
|
||||
(Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => {
|
||||
self.visit_mod_outside_ast(items)
|
||||
}
|
||||
(Some(Cow::Owned(ast::ModKind::Loaded(items, _, _, _))), _)
|
||||
| (_, Cow::Owned(items)) => self.visit_mod_outside_ast(items),
|
||||
(_, _) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1016,6 +1016,31 @@ impl Rewrite for ast::Ty {
|
|||
let pat = pat.rewrite_result(context, shape)?;
|
||||
Ok(format!("{ty} is {pat}"))
|
||||
}
|
||||
ast::TyKind::UnsafeBinder(ref binder) => {
|
||||
let mut result = String::new();
|
||||
if let Some(ref lifetime_str) =
|
||||
rewrite_bound_params(context, shape, &binder.generic_params)
|
||||
{
|
||||
result.push_str("unsafe<");
|
||||
result.push_str(lifetime_str);
|
||||
result.push_str("> ");
|
||||
}
|
||||
|
||||
let inner_ty_shape = if context.use_block_indent() {
|
||||
shape
|
||||
.offset_left(result.len())
|
||||
.max_width_error(shape.width, self.span())?
|
||||
} else {
|
||||
shape
|
||||
.visual_indent(result.len())
|
||||
.sub_width(result.len())
|
||||
.max_width_error(shape.width, self.span())?
|
||||
};
|
||||
|
||||
let rewrite = binder.inner_ty.rewrite_result(context, inner_ty_shape)?;
|
||||
result.push_str(&rewrite);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -504,6 +504,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
|
|||
| ast::ExprKind::IncludedBytes(..)
|
||||
| ast::ExprKind::InlineAsm(..)
|
||||
| ast::ExprKind::OffsetOf(..)
|
||||
| ast::ExprKind::UnsafeBinderCast(..)
|
||||
| ast::ExprKind::Let(..)
|
||||
| ast::ExprKind::Path(..)
|
||||
| ast::ExprKind::Range(..)
|
||||
|
|
|
@ -927,7 +927,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
|||
let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
|
||||
self.push_str(&ident_str);
|
||||
|
||||
if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans) = mod_kind {
|
||||
if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans, _) = mod_kind {
|
||||
let ast::ModSpans {
|
||||
inner_span,
|
||||
inject_use_span: _,
|
||||
|
|
11
src/tools/rustfmt/tests/source/unsafe-binders.rs
Normal file
11
src/tools/rustfmt/tests/source/unsafe-binders.rs
Normal 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 () {}
|
9
src/tools/rustfmt/tests/target/unsafe-binders.rs
Normal file
9
src/tools/rustfmt/tests/target/unsafe-binders.rs
Normal 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 () {}
|
|
@ -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>); }
|
|
@ -1,8 +0,0 @@
|
|||
//@ compile-flags: -Awarnings
|
||||
//@ check-pass
|
||||
|
||||
#[derive()]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Foo;
|
||||
|
||||
pub fn main() {}
|
|
@ -1,5 +0,0 @@
|
|||
//@ run-pass
|
||||
|
||||
fn f() -> isize { { return 3; } }
|
||||
|
||||
pub fn main() { assert_eq!(f(), 3); }
|
|
@ -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);
|
||||
}
|
26
tests/ui/codegen/alias-uninit-value.rs
Normal file
26
tests/ui/codegen/alias-uninit-value.rs
Normal 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
Loading…
Add table
Add a link
Reference in a new issue