mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #133120 - matthiaskrgr:rollup-4actosy, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #131717 (Stabilize `const_atomic_from_ptr`) - #132134 (Remove `ResultsVisitable`) - #132449 (mark is_val_statically_known intrinsic as stably const-callable) - #132569 (rustdoc search: allow queries to end in an empty path segment) - #132787 (Unify FnKind between AST visitors and make WalkItemKind more straight forward) - #132832 (Deny capturing late-bound ty/const params in nested opaques) - #133097 (Opt out TaKO8Ki from review rotation for now) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
1e0df74445
@ -23,7 +23,7 @@ use crate::ast::*;
|
|||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
use crate::token::{self, Token};
|
use crate::token::{self, Token};
|
||||||
use crate::tokenstream::*;
|
use crate::tokenstream::*;
|
||||||
use crate::visit::{AssocCtxt, BoundKind};
|
use crate::visit::{AssocCtxt, BoundKind, FnCtxt};
|
||||||
|
|
||||||
pub trait ExpectOne<A: Array> {
|
pub trait ExpectOne<A: Array> {
|
||||||
fn expect_one(self, err: &'static str) -> A::Item;
|
fn expect_one(self, err: &'static str) -> A::Item;
|
||||||
@ -37,7 +37,16 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait WalkItemKind {
|
pub trait WalkItemKind {
|
||||||
fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor);
|
type Ctxt;
|
||||||
|
fn walk(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
id: NodeId,
|
||||||
|
ident: &mut Ident,
|
||||||
|
visibility: &mut Visibility,
|
||||||
|
ctxt: Self::Ctxt,
|
||||||
|
visitor: &mut impl MutVisitor,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MutVisitor: Sized {
|
pub trait MutVisitor: Sized {
|
||||||
@ -114,9 +123,9 @@ pub trait MutVisitor: Sized {
|
|||||||
fn flat_map_assoc_item(
|
fn flat_map_assoc_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
i: P<AssocItem>,
|
i: P<AssocItem>,
|
||||||
_ctxt: AssocCtxt,
|
ctxt: AssocCtxt,
|
||||||
) -> SmallVec<[P<AssocItem>; 1]> {
|
) -> SmallVec<[P<AssocItem>; 1]> {
|
||||||
walk_flat_map_item(self, i)
|
walk_flat_map_assoc_item(self, i, ctxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
|
fn visit_fn_decl(&mut self, d: &mut P<FnDecl>) {
|
||||||
@ -880,7 +889,7 @@ fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut Coroutin
|
|||||||
|
|
||||||
fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
||||||
match kind {
|
match kind {
|
||||||
FnKind::Fn(FnSig { header, decl, span }, generics, body) => {
|
FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span }, _visibility, generics, body) => {
|
||||||
// Identifier and visibility are visited as a part of the item.
|
// Identifier and visibility are visited as a part of the item.
|
||||||
vis.visit_fn_header(header);
|
vis.visit_fn_header(header);
|
||||||
vis.visit_generics(generics);
|
vis.visit_generics(generics);
|
||||||
@ -890,8 +899,9 @@ fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
|||||||
}
|
}
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
}
|
}
|
||||||
FnKind::Closure(binder, decl, body) => {
|
FnKind::Closure(binder, coroutine_kind, decl, body) => {
|
||||||
vis.visit_closure_binder(binder);
|
vis.visit_closure_binder(binder);
|
||||||
|
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
|
||||||
vis.visit_fn_decl(decl);
|
vis.visit_fn_decl(decl);
|
||||||
vis.visit_expr(body);
|
vis.visit_expr(body);
|
||||||
}
|
}
|
||||||
@ -1079,17 +1089,29 @@ pub fn walk_block<T: MutVisitor>(vis: &mut T, block: &mut P<Block>) {
|
|||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_item_kind(
|
pub fn walk_item_kind<K: WalkItemKind>(
|
||||||
kind: &mut impl WalkItemKind,
|
kind: &mut K,
|
||||||
span: Span,
|
span: Span,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
|
ident: &mut Ident,
|
||||||
|
visibility: &mut Visibility,
|
||||||
|
ctxt: K::Ctxt,
|
||||||
vis: &mut impl MutVisitor,
|
vis: &mut impl MutVisitor,
|
||||||
) {
|
) {
|
||||||
kind.walk(span, id, vis)
|
kind.walk(span, id, ident, visibility, ctxt, vis)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for ItemKind {
|
impl WalkItemKind for ItemKind {
|
||||||
fn walk(&mut self, span: Span, id: NodeId, vis: &mut impl MutVisitor) {
|
type Ctxt = ();
|
||||||
|
fn walk(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
id: NodeId,
|
||||||
|
ident: &mut Ident,
|
||||||
|
visibility: &mut Visibility,
|
||||||
|
_ctxt: Self::Ctxt,
|
||||||
|
vis: &mut impl MutVisitor,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
ItemKind::ExternCrate(_orig_name) => {}
|
ItemKind::ExternCrate(_orig_name) => {}
|
||||||
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
|
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
|
||||||
@ -1102,7 +1124,11 @@ impl WalkItemKind for ItemKind {
|
|||||||
}
|
}
|
||||||
ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||||
visit_defaultness(vis, defaultness);
|
visit_defaultness(vis, defaultness);
|
||||||
vis.visit_fn(FnKind::Fn(sig, generics, body), span, id);
|
vis.visit_fn(
|
||||||
|
FnKind::Fn(FnCtxt::Free, ident, sig, visibility, generics, body),
|
||||||
|
span,
|
||||||
|
id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ItemKind::Mod(safety, mod_kind) => {
|
ItemKind::Mod(safety, mod_kind) => {
|
||||||
visit_safety(vis, safety);
|
visit_safety(vis, safety);
|
||||||
@ -1201,14 +1227,27 @@ impl WalkItemKind for ItemKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for AssocItemKind {
|
impl WalkItemKind for AssocItemKind {
|
||||||
fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
|
type Ctxt = AssocCtxt;
|
||||||
|
fn walk(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
id: NodeId,
|
||||||
|
ident: &mut Ident,
|
||||||
|
visibility: &mut Visibility,
|
||||||
|
ctxt: Self::Ctxt,
|
||||||
|
visitor: &mut impl MutVisitor,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
AssocItemKind::Const(item) => {
|
AssocItemKind::Const(item) => {
|
||||||
visit_const_item(item, visitor);
|
visit_const_item(item, visitor);
|
||||||
}
|
}
|
||||||
AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||||
visit_defaultness(visitor, defaultness);
|
visit_defaultness(visitor, defaultness);
|
||||||
visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
|
visitor.visit_fn(
|
||||||
|
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, visibility, generics, body),
|
||||||
|
span,
|
||||||
|
id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
AssocItemKind::Type(box TyAlias {
|
AssocItemKind::Type(box TyAlias {
|
||||||
defaultness,
|
defaultness,
|
||||||
@ -1288,24 +1327,40 @@ pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) {
|
|||||||
vis.visit_span(inject_use_span);
|
vis.visit_span(inject_use_span);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mutates one item, returning the item again.
|
pub fn walk_flat_map_item<K: WalkItemKind<Ctxt = ()>>(
|
||||||
pub fn walk_flat_map_item<K: WalkItemKind>(
|
visitor: &mut impl MutVisitor,
|
||||||
|
item: P<Item<K>>,
|
||||||
|
) -> SmallVec<[P<Item<K>>; 1]> {
|
||||||
|
walk_flat_map_assoc_item(visitor, item, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_flat_map_assoc_item<K: WalkItemKind>(
|
||||||
visitor: &mut impl MutVisitor,
|
visitor: &mut impl MutVisitor,
|
||||||
mut item: P<Item<K>>,
|
mut item: P<Item<K>>,
|
||||||
|
ctxt: K::Ctxt,
|
||||||
) -> SmallVec<[P<Item<K>>; 1]> {
|
) -> SmallVec<[P<Item<K>>; 1]> {
|
||||||
let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
|
let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
|
||||||
visitor.visit_id(id);
|
visitor.visit_id(id);
|
||||||
visit_attrs(visitor, attrs);
|
visit_attrs(visitor, attrs);
|
||||||
visitor.visit_vis(vis);
|
visitor.visit_vis(vis);
|
||||||
visitor.visit_ident(ident);
|
visitor.visit_ident(ident);
|
||||||
kind.walk(*span, *id, visitor);
|
kind.walk(*span, *id, ident, vis, ctxt, visitor);
|
||||||
visit_lazy_tts(visitor, tokens);
|
visit_lazy_tts(visitor, tokens);
|
||||||
visitor.visit_span(span);
|
visitor.visit_span(span);
|
||||||
smallvec![item]
|
smallvec![item]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for ForeignItemKind {
|
impl WalkItemKind for ForeignItemKind {
|
||||||
fn walk(&mut self, span: Span, id: NodeId, visitor: &mut impl MutVisitor) {
|
type Ctxt = ();
|
||||||
|
fn walk(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
id: NodeId,
|
||||||
|
ident: &mut Ident,
|
||||||
|
visibility: &mut Visibility,
|
||||||
|
_ctxt: Self::Ctxt,
|
||||||
|
visitor: &mut impl MutVisitor,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
|
ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
|
||||||
visitor.visit_ty(ty);
|
visitor.visit_ty(ty);
|
||||||
@ -1313,7 +1368,11 @@ impl WalkItemKind for ForeignItemKind {
|
|||||||
}
|
}
|
||||||
ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
|
||||||
visit_defaultness(visitor, defaultness);
|
visit_defaultness(visitor, defaultness);
|
||||||
visitor.visit_fn(FnKind::Fn(sig, generics, body), span, id);
|
visitor.visit_fn(
|
||||||
|
FnKind::Fn(FnCtxt::Foreign, ident, sig, visibility, generics, body),
|
||||||
|
span,
|
||||||
|
id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ForeignItemKind::TyAlias(box TyAlias {
|
ForeignItemKind::TyAlias(box TyAlias {
|
||||||
defaultness,
|
defaultness,
|
||||||
@ -1522,9 +1581,8 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
|
|||||||
fn_arg_span,
|
fn_arg_span,
|
||||||
}) => {
|
}) => {
|
||||||
visit_constness(vis, constness);
|
visit_constness(vis, constness);
|
||||||
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
|
|
||||||
vis.visit_capture_by(capture_clause);
|
vis.visit_capture_by(capture_clause);
|
||||||
vis.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id);
|
vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id);
|
||||||
vis.visit_span(fn_decl_span);
|
vis.visit_span(fn_decl_span);
|
||||||
vis.visit_span(fn_arg_span);
|
vis.visit_span(fn_arg_span);
|
||||||
}
|
}
|
||||||
@ -1785,8 +1843,20 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FnKind<'a> {
|
pub enum FnKind<'a> {
|
||||||
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
||||||
Fn(&'a mut FnSig, &'a mut Generics, &'a mut Option<P<Block>>),
|
Fn(
|
||||||
|
FnCtxt,
|
||||||
|
&'a mut Ident,
|
||||||
|
&'a mut FnSig,
|
||||||
|
&'a mut Visibility,
|
||||||
|
&'a mut Generics,
|
||||||
|
&'a mut Option<P<Block>>,
|
||||||
|
),
|
||||||
|
|
||||||
/// E.g., `|x, y| body`.
|
/// E.g., `|x, y| body`.
|
||||||
Closure(&'a mut ClosureBinder, &'a mut P<FnDecl>, &'a mut P<Expr>),
|
Closure(
|
||||||
|
&'a mut ClosureBinder,
|
||||||
|
&'a mut Option<CoroutineKind>,
|
||||||
|
&'a mut P<FnDecl>,
|
||||||
|
&'a mut P<Expr>,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ impl BoundKind {
|
|||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum FnKind<'a> {
|
pub enum FnKind<'a> {
|
||||||
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
|
||||||
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
|
Fn(FnCtxt, &'a Ident, &'a FnSig, &'a Visibility, &'a Generics, &'a Option<P<Block>>),
|
||||||
|
|
||||||
/// E.g., `|x, y| body`.
|
/// E.g., `|x, y| body`.
|
||||||
Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
|
Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
|
||||||
@ -112,11 +112,15 @@ pub enum LifetimeCtxt {
|
|||||||
GenericArg,
|
GenericArg,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WalkItemKind: Sized {
|
pub trait WalkItemKind {
|
||||||
|
type Ctxt;
|
||||||
fn walk<'a, V: Visitor<'a>>(
|
fn walk<'a, V: Visitor<'a>>(
|
||||||
&'a self,
|
&'a self,
|
||||||
item: &'a Item<Self>,
|
span: Span,
|
||||||
ctxt: AssocCtxt,
|
id: NodeId,
|
||||||
|
ident: &'a Ident,
|
||||||
|
visibility: &'a Visibility,
|
||||||
|
ctxt: Self::Ctxt,
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
) -> V::Result;
|
) -> V::Result;
|
||||||
}
|
}
|
||||||
@ -340,16 +344,19 @@ pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitR
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for ItemKind {
|
impl WalkItemKind for ItemKind {
|
||||||
|
type Ctxt = ();
|
||||||
fn walk<'a, V: Visitor<'a>>(
|
fn walk<'a, V: Visitor<'a>>(
|
||||||
&'a self,
|
&'a self,
|
||||||
item: &'a Item<Self>,
|
span: Span,
|
||||||
_ctxt: AssocCtxt,
|
id: NodeId,
|
||||||
|
ident: &'a Ident,
|
||||||
|
vis: &'a Visibility,
|
||||||
|
_ctxt: Self::Ctxt,
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
let Item { id, span, vis, ident, .. } = item;
|
|
||||||
match self {
|
match self {
|
||||||
ItemKind::ExternCrate(_rename) => {}
|
ItemKind::ExternCrate(_rename) => {}
|
||||||
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, *id, false)),
|
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, id, false)),
|
||||||
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
|
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
|
||||||
try_visit!(visitor.visit_ty(ty));
|
try_visit!(visitor.visit_ty(ty));
|
||||||
visit_opt!(visitor, visit_expr, expr);
|
visit_opt!(visitor, visit_expr, expr);
|
||||||
@ -360,8 +367,8 @@ impl WalkItemKind for ItemKind {
|
|||||||
visit_opt!(visitor, visit_expr, expr);
|
visit_opt!(visitor, visit_expr, expr);
|
||||||
}
|
}
|
||||||
ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||||
let kind = FnKind::Fn(FnCtxt::Free, *ident, sig, vis, generics, body.as_deref());
|
let kind = FnKind::Fn(FnCtxt::Free, ident, sig, vis, generics, body);
|
||||||
try_visit!(visitor.visit_fn(kind, *span, *id));
|
try_visit!(visitor.visit_fn(kind, span, id));
|
||||||
}
|
}
|
||||||
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
|
||||||
ModKind::Loaded(items, _inline, _inner_span) => {
|
ModKind::Loaded(items, _inline, _inner_span) => {
|
||||||
@ -418,7 +425,7 @@ impl WalkItemKind for ItemKind {
|
|||||||
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
|
||||||
}
|
}
|
||||||
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
|
ItemKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
|
||||||
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, *id)),
|
ItemKind::MacroDef(ts) => try_visit!(visitor.visit_mac_def(ts, id)),
|
||||||
ItemKind::Delegation(box Delegation {
|
ItemKind::Delegation(box Delegation {
|
||||||
id,
|
id,
|
||||||
qself,
|
qself,
|
||||||
@ -434,7 +441,7 @@ impl WalkItemKind for ItemKind {
|
|||||||
}
|
}
|
||||||
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
|
||||||
try_visit!(walk_qself(visitor, qself));
|
try_visit!(walk_qself(visitor, qself));
|
||||||
try_visit!(visitor.visit_path(prefix, *id));
|
try_visit!(visitor.visit_path(prefix, id));
|
||||||
if let Some(suffixes) = suffixes {
|
if let Some(suffixes) = suffixes {
|
||||||
for (ident, rename) in suffixes {
|
for (ident, rename) in suffixes {
|
||||||
visitor.visit_ident(ident);
|
visitor.visit_ident(ident);
|
||||||
@ -452,9 +459,9 @@ impl WalkItemKind for ItemKind {
|
|||||||
|
|
||||||
pub fn walk_item<'a, V: Visitor<'a>>(
|
pub fn walk_item<'a, V: Visitor<'a>>(
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
item: &'a Item<impl WalkItemKind>,
|
item: &'a Item<impl WalkItemKind<Ctxt = ()>>,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
walk_assoc_item(visitor, item, AssocCtxt::Trait /*ignored*/)
|
walk_assoc_item(visitor, item, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_enum_def<'a, V: Visitor<'a>>(
|
pub fn walk_enum_def<'a, V: Visitor<'a>>(
|
||||||
@ -684,20 +691,23 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for ForeignItemKind {
|
impl WalkItemKind for ForeignItemKind {
|
||||||
|
type Ctxt = ();
|
||||||
fn walk<'a, V: Visitor<'a>>(
|
fn walk<'a, V: Visitor<'a>>(
|
||||||
&'a self,
|
&'a self,
|
||||||
item: &'a Item<Self>,
|
span: Span,
|
||||||
_ctxt: AssocCtxt,
|
id: NodeId,
|
||||||
|
ident: &'a Ident,
|
||||||
|
vis: &'a Visibility,
|
||||||
|
_ctxt: Self::Ctxt,
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
let &Item { id, span, ident, ref vis, .. } = item;
|
|
||||||
match self {
|
match self {
|
||||||
ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
|
ForeignItemKind::Static(box StaticItem { ty, mutability: _, expr, safety: _ }) => {
|
||||||
try_visit!(visitor.visit_ty(ty));
|
try_visit!(visitor.visit_ty(ty));
|
||||||
visit_opt!(visitor, visit_expr, expr);
|
visit_opt!(visitor, visit_expr, expr);
|
||||||
}
|
}
|
||||||
ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||||
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
|
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body);
|
||||||
try_visit!(visitor.visit_fn(kind, span, id));
|
try_visit!(visitor.visit_fn(kind, span, id));
|
||||||
}
|
}
|
||||||
ForeignItemKind::TyAlias(box TyAlias {
|
ForeignItemKind::TyAlias(box TyAlias {
|
||||||
@ -850,13 +860,16 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WalkItemKind for AssocItemKind {
|
impl WalkItemKind for AssocItemKind {
|
||||||
|
type Ctxt = AssocCtxt;
|
||||||
fn walk<'a, V: Visitor<'a>>(
|
fn walk<'a, V: Visitor<'a>>(
|
||||||
&'a self,
|
&'a self,
|
||||||
item: &'a Item<Self>,
|
span: Span,
|
||||||
ctxt: AssocCtxt,
|
id: NodeId,
|
||||||
|
ident: &'a Ident,
|
||||||
|
vis: &'a Visibility,
|
||||||
|
ctxt: Self::Ctxt,
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
let &Item { id, span, ident, ref vis, .. } = item;
|
|
||||||
match self {
|
match self {
|
||||||
AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
|
AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
|
||||||
try_visit!(visitor.visit_generics(generics));
|
try_visit!(visitor.visit_generics(generics));
|
||||||
@ -864,8 +877,7 @@ impl WalkItemKind for AssocItemKind {
|
|||||||
visit_opt!(visitor, visit_expr, expr);
|
visit_opt!(visitor, visit_expr, expr);
|
||||||
}
|
}
|
||||||
AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
|
||||||
let kind =
|
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body);
|
||||||
FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
|
|
||||||
try_visit!(visitor.visit_fn(kind, span, id));
|
try_visit!(visitor.visit_fn(kind, span, id));
|
||||||
}
|
}
|
||||||
AssocItemKind::Type(box TyAlias {
|
AssocItemKind::Type(box TyAlias {
|
||||||
@ -913,16 +925,16 @@ impl WalkItemKind for AssocItemKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_assoc_item<'a, V: Visitor<'a>>(
|
pub fn walk_assoc_item<'a, V: Visitor<'a>, K: WalkItemKind>(
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
item: &'a Item<impl WalkItemKind>,
|
item: &'a Item<K>,
|
||||||
ctxt: AssocCtxt,
|
ctxt: K::Ctxt,
|
||||||
) -> V::Result {
|
) -> V::Result {
|
||||||
let Item { id: _, span: _, ident, vis, attrs, kind, tokens: _ } = item;
|
let Item { id, span, ident, vis, attrs, kind, tokens: _ } = item;
|
||||||
walk_list!(visitor, visit_attribute, attrs);
|
walk_list!(visitor, visit_attribute, attrs);
|
||||||
try_visit!(visitor.visit_vis(vis));
|
try_visit!(visitor.visit_vis(vis));
|
||||||
try_visit!(visitor.visit_ident(ident));
|
try_visit!(visitor.visit_ident(ident));
|
||||||
try_visit!(kind.walk(item, ctxt, visitor));
|
try_visit!(kind.walk(*span, *id, ident, vis, ctxt, visitor));
|
||||||
V::Result::output()
|
V::Result::output()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -946,8 +946,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||||||
|
|
||||||
self.visit_vis(&item.vis);
|
self.visit_vis(&item.vis);
|
||||||
self.visit_ident(&item.ident);
|
self.visit_ident(&item.ident);
|
||||||
let kind =
|
let kind = FnKind::Fn(FnCtxt::Free, &item.ident, sig, &item.vis, generics, body);
|
||||||
FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
|
|
||||||
self.visit_fn(kind, item.span, item.id);
|
self.visit_fn(kind, item.span, item.id);
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
walk_list!(self, visit_attribute, &item.attrs);
|
||||||
return; // Avoid visiting again.
|
return; // Avoid visiting again.
|
||||||
@ -1476,14 +1475,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||||||
{
|
{
|
||||||
self.visit_vis(&item.vis);
|
self.visit_vis(&item.vis);
|
||||||
self.visit_ident(&item.ident);
|
self.visit_ident(&item.ident);
|
||||||
let kind = FnKind::Fn(
|
let kind =
|
||||||
FnCtxt::Assoc(ctxt),
|
FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, sig, &item.vis, generics, body);
|
||||||
item.ident,
|
|
||||||
sig,
|
|
||||||
&item.vis,
|
|
||||||
generics,
|
|
||||||
body.as_deref(),
|
|
||||||
);
|
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
walk_list!(self, visit_attribute, &item.attrs);
|
||||||
self.visit_fn(kind, item.span, item.id);
|
self.visit_fn(kind, item.span, item.id);
|
||||||
}
|
}
|
||||||
|
@ -1,93 +1,171 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_data_structures::graph;
|
use rustc_data_structures::graph;
|
||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use rustc_middle::mir::{self, BasicBlock, Body, Location, Place, TerminatorEdges};
|
use rustc_middle::mir::{
|
||||||
|
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
|
||||||
|
};
|
||||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||||
use rustc_mir_dataflow::fmt::DebugWithContext;
|
use rustc_mir_dataflow::fmt::DebugWithContext;
|
||||||
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
|
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
|
||||||
use rustc_mir_dataflow::{Analysis, Forward, GenKill, Results, ResultsVisitable};
|
use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
|
use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
|
||||||
|
|
||||||
/// The results of the dataflow analyses used by the borrow checker.
|
// This analysis is different to most others. Its results aren't computed with
|
||||||
pub(crate) struct BorrowckResults<'a, 'tcx> {
|
// `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are
|
||||||
pub(crate) borrows: Results<'tcx, Borrows<'a, 'tcx>>,
|
// computed individually with `iterate_to_fixpoint`.
|
||||||
pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>,
|
pub(crate) struct Borrowck<'a, 'tcx> {
|
||||||
pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'tcx>>,
|
pub(crate) borrows: Borrows<'a, 'tcx>,
|
||||||
|
pub(crate) uninits: MaybeUninitializedPlaces<'a, 'tcx>,
|
||||||
|
pub(crate) ever_inits: EverInitializedPlaces<'a, 'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
|
||||||
|
type Domain = BorrowckDomain<'a, 'tcx>;
|
||||||
|
|
||||||
|
const NAME: &'static str = "borrowck";
|
||||||
|
|
||||||
|
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
|
||||||
|
BorrowckDomain {
|
||||||
|
borrows: self.borrows.bottom_value(body),
|
||||||
|
uninits: self.uninits.bottom_value(body),
|
||||||
|
ever_inits: self.ever_inits.bottom_value(body),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _state: &mut Self::Domain) {
|
||||||
|
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_before_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_before_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_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);
|
||||||
|
|
||||||
|
// This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
|
||||||
|
// analysis doesn't use.
|
||||||
|
TerminatorEdges::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_call_return_effect(
|
||||||
|
&mut self,
|
||||||
|
_state: &mut Self::Domain,
|
||||||
|
_block: BasicBlock,
|
||||||
|
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||||
|
) {
|
||||||
|
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_switch_int_edge_effects(
|
||||||
|
&mut self,
|
||||||
|
_block: BasicBlock,
|
||||||
|
_discr: &mir::Operand<'tcx>,
|
||||||
|
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
|
||||||
|
) {
|
||||||
|
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
where
|
||||||
|
C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>,
|
||||||
|
{
|
||||||
|
fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("borrows: ")?;
|
||||||
|
self.borrows.fmt_with(ctxt, f)?;
|
||||||
|
f.write_str(" uninits: ")?;
|
||||||
|
self.uninits.fmt_with(ctxt, f)?;
|
||||||
|
f.write_str(" ever_inits: ")?;
|
||||||
|
self.ever_inits.fmt_with(ctxt, f)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if self == old {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.borrows != old.borrows {
|
||||||
|
f.write_str("borrows: ")?;
|
||||||
|
self.borrows.fmt_diff_with(&old.borrows, ctxt, f)?;
|
||||||
|
f.write_str("\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.uninits != old.uninits {
|
||||||
|
f.write_str("uninits: ")?;
|
||||||
|
self.uninits.fmt_diff_with(&old.uninits, ctxt, f)?;
|
||||||
|
f.write_str("\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.ever_inits != old.ever_inits {
|
||||||
|
f.write_str("ever_inits: ")?;
|
||||||
|
self.ever_inits.fmt_diff_with(&old.ever_inits, ctxt, f)?;
|
||||||
|
f.write_str("\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The transient state of the dataflow analyses used by the borrow checker.
|
/// The transient state of the dataflow analyses used by the borrow checker.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub(crate) struct BorrowckDomain<'a, 'tcx> {
|
pub(crate) struct BorrowckDomain<'a, 'tcx> {
|
||||||
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||||
pub(crate) uninits: <MaybeUninitializedPlaces<'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) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
|
|
||||||
type Direction = Forward;
|
|
||||||
type Domain = BorrowckDomain<'a, 'tcx>;
|
|
||||||
|
|
||||||
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
|
|
||||||
BorrowckDomain {
|
|
||||||
borrows: self.borrows.analysis.bottom_value(body),
|
|
||||||
uninits: self.uninits.analysis.bottom_value(body),
|
|
||||||
ever_inits: self.ever_inits.analysis.bottom_value(body),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
|
|
||||||
state.borrows.clone_from(self.borrows.entry_set_for_block(block));
|
|
||||||
state.uninits.clone_from(self.uninits.entry_set_for_block(block));
|
|
||||||
state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_before_statement_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
stmt: &mir::Statement<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc);
|
|
||||||
self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc);
|
|
||||||
self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_statement_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
stmt: &mir::Statement<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc);
|
|
||||||
self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc);
|
|
||||||
self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_before_terminator_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
term: &mir::Terminator<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc);
|
|
||||||
self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc);
|
|
||||||
self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_terminator_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
term: &mir::Terminator<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc);
|
|
||||||
self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc);
|
|
||||||
self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rustc_index::newtype_index! {
|
rustc_index::newtype_index! {
|
||||||
#[orderable]
|
#[orderable]
|
||||||
#[debug_format = "bw{}"]
|
#[debug_format = "bw{}"]
|
||||||
|
@ -36,13 +36,13 @@ use rustc_middle::mir::*;
|
|||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
|
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_mir_dataflow::Analysis;
|
|
||||||
use rustc_mir_dataflow::impls::{
|
use rustc_mir_dataflow::impls::{
|
||||||
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
|
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
|
||||||
};
|
};
|
||||||
use rustc_mir_dataflow::move_paths::{
|
use rustc_mir_dataflow::move_paths::{
|
||||||
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
|
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
|
||||||
};
|
};
|
||||||
|
use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results};
|
||||||
use rustc_session::lint::builtin::UNUSED_MUT;
|
use rustc_session::lint::builtin::UNUSED_MUT;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
@ -50,7 +50,7 @@ use tracing::{debug, instrument};
|
|||||||
|
|
||||||
use crate::borrow_set::{BorrowData, BorrowSet};
|
use crate::borrow_set::{BorrowData, BorrowSet};
|
||||||
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
|
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
|
||||||
use crate::dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows};
|
use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
|
||||||
use crate::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName};
|
use crate::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName};
|
||||||
use crate::location::LocationTable;
|
use crate::location::LocationTable;
|
||||||
use crate::nll::PoloniusOutput;
|
use crate::nll::PoloniusOutput;
|
||||||
@ -221,6 +221,10 @@ fn do_mir_borrowck<'tcx>(
|
|||||||
consumer_options,
|
consumer_options,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// `flow_inits` is large, so we drop it as soon as possible. This reduces
|
||||||
|
// peak memory usage significantly on some benchmarks.
|
||||||
|
drop(flow_inits);
|
||||||
|
|
||||||
// Dump MIR results into a file, if that is enabled. This let us
|
// Dump MIR results into a file, if that is enabled. This let us
|
||||||
// write unit-tests, as well as helping with debugging.
|
// write unit-tests, as well as helping with debugging.
|
||||||
nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
|
nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
|
||||||
@ -229,27 +233,6 @@ fn do_mir_borrowck<'tcx>(
|
|||||||
// information.
|
// information.
|
||||||
nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, &opaque_type_values, diags);
|
nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, &opaque_type_values, diags);
|
||||||
|
|
||||||
// The various `flow_*` structures can be large. We drop `flow_inits` here
|
|
||||||
// so it doesn't overlap with the others below. This reduces peak memory
|
|
||||||
// usage significantly on some benchmarks.
|
|
||||||
drop(flow_inits);
|
|
||||||
|
|
||||||
let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set).iterate_to_fixpoint(
|
|
||||||
tcx,
|
|
||||||
body,
|
|
||||||
Some("borrowck"),
|
|
||||||
);
|
|
||||||
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(
|
|
||||||
tcx,
|
|
||||||
body,
|
|
||||||
Some("borrowck"),
|
|
||||||
);
|
|
||||||
let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(
|
|
||||||
tcx,
|
|
||||||
body,
|
|
||||||
Some("borrowck"),
|
|
||||||
);
|
|
||||||
|
|
||||||
let movable_coroutine =
|
let movable_coroutine =
|
||||||
// The first argument is the coroutine type passed by value
|
// The first argument is the coroutine type passed by value
|
||||||
if let Some(local) = body.local_decls.raw.get(1)
|
if let Some(local) = body.local_decls.raw.get(1)
|
||||||
@ -334,16 +317,11 @@ fn do_mir_borrowck<'tcx>(
|
|||||||
// Compute and report region errors, if any.
|
// Compute and report region errors, if any.
|
||||||
mbcx.report_region_errors(nll_errors);
|
mbcx.report_region_errors(nll_errors);
|
||||||
|
|
||||||
let mut results = BorrowckResults {
|
let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
|
||||||
ever_inits: flow_ever_inits,
|
visit_results(
|
||||||
uninits: flow_uninits,
|
|
||||||
borrows: flow_borrows,
|
|
||||||
};
|
|
||||||
|
|
||||||
rustc_mir_dataflow::visit_results(
|
|
||||||
body,
|
body,
|
||||||
traversal::reverse_postorder(body).map(|(bb, _)| bb),
|
traversal::reverse_postorder(body).map(|(bb, _)| bb),
|
||||||
&mut results,
|
&mut flow_results,
|
||||||
&mut mbcx,
|
&mut mbcx,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -426,6 +404,47 @@ fn do_mir_borrowck<'tcx>(
|
|||||||
(result, body_with_facts)
|
(result, body_with_facts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_flow_results<'a, 'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
body: &'a Body<'tcx>,
|
||||||
|
move_data: &'a MoveData<'tcx>,
|
||||||
|
borrow_set: &'a BorrowSet<'tcx>,
|
||||||
|
regioncx: &RegionInferenceContext<'tcx>,
|
||||||
|
) -> Results<'tcx, Borrowck<'a, 'tcx>> {
|
||||||
|
// We compute these three analyses individually, but them combine them into
|
||||||
|
// a single results so that `mbcx` can visit them all together.
|
||||||
|
let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
Some("borrowck"),
|
||||||
|
);
|
||||||
|
let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
Some("borrowck"),
|
||||||
|
);
|
||||||
|
let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
|
||||||
|
tcx,
|
||||||
|
body,
|
||||||
|
Some("borrowck"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let analysis = Borrowck {
|
||||||
|
borrows: borrows.analysis,
|
||||||
|
uninits: uninits.analysis,
|
||||||
|
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)
|
||||||
|
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Results { analysis, entry_sets }
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct BorrowckInferCtxt<'tcx> {
|
pub(crate) struct BorrowckInferCtxt<'tcx> {
|
||||||
pub(crate) infcx: InferCtxt<'tcx>,
|
pub(crate) infcx: InferCtxt<'tcx>,
|
||||||
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
|
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
|
||||||
@ -588,14 +607,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||||||
// 2. loans made in overlapping scopes do not conflict
|
// 2. loans made in overlapping scopes do not conflict
|
||||||
// 3. assignments do not affect things loaned out as immutable
|
// 3. assignments do not affect things loaned out as immutable
|
||||||
// 4. moves do not affect things loaned out in any way
|
// 4. moves do not affect things loaned out in any way
|
||||||
impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
|
||||||
for MirBorrowckCtxt<'a, '_, 'tcx>
|
|
||||||
{
|
|
||||||
type Domain = BorrowckDomain<'a, 'tcx>;
|
|
||||||
|
|
||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||||
state: &BorrowckDomain<'a, 'tcx>,
|
state: &BorrowckDomain<'a, 'tcx>,
|
||||||
stmt: &'a Statement<'tcx>,
|
stmt: &'a Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
@ -667,7 +682,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
|||||||
|
|
||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||||
state: &BorrowckDomain<'a, 'tcx>,
|
state: &BorrowckDomain<'a, 'tcx>,
|
||||||
term: &'a Terminator<'tcx>,
|
term: &'a Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
@ -780,7 +795,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
|||||||
|
|
||||||
fn visit_terminator_after_primary_effect(
|
fn visit_terminator_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
|
||||||
state: &BorrowckDomain<'a, 'tcx>,
|
state: &BorrowckDomain<'a, 'tcx>,
|
||||||
term: &'a Terminator<'tcx>,
|
term: &'a Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
|
@ -204,10 +204,10 @@ impl MutVisitor for CfgEval<'_> {
|
|||||||
fn flat_map_assoc_item(
|
fn flat_map_assoc_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
item: P<ast::AssocItem>,
|
item: P<ast::AssocItem>,
|
||||||
_ctxt: AssocCtxt,
|
ctxt: AssocCtxt,
|
||||||
) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
) -> SmallVec<[P<ast::AssocItem>; 1]> {
|
||||||
let item = configure!(self, item);
|
let item = configure!(self, item);
|
||||||
mut_visit::walk_flat_map_item(self, item)
|
mut_visit::walk_flat_map_assoc_item(self, item, ctxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flat_map_foreign_item(
|
fn flat_map_foreign_item(
|
||||||
|
@ -144,7 +144,15 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
|||||||
item.kind
|
item.kind
|
||||||
{
|
{
|
||||||
let prev_tests = mem::take(&mut self.tests);
|
let prev_tests = mem::take(&mut self.tests);
|
||||||
walk_item_kind(&mut item.kind, item.span, item.id, self);
|
walk_item_kind(
|
||||||
|
&mut item.kind,
|
||||||
|
item.span,
|
||||||
|
item.id,
|
||||||
|
&mut item.ident,
|
||||||
|
&mut item.vis,
|
||||||
|
(),
|
||||||
|
self,
|
||||||
|
);
|
||||||
self.add_test_cases(item.id, span, prev_tests);
|
self.add_test_cases(item.id, span, prev_tests);
|
||||||
} else {
|
} else {
|
||||||
// But in those cases, we emit a lint to warn the user of these missing tests.
|
// But in those cases, we emit a lint to warn the user of these missing tests.
|
||||||
|
@ -1303,7 +1303,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
|
|||||||
fragment.make_trait_items()
|
fragment.make_trait_items()
|
||||||
}
|
}
|
||||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||||
walk_flat_map_item(visitor, self.wrapped)
|
walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Trait)
|
||||||
}
|
}
|
||||||
fn is_mac_call(&self) -> bool {
|
fn is_mac_call(&self) -> bool {
|
||||||
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
||||||
@ -1344,7 +1344,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
|
|||||||
fragment.make_impl_items()
|
fragment.make_impl_items()
|
||||||
}
|
}
|
||||||
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
fn walk_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
|
||||||
walk_flat_map_item(visitor, self.wrapped)
|
walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl)
|
||||||
}
|
}
|
||||||
fn is_mac_call(&self) -> bool {
|
fn is_mac_call(&self) -> bool {
|
||||||
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
|
||||||
|
@ -286,7 +286,7 @@ impl MutVisitor for PlaceholderExpander {
|
|||||||
AssocCtxt::Impl => it.make_impl_items(),
|
AssocCtxt::Impl => it.make_impl_items(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => walk_flat_map_item(self, item),
|
_ => walk_flat_map_assoc_item(self, item, ctxt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +177,7 @@ enum Scope<'a> {
|
|||||||
LateBoundary {
|
LateBoundary {
|
||||||
s: ScopeRef<'a>,
|
s: ScopeRef<'a>,
|
||||||
what: &'static str,
|
what: &'static str,
|
||||||
|
deny_late_regions: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
Root {
|
Root {
|
||||||
@ -234,9 +235,11 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
|
|||||||
.field("s", &"..")
|
.field("s", &"..")
|
||||||
.finish(),
|
.finish(),
|
||||||
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
|
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
|
||||||
Scope::LateBoundary { s: _, what } => {
|
Scope::LateBoundary { s: _, what, deny_late_regions } => f
|
||||||
f.debug_struct("LateBoundary").field("what", what).finish()
|
.debug_struct("LateBoundary")
|
||||||
}
|
.field("what", what)
|
||||||
|
.field("deny_late_regions", deny_late_regions)
|
||||||
|
.finish(),
|
||||||
Scope::Root { opt_parent_item } => {
|
Scope::Root { opt_parent_item } => {
|
||||||
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
|
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
|
||||||
}
|
}
|
||||||
@ -573,17 +576,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||||||
// give, we will reverse the IndexMap after early captures.
|
// give, we will reverse the IndexMap after early captures.
|
||||||
let mut late_depth = 0;
|
let mut late_depth = 0;
|
||||||
let mut scope = self.scope;
|
let mut scope = self.scope;
|
||||||
let mut crossed_late_boundary = None;
|
|
||||||
let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)];
|
let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)];
|
||||||
loop {
|
loop {
|
||||||
match *scope {
|
match *scope {
|
||||||
Scope::Binder { ref bound_vars, scope_type, s, .. } => {
|
Scope::Binder { ref bound_vars, scope_type, s, .. } => {
|
||||||
for (&original_lifetime, &def) in bound_vars.iter().rev() {
|
for (&original_lifetime, &def) in bound_vars.iter().rev() {
|
||||||
if let ResolvedArg::LateBound(..) = def
|
|
||||||
&& crossed_late_boundary.is_some()
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) {
|
if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) {
|
||||||
let def = def.shifted(late_depth);
|
let def = def.shifted(late_depth);
|
||||||
let ident = lifetime_ident(original_lifetime);
|
let ident = lifetime_ident(original_lifetime);
|
||||||
@ -624,12 +621,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||||||
|
|
||||||
Scope::ObjectLifetimeDefault { s, .. }
|
Scope::ObjectLifetimeDefault { s, .. }
|
||||||
| Scope::Supertrait { s, .. }
|
| Scope::Supertrait { s, .. }
|
||||||
| Scope::TraitRefBoundary { s, .. } => {
|
| Scope::TraitRefBoundary { s, .. }
|
||||||
scope = s;
|
| Scope::LateBoundary { s, .. } => {
|
||||||
}
|
|
||||||
|
|
||||||
Scope::LateBoundary { s, what, .. } => {
|
|
||||||
crossed_late_boundary = Some(what);
|
|
||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -640,7 +633,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||||||
let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope };
|
let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope };
|
||||||
self.with(scope, |this| {
|
self.with(scope, |this| {
|
||||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||||
this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
|
this.with(scope, |this| {
|
||||||
|
let scope = Scope::LateBoundary {
|
||||||
|
s: this.scope,
|
||||||
|
what: "nested `impl Trait`",
|
||||||
|
// We can capture late-bound regions; we just don't duplicate
|
||||||
|
// lifetime or const params, so we can't allow those.
|
||||||
|
deny_late_regions: false,
|
||||||
|
};
|
||||||
|
this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let captures = captures.into_inner().into_iter().collect();
|
let captures = captures.into_inner().into_iter().collect();
|
||||||
@ -997,9 +999,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
|
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
|
||||||
self.with(Scope::LateBoundary { s: self.scope, what: "constant" }, |this| {
|
self.with(
|
||||||
intravisit::walk_anon_const(this, c);
|
Scope::LateBoundary { s: self.scope, what: "constant", deny_late_regions: true },
|
||||||
});
|
|this| {
|
||||||
|
intravisit::walk_anon_const(this, c);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
|
fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
|
||||||
@ -1291,8 +1296,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope::LateBoundary { s, what } => {
|
Scope::LateBoundary { s, what, deny_late_regions } => {
|
||||||
crossed_late_boundary = Some(what);
|
if deny_late_regions {
|
||||||
|
crossed_late_boundary = Some(what);
|
||||||
|
}
|
||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1508,7 +1515,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope::LateBoundary { s, what } => {
|
Scope::LateBoundary { s, what, deny_late_regions: _ } => {
|
||||||
crossed_late_boundary = Some(what);
|
crossed_late_boundary = Some(what);
|
||||||
scope = s;
|
scope = s;
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ use rustc_middle::mir::{
|
|||||||
self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges,
|
self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::visitor::{ResultsVisitable, ResultsVisitor};
|
use super::visitor::ResultsVisitor;
|
||||||
use super::{Analysis, Effect, EffectIndex, SwitchIntTarget};
|
use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget};
|
||||||
|
|
||||||
pub trait Direction {
|
pub trait Direction {
|
||||||
const IS_FORWARD: bool;
|
const IS_FORWARD: bool;
|
||||||
@ -33,14 +33,14 @@ pub trait Direction {
|
|||||||
where
|
where
|
||||||
A: Analysis<'tcx>;
|
A: Analysis<'tcx>;
|
||||||
|
|
||||||
fn visit_results_in_block<'mir, 'tcx, D, R>(
|
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||||
state: &mut D,
|
state: &mut A::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||||
results: &mut R,
|
results: &mut Results<'tcx, A>,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||||
) where
|
) where
|
||||||
R: ResultsVisitable<'tcx, Domain = D>;
|
A: Analysis<'tcx>;
|
||||||
|
|
||||||
fn join_state_into_successors_of<'tcx, A>(
|
fn join_state_into_successors_of<'tcx, A>(
|
||||||
analysis: &mut A,
|
analysis: &mut A,
|
||||||
@ -53,7 +53,7 @@ pub trait Direction {
|
|||||||
A: Analysis<'tcx>;
|
A: Analysis<'tcx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dataflow that runs from the exit of a block (the terminator), to its entry (the first statement).
|
/// Dataflow that runs from the exit of a block (terminator), to its entry (the first statement).
|
||||||
pub struct Backward;
|
pub struct Backward;
|
||||||
|
|
||||||
impl Direction for Backward {
|
impl Direction for Backward {
|
||||||
@ -157,32 +157,32 @@ impl Direction for Backward {
|
|||||||
analysis.apply_statement_effect(state, statement, location);
|
analysis.apply_statement_effect(state, statement, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_results_in_block<'mir, 'tcx, D, R>(
|
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||||
state: &mut D,
|
state: &mut A::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||||
results: &mut R,
|
results: &mut Results<'tcx, A>,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||||
) where
|
) where
|
||||||
R: ResultsVisitable<'tcx, Domain = D>,
|
A: Analysis<'tcx>,
|
||||||
{
|
{
|
||||||
results.reset_to_block_entry(state, block);
|
state.clone_from(results.entry_set_for_block(block));
|
||||||
|
|
||||||
vis.visit_block_end(state);
|
vis.visit_block_end(state);
|
||||||
|
|
||||||
// Terminator
|
// Terminator
|
||||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||||
let term = block_data.terminator();
|
let term = block_data.terminator();
|
||||||
results.reconstruct_before_terminator_effect(state, term, loc);
|
results.analysis.apply_before_terminator_effect(state, term, loc);
|
||||||
vis.visit_terminator_before_primary_effect(results, state, term, loc);
|
vis.visit_terminator_before_primary_effect(results, state, term, loc);
|
||||||
results.reconstruct_terminator_effect(state, term, loc);
|
results.analysis.apply_terminator_effect(state, term, loc);
|
||||||
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
||||||
|
|
||||||
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
|
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
|
||||||
let loc = Location { block, statement_index };
|
let loc = Location { block, statement_index };
|
||||||
results.reconstruct_before_statement_effect(state, stmt, loc);
|
results.analysis.apply_before_statement_effect(state, stmt, loc);
|
||||||
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
|
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
|
||||||
results.reconstruct_statement_effect(state, stmt, loc);
|
results.analysis.apply_statement_effect(state, stmt, loc);
|
||||||
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,32 +389,32 @@ impl Direction for Forward {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_results_in_block<'mir, 'tcx, F, R>(
|
fn visit_results_in_block<'mir, 'tcx, A>(
|
||||||
state: &mut F,
|
state: &mut A::Domain,
|
||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
block_data: &'mir mir::BasicBlockData<'tcx>,
|
block_data: &'mir mir::BasicBlockData<'tcx>,
|
||||||
results: &mut R,
|
results: &mut Results<'tcx, A>,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = F>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||||
) where
|
) where
|
||||||
R: ResultsVisitable<'tcx, Domain = F>,
|
A: Analysis<'tcx>,
|
||||||
{
|
{
|
||||||
results.reset_to_block_entry(state, block);
|
state.clone_from(results.entry_set_for_block(block));
|
||||||
|
|
||||||
vis.visit_block_start(state);
|
vis.visit_block_start(state);
|
||||||
|
|
||||||
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
|
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
|
||||||
let loc = Location { block, statement_index };
|
let loc = Location { block, statement_index };
|
||||||
results.reconstruct_before_statement_effect(state, stmt, loc);
|
results.analysis.apply_before_statement_effect(state, stmt, loc);
|
||||||
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
|
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
|
||||||
results.reconstruct_statement_effect(state, stmt, loc);
|
results.analysis.apply_statement_effect(state, stmt, loc);
|
||||||
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
let loc = Location { block, statement_index: block_data.statements.len() };
|
let loc = Location { block, statement_index: block_data.statements.len() };
|
||||||
let term = block_data.terminator();
|
let term = block_data.terminator();
|
||||||
results.reconstruct_before_terminator_effect(state, term, loc);
|
results.analysis.apply_before_terminator_effect(state, term, loc);
|
||||||
vis.visit_terminator_before_primary_effect(results, state, term, loc);
|
vis.visit_terminator_before_primary_effect(results, state, term, loc);
|
||||||
results.reconstruct_terminator_effect(state, term, loc);
|
results.analysis.apply_terminator_effect(state, term, loc);
|
||||||
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
vis.visit_terminator_after_primary_effect(results, state, term, loc);
|
||||||
|
|
||||||
vis.visit_block_end(state);
|
vis.visit_block_end(state);
|
||||||
|
@ -544,20 +544,18 @@ impl<D> StateDiffCollector<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, A> ResultsVisitor<'_, 'tcx, Results<'tcx, A>> for StateDiffCollector<A::Domain>
|
impl<'tcx, A> ResultsVisitor<'_, 'tcx, A> for StateDiffCollector<A::Domain>
|
||||||
where
|
where
|
||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
A::Domain: DebugWithContext<A>,
|
A::Domain: DebugWithContext<A>,
|
||||||
{
|
{
|
||||||
type Domain = A::Domain;
|
fn visit_block_start(&mut self, state: &A::Domain) {
|
||||||
|
|
||||||
fn visit_block_start(&mut self, state: &Self::Domain) {
|
|
||||||
if A::Direction::IS_FORWARD {
|
if A::Direction::IS_FORWARD {
|
||||||
self.prev_state.clone_from(state);
|
self.prev_state.clone_from(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_block_end(&mut self, state: &Self::Domain) {
|
fn visit_block_end(&mut self, state: &A::Domain) {
|
||||||
if A::Direction::IS_BACKWARD {
|
if A::Direction::IS_BACKWARD {
|
||||||
self.prev_state.clone_from(state);
|
self.prev_state.clone_from(state);
|
||||||
}
|
}
|
||||||
@ -566,7 +564,7 @@ where
|
|||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
results: &mut Results<'tcx, A>,
|
results: &mut Results<'tcx, A>,
|
||||||
state: &Self::Domain,
|
state: &A::Domain,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
@ -579,7 +577,7 @@ where
|
|||||||
fn visit_statement_after_primary_effect(
|
fn visit_statement_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
results: &mut Results<'tcx, A>,
|
results: &mut Results<'tcx, A>,
|
||||||
state: &Self::Domain,
|
state: &A::Domain,
|
||||||
_statement: &mir::Statement<'tcx>,
|
_statement: &mir::Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
@ -590,7 +588,7 @@ where
|
|||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
results: &mut Results<'tcx, A>,
|
results: &mut Results<'tcx, A>,
|
||||||
state: &Self::Domain,
|
state: &A::Domain,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
@ -603,7 +601,7 @@ where
|
|||||||
fn visit_terminator_after_primary_effect(
|
fn visit_terminator_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
results: &mut Results<'tcx, A>,
|
results: &mut Results<'tcx, A>,
|
||||||
state: &Self::Domain,
|
state: &A::Domain,
|
||||||
_terminator: &mir::Terminator<'tcx>,
|
_terminator: &mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
|
@ -55,8 +55,8 @@ mod visitor;
|
|||||||
pub use self::cursor::ResultsCursor;
|
pub use self::cursor::ResultsCursor;
|
||||||
pub use self::direction::{Backward, Direction, Forward};
|
pub use self::direction::{Backward, Direction, Forward};
|
||||||
pub use self::lattice::{JoinSemiLattice, MaybeReachable};
|
pub use self::lattice::{JoinSemiLattice, MaybeReachable};
|
||||||
pub use self::results::Results;
|
pub use self::results::{EntrySets, Results};
|
||||||
pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};
|
pub use self::visitor::{ResultsVisitor, visit_results};
|
||||||
|
|
||||||
/// Analysis domains are all bitsets of various kinds. This trait holds
|
/// Analysis domains are all bitsets of various kinds. This trait holds
|
||||||
/// operations needed by all of them.
|
/// operations needed by all of them.
|
||||||
|
@ -18,7 +18,7 @@ use crate::errors::{
|
|||||||
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
|
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
|
||||||
};
|
};
|
||||||
|
|
||||||
type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
|
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
|
||||||
|
|
||||||
/// A dataflow analysis that has converged to fixpoint.
|
/// A dataflow analysis that has converged to fixpoint.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -27,7 +27,7 @@ where
|
|||||||
A: Analysis<'tcx>,
|
A: Analysis<'tcx>,
|
||||||
{
|
{
|
||||||
pub analysis: A,
|
pub analysis: A,
|
||||||
pub(super) entry_sets: EntrySets<'tcx, A>,
|
pub entry_sets: EntrySets<'tcx, A>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, A> Results<'tcx, A>
|
impl<'tcx, A> Results<'tcx, A>
|
||||||
@ -51,7 +51,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
body: &'mir mir::Body<'tcx>,
|
body: &'mir mir::Body<'tcx>,
|
||||||
blocks: impl IntoIterator<Item = BasicBlock>,
|
blocks: impl IntoIterator<Item = BasicBlock>,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||||
) {
|
) {
|
||||||
visit_results(body, blocks, self, vis)
|
visit_results(body, blocks, self, vis)
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ where
|
|||||||
pub fn visit_reachable_with<'mir>(
|
pub fn visit_reachable_with<'mir>(
|
||||||
&mut self,
|
&mut self,
|
||||||
body: &'mir mir::Body<'tcx>,
|
body: &'mir mir::Body<'tcx>,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||||
) {
|
) {
|
||||||
let blocks = traversal::reachable(body);
|
let blocks = traversal::reachable(body);
|
||||||
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
|
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
|
||||||
|
@ -4,15 +4,15 @@ use super::{Analysis, Direction, Results};
|
|||||||
|
|
||||||
/// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
|
/// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
|
||||||
/// dataflow state at that location.
|
/// dataflow state at that location.
|
||||||
pub fn visit_results<'mir, 'tcx, D, R>(
|
pub fn visit_results<'mir, 'tcx, A>(
|
||||||
body: &'mir mir::Body<'tcx>,
|
body: &'mir mir::Body<'tcx>,
|
||||||
blocks: impl IntoIterator<Item = BasicBlock>,
|
blocks: impl IntoIterator<Item = BasicBlock>,
|
||||||
results: &mut R,
|
results: &mut Results<'tcx, A>,
|
||||||
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
|
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
|
||||||
) where
|
) where
|
||||||
R: ResultsVisitable<'tcx, Domain = D>,
|
A: Analysis<'tcx>,
|
||||||
{
|
{
|
||||||
let mut state = results.bottom_value(body);
|
let mut state = results.analysis.bottom_value(body);
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
let reachable_blocks = mir::traversal::reachable_as_bitset(body);
|
let reachable_blocks = mir::traversal::reachable_as_bitset(body);
|
||||||
@ -22,23 +22,23 @@ pub fn visit_results<'mir, 'tcx, D, R>(
|
|||||||
assert!(reachable_blocks.contains(block));
|
assert!(reachable_blocks.contains(block));
|
||||||
|
|
||||||
let block_data = &body[block];
|
let block_data = &body[block];
|
||||||
R::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
|
A::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being
|
/// A visitor over the results of an `Analysis`.
|
||||||
/// visited.
|
pub trait ResultsVisitor<'mir, 'tcx, A>
|
||||||
pub trait ResultsVisitor<'mir, 'tcx, R> {
|
where
|
||||||
type Domain;
|
A: Analysis<'tcx>,
|
||||||
|
{
|
||||||
fn visit_block_start(&mut self, _state: &Self::Domain) {}
|
fn visit_block_start(&mut self, _state: &A::Domain) {}
|
||||||
|
|
||||||
/// Called with the `before_statement_effect` of the given statement applied to `state` but not
|
/// Called with the `before_statement_effect` of the given statement applied to `state` but not
|
||||||
/// its `statement_effect`.
|
/// its `statement_effect`.
|
||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, A>,
|
||||||
_state: &Self::Domain,
|
_state: &A::Domain,
|
||||||
_statement: &'mir mir::Statement<'tcx>,
|
_statement: &'mir mir::Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
@ -48,19 +48,19 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
|
|||||||
/// statement applied to `state`.
|
/// statement applied to `state`.
|
||||||
fn visit_statement_after_primary_effect(
|
fn visit_statement_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, A>,
|
||||||
_state: &Self::Domain,
|
_state: &A::Domain,
|
||||||
_statement: &'mir mir::Statement<'tcx>,
|
_statement: &'mir mir::Statement<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called with the `before_terminator_effect` of the given terminator applied to `state` but not
|
/// Called with the `before_terminator_effect` of the given terminator applied to `state` but
|
||||||
/// its `terminator_effect`.
|
/// not its `terminator_effect`.
|
||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, A>,
|
||||||
_state: &Self::Domain,
|
_state: &A::Domain,
|
||||||
_terminator: &'mir mir::Terminator<'tcx>,
|
_terminator: &'mir mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
@ -72,109 +72,12 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
|
|||||||
/// The `call_return_effect` (if one exists) will *not* be applied to `state`.
|
/// The `call_return_effect` (if one exists) will *not* be applied to `state`.
|
||||||
fn visit_terminator_after_primary_effect(
|
fn visit_terminator_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, A>,
|
||||||
_state: &Self::Domain,
|
_state: &A::Domain,
|
||||||
_terminator: &'mir mir::Terminator<'tcx>,
|
_terminator: &'mir mir::Terminator<'tcx>,
|
||||||
_location: Location,
|
_location: Location,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_block_end(&mut self, _state: &Self::Domain) {}
|
fn visit_block_end(&mut self, _state: &A::Domain) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// Things that can be visited by a `ResultsVisitor`.
|
|
||||||
///
|
|
||||||
/// This trait exists so that we can visit the results of one or more dataflow analyses
|
|
||||||
/// simultaneously.
|
|
||||||
pub trait ResultsVisitable<'tcx> {
|
|
||||||
type Direction: Direction;
|
|
||||||
type Domain;
|
|
||||||
|
|
||||||
/// Creates an empty `Domain` to hold the transient state for these dataflow results.
|
|
||||||
///
|
|
||||||
/// The value of the newly created `Domain` will be overwritten by `reset_to_block_entry`
|
|
||||||
/// before it can be observed by a `ResultsVisitor`.
|
|
||||||
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain;
|
|
||||||
|
|
||||||
fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock);
|
|
||||||
|
|
||||||
fn reconstruct_before_statement_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
statement: &mir::Statement<'tcx>,
|
|
||||||
location: Location,
|
|
||||||
);
|
|
||||||
|
|
||||||
fn reconstruct_statement_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
statement: &mir::Statement<'tcx>,
|
|
||||||
location: Location,
|
|
||||||
);
|
|
||||||
|
|
||||||
fn reconstruct_before_terminator_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
terminator: &mir::Terminator<'tcx>,
|
|
||||||
location: Location,
|
|
||||||
);
|
|
||||||
|
|
||||||
fn reconstruct_terminator_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
terminator: &mir::Terminator<'tcx>,
|
|
||||||
location: Location,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
|
|
||||||
where
|
|
||||||
A: Analysis<'tcx>,
|
|
||||||
{
|
|
||||||
type Domain = A::Domain;
|
|
||||||
type Direction = A::Direction;
|
|
||||||
|
|
||||||
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
|
|
||||||
self.analysis.bottom_value(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
|
|
||||||
state.clone_from(self.entry_set_for_block(block));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_before_statement_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
stmt: &mir::Statement<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.analysis.apply_before_statement_effect(state, stmt, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_statement_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
stmt: &mir::Statement<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.analysis.apply_statement_effect(state, stmt, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_before_terminator_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
term: &mir::Terminator<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.analysis.apply_before_terminator_effect(state, term, loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconstruct_terminator_effect(
|
|
||||||
&mut self,
|
|
||||||
state: &mut Self::Domain,
|
|
||||||
term: &mir::Terminator<'tcx>,
|
|
||||||
loc: Location,
|
|
||||||
) {
|
|
||||||
self.analysis.apply_terminator_effect(state, term, loc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ pub use self::drop_flag_effects::{
|
|||||||
move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
|
move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
|
||||||
};
|
};
|
||||||
pub use self::framework::{
|
pub use self::framework::{
|
||||||
Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results,
|
Analysis, Backward, Direction, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable,
|
||||||
ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
|
Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
|
||||||
visit_results,
|
visit_results,
|
||||||
};
|
};
|
||||||
use self::move_paths::MoveData;
|
use self::move_paths::MoveData;
|
||||||
|
@ -3,7 +3,7 @@ use rustc_index::interval::SparseIntervalMatrix;
|
|||||||
use rustc_index::{Idx, IndexVec};
|
use rustc_index::{Idx, IndexVec};
|
||||||
use rustc_middle::mir::{self, BasicBlock, Body, Location};
|
use rustc_middle::mir::{self, BasicBlock, Body, Location};
|
||||||
|
|
||||||
use crate::framework::{ResultsVisitable, ResultsVisitor, visit_results};
|
use crate::framework::{Analysis, Results, ResultsVisitor, visit_results};
|
||||||
|
|
||||||
/// Maps between a `Location` and a `PointIndex` (and vice versa).
|
/// Maps between a `Location` and a `PointIndex` (and vice versa).
|
||||||
pub struct DenseLocationMap {
|
pub struct DenseLocationMap {
|
||||||
@ -95,14 +95,14 @@ rustc_index::newtype_index! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add points depending on the result of the given dataflow analysis.
|
/// Add points depending on the result of the given dataflow analysis.
|
||||||
pub fn save_as_intervals<'tcx, N, R>(
|
pub fn save_as_intervals<'tcx, N, A>(
|
||||||
elements: &DenseLocationMap,
|
elements: &DenseLocationMap,
|
||||||
body: &mir::Body<'tcx>,
|
body: &mir::Body<'tcx>,
|
||||||
mut results: R,
|
mut results: Results<'tcx, A>,
|
||||||
) -> SparseIntervalMatrix<N, PointIndex>
|
) -> SparseIntervalMatrix<N, PointIndex>
|
||||||
where
|
where
|
||||||
N: Idx,
|
N: Idx,
|
||||||
R: ResultsVisitable<'tcx, Domain = BitSet<N>>,
|
A: Analysis<'tcx, Domain = BitSet<N>>,
|
||||||
{
|
{
|
||||||
let values = SparseIntervalMatrix::new(elements.num_points());
|
let values = SparseIntervalMatrix::new(elements.num_points());
|
||||||
let mut visitor = Visitor { elements, values };
|
let mut visitor = Visitor { elements, values };
|
||||||
@ -120,16 +120,15 @@ struct Visitor<'a, N: Idx> {
|
|||||||
values: SparseIntervalMatrix<N, PointIndex>,
|
values: SparseIntervalMatrix<N, PointIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N>
|
impl<'mir, 'tcx, A, N> ResultsVisitor<'mir, 'tcx, A> for Visitor<'_, N>
|
||||||
where
|
where
|
||||||
|
A: Analysis<'tcx, Domain = BitSet<N>>,
|
||||||
N: Idx,
|
N: Idx,
|
||||||
{
|
{
|
||||||
type Domain = BitSet<N>;
|
|
||||||
|
|
||||||
fn visit_statement_after_primary_effect(
|
fn visit_statement_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, A>,
|
||||||
state: &Self::Domain,
|
state: &A::Domain,
|
||||||
_statement: &'mir mir::Statement<'tcx>,
|
_statement: &'mir mir::Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
@ -142,8 +141,8 @@ where
|
|||||||
|
|
||||||
fn visit_terminator_after_primary_effect(
|
fn visit_terminator_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, A>,
|
||||||
state: &Self::Domain,
|
state: &A::Domain,
|
||||||
_terminator: &'mir mir::Terminator<'tcx>,
|
_terminator: &'mir mir::Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
|
@ -68,11 +68,11 @@ use rustc_middle::ty::{
|
|||||||
self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode,
|
self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode,
|
||||||
};
|
};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_mir_dataflow::Analysis;
|
|
||||||
use rustc_mir_dataflow::impls::{
|
use rustc_mir_dataflow::impls::{
|
||||||
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
|
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
|
||||||
};
|
};
|
||||||
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
use rustc_mir_dataflow::storage::always_storage_live_locals;
|
||||||
|
use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_span::def_id::{DefId, LocalDefId};
|
use rustc_span::def_id::{DefId, LocalDefId};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
@ -817,9 +817,9 @@ impl ops::Deref for CoroutineSavedLocals {
|
|||||||
/// computation; see `CoroutineLayout` for more.
|
/// computation; see `CoroutineLayout` for more.
|
||||||
fn compute_storage_conflicts<'mir, 'tcx>(
|
fn compute_storage_conflicts<'mir, 'tcx>(
|
||||||
body: &'mir Body<'tcx>,
|
body: &'mir Body<'tcx>,
|
||||||
saved_locals: &CoroutineSavedLocals,
|
saved_locals: &'mir CoroutineSavedLocals,
|
||||||
always_live_locals: BitSet<Local>,
|
always_live_locals: BitSet<Local>,
|
||||||
mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
|
mut requires_storage: Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
|
||||||
) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
|
) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
|
||||||
assert_eq!(body.local_decls.len(), saved_locals.domain_size());
|
assert_eq!(body.local_decls.len(), saved_locals.domain_size());
|
||||||
|
|
||||||
@ -877,15 +877,13 @@ struct StorageConflictVisitor<'a, 'tcx> {
|
|||||||
eligible_storage_live: BitSet<Local>,
|
eligible_storage_live: BitSet<Local>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
|
||||||
for StorageConflictVisitor<'a, 'tcx>
|
for StorageConflictVisitor<'a, 'tcx>
|
||||||
{
|
{
|
||||||
type Domain = BitSet<Local>;
|
|
||||||
|
|
||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
|
||||||
state: &Self::Domain,
|
state: &BitSet<Local>,
|
||||||
_statement: &'a Statement<'tcx>,
|
_statement: &'a Statement<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
) {
|
) {
|
||||||
@ -894,8 +892,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
|
|||||||
|
|
||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
_results: &mut R,
|
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
|
||||||
state: &Self::Domain,
|
state: &BitSet<Local>,
|
||||||
_terminator: &'a Terminator<'tcx>,
|
_terminator: &'a Terminator<'tcx>,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
) {
|
) {
|
||||||
|
@ -941,16 +941,12 @@ fn try_write_constant<'tcx>(
|
|||||||
interp_ok(())
|
interp_ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx>>>
|
impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
|
||||||
for Collector<'_, 'tcx>
|
|
||||||
{
|
|
||||||
type Domain = State<FlatSet<Scalar>>;
|
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(self, results, statement))]
|
#[instrument(level = "trace", skip(self, results, statement))]
|
||||||
fn visit_statement_before_primary_effect(
|
fn visit_statement_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
||||||
state: &Self::Domain,
|
state: &State<FlatSet<Scalar>>,
|
||||||
statement: &'mir Statement<'tcx>,
|
statement: &'mir Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
@ -972,7 +968,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
|
|||||||
fn visit_statement_after_primary_effect(
|
fn visit_statement_after_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
||||||
state: &Self::Domain,
|
state: &State<FlatSet<Scalar>>,
|
||||||
statement: &'mir Statement<'tcx>,
|
statement: &'mir Statement<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
@ -997,7 +993,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
|
|||||||
fn visit_terminator_before_primary_effect(
|
fn visit_terminator_before_primary_effect(
|
||||||
&mut self,
|
&mut self,
|
||||||
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
|
||||||
state: &Self::Domain,
|
state: &State<FlatSet<Scalar>>,
|
||||||
terminator: &'mir Terminator<'tcx>,
|
terminator: &'mir Terminator<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
|
@ -1324,7 +1324,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||||||
// This way they can use `macro_rules` defined later.
|
// This way they can use `macro_rules` defined later.
|
||||||
self.visit_vis(&item.vis);
|
self.visit_vis(&item.vis);
|
||||||
self.visit_ident(&item.ident);
|
self.visit_ident(&item.ident);
|
||||||
item.kind.walk(item, AssocCtxt::Trait, self);
|
item.kind.walk(item.span, item.id, &item.ident, &item.vis, (), self);
|
||||||
visit::walk_list!(self, visit_attribute, &item.attrs);
|
visit::walk_list!(self, visit_attribute, &item.attrs);
|
||||||
}
|
}
|
||||||
_ => visit::walk_item(self, item),
|
_ => visit::walk_item(self, item),
|
||||||
|
@ -3535,7 +3535,6 @@ pub(crate) macro const_eval_select {
|
|||||||
/// In other words, the following code has *Undefined Behavior*:
|
/// In other words, the following code has *Undefined Behavior*:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// #![feature(is_val_statically_known)]
|
|
||||||
/// #![feature(core_intrinsics)]
|
/// #![feature(core_intrinsics)]
|
||||||
/// # #![allow(internal_features)]
|
/// # #![allow(internal_features)]
|
||||||
/// use std::hint::unreachable_unchecked;
|
/// use std::hint::unreachable_unchecked;
|
||||||
@ -3548,7 +3547,6 @@ pub(crate) macro const_eval_select {
|
|||||||
/// may panic, or it may not:
|
/// may panic, or it may not:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// #![feature(is_val_statically_known)]
|
|
||||||
/// #![feature(core_intrinsics)]
|
/// #![feature(core_intrinsics)]
|
||||||
/// # #![allow(internal_features)]
|
/// # #![allow(internal_features)]
|
||||||
/// use std::intrinsics::is_val_statically_known;
|
/// use std::intrinsics::is_val_statically_known;
|
||||||
@ -3581,7 +3579,6 @@ pub(crate) macro const_eval_select {
|
|||||||
/// behave identically:
|
/// behave identically:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(is_val_statically_known)]
|
|
||||||
/// #![feature(core_intrinsics)]
|
/// #![feature(core_intrinsics)]
|
||||||
/// # #![allow(internal_features)]
|
/// # #![allow(internal_features)]
|
||||||
/// use std::intrinsics::is_val_statically_known;
|
/// use std::intrinsics::is_val_statically_known;
|
||||||
@ -3598,7 +3595,11 @@ pub(crate) macro const_eval_select {
|
|||||||
/// # _ = foo(&5_i32);
|
/// # _ = foo(&5_i32);
|
||||||
/// # _ = bar(&5_i32);
|
/// # _ = bar(&5_i32);
|
||||||
/// ```
|
/// ```
|
||||||
#[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")]
|
#[cfg_attr(
|
||||||
|
bootstrap,
|
||||||
|
rustc_const_stable(feature = "const_is_val_statically_known", since = "CURRENT_RUSTC_VERSION")
|
||||||
|
)]
|
||||||
|
#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)]
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||||
#[rustc_intrinsic]
|
#[rustc_intrinsic]
|
||||||
|
@ -139,7 +139,6 @@
|
|||||||
#![feature(internal_impls_macro)]
|
#![feature(internal_impls_macro)]
|
||||||
#![feature(ip)]
|
#![feature(ip)]
|
||||||
#![feature(is_ascii_octdigit)]
|
#![feature(is_ascii_octdigit)]
|
||||||
#![feature(is_val_statically_known)]
|
|
||||||
#![feature(lazy_get)]
|
#![feature(lazy_get)]
|
||||||
#![feature(link_cfg)]
|
#![feature(link_cfg)]
|
||||||
#![feature(non_null_from_ref)]
|
#![feature(non_null_from_ref)]
|
||||||
|
@ -2242,7 +2242,6 @@ macro_rules! int_impl {
|
|||||||
#[must_use = "this returns the result of the operation, \
|
#[must_use = "this returns the result of the operation, \
|
||||||
without modifying the original"]
|
without modifying the original"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
|
|
||||||
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
|
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
|
||||||
if exp == 0 {
|
if exp == 0 {
|
||||||
return 1;
|
return 1;
|
||||||
@ -2808,7 +2807,6 @@ macro_rules! int_impl {
|
|||||||
without modifying the original"]
|
without modifying the original"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_inherit_overflow_checks]
|
#[rustc_inherit_overflow_checks]
|
||||||
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
|
|
||||||
pub const fn pow(self, mut exp: u32) -> Self {
|
pub const fn pow(self, mut exp: u32) -> Self {
|
||||||
if exp == 0 {
|
if exp == 0 {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2251,7 +2251,6 @@ macro_rules! uint_impl {
|
|||||||
#[must_use = "this returns the result of the operation, \
|
#[must_use = "this returns the result of the operation, \
|
||||||
without modifying the original"]
|
without modifying the original"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
|
|
||||||
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
|
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
|
||||||
if exp == 0 {
|
if exp == 0 {
|
||||||
return 1;
|
return 1;
|
||||||
@ -2791,7 +2790,6 @@ macro_rules! uint_impl {
|
|||||||
without modifying the original"]
|
without modifying the original"]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_inherit_overflow_checks]
|
#[rustc_inherit_overflow_checks]
|
||||||
#[rustc_allow_const_fn_unstable(is_val_statically_known)]
|
|
||||||
pub const fn pow(self, mut exp: u32) -> Self {
|
pub const fn pow(self, mut exp: u32) -> Self {
|
||||||
if exp == 0 {
|
if exp == 0 {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -469,7 +469,7 @@ impl AtomicBool {
|
|||||||
/// [valid]: crate::ptr#safety
|
/// [valid]: crate::ptr#safety
|
||||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||||
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
|
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
|
||||||
#[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
|
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
|
pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
|
||||||
// SAFETY: guaranteed by the caller
|
// SAFETY: guaranteed by the caller
|
||||||
unsafe { &*ptr.cast() }
|
unsafe { &*ptr.cast() }
|
||||||
@ -1264,7 +1264,7 @@ impl<T> AtomicPtr<T> {
|
|||||||
/// [valid]: crate::ptr#safety
|
/// [valid]: crate::ptr#safety
|
||||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||||
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
|
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
|
||||||
#[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
|
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
|
pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
|
||||||
// SAFETY: guaranteed by the caller
|
// SAFETY: guaranteed by the caller
|
||||||
unsafe { &*ptr.cast() }
|
unsafe { &*ptr.cast() }
|
||||||
@ -2263,7 +2263,7 @@ macro_rules! atomic_int {
|
|||||||
/// [valid]: crate::ptr#safety
|
/// [valid]: crate::ptr#safety
|
||||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||||
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
|
#[stable(feature = "atomic_from_ptr", since = "1.75.0")]
|
||||||
#[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
|
#[rustc_const_stable(feature = "const_atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
|
||||||
pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {
|
pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {
|
||||||
// SAFETY: guaranteed by the caller
|
// SAFETY: guaranteed by the caller
|
||||||
unsafe { &*ptr.cast() }
|
unsafe { &*ptr.cast() }
|
||||||
|
@ -692,8 +692,6 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
|
|||||||
const quadcolon = /::\s*::/.exec(path);
|
const quadcolon = /::\s*::/.exec(path);
|
||||||
if (path.startsWith("::")) {
|
if (path.startsWith("::")) {
|
||||||
throw ["Paths cannot start with ", "::"];
|
throw ["Paths cannot start with ", "::"];
|
||||||
} else if (path.endsWith("::")) {
|
|
||||||
throw ["Paths cannot end with ", "::"];
|
|
||||||
} else if (quadcolon !== null) {
|
} else if (quadcolon !== null) {
|
||||||
throw ["Unexpected ", quadcolon[0]];
|
throw ["Unexpected ", quadcolon[0]];
|
||||||
}
|
}
|
||||||
@ -3974,18 +3972,19 @@ class DocSearch {
|
|||||||
|
|
||||||
if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) {
|
if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) {
|
||||||
const elem = parsedQuery.elems[0];
|
const elem = parsedQuery.elems[0];
|
||||||
for (const id of this.nameTrie.search(elem.normalizedPathLast, this.tailTable)) {
|
// use arrow functions to preserve `this`.
|
||||||
|
const handleNameSearch = id => {
|
||||||
const row = this.searchIndex[id];
|
const row = this.searchIndex[id];
|
||||||
if (!typePassesFilter(elem.typeFilter, row.ty) ||
|
if (!typePassesFilter(elem.typeFilter, row.ty) ||
|
||||||
(filterCrates !== null && row.crate !== filterCrates)) {
|
(filterCrates !== null && row.crate !== filterCrates)) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pathDist = 0;
|
let pathDist = 0;
|
||||||
if (elem.fullPath.length > 1) {
|
if (elem.fullPath.length > 1) {
|
||||||
pathDist = checkPath(elem.pathWithoutLast, row);
|
pathDist = checkPath(elem.pathWithoutLast, row);
|
||||||
if (pathDist === null) {
|
if (pathDist === null) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4008,9 +4007,20 @@ class DocSearch {
|
|||||||
maxEditDistance,
|
maxEditDistance,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
if (elem.normalizedPathLast !== "") {
|
||||||
|
const last = elem.normalizedPathLast;
|
||||||
|
for (const id of this.nameTrie.search(last, this.tailTable)) {
|
||||||
|
handleNameSearch(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const length = this.searchIndex.length;
|
const length = this.searchIndex.length;
|
||||||
|
|
||||||
for (let i = 0, nSearchIndex = length; i < nSearchIndex; ++i) {
|
for (let i = 0, nSearchIndex = length; i < nSearchIndex; ++i) {
|
||||||
|
// queries that end in :: bypass the trie
|
||||||
|
if (elem.normalizedPathLast === "") {
|
||||||
|
handleNameSearch(i);
|
||||||
|
}
|
||||||
const row = this.searchIndex[i];
|
const row = this.searchIndex[i];
|
||||||
if (filterCrates !== null && row.crate !== filterCrates) {
|
if (filterCrates !== null && row.crate !== filterCrates) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -3449,21 +3449,14 @@ impl Rewrite for ast::ForeignItem {
|
|||||||
ref generics,
|
ref generics,
|
||||||
ref body,
|
ref body,
|
||||||
} = **fn_kind;
|
} = **fn_kind;
|
||||||
if let Some(ref body) = body {
|
if body.is_some() {
|
||||||
let mut visitor = FmtVisitor::from_context(context);
|
let mut visitor = FmtVisitor::from_context(context);
|
||||||
visitor.block_indent = shape.indent;
|
visitor.block_indent = shape.indent;
|
||||||
visitor.last_pos = self.span.lo();
|
visitor.last_pos = self.span.lo();
|
||||||
let inner_attrs = inner_attributes(&self.attrs);
|
let inner_attrs = inner_attributes(&self.attrs);
|
||||||
let fn_ctxt = visit::FnCtxt::Foreign;
|
let fn_ctxt = visit::FnCtxt::Foreign;
|
||||||
visitor.visit_fn(
|
visitor.visit_fn(
|
||||||
visit::FnKind::Fn(
|
visit::FnKind::Fn(fn_ctxt, &self.ident, sig, &self.vis, generics, body),
|
||||||
fn_ctxt,
|
|
||||||
self.ident,
|
|
||||||
sig,
|
|
||||||
&self.vis,
|
|
||||||
generics,
|
|
||||||
Some(body),
|
|
||||||
),
|
|
||||||
&sig.decl,
|
&sig.decl,
|
||||||
self.span,
|
self.span,
|
||||||
defaultness,
|
defaultness,
|
||||||
|
@ -390,7 +390,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
|||||||
block = b;
|
block = b;
|
||||||
self.rewrite_fn_before_block(
|
self.rewrite_fn_before_block(
|
||||||
indent,
|
indent,
|
||||||
ident,
|
*ident,
|
||||||
&FnSig::from_fn_kind(&fk, fd, defaultness),
|
&FnSig::from_fn_kind(&fk, fd, defaultness),
|
||||||
mk_sp(s.lo(), b.span.lo()),
|
mk_sp(s.lo(), b.span.lo()),
|
||||||
)
|
)
|
||||||
@ -540,21 +540,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
|||||||
ref generics,
|
ref generics,
|
||||||
ref body,
|
ref body,
|
||||||
} = **fn_kind;
|
} = **fn_kind;
|
||||||
if let Some(ref body) = body {
|
if body.is_some() {
|
||||||
let inner_attrs = inner_attributes(&item.attrs);
|
let inner_attrs = inner_attributes(&item.attrs);
|
||||||
let fn_ctxt = match sig.header.ext {
|
let fn_ctxt = match sig.header.ext {
|
||||||
ast::Extern::None => visit::FnCtxt::Free,
|
ast::Extern::None => visit::FnCtxt::Free,
|
||||||
_ => visit::FnCtxt::Foreign,
|
_ => visit::FnCtxt::Foreign,
|
||||||
};
|
};
|
||||||
self.visit_fn(
|
self.visit_fn(
|
||||||
visit::FnKind::Fn(
|
visit::FnKind::Fn(fn_ctxt, &item.ident, sig, &item.vis, generics, body),
|
||||||
fn_ctxt,
|
|
||||||
item.ident,
|
|
||||||
sig,
|
|
||||||
&item.vis,
|
|
||||||
generics,
|
|
||||||
Some(body),
|
|
||||||
),
|
|
||||||
&sig.decl,
|
&sig.decl,
|
||||||
item.span,
|
item.span,
|
||||||
defaultness,
|
defaultness,
|
||||||
@ -648,11 +641,11 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
|||||||
ref generics,
|
ref generics,
|
||||||
ref body,
|
ref body,
|
||||||
} = **fn_kind;
|
} = **fn_kind;
|
||||||
if let Some(ref body) = body {
|
if body.is_some() {
|
||||||
let inner_attrs = inner_attributes(&ai.attrs);
|
let inner_attrs = inner_attributes(&ai.attrs);
|
||||||
let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
|
let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
|
||||||
self.visit_fn(
|
self.visit_fn(
|
||||||
visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)),
|
visit::FnKind::Fn(fn_ctxt, &ai.ident, sig, &ai.vis, generics, body),
|
||||||
&sig.decl,
|
&sig.decl,
|
||||||
ai.span,
|
ai.span,
|
||||||
defaultness,
|
defaultness,
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
//@ known-bug: #131535
|
|
||||||
#![feature(non_lifetime_binders)]
|
|
||||||
trait v0<> {}
|
|
||||||
fn kind :(v0<'_, > impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {}
|
|
@ -1,7 +0,0 @@
|
|||||||
//@ known-bug: #121637
|
|
||||||
#![feature(non_lifetime_binders)]
|
|
||||||
trait Trait<Type> {
|
|
||||||
type Type;
|
|
||||||
|
|
||||||
fn method(&self) -> impl for<T> Trait<impl Trait<T>>;
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
//@ known-bug: #132530
|
|
||||||
|
|
||||||
#![feature(non_lifetime_binders)]
|
|
||||||
|
|
||||||
trait Trait<'a, A> {
|
|
||||||
type Assoc<'a> = i32;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn a() -> impl for<T> Trait<Assoc = impl Trait<T>> {}
|
|
@ -143,14 +143,6 @@ const PARSED = [
|
|||||||
returned: [],
|
returned: [],
|
||||||
error: "Unexpected `:: ::`",
|
error: "Unexpected `:: ::`",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
query: "a::b::",
|
|
||||||
elems: [],
|
|
||||||
foundElems: 0,
|
|
||||||
userQuery: "a::b::",
|
|
||||||
returned: [],
|
|
||||||
error: "Paths cannot end with `::`",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
query: ":a",
|
query: ":a",
|
||||||
elems: [],
|
elems: [],
|
||||||
|
6
tests/rustdoc-js-std/path-end-empty.js
Normal file
6
tests/rustdoc-js-std/path-end-empty.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
const EXPECTED = {
|
||||||
|
'query': 'Option::',
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'std::option::Option', 'name': 'get_or_insert_default' },
|
||||||
|
],
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
//@ run-pass
|
//@ run-pass
|
||||||
|
|
||||||
#![feature(core_intrinsics, is_val_statically_known)]
|
#![feature(core_intrinsics)]
|
||||||
|
|
||||||
use std::intrinsics::is_val_statically_known;
|
use std::intrinsics::is_val_statically_known;
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> {
|
|||||||
//~^ ERROR associated type `Assoc` not found for `Trait`
|
//~^ ERROR associated type `Assoc` not found for `Trait`
|
||||||
//~| ERROR associated type `Assoc` not found for `Trait`
|
//~| ERROR associated type `Assoc` not found for `Trait`
|
||||||
//~| the trait bound `{integer}: Trait<()>` is not satisfied
|
//~| the trait bound `{integer}: Trait<()>` is not satisfied
|
||||||
|
//~| ERROR cannot capture late-bound type parameter in nested `impl Trait`
|
||||||
16
|
16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
error: cannot capture late-bound type parameter in nested `impl Trait`
|
||||||
|
--> $DIR/non-lifetime-binder-in-constraint.rs:6:58
|
||||||
|
|
|
||||||
|
LL | fn produce() -> impl for<T> Trait<(), Assoc = impl Trait<T>> {
|
||||||
|
| - parameter defined here ^
|
||||||
|
|
||||||
error[E0220]: associated type `Assoc` not found for `Trait`
|
error[E0220]: associated type `Assoc` not found for `Trait`
|
||||||
--> $DIR/non-lifetime-binder-in-constraint.rs:6:39
|
--> $DIR/non-lifetime-binder-in-constraint.rs:6:39
|
||||||
|
|
|
|
||||||
@ -27,7 +33,7 @@ help: this trait has no implementations, consider adding one
|
|||||||
LL | trait Trait<T: ?Sized> {}
|
LL | trait Trait<T: ?Sized> {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0220, E0277.
|
Some errors have detailed explanations: E0220, E0277.
|
||||||
For more information about an error, try `rustc --explain E0220`.
|
For more information about an error, try `rustc --explain E0220`.
|
||||||
|
@ -5,6 +5,7 @@ trait Trait<T> {}
|
|||||||
|
|
||||||
fn f() -> impl for<T> Trait<impl Trait<T>> {}
|
fn f() -> impl for<T> Trait<impl Trait<T>> {}
|
||||||
//~^ ERROR nested `impl Trait` is not allowed
|
//~^ ERROR nested `impl Trait` is not allowed
|
||||||
//~| ERROR the trait bound `(): Trait<impl Trait<T>>` is not satisfied
|
//~| ERROR the trait bound `(): Trait<impl Trait<{type error}>>` is not satisfied
|
||||||
|
//~| ERROR cannot capture late-bound type parameter in nested `impl Trait`
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -7,11 +7,19 @@ LL | fn f() -> impl for<T> Trait<impl Trait<T>> {}
|
|||||||
| | nested `impl Trait` here
|
| | nested `impl Trait` here
|
||||||
| outer `impl Trait`
|
| outer `impl Trait`
|
||||||
|
|
||||||
error[E0277]: the trait bound `(): Trait<impl Trait<T>>` is not satisfied
|
error: cannot capture late-bound type parameter in nested `impl Trait`
|
||||||
|
--> $DIR/non-lifetime-binder.rs:6:40
|
||||||
|
|
|
||||||
|
LL | fn f() -> impl for<T> Trait<impl Trait<T>> {}
|
||||||
|
| - ^
|
||||||
|
| |
|
||||||
|
| parameter defined here
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `(): Trait<impl Trait<{type error}>>` is not satisfied
|
||||||
--> $DIR/non-lifetime-binder.rs:6:11
|
--> $DIR/non-lifetime-binder.rs:6:11
|
||||||
|
|
|
|
||||||
LL | fn f() -> impl for<T> Trait<impl Trait<T>> {}
|
LL | fn f() -> impl for<T> Trait<impl Trait<T>> {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<impl Trait<T>>` is not implemented for `()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<impl Trait<{type error}>>` is not implemented for `()`
|
||||||
|
|
|
|
||||||
help: this trait has no implementations, consider adding one
|
help: this trait has no implementations, consider adding one
|
||||||
--> $DIR/non-lifetime-binder.rs:4:1
|
--> $DIR/non-lifetime-binder.rs:4:1
|
||||||
@ -19,7 +27,7 @@ help: this trait has no implementations, consider adding one
|
|||||||
LL | trait Trait<T> {}
|
LL | trait Trait<T> {}
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0277, E0666.
|
Some errors have detailed explanations: E0277, E0666.
|
||||||
For more information about an error, try `rustc --explain E0277`.
|
For more information about an error, try `rustc --explain E0277`.
|
||||||
|
@ -997,7 +997,6 @@ compiler = [
|
|||||||
"@oli-obk",
|
"@oli-obk",
|
||||||
"@petrochenkov",
|
"@petrochenkov",
|
||||||
"@pnkfelix",
|
"@pnkfelix",
|
||||||
"@TaKO8Ki",
|
|
||||||
"@wesleywiser",
|
"@wesleywiser",
|
||||||
]
|
]
|
||||||
libs = [
|
libs = [
|
||||||
@ -1048,7 +1047,6 @@ diagnostics = [
|
|||||||
"@davidtwco",
|
"@davidtwco",
|
||||||
"@estebank",
|
"@estebank",
|
||||||
"@oli-obk",
|
"@oli-obk",
|
||||||
"@TaKO8Ki",
|
|
||||||
"@chenyukang",
|
"@chenyukang",
|
||||||
]
|
]
|
||||||
parser = [
|
parser = [
|
||||||
|
Loading…
Reference in New Issue
Block a user