Auto merge of #54756 - ljedrz:cleanup_middle, r=michaelwoerister
Cleanup rustc/middle - improve allocations - use `Cow<'static, str>` where applicable - improve some patterns - whitespace & formatting fixes
This commit is contained in:
commit
4efdc04a5d
16 changed files with 637 additions and 707 deletions
|
@ -131,12 +131,10 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
fn mark_live_symbols(&mut self) {
|
fn mark_live_symbols(&mut self) {
|
||||||
let mut scanned = FxHashSet();
|
let mut scanned = FxHashSet();
|
||||||
while !self.worklist.is_empty() {
|
while let Some(id) = self.worklist.pop() {
|
||||||
let id = self.worklist.pop().unwrap();
|
if !scanned.insert(id) {
|
||||||
if scanned.contains(&id) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
scanned.insert(id);
|
|
||||||
|
|
||||||
if let Some(ref node) = self.tcx.hir.find(id) {
|
if let Some(ref node) = self.tcx.hir.find(id) {
|
||||||
self.live_symbols.insert(id);
|
self.live_symbols.insert(id);
|
||||||
|
@ -212,7 +210,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_variant_data(&mut self, def: &'tcx hir::VariantData, _: ast::Name,
|
fn visit_variant_data(&mut self, def: &'tcx hir::VariantData, _: ast::Name,
|
||||||
_: &hir::Generics, _: ast::NodeId, _: syntax_pos::Span) {
|
_: &hir::Generics, _: ast::NodeId, _: syntax_pos::Span) {
|
||||||
let has_repr_c = self.repr_has_repr_c;
|
let has_repr_c = self.repr_has_repr_c;
|
||||||
let inherited_pub_visibility = self.inherited_pub_visibility;
|
let inherited_pub_visibility = self.inherited_pub_visibility;
|
||||||
let live_fields = def.fields().iter().filter(|f| {
|
let live_fields = def.fields().iter().filter(|f| {
|
||||||
|
@ -494,8 +492,8 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
|
||||||
ctor_id: Option<ast::NodeId>)
|
ctor_id: Option<ast::NodeId>)
|
||||||
-> bool {
|
-> bool {
|
||||||
if self.live_symbols.contains(&id)
|
if self.live_symbols.contains(&id)
|
||||||
|| ctor_id.map_or(false,
|
|| ctor_id.map_or(false, |ctor| self.live_symbols.contains(&ctor))
|
||||||
|ctor| self.live_symbols.contains(&ctor)) {
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// If it's a type whose items are live, then it's live, too.
|
// If it's a type whose items are live, then it's live, too.
|
||||||
|
|
|
@ -163,7 +163,7 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
let src = tcx.used_crate_source(cnum);
|
let src = tcx.used_crate_source(cnum);
|
||||||
if src.rlib.is_some() { continue }
|
if src.rlib.is_some() { continue }
|
||||||
sess.err(&format!("crate `{}` required to be available in rlib format, \
|
sess.err(&format!("crate `{}` required to be available in rlib format, \
|
||||||
but was not found in this form",
|
but was not found in this form",
|
||||||
tcx.crate_name(cnum)));
|
tcx.crate_name(cnum)));
|
||||||
}
|
}
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
|
@ -247,13 +247,13 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
_ => "dylib",
|
_ => "dylib",
|
||||||
};
|
};
|
||||||
sess.err(&format!("crate `{}` required to be available in {} format, \
|
sess.err(&format!("crate `{}` required to be available in {} format, \
|
||||||
but was not found in this form",
|
but was not found in this form",
|
||||||
tcx.crate_name(cnum), kind));
|
tcx.crate_name(cnum), kind));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_library(tcx: TyCtxt<'_, '_, '_>,
|
fn add_library(tcx: TyCtxt<'_, '_, '_>,
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
|
||||||
use hir::map as hir_map;
|
use hir::map as hir_map;
|
||||||
use hir::def_id::{CRATE_DEF_INDEX};
|
use hir::def_id::{CRATE_DEF_INDEX};
|
||||||
use session::{config, Session};
|
use session::{config, Session};
|
||||||
|
@ -131,7 +130,7 @@ fn find_item(item: &Item, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
|
||||||
ctxt.attr_main_fn = Some((item.id, item.span));
|
ctxt.attr_main_fn = Some((item.id, item.span));
|
||||||
} else {
|
} else {
|
||||||
struct_span_err!(ctxt.session, item.span, E0137,
|
struct_span_err!(ctxt.session, item.span, E0137,
|
||||||
"multiple functions with a #[main] attribute")
|
"multiple functions with a #[main] attribute")
|
||||||
.span_label(item.span, "additional #[main] function")
|
.span_label(item.span, "additional #[main] function")
|
||||||
.span_label(ctxt.attr_main_fn.unwrap().1, "first #[main] function")
|
.span_label(ctxt.attr_main_fn.unwrap().1, "first #[main] function")
|
||||||
.emit();
|
.emit();
|
||||||
|
@ -141,11 +140,8 @@ fn find_item(item: &Item, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
|
||||||
if ctxt.start_fn.is_none() {
|
if ctxt.start_fn.is_none() {
|
||||||
ctxt.start_fn = Some((item.id, item.span));
|
ctxt.start_fn = Some((item.id, item.span));
|
||||||
} else {
|
} else {
|
||||||
struct_span_err!(
|
struct_span_err!(ctxt.session, item.span, E0138, "multiple 'start' functions")
|
||||||
ctxt.session, item.span, E0138,
|
.span_label(ctxt.start_fn.unwrap().1, "previous `start` function here")
|
||||||
"multiple 'start' functions")
|
|
||||||
.span_label(ctxt.start_fn.unwrap().1,
|
|
||||||
"previous `start` function here")
|
|
||||||
.span_label(item.span, "multiple `start` functions")
|
.span_label(item.span, "multiple `start` functions")
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,12 +35,8 @@ impl_stable_hash_for!(enum self::SymbolExportLevel {
|
||||||
|
|
||||||
impl SymbolExportLevel {
|
impl SymbolExportLevel {
|
||||||
pub fn is_below_threshold(self, threshold: SymbolExportLevel) -> bool {
|
pub fn is_below_threshold(self, threshold: SymbolExportLevel) -> bool {
|
||||||
if threshold == SymbolExportLevel::Rust {
|
threshold == SymbolExportLevel::Rust // export everything from Rust dylibs
|
||||||
// We export everything from Rust dylibs
|
|| self == SymbolExportLevel::C
|
||||||
true
|
|
||||||
} else {
|
|
||||||
self == SymbolExportLevel::C
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -321,7 +321,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
region::Scope {
|
region::Scope {
|
||||||
id: body.value.hir_id.local_id,
|
id: body.value.hir_id.local_id,
|
||||||
data: region::ScopeData::Node
|
data: region::ScopeData::Node
|
||||||
}));
|
}));
|
||||||
let arg_cmt = Rc::new(self.mc.cat_rvalue(
|
let arg_cmt = Rc::new(self.mc.cat_rvalue(
|
||||||
arg.hir_id,
|
arg.hir_id,
|
||||||
arg.pat.span,
|
arg.pat.span,
|
||||||
|
@ -402,20 +402,20 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
self.walk_expr(&subexpr)
|
self.walk_expr(&subexpr)
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Unary(hir::UnDeref, ref base) => { // *base
|
hir::ExprKind::Unary(hir::UnDeref, ref base) => { // *base
|
||||||
self.select_from_expr(&base);
|
self.select_from_expr(&base);
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Field(ref base, _) => { // base.f
|
hir::ExprKind::Field(ref base, _) => { // base.f
|
||||||
self.select_from_expr(&base);
|
self.select_from_expr(&base);
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Index(ref lhs, ref rhs) => { // lhs[rhs]
|
hir::ExprKind::Index(ref lhs, ref rhs) => { // lhs[rhs]
|
||||||
self.select_from_expr(&lhs);
|
self.select_from_expr(&lhs);
|
||||||
self.consume_expr(&rhs);
|
self.consume_expr(&rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Call(ref callee, ref args) => { // callee(args)
|
hir::ExprKind::Call(ref callee, ref args) => { // callee(args)
|
||||||
self.walk_callee(expr, &callee);
|
self.walk_callee(expr, &callee);
|
||||||
self.consume_exprs(args);
|
self.consume_exprs(args);
|
||||||
}
|
}
|
||||||
|
@ -801,10 +801,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
self.walk_pat(discr_cmt.clone(), &pat, mode);
|
self.walk_pat(discr_cmt.clone(), &pat, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref guard) = arm.guard {
|
if let Some(hir::Guard::If(ref e)) = arm.guard {
|
||||||
match guard {
|
self.consume_expr(e)
|
||||||
hir::Guard::If(ref e) => self.consume_expr(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.consume_expr(&arm.body);
|
self.consume_expr(&arm.body);
|
||||||
|
@ -826,12 +824,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
cmt_discr: mc::cmt<'tcx>,
|
cmt_discr: mc::cmt<'tcx>,
|
||||||
pat: &hir::Pat,
|
pat: &hir::Pat,
|
||||||
mode: &mut TrackMatchMode) {
|
mode: &mut TrackMatchMode) {
|
||||||
debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr,
|
debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr, pat);
|
||||||
pat);
|
|
||||||
return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
|
return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
|
||||||
if let PatKind::Binding(..) = pat.node {
|
if let PatKind::Binding(..) = pat.node {
|
||||||
let bm = *self.mc.tables.pat_binding_modes().get(pat.hir_id)
|
let bm = *self.mc.tables.pat_binding_modes()
|
||||||
.expect("missing binding mode");
|
.get(pat.hir_id)
|
||||||
|
.expect("missing binding mode");
|
||||||
match bm {
|
match bm {
|
||||||
ty::BindByReference(..) =>
|
ty::BindByReference(..) =>
|
||||||
mode.lub(BorrowingMatch),
|
mode.lub(BorrowingMatch),
|
||||||
|
|
|
@ -107,7 +107,7 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
Err(LayoutError::Unknown(bad)) => {
|
Err(LayoutError::Unknown(bad)) => {
|
||||||
if bad == ty {
|
if bad == ty {
|
||||||
"this type's size can vary".to_string()
|
"this type's size can vary".to_owned()
|
||||||
} else {
|
} else {
|
||||||
format!("size can vary because of {}", bad)
|
format!("size can vary because of {}", bad)
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ impl<'a, 'tcx> ExprVisitor<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct_span_err!(self.tcx.sess, span, E0512,
|
struct_span_err!(self.tcx.sess, span, E0512,
|
||||||
"transmute called with types of different sizes")
|
"transmute called with types of different sizes")
|
||||||
.note(&format!("source type: {} ({})", from, skeleton_string(from, sk_from)))
|
.note(&format!("source type: {} ({})", from, skeleton_string(from, sk_from)))
|
||||||
.note(&format!("target type: {} ({})", to, skeleton_string(to, sk_to)))
|
.note(&format!("target type: {} ({})", to, skeleton_string(to, sk_to)))
|
||||||
.emit();
|
.emit();
|
||||||
|
|
|
@ -39,7 +39,6 @@ macro_rules! language_item_table {
|
||||||
$( $variant:ident, $name:expr, $method:ident; )*
|
$( $variant:ident, $name:expr, $method:ident; )*
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
|
|
||||||
enum_from_u32! {
|
enum_from_u32! {
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||||
pub enum LangItem {
|
pub enum LangItem {
|
||||||
|
@ -145,8 +144,8 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
|
||||||
|
|
||||||
fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
|
fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
|
||||||
// Check for duplicates.
|
// Check for duplicates.
|
||||||
match self.items.items[item_index] {
|
if let Some(original_def_id) = self.items.items[item_index] {
|
||||||
Some(original_def_id) if original_def_id != item_def_id => {
|
if original_def_id != item_def_id {
|
||||||
let name = LangItem::from_u32(item_index as u32).unwrap().name();
|
let name = LangItem::from_u32(item_index as u32).unwrap().name();
|
||||||
let mut err = match self.tcx.hir.span_if_local(item_def_id) {
|
let mut err = match self.tcx.hir.span_if_local(item_def_id) {
|
||||||
Some(span) => struct_span_err!(
|
Some(span) => struct_span_err!(
|
||||||
|
@ -161,17 +160,13 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
|
||||||
name)),
|
name)),
|
||||||
};
|
};
|
||||||
if let Some(span) = self.tcx.hir.span_if_local(original_def_id) {
|
if let Some(span) = self.tcx.hir.span_if_local(original_def_id) {
|
||||||
span_note!(&mut err, span,
|
span_note!(&mut err, span, "first defined here.");
|
||||||
"first defined here.");
|
|
||||||
} else {
|
} else {
|
||||||
err.note(&format!("first defined in crate `{}`.",
|
err.note(&format!("first defined in crate `{}`.",
|
||||||
self.tcx.crate_name(original_def_id.krate)));
|
self.tcx.crate_name(original_def_id.krate)));
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
// OK.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matched.
|
// Matched.
|
||||||
|
@ -194,7 +189,7 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
|
pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
|
||||||
|
|
|
@ -128,8 +128,8 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"feature `{}` is declared {}, but was previously declared {}",
|
"feature `{}` is declared {}, but was previously declared {}",
|
||||||
feature,
|
feature,
|
||||||
if since.is_some() { "stable"} else { "unstable" },
|
if since.is_some() { "stable" } else { "unstable" },
|
||||||
if since.is_none() { "stable"} else { "unstable" },
|
if since.is_none() { "stable" } else { "unstable" },
|
||||||
);
|
);
|
||||||
self.tcx.sess.struct_span_err_with_code(span, &msg,
|
self.tcx.sess.struct_span_err_with_code(span, &msg,
|
||||||
DiagnosticId::Error("E0711".into())).emit();
|
DiagnosticId::Error("E0711".into())).emit();
|
||||||
|
|
|
@ -170,7 +170,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_, '_, '_>) -> Strin
|
||||||
VarDefNode(s) => {
|
VarDefNode(s) => {
|
||||||
format!("Var def node [{}]", cm.span_to_string(s))
|
format!("Var def node [{}]", cm.span_to_string(s))
|
||||||
}
|
}
|
||||||
ExitNode => "Exit node".to_string(),
|
ExitNode => "Exit node".to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,7 +257,6 @@ enum VarKind {
|
||||||
|
|
||||||
struct IrMaps<'a, 'tcx: 'a> {
|
struct IrMaps<'a, 'tcx: 'a> {
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
|
||||||
num_live_nodes: usize,
|
num_live_nodes: usize,
|
||||||
num_vars: usize,
|
num_vars: usize,
|
||||||
live_node_map: HirIdMap<LiveNode>,
|
live_node_map: HirIdMap<LiveNode>,
|
||||||
|
@ -330,7 +329,7 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
|
||||||
Local(LocalInfo { name, .. }) | Arg(_, name) => {
|
Local(LocalInfo { name, .. }) | Arg(_, name) => {
|
||||||
name.to_string()
|
name.to_string()
|
||||||
},
|
},
|
||||||
CleanExit => "<clean-exit>".to_string()
|
CleanExit => "<clean-exit>".to_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,13 +473,15 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
|
||||||
// construction site.
|
// construction site.
|
||||||
let mut call_caps = Vec::new();
|
let mut call_caps = Vec::new();
|
||||||
ir.tcx.with_freevars(expr.id, |freevars| {
|
ir.tcx.with_freevars(expr.id, |freevars| {
|
||||||
for fv in freevars {
|
call_caps.extend(freevars.iter().filter_map(|fv| {
|
||||||
if let Def::Local(rv) = fv.def {
|
if let Def::Local(rv) = fv.def {
|
||||||
let fv_ln = ir.add_live_node(FreeVarNode(fv.span));
|
let fv_ln = ir.add_live_node(FreeVarNode(fv.span));
|
||||||
let var_hid = ir.tcx.hir.node_to_hir_id(rv);
|
let var_hid = ir.tcx.hir.node_to_hir_id(rv);
|
||||||
call_caps.push(CaptureInfo { ln: fv_ln, var_hid });
|
Some(CaptureInfo { ln: fv_ln, var_hid })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}));
|
||||||
});
|
});
|
||||||
ir.set_captures(expr.id, call_caps);
|
ir.set_captures(expr.id, call_caps);
|
||||||
|
|
||||||
|
@ -918,8 +919,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
self.rwu_table.assign_unpacked(idx, rwu);
|
self.rwu_table.assign_unpacked(idx, rwu);
|
||||||
}
|
}
|
||||||
|
|
||||||
// _______________________________________________________________________
|
|
||||||
|
|
||||||
fn compute(&mut self, body: &hir::Expr) -> LiveNode {
|
fn compute(&mut self, body: &hir::Expr) -> LiveNode {
|
||||||
// if there is a `break` or `again` at the top level, then it's
|
// if there is a `break` or `again` at the top level, then it's
|
||||||
// effectively a return---this only occurs in `for` loops,
|
// effectively a return---this only occurs in `for` loops,
|
||||||
|
@ -941,10 +940,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
let entry_ln = self.propagate_through_expr(body, s.fallthrough_ln);
|
let entry_ln = self.propagate_through_expr(body, s.fallthrough_ln);
|
||||||
|
|
||||||
// hack to skip the loop unless debug! is enabled:
|
// hack to skip the loop unless debug! is enabled:
|
||||||
debug!("^^ liveness computation results for body {} (entry={:?})",
|
debug!("^^ liveness computation results for body {} (entry={:?})", {
|
||||||
{
|
|
||||||
for ln_idx in 0..self.ir.num_live_nodes {
|
for ln_idx in 0..self.ir.num_live_nodes {
|
||||||
debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32)));
|
debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32)));
|
||||||
}
|
}
|
||||||
body.id
|
body.id
|
||||||
},
|
},
|
||||||
|
@ -1026,241 +1024,232 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
debug!("propagate_through_expr: {}", self.ir.tcx.hir.node_to_pretty_string(expr.id));
|
debug!("propagate_through_expr: {}", self.ir.tcx.hir.node_to_pretty_string(expr.id));
|
||||||
|
|
||||||
match expr.node {
|
match expr.node {
|
||||||
// Interesting cases with control flow or which gen/kill
|
// Interesting cases with control flow or which gen/kill
|
||||||
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
|
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
|
||||||
self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE)
|
self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE)
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Field(ref e, _) => {
|
hir::ExprKind::Field(ref e, _) => {
|
||||||
self.propagate_through_expr(&e, succ)
|
self.propagate_through_expr(&e, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Closure(.., blk_id, _, _) => {
|
hir::ExprKind::Closure(.., blk_id, _, _) => {
|
||||||
debug!("{} is an ExprKind::Closure", self.ir.tcx.hir.node_to_pretty_string(expr.id));
|
debug!("{} is an ExprKind::Closure",
|
||||||
|
self.ir.tcx.hir.node_to_pretty_string(expr.id));
|
||||||
|
|
||||||
// The next-node for a break is the successor of the entire
|
// The next-node for a break is the successor of the entire
|
||||||
// loop. The next-node for a continue is the top of this loop.
|
// loop. The next-node for a continue is the top of this loop.
|
||||||
let node = self.live_node(expr.hir_id, expr.span);
|
let node = self.live_node(expr.hir_id, expr.span);
|
||||||
|
|
||||||
let break_ln = succ;
|
let break_ln = succ;
|
||||||
let cont_ln = node;
|
let cont_ln = node;
|
||||||
self.break_ln.insert(blk_id.node_id, break_ln);
|
self.break_ln.insert(blk_id.node_id, break_ln);
|
||||||
self.cont_ln.insert(blk_id.node_id, cont_ln);
|
self.cont_ln.insert(blk_id.node_id, cont_ln);
|
||||||
|
|
||||||
// the construction of a closure itself is not important,
|
// the construction of a closure itself is not important,
|
||||||
// but we have to consider the closed over variables.
|
// but we have to consider the closed over variables.
|
||||||
let caps = match self.ir.capture_info_map.get(&expr.id) {
|
let caps = self.ir.capture_info_map.get(&expr.id).cloned().unwrap_or_else(||
|
||||||
Some(caps) => caps.clone(),
|
span_bug!(expr.span, "no registered caps"));
|
||||||
None => {
|
|
||||||
span_bug!(expr.span, "no registered caps");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
caps.iter().rev().fold(succ, |succ, cap| {
|
|
||||||
self.init_from_succ(cap.ln, succ);
|
|
||||||
let var = self.variable(cap.var_hid, expr.span);
|
|
||||||
self.acc(cap.ln, var, ACC_READ | ACC_USE);
|
|
||||||
cap.ln
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::If(ref cond, ref then, ref els) => {
|
caps.iter().rev().fold(succ, |succ, cap| {
|
||||||
//
|
self.init_from_succ(cap.ln, succ);
|
||||||
// (cond)
|
let var = self.variable(cap.var_hid, expr.span);
|
||||||
// |
|
self.acc(cap.ln, var, ACC_READ | ACC_USE);
|
||||||
// v
|
cap.ln
|
||||||
// (expr)
|
})
|
||||||
// / \
|
}
|
||||||
// | |
|
|
||||||
// v v
|
|
||||||
// (then)(els)
|
|
||||||
// | |
|
|
||||||
// v v
|
|
||||||
// ( succ )
|
|
||||||
//
|
|
||||||
let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ);
|
|
||||||
let then_ln = self.propagate_through_expr(&then, succ);
|
|
||||||
let ln = self.live_node(expr.hir_id, expr.span);
|
|
||||||
self.init_from_succ(ln, else_ln);
|
|
||||||
self.merge_from_succ(ln, then_ln, false);
|
|
||||||
self.propagate_through_expr(&cond, ln)
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::While(ref cond, ref blk, _) => {
|
hir::ExprKind::If(ref cond, ref then, ref els) => {
|
||||||
self.propagate_through_loop(expr, WhileLoop(&cond), &blk, succ)
|
//
|
||||||
}
|
// (cond)
|
||||||
|
// |
|
||||||
|
// v
|
||||||
|
// (expr)
|
||||||
|
// / \
|
||||||
|
// | |
|
||||||
|
// v v
|
||||||
|
// (then)(els)
|
||||||
|
// | |
|
||||||
|
// v v
|
||||||
|
// ( succ )
|
||||||
|
//
|
||||||
|
let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ);
|
||||||
|
let then_ln = self.propagate_through_expr(&then, succ);
|
||||||
|
let ln = self.live_node(expr.hir_id, expr.span);
|
||||||
|
self.init_from_succ(ln, else_ln);
|
||||||
|
self.merge_from_succ(ln, then_ln, false);
|
||||||
|
self.propagate_through_expr(&cond, ln)
|
||||||
|
}
|
||||||
|
|
||||||
// Note that labels have been resolved, so we don't need to look
|
hir::ExprKind::While(ref cond, ref blk, _) => {
|
||||||
// at the label ident
|
self.propagate_through_loop(expr, WhileLoop(&cond), &blk, succ)
|
||||||
hir::ExprKind::Loop(ref blk, _, _) => {
|
}
|
||||||
self.propagate_through_loop(expr, LoopLoop, &blk, succ)
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::Match(ref e, ref arms, _) => {
|
// Note that labels have been resolved, so we don't need to look
|
||||||
//
|
// at the label ident
|
||||||
// (e)
|
hir::ExprKind::Loop(ref blk, _, _) => {
|
||||||
// |
|
self.propagate_through_loop(expr, LoopLoop, &blk, succ)
|
||||||
// v
|
}
|
||||||
// (expr)
|
|
||||||
// / | \
|
|
||||||
// | | |
|
|
||||||
// v v v
|
|
||||||
// (..arms..)
|
|
||||||
// | | |
|
|
||||||
// v v v
|
|
||||||
// ( succ )
|
|
||||||
//
|
|
||||||
//
|
|
||||||
let ln = self.live_node(expr.hir_id, expr.span);
|
|
||||||
self.init_empty(ln, succ);
|
|
||||||
let mut first_merge = true;
|
|
||||||
for arm in arms {
|
|
||||||
let body_succ =
|
|
||||||
self.propagate_through_expr(&arm.body, succ);
|
|
||||||
let guard_succ =
|
|
||||||
self.propagate_through_opt_expr(
|
|
||||||
arm.guard.as_ref().map(|g|
|
|
||||||
match g {
|
|
||||||
hir::Guard::If(e) => &**e,
|
|
||||||
}),
|
|
||||||
body_succ);
|
|
||||||
// only consider the first pattern; any later patterns must have
|
|
||||||
// the same bindings, and we also consider the first pattern to be
|
|
||||||
// the "authoritative" set of ids
|
|
||||||
let arm_succ =
|
|
||||||
self.define_bindings_in_arm_pats(arm.pats.first().map(|p| &**p),
|
|
||||||
guard_succ);
|
|
||||||
self.merge_from_succ(ln, arm_succ, first_merge);
|
|
||||||
first_merge = false;
|
|
||||||
};
|
|
||||||
self.propagate_through_expr(&e, ln)
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::Ret(ref o_e) => {
|
hir::ExprKind::Match(ref e, ref arms, _) => {
|
||||||
// ignore succ and subst exit_ln:
|
//
|
||||||
let exit_ln = self.s.exit_ln;
|
// (e)
|
||||||
self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln)
|
// |
|
||||||
}
|
// v
|
||||||
|
// (expr)
|
||||||
|
// / | \
|
||||||
|
// | | |
|
||||||
|
// v v v
|
||||||
|
// (..arms..)
|
||||||
|
// | | |
|
||||||
|
// v v v
|
||||||
|
// ( succ )
|
||||||
|
//
|
||||||
|
//
|
||||||
|
let ln = self.live_node(expr.hir_id, expr.span);
|
||||||
|
self.init_empty(ln, succ);
|
||||||
|
let mut first_merge = true;
|
||||||
|
for arm in arms {
|
||||||
|
let body_succ = self.propagate_through_expr(&arm.body, succ);
|
||||||
|
|
||||||
hir::ExprKind::Break(label, ref opt_expr) => {
|
let guard_succ = self.propagate_through_opt_expr(
|
||||||
// Find which label this break jumps to
|
arm.guard.as_ref().map(|hir::Guard::If(e)| &**e),
|
||||||
let target = match label.target_id {
|
body_succ
|
||||||
|
);
|
||||||
|
// only consider the first pattern; any later patterns must have
|
||||||
|
// the same bindings, and we also consider the first pattern to be
|
||||||
|
// the "authoritative" set of ids
|
||||||
|
let arm_succ =
|
||||||
|
self.define_bindings_in_arm_pats(arm.pats.first().map(|p| &**p),
|
||||||
|
guard_succ);
|
||||||
|
self.merge_from_succ(ln, arm_succ, first_merge);
|
||||||
|
first_merge = false;
|
||||||
|
};
|
||||||
|
self.propagate_through_expr(&e, ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::ExprKind::Ret(ref o_e) => {
|
||||||
|
// ignore succ and subst exit_ln:
|
||||||
|
let exit_ln = self.s.exit_ln;
|
||||||
|
self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::ExprKind::Break(label, ref opt_expr) => {
|
||||||
|
// Find which label this break jumps to
|
||||||
|
let target = match label.target_id {
|
||||||
Ok(node_id) => self.break_ln.get(&node_id),
|
Ok(node_id) => self.break_ln.get(&node_id),
|
||||||
Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
|
Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
|
||||||
}.map(|x| *x);
|
}.cloned();
|
||||||
|
|
||||||
// Now that we know the label we're going to,
|
// Now that we know the label we're going to,
|
||||||
// look it up in the break loop nodes table
|
// look it up in the break loop nodes table
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
Some(b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b),
|
Some(b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b),
|
||||||
None => span_bug!(expr.span, "break to unknown label")
|
None => span_bug!(expr.span, "break to unknown label")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Continue(label) => {
|
hir::ExprKind::Continue(label) => {
|
||||||
// Find which label this expr continues to
|
// Find which label this expr continues to
|
||||||
let sc = match label.target_id {
|
let sc = label.target_id.unwrap_or_else(|err|
|
||||||
Ok(node_id) => node_id,
|
span_bug!(expr.span, "loop scope error: {}", err));
|
||||||
Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Now that we know the label we're going to,
|
// Now that we know the label we're going to,
|
||||||
// look it up in the continue loop nodes table
|
// look it up in the continue loop nodes table
|
||||||
|
self.cont_ln.get(&sc).cloned().unwrap_or_else(||
|
||||||
|
span_bug!(expr.span, "continue to unknown label"))
|
||||||
|
}
|
||||||
|
|
||||||
match self.cont_ln.get(&sc) {
|
hir::ExprKind::Assign(ref l, ref r) => {
|
||||||
Some(&b) => b,
|
|
||||||
None => span_bug!(expr.span, "continue to unknown label")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::Assign(ref l, ref r) => {
|
|
||||||
// see comment on places in
|
|
||||||
// propagate_through_place_components()
|
|
||||||
let succ = self.write_place(&l, succ, ACC_WRITE);
|
|
||||||
let succ = self.propagate_through_place_components(&l, succ);
|
|
||||||
self.propagate_through_expr(&r, succ)
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::AssignOp(_, ref l, ref r) => {
|
|
||||||
// an overloaded assign op is like a method call
|
|
||||||
if self.tables.is_method_call(expr) {
|
|
||||||
let succ = self.propagate_through_expr(&l, succ);
|
|
||||||
self.propagate_through_expr(&r, succ)
|
|
||||||
} else {
|
|
||||||
// see comment on places in
|
// see comment on places in
|
||||||
// propagate_through_place_components()
|
// propagate_through_place_components()
|
||||||
let succ = self.write_place(&l, succ, ACC_WRITE|ACC_READ);
|
let succ = self.write_place(&l, succ, ACC_WRITE);
|
||||||
let succ = self.propagate_through_expr(&r, succ);
|
let succ = self.propagate_through_place_components(&l, succ);
|
||||||
self.propagate_through_place_components(&l, succ)
|
self.propagate_through_expr(&r, succ)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Uninteresting cases: just propagate in rev exec order
|
hir::ExprKind::AssignOp(_, ref l, ref r) => {
|
||||||
|
// an overloaded assign op is like a method call
|
||||||
|
if self.tables.is_method_call(expr) {
|
||||||
|
let succ = self.propagate_through_expr(&l, succ);
|
||||||
|
self.propagate_through_expr(&r, succ)
|
||||||
|
} else {
|
||||||
|
// see comment on places in
|
||||||
|
// propagate_through_place_components()
|
||||||
|
let succ = self.write_place(&l, succ, ACC_WRITE|ACC_READ);
|
||||||
|
let succ = self.propagate_through_expr(&r, succ);
|
||||||
|
self.propagate_through_place_components(&l, succ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hir::ExprKind::Array(ref exprs) => {
|
// Uninteresting cases: just propagate in rev exec order
|
||||||
self.propagate_through_exprs(exprs, succ)
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::Struct(_, ref fields, ref with_expr) => {
|
hir::ExprKind::Array(ref exprs) => {
|
||||||
let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ);
|
self.propagate_through_exprs(exprs, succ)
|
||||||
fields.iter().rev().fold(succ, |succ, field| {
|
}
|
||||||
self.propagate_through_expr(&field.expr, succ)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::Call(ref f, ref args) => {
|
hir::ExprKind::Struct(_, ref fields, ref with_expr) => {
|
||||||
// FIXME(canndrew): This is_never should really be an is_uninhabited
|
let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ);
|
||||||
let succ = if self.tables.expr_ty(expr).is_never() {
|
fields.iter().rev().fold(succ, |succ, field| {
|
||||||
self.s.exit_ln
|
self.propagate_through_expr(&field.expr, succ)
|
||||||
} else {
|
})
|
||||||
succ
|
}
|
||||||
};
|
|
||||||
let succ = self.propagate_through_exprs(args, succ);
|
|
||||||
self.propagate_through_expr(&f, succ)
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::MethodCall(.., ref args) => {
|
hir::ExprKind::Call(ref f, ref args) => {
|
||||||
// FIXME(canndrew): This is_never should really be an is_uninhabited
|
// FIXME(canndrew): This is_never should really be an is_uninhabited
|
||||||
let succ = if self.tables.expr_ty(expr).is_never() {
|
let succ = if self.tables.expr_ty(expr).is_never() {
|
||||||
self.s.exit_ln
|
self.s.exit_ln
|
||||||
} else {
|
} else {
|
||||||
succ
|
succ
|
||||||
};
|
};
|
||||||
self.propagate_through_exprs(args, succ)
|
let succ = self.propagate_through_exprs(args, succ);
|
||||||
}
|
self.propagate_through_expr(&f, succ)
|
||||||
|
}
|
||||||
|
|
||||||
hir::ExprKind::Tup(ref exprs) => {
|
hir::ExprKind::MethodCall(.., ref args) => {
|
||||||
self.propagate_through_exprs(exprs, succ)
|
// FIXME(canndrew): This is_never should really be an is_uninhabited
|
||||||
}
|
let succ = if self.tables.expr_ty(expr).is_never() {
|
||||||
|
self.s.exit_ln
|
||||||
|
} else {
|
||||||
|
succ
|
||||||
|
};
|
||||||
|
|
||||||
hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => {
|
self.propagate_through_exprs(args, succ)
|
||||||
let r_succ = self.propagate_through_expr(&r, succ);
|
}
|
||||||
|
|
||||||
let ln = self.live_node(expr.hir_id, expr.span);
|
hir::ExprKind::Tup(ref exprs) => {
|
||||||
self.init_from_succ(ln, succ);
|
self.propagate_through_exprs(exprs, succ)
|
||||||
self.merge_from_succ(ln, r_succ, false);
|
}
|
||||||
|
|
||||||
self.propagate_through_expr(&l, ln)
|
hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => {
|
||||||
}
|
let r_succ = self.propagate_through_expr(&r, succ);
|
||||||
|
|
||||||
hir::ExprKind::Index(ref l, ref r) |
|
let ln = self.live_node(expr.hir_id, expr.span);
|
||||||
hir::ExprKind::Binary(_, ref l, ref r) => {
|
self.init_from_succ(ln, succ);
|
||||||
let r_succ = self.propagate_through_expr(&r, succ);
|
self.merge_from_succ(ln, r_succ, false);
|
||||||
self.propagate_through_expr(&l, r_succ)
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::Box(ref e) |
|
self.propagate_through_expr(&l, ln)
|
||||||
hir::ExprKind::AddrOf(_, ref e) |
|
}
|
||||||
hir::ExprKind::Cast(ref e, _) |
|
|
||||||
hir::ExprKind::Type(ref e, _) |
|
|
||||||
hir::ExprKind::Unary(_, ref e) |
|
|
||||||
hir::ExprKind::Yield(ref e) |
|
|
||||||
hir::ExprKind::Repeat(ref e, _) => {
|
|
||||||
self.propagate_through_expr(&e, succ)
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => {
|
hir::ExprKind::Index(ref l, ref r) |
|
||||||
let succ = ia.outputs.iter().zip(outputs).rev().fold(succ, |succ, (o, output)| {
|
hir::ExprKind::Binary(_, ref l, ref r) => {
|
||||||
|
let r_succ = self.propagate_through_expr(&r, succ);
|
||||||
|
self.propagate_through_expr(&l, r_succ)
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::ExprKind::Box(ref e) |
|
||||||
|
hir::ExprKind::AddrOf(_, ref e) |
|
||||||
|
hir::ExprKind::Cast(ref e, _) |
|
||||||
|
hir::ExprKind::Type(ref e, _) |
|
||||||
|
hir::ExprKind::Unary(_, ref e) |
|
||||||
|
hir::ExprKind::Yield(ref e) |
|
||||||
|
hir::ExprKind::Repeat(ref e, _) => {
|
||||||
|
self.propagate_through_expr(&e, succ)
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => {
|
||||||
|
let succ = ia.outputs.iter().zip(outputs).rev().fold(succ, |succ, (o, output)| {
|
||||||
// see comment on places
|
// see comment on places
|
||||||
// in propagate_through_place_components()
|
// in propagate_through_place_components()
|
||||||
if o.is_indirect {
|
if o.is_indirect {
|
||||||
|
@ -1269,29 +1258,28 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
let acc = if o.is_rw { ACC_WRITE|ACC_READ } else { ACC_WRITE };
|
let acc = if o.is_rw { ACC_WRITE|ACC_READ } else { ACC_WRITE };
|
||||||
let succ = self.write_place(output, succ, acc);
|
let succ = self.write_place(output, succ, acc);
|
||||||
self.propagate_through_place_components(output, succ)
|
self.propagate_through_place_components(output, succ)
|
||||||
}
|
}});
|
||||||
});
|
|
||||||
|
|
||||||
// Inputs are executed first. Propagate last because of rev order
|
// Inputs are executed first. Propagate last because of rev order
|
||||||
self.propagate_through_exprs(inputs, succ)
|
self.propagate_through_exprs(inputs, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Lit(..) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
|
hir::ExprKind::Lit(..) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
|
||||||
succ
|
succ
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that labels have been resolved, so we don't need to look
|
// Note that labels have been resolved, so we don't need to look
|
||||||
// at the label ident
|
// at the label ident
|
||||||
hir::ExprKind::Block(ref blk, _) => {
|
hir::ExprKind::Block(ref blk, _) => {
|
||||||
self.propagate_through_block(&blk, succ)
|
self.propagate_through_block(&blk, succ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_through_place_components(&mut self,
|
fn propagate_through_place_components(&mut self,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
succ: LiveNode)
|
succ: LiveNode)
|
||||||
-> LiveNode {
|
-> LiveNode {
|
||||||
// # Places
|
// # Places
|
||||||
//
|
//
|
||||||
// In general, the full flow graph structure for an
|
// In general, the full flow graph structure for an
|
||||||
|
@ -1349,18 +1337,17 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// see comment on propagate_through_place()
|
// see comment on propagate_through_place()
|
||||||
fn write_place(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
|
fn write_place(&mut self, expr: &Expr, succ: LiveNode, acc: u32) -> LiveNode {
|
||||||
-> LiveNode {
|
|
||||||
match expr.node {
|
match expr.node {
|
||||||
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
|
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
|
||||||
self.access_path(expr.hir_id, path, succ, acc)
|
self.access_path(expr.hir_id, path, succ, acc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We do not track other places, so just propagate through
|
// We do not track other places, so just propagate through
|
||||||
// to their subcomponents. Also, it may happen that
|
// to their subcomponents. Also, it may happen that
|
||||||
// non-places occur here, because those are detected in the
|
// non-places occur here, because those are detected in the
|
||||||
// later pass borrowck.
|
// later pass borrowck.
|
||||||
_ => succ
|
_ => succ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1379,10 +1366,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
fn access_path(&mut self, hir_id: HirId, path: &hir::Path, succ: LiveNode, acc: u32)
|
fn access_path(&mut self, hir_id: HirId, path: &hir::Path, succ: LiveNode, acc: u32)
|
||||||
-> LiveNode {
|
-> LiveNode {
|
||||||
match path.def {
|
match path.def {
|
||||||
Def::Local(nid) => {
|
Def::Local(nid) => {
|
||||||
self.access_var(hir_id, nid, succ, acc, path.span)
|
self.access_var(hir_id, nid, succ, acc, path.span)
|
||||||
}
|
}
|
||||||
_ => succ
|
_ => succ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1392,7 +1379,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
body: &hir::Block,
|
body: &hir::Block,
|
||||||
succ: LiveNode)
|
succ: LiveNode)
|
||||||
-> LiveNode {
|
-> LiveNode {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
We model control flow like this:
|
We model control flow like this:
|
||||||
|
@ -1450,8 +1436,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
self.propagate_through_expr(&cond, ln)
|
self.propagate_through_expr(&cond, ln)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
assert!(cond_ln == new_cond_ln);
|
assert_eq!(cond_ln, new_cond_ln);
|
||||||
assert!(body_ln == self.propagate_through_block(body, cond_ln));
|
assert_eq!(body_ln, self.propagate_through_block(body, cond_ln));
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_ln
|
cond_ln
|
||||||
|
@ -1505,49 +1491,49 @@ fn check_arm<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, arm: &'tcx hir::Arm) {
|
||||||
|
|
||||||
fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
|
fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
hir::ExprKind::Assign(ref l, _) => {
|
hir::ExprKind::Assign(ref l, _) => {
|
||||||
this.check_place(&l);
|
|
||||||
|
|
||||||
intravisit::walk_expr(this, expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::AssignOp(_, ref l, _) => {
|
|
||||||
if !this.tables.is_method_call(expr) {
|
|
||||||
this.check_place(&l);
|
this.check_place(&l);
|
||||||
|
|
||||||
|
intravisit::walk_expr(this, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
intravisit::walk_expr(this, expr);
|
hir::ExprKind::AssignOp(_, ref l, _) => {
|
||||||
}
|
if !this.tables.is_method_call(expr) {
|
||||||
|
this.check_place(&l);
|
||||||
|
}
|
||||||
|
|
||||||
hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => {
|
intravisit::walk_expr(this, expr);
|
||||||
for input in inputs {
|
|
||||||
this.visit_expr(input);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output operands must be places
|
hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => {
|
||||||
for (o, output) in ia.outputs.iter().zip(outputs) {
|
for input in inputs {
|
||||||
if !o.is_indirect {
|
this.visit_expr(input);
|
||||||
this.check_place(output);
|
}
|
||||||
}
|
|
||||||
this.visit_expr(output);
|
// Output operands must be places
|
||||||
|
for (o, output) in ia.outputs.iter().zip(outputs) {
|
||||||
|
if !o.is_indirect {
|
||||||
|
this.check_place(output);
|
||||||
|
}
|
||||||
|
this.visit_expr(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
intravisit::walk_expr(this, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
intravisit::walk_expr(this, expr);
|
// no correctness conditions related to liveness
|
||||||
}
|
hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) | hir::ExprKind::If(..) |
|
||||||
|
hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) |
|
||||||
// no correctness conditions related to liveness
|
hir::ExprKind::Index(..) | hir::ExprKind::Field(..) |
|
||||||
hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) | hir::ExprKind::If(..) |
|
hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) |
|
||||||
hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) |
|
hir::ExprKind::Cast(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Ret(..) |
|
||||||
hir::ExprKind::Index(..) | hir::ExprKind::Field(..) |
|
hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Lit(_) |
|
||||||
hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) |
|
hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) |
|
||||||
hir::ExprKind::Cast(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Ret(..) |
|
hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
|
||||||
hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Lit(_) |
|
hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) |
|
||||||
hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) |
|
hir::ExprKind::Box(..) | hir::ExprKind::Type(..) => {
|
||||||
hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
|
intravisit::walk_expr(this, expr);
|
||||||
hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) |
|
}
|
||||||
hir::ExprKind::Box(..) | hir::ExprKind::Type(..) => {
|
|
||||||
intravisit::walk_expr(this, expr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1576,7 +1562,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
|
|
||||||
fn should_warn(&self, var: Variable) -> Option<String> {
|
fn should_warn(&self, var: Variable) -> Option<String> {
|
||||||
let name = self.ir.variable_name(var);
|
let name = self.ir.variable_name(var);
|
||||||
if name.is_empty() || name.as_bytes()[0] == ('_' as u8) {
|
if name.is_empty() || name.as_bytes()[0] == b'_' {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(name)
|
Some(name)
|
||||||
|
@ -1617,7 +1603,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
if !self.used_on_entry(ln, var) {
|
if !self.used_on_entry(ln, var) {
|
||||||
let r = self.should_warn(var);
|
let r = self.should_warn(var);
|
||||||
if let Some(name) = r {
|
if let Some(name) = r {
|
||||||
|
|
||||||
// annoying: for parameters in funcs like `fn(x: i32)
|
// annoying: for parameters in funcs like `fn(x: i32)
|
||||||
// {ret}`, there is only one node, so asking about
|
// {ret}`, there is only one node, so asking about
|
||||||
// assigned_on_exit() is not meaningful.
|
// assigned_on_exit() is not meaningful.
|
||||||
|
@ -1627,8 +1612,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
self.assigned_on_exit(ln, var).is_some()
|
self.assigned_on_exit(ln, var).is_some()
|
||||||
};
|
};
|
||||||
|
|
||||||
let suggest_underscore_msg = format!("consider using `_{}` instead",
|
let suggest_underscore_msg = format!("consider using `_{}` instead", name);
|
||||||
name);
|
|
||||||
|
|
||||||
if is_assigned {
|
if is_assigned {
|
||||||
self.ir.tcx
|
self.ir.tcx
|
||||||
|
|
|
@ -83,6 +83,7 @@ use hir;
|
||||||
use syntax::ast::{self, Name};
|
use syntax::ast::{self, Name};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
@ -91,13 +92,13 @@ use util::nodemap::ItemLocalSet;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Categorization<'tcx> {
|
pub enum Categorization<'tcx> {
|
||||||
Rvalue(ty::Region<'tcx>), // temporary val, argument is its scope
|
Rvalue(ty::Region<'tcx>), // temporary val, argument is its scope
|
||||||
StaticItem,
|
StaticItem,
|
||||||
Upvar(Upvar), // upvar referenced by closure env
|
Upvar(Upvar), // upvar referenced by closure env
|
||||||
Local(ast::NodeId), // local variable
|
Local(ast::NodeId), // local variable
|
||||||
Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr
|
Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr
|
||||||
Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc
|
Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc
|
||||||
Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1)
|
Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1)
|
||||||
|
|
||||||
// (*1) downcast is only required if the enum has more than one variant
|
// (*1) downcast is only required if the enum has more than one variant
|
||||||
}
|
}
|
||||||
|
@ -149,8 +150,8 @@ impl Hash for FieldIndex {
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
pub enum InteriorOffsetKind {
|
pub enum InteriorOffsetKind {
|
||||||
Index, // e.g. `array_expr[index_expr]`
|
Index, // e.g. `array_expr[index_expr]`
|
||||||
Pattern, // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }`
|
Pattern, // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }`
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
|
@ -580,7 +581,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>,
|
fn helper<'a, 'gcx, 'tcx>(mc: &MemCategorizationContext<'a, 'gcx, 'tcx>,
|
||||||
expr: &hir::Expr,
|
expr: &hir::Expr,
|
||||||
adjustments: &[adjustment::Adjustment<'tcx>])
|
adjustments: &[adjustment::Adjustment<'tcx>])
|
||||||
-> McResult<cmt_<'tcx>> {
|
-> McResult<cmt_<'tcx>> {
|
||||||
match adjustments.split_last() {
|
match adjustments.split_last() {
|
||||||
None => mc.cat_expr_unadjusted(expr),
|
None => mc.cat_expr_unadjusted(expr),
|
||||||
Some((adjustment, previous)) => {
|
Some((adjustment, previous)) => {
|
||||||
|
@ -640,61 +641,61 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let expr_ty = self.expr_ty(expr)?;
|
let expr_ty = self.expr_ty(expr)?;
|
||||||
match expr.node {
|
match expr.node {
|
||||||
hir::ExprKind::Unary(hir::UnDeref, ref e_base) => {
|
hir::ExprKind::Unary(hir::UnDeref, ref e_base) => {
|
||||||
if self.tables.is_method_call(expr) {
|
if self.tables.is_method_call(expr) {
|
||||||
self.cat_overloaded_place(expr, e_base, NoteNone)
|
self.cat_overloaded_place(expr, e_base, NoteNone)
|
||||||
} else {
|
} else {
|
||||||
let base_cmt = Rc::new(self.cat_expr(&e_base)?);
|
let base_cmt = Rc::new(self.cat_expr(&e_base)?);
|
||||||
self.cat_deref(expr, base_cmt, NoteNone)
|
self.cat_deref(expr, base_cmt, NoteNone)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::Field(ref base, f_ident) => {
|
hir::ExprKind::Field(ref base, f_ident) => {
|
||||||
let base_cmt = Rc::new(self.cat_expr(&base)?);
|
|
||||||
debug!("cat_expr(cat_field): id={} expr={:?} base={:?}",
|
|
||||||
expr.id,
|
|
||||||
expr,
|
|
||||||
base_cmt);
|
|
||||||
let f_index = self.tcx.field_index(expr.id, self.tables);
|
|
||||||
Ok(self.cat_field(expr, base_cmt, f_index, f_ident, expr_ty))
|
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::Index(ref base, _) => {
|
|
||||||
if self.tables.is_method_call(expr) {
|
|
||||||
// If this is an index implemented by a method call, then it
|
|
||||||
// will include an implicit deref of the result.
|
|
||||||
// The call to index() returns a `&T` value, which
|
|
||||||
// is an rvalue. That is what we will be
|
|
||||||
// dereferencing.
|
|
||||||
self.cat_overloaded_place(expr, base, NoteIndex)
|
|
||||||
} else {
|
|
||||||
let base_cmt = Rc::new(self.cat_expr(&base)?);
|
let base_cmt = Rc::new(self.cat_expr(&base)?);
|
||||||
self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index)
|
debug!("cat_expr(cat_field): id={} expr={:?} base={:?}",
|
||||||
|
expr.id,
|
||||||
|
expr,
|
||||||
|
base_cmt);
|
||||||
|
let f_index = self.tcx.field_index(expr.id, self.tables);
|
||||||
|
Ok(self.cat_field(expr, base_cmt, f_index, f_ident, expr_ty))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
hir::ExprKind::Path(ref qpath) => {
|
hir::ExprKind::Index(ref base, _) => {
|
||||||
let def = self.tables.qpath_def(qpath, expr.hir_id);
|
if self.tables.is_method_call(expr) {
|
||||||
self.cat_def(expr.hir_id, expr.span, expr_ty, def)
|
// If this is an index implemented by a method call, then it
|
||||||
}
|
// will include an implicit deref of the result.
|
||||||
|
// The call to index() returns a `&T` value, which
|
||||||
|
// is an rvalue. That is what we will be
|
||||||
|
// dereferencing.
|
||||||
|
self.cat_overloaded_place(expr, base, NoteIndex)
|
||||||
|
} else {
|
||||||
|
let base_cmt = Rc::new(self.cat_expr(&base)?);
|
||||||
|
self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hir::ExprKind::Type(ref e, _) => {
|
hir::ExprKind::Path(ref qpath) => {
|
||||||
self.cat_expr(&e)
|
let def = self.tables.qpath_def(qpath, expr.hir_id);
|
||||||
}
|
self.cat_def(expr.hir_id, expr.span, expr_ty, def)
|
||||||
|
}
|
||||||
|
|
||||||
hir::ExprKind::AddrOf(..) | hir::ExprKind::Call(..) |
|
hir::ExprKind::Type(ref e, _) => {
|
||||||
hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) |
|
self.cat_expr(&e)
|
||||||
hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) |
|
}
|
||||||
hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) |
|
|
||||||
hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) |
|
hir::ExprKind::AddrOf(..) | hir::ExprKind::Call(..) |
|
||||||
hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::If(..) |
|
hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) |
|
||||||
hir::ExprKind::Binary(..) | hir::ExprKind::While(..) |
|
hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) |
|
||||||
hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) |
|
hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) |
|
||||||
hir::ExprKind::Lit(..) | hir::ExprKind::Break(..) |
|
hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) |
|
||||||
hir::ExprKind::Continue(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
|
hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::If(..) |
|
||||||
hir::ExprKind::InlineAsm(..) | hir::ExprKind::Box(..) => {
|
hir::ExprKind::Binary(..) | hir::ExprKind::While(..) |
|
||||||
Ok(self.cat_rvalue_node(expr.hir_id, expr.span, expr_ty))
|
hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) |
|
||||||
}
|
hir::ExprKind::Lit(..) | hir::ExprKind::Break(..) |
|
||||||
|
hir::ExprKind::Continue(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
|
||||||
|
hir::ExprKind::InlineAsm(..) | hir::ExprKind::Box(..) => {
|
||||||
|
Ok(self.cat_rvalue_node(expr.hir_id, expr.span, expr_ty))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -708,44 +709,45 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
hir_id, expr_ty, def);
|
hir_id, expr_ty, def);
|
||||||
|
|
||||||
match def {
|
match def {
|
||||||
Def::StructCtor(..) | Def::VariantCtor(..) | Def::Const(..) |
|
Def::StructCtor(..) | Def::VariantCtor(..) | Def::Const(..) |
|
||||||
Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => {
|
Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => {
|
||||||
Ok(self.cat_rvalue_node(hir_id, span, expr_ty))
|
Ok(self.cat_rvalue_node(hir_id, span, expr_ty))
|
||||||
}
|
|
||||||
|
|
||||||
Def::Static(def_id, mutbl) => {
|
|
||||||
// `#[thread_local]` statics may not outlive the current function.
|
|
||||||
for attr in &self.tcx.get_attrs(def_id)[..] {
|
|
||||||
if attr.check_name("thread_local") {
|
|
||||||
return Ok(self.cat_rvalue_node(hir_id, span, expr_ty));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(cmt_ {
|
|
||||||
hir_id,
|
|
||||||
span:span,
|
|
||||||
cat:Categorization::StaticItem,
|
|
||||||
mutbl: if mutbl { McDeclared } else { McImmutable},
|
|
||||||
ty:expr_ty,
|
|
||||||
note: NoteNone
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
Def::Upvar(var_id, _, fn_node_id) => {
|
Def::Static(def_id, mutbl) => {
|
||||||
self.cat_upvar(hir_id, span, var_id, fn_node_id)
|
// `#[thread_local]` statics may not outlive the current function.
|
||||||
}
|
for attr in &self.tcx.get_attrs(def_id)[..] {
|
||||||
|
if attr.check_name("thread_local") {
|
||||||
|
return Ok(self.cat_rvalue_node(hir_id, span, expr_ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Def::Local(vid) => {
|
Ok(cmt_ {
|
||||||
Ok(cmt_ {
|
hir_id,
|
||||||
hir_id,
|
span:span,
|
||||||
span,
|
cat:Categorization::StaticItem,
|
||||||
cat: Categorization::Local(vid),
|
mutbl: if mutbl { McDeclared } else { McImmutable},
|
||||||
mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vid),
|
ty:expr_ty,
|
||||||
ty: expr_ty,
|
note: NoteNone
|
||||||
note: NoteNone
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def)
|
Def::Upvar(var_id, _, fn_node_id) => {
|
||||||
|
self.cat_upvar(hir_id, span, var_id, fn_node_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
Def::Local(vid) => {
|
||||||
|
Ok(cmt_ {
|
||||||
|
hir_id,
|
||||||
|
span,
|
||||||
|
cat: Categorization::Local(vid),
|
||||||
|
mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vid),
|
||||||
|
ty: expr_ty,
|
||||||
|
note: NoteNone
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,19 +943,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
expr_ty: Ty<'tcx>)
|
expr_ty: Ty<'tcx>)
|
||||||
-> cmt_<'tcx> {
|
-> cmt_<'tcx> {
|
||||||
debug!(
|
debug!("cat_rvalue_node(id={:?}, span={:?}, expr_ty={:?})",
|
||||||
"cat_rvalue_node(id={:?}, span={:?}, expr_ty={:?})",
|
hir_id, span, expr_ty);
|
||||||
hir_id,
|
|
||||||
span,
|
|
||||||
expr_ty,
|
|
||||||
);
|
|
||||||
let promotable = self.rvalue_promotable_map.as_ref().map(|m| m.contains(&hir_id.local_id))
|
let promotable = self.rvalue_promotable_map.as_ref().map(|m| m.contains(&hir_id.local_id))
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
debug!(
|
debug!("cat_rvalue_node: promotable = {:?}", promotable);
|
||||||
"cat_rvalue_node: promotable = {:?}",
|
|
||||||
promotable,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
|
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
|
||||||
let promotable = match expr_ty.sty {
|
let promotable = match expr_ty.sty {
|
||||||
|
@ -961,10 +957,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
_ => promotable,
|
_ => promotable,
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(
|
debug!("cat_rvalue_node: promotable = {:?} (2)", promotable);
|
||||||
"cat_rvalue_node: promotable = {:?} (2)",
|
|
||||||
promotable,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Compute maximum lifetime of this rvalue. This is 'static if
|
// Compute maximum lifetime of this rvalue. This is 'static if
|
||||||
// we can promote to a constant, otherwise equal to enclosing temp
|
// we can promote to a constant, otherwise equal to enclosing temp
|
||||||
|
@ -1022,12 +1015,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
base: &hir::Expr,
|
base: &hir::Expr,
|
||||||
note: Note,
|
note: Note,
|
||||||
) -> McResult<cmt_<'tcx>> {
|
) -> McResult<cmt_<'tcx>> {
|
||||||
debug!(
|
debug!("cat_overloaded_place(expr={:?}, base={:?}, note={:?})",
|
||||||
"cat_overloaded_place(expr={:?}, base={:?}, note={:?})",
|
expr,
|
||||||
expr,
|
base,
|
||||||
base,
|
note);
|
||||||
note,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Reconstruct the output assuming it's a reference with the
|
// Reconstruct the output assuming it's a reference with the
|
||||||
// same region and mutability as the receiver. This holds for
|
// same region and mutability as the receiver. This holds for
|
||||||
|
@ -1037,9 +1028,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let (region, mutbl) = match base_ty.sty {
|
let (region, mutbl) = match base_ty.sty {
|
||||||
ty::Ref(region, _, mutbl) => (region, mutbl),
|
ty::Ref(region, _, mutbl) => (region, mutbl),
|
||||||
_ => {
|
_ => span_bug!(expr.span, "cat_overloaded_place: base is not a reference")
|
||||||
span_bug!(expr.span, "cat_overloaded_place: base is not a reference")
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut {
|
let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut {
|
||||||
ty: place_ty,
|
ty: place_ty,
|
||||||
|
@ -1062,8 +1051,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
let deref_ty = match base_cmt_ty.builtin_deref(true) {
|
let deref_ty = match base_cmt_ty.builtin_deref(true) {
|
||||||
Some(mt) => mt.ty,
|
Some(mt) => mt.ty,
|
||||||
None => {
|
None => {
|
||||||
debug!("Explicit deref of non-derefable type: {:?}",
|
debug!("Explicit deref of non-derefable type: {:?}", base_cmt_ty);
|
||||||
base_cmt_ty);
|
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1120,11 +1108,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cat_imm_interior<N:HirNode>(&self,
|
pub fn cat_imm_interior<N:HirNode>(&self,
|
||||||
node: &N,
|
node: &N,
|
||||||
base_cmt: cmt<'tcx>,
|
base_cmt: cmt<'tcx>,
|
||||||
interior_ty: Ty<'tcx>,
|
interior_ty: Ty<'tcx>,
|
||||||
interior: InteriorKind)
|
interior: InteriorKind)
|
||||||
-> cmt_<'tcx> {
|
-> cmt_<'tcx> {
|
||||||
let ret = cmt_ {
|
let ret = cmt_ {
|
||||||
hir_id: node.hir_id(),
|
hir_id: node.hir_id(),
|
||||||
span: node.span(),
|
span: node.span(),
|
||||||
|
@ -1138,10 +1126,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cat_downcast_if_needed<N:HirNode>(&self,
|
pub fn cat_downcast_if_needed<N:HirNode>(&self,
|
||||||
node: &N,
|
node: &N,
|
||||||
base_cmt: cmt<'tcx>,
|
base_cmt: cmt<'tcx>,
|
||||||
variant_did: DefId)
|
variant_did: DefId)
|
||||||
-> cmt<'tcx> {
|
-> cmt<'tcx> {
|
||||||
// univariant enums do not need downcasts
|
// univariant enums do not need downcasts
|
||||||
let base_did = self.tcx.parent_def_id(variant_did).unwrap();
|
let base_did = self.tcx.parent_def_id(variant_did).unwrap();
|
||||||
if self.tcx.adt_def(base_did).variants.len() != 1 {
|
if self.tcx.adt_def(base_did).variants.len() != 1 {
|
||||||
|
@ -1277,117 +1265,120 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
op(cmt.clone(), pat);
|
op(cmt.clone(), pat);
|
||||||
|
|
||||||
match pat.node {
|
match pat.node {
|
||||||
PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => {
|
PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => {
|
||||||
let def = self.tables.qpath_def(qpath, pat.hir_id);
|
let def = self.tables.qpath_def(qpath, pat.hir_id);
|
||||||
let (cmt, expected_len) = match def {
|
let (cmt, expected_len) = match def {
|
||||||
Def::Err => {
|
Def::Err => {
|
||||||
debug!("access to unresolvable pattern {:?}", pat);
|
debug!("access to unresolvable pattern {:?}", pat);
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
Def::VariantCtor(def_id, CtorKind::Fn) => {
|
Def::VariantCtor(def_id, CtorKind::Fn) => {
|
||||||
let enum_def = self.tcx.parent_def_id(def_id).unwrap();
|
let enum_def = self.tcx.parent_def_id(def_id).unwrap();
|
||||||
(self.cat_downcast_if_needed(pat, cmt, def_id),
|
(self.cat_downcast_if_needed(pat, cmt, def_id),
|
||||||
self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len())
|
self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len())
|
||||||
}
|
}
|
||||||
Def::StructCtor(_, CtorKind::Fn) | Def::SelfCtor(..) => {
|
Def::StructCtor(_, CtorKind::Fn) | Def::SelfCtor(..) => {
|
||||||
match self.pat_ty_unadjusted(&pat)?.sty {
|
match self.pat_ty_unadjusted(&pat)?.sty {
|
||||||
ty::Adt(adt_def, _) => {
|
ty::Adt(adt_def, _) => {
|
||||||
(cmt, adt_def.non_enum_variant().fields.len())
|
(cmt, adt_def.non_enum_variant().fields.len())
|
||||||
}
|
}
|
||||||
ref ty => {
|
ref ty => {
|
||||||
span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty);
|
span_bug!(pat.span,
|
||||||
|
"tuple struct pattern unexpected type {:?}", ty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
def => {
|
||||||
def => {
|
span_bug!(pat.span, "tuple struct pattern didn't resolve \
|
||||||
span_bug!(pat.span, "tuple struct pattern didn't resolve \
|
to variant or struct {:?}", def);
|
||||||
to variant or struct {:?}", def);
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
|
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
|
||||||
let subpat_ty = self.pat_ty_adjusted(&subpat)?; // see (*2)
|
let subpat_ty = self.pat_ty_adjusted(&subpat)?; // see (*2)
|
||||||
let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string())));
|
let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string())));
|
||||||
let subcmt = Rc::new(self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior));
|
let subcmt = Rc::new(
|
||||||
|
self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior));
|
||||||
|
self.cat_pattern_(subcmt, &subpat, op)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PatKind::Struct(ref qpath, ref field_pats, _) => {
|
||||||
|
// {f1: p1, ..., fN: pN}
|
||||||
|
let def = self.tables.qpath_def(qpath, pat.hir_id);
|
||||||
|
let cmt = match def {
|
||||||
|
Def::Err => {
|
||||||
|
debug!("access to unresolvable pattern {:?}", pat);
|
||||||
|
return Err(())
|
||||||
|
},
|
||||||
|
Def::Variant(variant_did) |
|
||||||
|
Def::VariantCtor(variant_did, ..) => {
|
||||||
|
self.cat_downcast_if_needed(pat, cmt, variant_did)
|
||||||
|
},
|
||||||
|
_ => cmt
|
||||||
|
};
|
||||||
|
|
||||||
|
for fp in field_pats {
|
||||||
|
let field_ty = self.pat_ty_adjusted(&fp.node.pat)?; // see (*2)
|
||||||
|
let f_index = self.tcx.field_index(fp.node.id, self.tables);
|
||||||
|
let cmt_field = Rc::new(self.cat_field(pat, cmt.clone(), f_index,
|
||||||
|
fp.node.ident, field_ty));
|
||||||
|
self.cat_pattern_(cmt_field, &fp.node.pat, op)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PatKind::Binding(.., Some(ref subpat)) => {
|
||||||
|
self.cat_pattern_(cmt, &subpat, op)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
PatKind::Tuple(ref subpats, ddpos) => {
|
||||||
|
// (p1, ..., pN)
|
||||||
|
let expected_len = match self.pat_ty_unadjusted(&pat)?.sty {
|
||||||
|
ty::Tuple(ref tys) => tys.len(),
|
||||||
|
ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
|
||||||
|
};
|
||||||
|
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
|
||||||
|
let subpat_ty = self.pat_ty_adjusted(&subpat)?; // see (*2)
|
||||||
|
let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string())));
|
||||||
|
let subcmt = Rc::new(
|
||||||
|
self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior));
|
||||||
|
self.cat_pattern_(subcmt, &subpat, op)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => {
|
||||||
|
// box p1, &p1, &mut p1. we can ignore the mutability of
|
||||||
|
// PatKind::Ref since that information is already contained
|
||||||
|
// in the type.
|
||||||
|
let subcmt = Rc::new(self.cat_deref(pat, cmt, NoteNone)?);
|
||||||
self.cat_pattern_(subcmt, &subpat, op)?;
|
self.cat_pattern_(subcmt, &subpat, op)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
PatKind::Struct(ref qpath, ref field_pats, _) => {
|
PatKind::Slice(ref before, ref slice, ref after) => {
|
||||||
// {f1: p1, ..., fN: pN}
|
let element_ty = match cmt.ty.builtin_index() {
|
||||||
let def = self.tables.qpath_def(qpath, pat.hir_id);
|
Some(ty) => ty,
|
||||||
let cmt = match def {
|
None => {
|
||||||
Def::Err => {
|
debug!("Explicit index of non-indexable type {:?}", cmt);
|
||||||
debug!("access to unresolvable pattern {:?}", pat);
|
return Err(());
|
||||||
return Err(())
|
}
|
||||||
},
|
};
|
||||||
Def::Variant(variant_did) |
|
let context = InteriorOffsetKind::Pattern;
|
||||||
Def::VariantCtor(variant_did, ..) => {
|
let elt_cmt = Rc::new(self.cat_index(pat, cmt, element_ty, context)?);
|
||||||
self.cat_downcast_if_needed(pat, cmt, variant_did)
|
for before_pat in before {
|
||||||
},
|
self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
|
||||||
_ => cmt
|
}
|
||||||
};
|
if let Some(ref slice_pat) = *slice {
|
||||||
|
self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
|
||||||
for fp in field_pats {
|
}
|
||||||
let field_ty = self.pat_ty_adjusted(&fp.node.pat)?; // see (*2)
|
for after_pat in after {
|
||||||
let f_index = self.tcx.field_index(fp.node.id, self.tables);
|
self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
|
||||||
let cmt_field = Rc::new(self.cat_field(pat, cmt.clone(), f_index,
|
|
||||||
fp.node.ident, field_ty));
|
|
||||||
self.cat_pattern_(cmt_field, &fp.node.pat, op)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PatKind::Binding(.., Some(ref subpat)) => {
|
|
||||||
self.cat_pattern_(cmt, &subpat, op)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
PatKind::Tuple(ref subpats, ddpos) => {
|
|
||||||
// (p1, ..., pN)
|
|
||||||
let expected_len = match self.pat_ty_unadjusted(&pat)?.sty {
|
|
||||||
ty::Tuple(ref tys) => tys.len(),
|
|
||||||
ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
|
|
||||||
};
|
|
||||||
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
|
|
||||||
let subpat_ty = self.pat_ty_adjusted(&subpat)?; // see (*2)
|
|
||||||
let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string())));
|
|
||||||
let subcmt = Rc::new(self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior));
|
|
||||||
self.cat_pattern_(subcmt, &subpat, op)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => {
|
|
||||||
// box p1, &p1, &mut p1. we can ignore the mutability of
|
|
||||||
// PatKind::Ref since that information is already contained
|
|
||||||
// in the type.
|
|
||||||
let subcmt = Rc::new(self.cat_deref(pat, cmt, NoteNone)?);
|
|
||||||
self.cat_pattern_(subcmt, &subpat, op)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
PatKind::Slice(ref before, ref slice, ref after) => {
|
|
||||||
let element_ty = match cmt.ty.builtin_index() {
|
|
||||||
Some(ty) => ty,
|
|
||||||
None => {
|
|
||||||
debug!("Explicit index of non-indexable type {:?}", cmt);
|
|
||||||
return Err(());
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
let context = InteriorOffsetKind::Pattern;
|
|
||||||
let elt_cmt = Rc::new(self.cat_index(pat, cmt, element_ty, context)?);
|
|
||||||
for before_pat in before {
|
|
||||||
self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
|
|
||||||
}
|
}
|
||||||
if let Some(ref slice_pat) = *slice {
|
|
||||||
self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
|
|
||||||
}
|
|
||||||
for after_pat in after {
|
|
||||||
self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PatKind::Path(_) | PatKind::Binding(.., None) |
|
PatKind::Path(_) | PatKind::Binding(.., None) |
|
||||||
PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => {
|
PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => {
|
||||||
// always ok
|
// always ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1489,59 +1480,59 @@ impl<'tcx> cmt_<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn descriptive_string(&self, tcx: TyCtxt<'_, '_, '_>) -> String {
|
pub fn descriptive_string(&self, tcx: TyCtxt<'_, '_, '_>) -> Cow<'static, str> {
|
||||||
match self.cat {
|
match self.cat {
|
||||||
Categorization::StaticItem => {
|
Categorization::StaticItem => {
|
||||||
"static item".to_string()
|
"static item".into()
|
||||||
}
|
}
|
||||||
Categorization::Rvalue(..) => {
|
Categorization::Rvalue(..) => {
|
||||||
"non-place".to_string()
|
"non-place".into()
|
||||||
}
|
}
|
||||||
Categorization::Local(vid) => {
|
Categorization::Local(vid) => {
|
||||||
if tcx.hir.is_argument(vid) {
|
if tcx.hir.is_argument(vid) {
|
||||||
"argument".to_string()
|
"argument"
|
||||||
} else {
|
} else {
|
||||||
"local variable".to_string()
|
"local variable"
|
||||||
}
|
}.into()
|
||||||
}
|
}
|
||||||
Categorization::Deref(_, pk) => {
|
Categorization::Deref(_, pk) => {
|
||||||
match self.upvar_cat() {
|
match self.upvar_cat() {
|
||||||
Some(&Categorization::Upvar(ref var)) => {
|
Some(&Categorization::Upvar(ref var)) => {
|
||||||
var.to_string()
|
var.to_string().into()
|
||||||
}
|
}
|
||||||
Some(_) => bug!(),
|
Some(_) => bug!(),
|
||||||
None => {
|
None => {
|
||||||
match pk {
|
match pk {
|
||||||
Unique => {
|
Unique => {
|
||||||
"`Box` content".to_string()
|
"`Box` content"
|
||||||
}
|
}
|
||||||
UnsafePtr(..) => {
|
UnsafePtr(..) => {
|
||||||
"dereference of raw pointer".to_string()
|
"dereference of raw pointer"
|
||||||
}
|
}
|
||||||
BorrowedPtr(..) => {
|
BorrowedPtr(..) => {
|
||||||
match self.note {
|
match self.note {
|
||||||
NoteIndex => "indexed content".to_string(),
|
NoteIndex => "indexed content",
|
||||||
_ => "borrowed content".to_string(),
|
_ => "borrowed content"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Categorization::Interior(_, InteriorField(..)) => {
|
Categorization::Interior(_, InteriorField(..)) => {
|
||||||
"field".to_string()
|
"field".into()
|
||||||
}
|
}
|
||||||
Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index)) => {
|
Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index)) => {
|
||||||
"indexed content".to_string()
|
"indexed content".into()
|
||||||
}
|
}
|
||||||
Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern)) => {
|
Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern)) => {
|
||||||
"pattern-bound indexed content".to_string()
|
"pattern-bound indexed content".into()
|
||||||
}
|
}
|
||||||
Categorization::Upvar(ref var) => {
|
Categorization::Upvar(ref var) => {
|
||||||
var.to_string()
|
var.to_string().into()
|
||||||
}
|
}
|
||||||
Categorization::Downcast(ref cmt, _) => {
|
Categorization::Downcast(ref cmt, _) => {
|
||||||
cmt.descriptive_string(tcx)
|
cmt.descriptive_string(tcx).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,7 +371,9 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for default_method in self.tcx.provided_trait_methods(trait_def_id) {
|
let provided_trait_methods = self.tcx.provided_trait_methods(trait_def_id);
|
||||||
|
self.worklist.reserve(provided_trait_methods.len());
|
||||||
|
for default_method in provided_trait_methods {
|
||||||
let node_id = self.tcx
|
let node_id = self.tcx
|
||||||
.hir
|
.hir
|
||||||
.as_local_node_id(default_method.def_id)
|
.as_local_node_id(default_method.def_id)
|
||||||
|
@ -394,7 +396,6 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a,
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ReachableSet(pub Lrc<NodeSet>);
|
pub struct ReachableSet(pub Lrc<NodeSet>);
|
||||||
|
|
||||||
|
|
||||||
fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> ReachableSet {
|
fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> ReachableSet {
|
||||||
debug_assert!(crate_num == LOCAL_CRATE);
|
debug_assert!(crate_num == LOCAL_CRATE);
|
||||||
|
|
||||||
|
|
|
@ -459,13 +459,13 @@ impl<'tcx> ScopeTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(Scope, Scope) {
|
pub fn each_encl_scope<E>(&self, mut e: E) where E: FnMut(Scope, Scope) {
|
||||||
for (&child, &parent) in &self.parent_map {
|
for (&child, &parent) in &self.parent_map {
|
||||||
e(child, parent.0)
|
e(child, parent.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&hir::ItemLocalId, Scope) {
|
pub fn each_var_scope<E>(&self, mut e: E) where E: FnMut(&hir::ItemLocalId, Scope) {
|
||||||
for (child, &parent) in self.var_map.iter() {
|
for (child, &parent) in self.var_map.iter() {
|
||||||
e(child, parent)
|
e(child, parent)
|
||||||
}
|
}
|
||||||
|
@ -515,10 +515,8 @@ impl<'tcx> ScopeTree {
|
||||||
|
|
||||||
/// Returns the lifetime of the local variable `var_id`
|
/// Returns the lifetime of the local variable `var_id`
|
||||||
pub fn var_scope(&self, var_id: hir::ItemLocalId) -> Scope {
|
pub fn var_scope(&self, var_id: hir::ItemLocalId) -> Scope {
|
||||||
match self.var_map.get(&var_id) {
|
self.var_map.get(&var_id).cloned().unwrap_or_else(||
|
||||||
Some(&r) => r,
|
bug!("no enclosing scope for id {:?}", var_id))
|
||||||
None => { bug!("no enclosing scope for id {:?}", var_id); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> Option<Scope> {
|
pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> Option<Scope> {
|
||||||
|
@ -559,8 +557,7 @@ impl<'tcx> ScopeTree {
|
||||||
scope
|
scope
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scopes_intersect(&self, scope1: Scope, scope2: Scope)
|
pub fn scopes_intersect(&self, scope1: Scope, scope2: Scope) -> bool {
|
||||||
-> bool {
|
|
||||||
self.is_subscope_of(scope1, scope2) ||
|
self.is_subscope_of(scope1, scope2) ||
|
||||||
self.is_subscope_of(scope2, scope1)
|
self.is_subscope_of(scope2, scope1)
|
||||||
}
|
}
|
||||||
|
@ -584,14 +581,13 @@ impl<'tcx> ScopeTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("is_subscope_of({:?}, {:?})=true",
|
debug!("is_subscope_of({:?}, {:?})=true", subscope, superscope);
|
||||||
subscope, superscope);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the id of the innermost containing body
|
/// Returns the id of the innermost containing body
|
||||||
pub fn containing_body(&self, mut scope: Scope)-> Option<hir::ItemLocalId> {
|
pub fn containing_body(&self, mut scope: Scope) -> Option<hir::ItemLocalId> {
|
||||||
loop {
|
loop {
|
||||||
if let ScopeData::CallSite = scope.data {
|
if let ScopeData::CallSite = scope.data {
|
||||||
return Some(scope.item_local_id());
|
return Some(scope.item_local_id());
|
||||||
|
@ -664,8 +660,8 @@ impl<'tcx> ScopeTree {
|
||||||
/// Assuming that the provided region was defined within this `ScopeTree`,
|
/// Assuming that the provided region was defined within this `ScopeTree`,
|
||||||
/// returns the outermost `Scope` that the region outlives.
|
/// returns the outermost `Scope` that the region outlives.
|
||||||
pub fn early_free_scope<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
pub fn early_free_scope<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
br: &ty::EarlyBoundRegion)
|
br: &ty::EarlyBoundRegion)
|
||||||
-> Scope {
|
-> Scope {
|
||||||
let param_owner = tcx.parent_def_id(br.def_id).unwrap();
|
let param_owner = tcx.parent_def_id(br.def_id).unwrap();
|
||||||
|
|
||||||
let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
|
let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
|
||||||
|
@ -828,10 +824,8 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
|
||||||
fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) {
|
fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) {
|
||||||
visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
|
visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
|
||||||
|
|
||||||
if let Some(ref g) = arm.guard {
|
if let Some(hir::Guard::If(ref expr)) = arm.guard {
|
||||||
match g {
|
visitor.terminating_scopes.insert(expr.hir_id.local_id);
|
||||||
hir::Guard::If(ref expr) => visitor.terminating_scopes.insert(expr.hir_id.local_id),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intravisit::walk_arm(visitor, arm);
|
intravisit::walk_arm(visitor, arm);
|
||||||
|
@ -890,11 +884,9 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
|
||||||
// This ensures fixed size stacks.
|
// This ensures fixed size stacks.
|
||||||
|
|
||||||
hir::ExprKind::Binary(
|
hir::ExprKind::Binary(
|
||||||
source_map::Spanned { node: hir::BinOpKind::And, .. },
|
source_map::Spanned { node: hir::BinOpKind::And, .. }, _, ref r) |
|
||||||
_, ref r) |
|
|
||||||
hir::ExprKind::Binary(
|
hir::ExprKind::Binary(
|
||||||
source_map::Spanned { node: hir::BinOpKind::Or, .. },
|
source_map::Spanned { node: hir::BinOpKind::Or, .. }, _, ref r) => {
|
||||||
_, ref r) => {
|
|
||||||
// For shortcircuiting operators, mark the RHS as a terminating
|
// For shortcircuiting operators, mark the RHS as a terminating
|
||||||
// scope since it only executes conditionally.
|
// scope since it only executes conditionally.
|
||||||
terminating(r.hir_id.local_id);
|
terminating(r.hir_id.local_id);
|
||||||
|
|
|
@ -25,6 +25,7 @@ use errors::DiagnosticBuilder;
|
||||||
use rustc::lint;
|
use rustc::lint;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use session::Session;
|
use session::Session;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
@ -360,17 +361,17 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||||
is_late_bound_map: |tcx, id| {
|
is_late_bound_map: |tcx, id| {
|
||||||
let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
|
let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
|
||||||
tcx.resolve_lifetimes(LOCAL_CRATE)
|
tcx.resolve_lifetimes(LOCAL_CRATE)
|
||||||
.late_bound
|
.late_bound
|
||||||
.get(&id)
|
.get(&id)
|
||||||
.cloned()
|
.cloned()
|
||||||
},
|
},
|
||||||
|
|
||||||
object_lifetime_defaults_map: |tcx, id| {
|
object_lifetime_defaults_map: |tcx, id| {
|
||||||
let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
|
let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
|
||||||
tcx.resolve_lifetimes(LOCAL_CRATE)
|
tcx.resolve_lifetimes(LOCAL_CRATE)
|
||||||
.object_lifetime_defaults
|
.object_lifetime_defaults
|
||||||
.get(&id)
|
.get(&id)
|
||||||
.cloned()
|
.cloned()
|
||||||
},
|
},
|
||||||
|
|
||||||
..*providers
|
..*providers
|
||||||
|
@ -410,8 +411,8 @@ fn resolve_lifetimes<'tcx>(
|
||||||
for (k, v) in named_region_map.object_lifetime_defaults {
|
for (k, v) in named_region_map.object_lifetime_defaults {
|
||||||
let hir_id = tcx.hir.node_to_hir_id(k);
|
let hir_id = tcx.hir.node_to_hir_id(k);
|
||||||
let map = rl.object_lifetime_defaults
|
let map = rl.object_lifetime_defaults
|
||||||
.entry(hir_id.owner_local_def_id())
|
.entry(hir_id.owner_local_def_id())
|
||||||
.or_default();
|
.or_default();
|
||||||
Lrc::get_mut(map)
|
Lrc::get_mut(map)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert(hir_id.local_id, Lrc::new(v));
|
.insert(hir_id.local_id, Lrc::new(v));
|
||||||
|
@ -676,7 +677,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
lifetime.span,
|
lifetime.span,
|
||||||
E0657,
|
E0657,
|
||||||
"`impl Trait` can only capture lifetimes \
|
"`impl Trait` can only capture lifetimes \
|
||||||
bound at the fn or impl level"
|
bound at the fn or impl level"
|
||||||
);
|
);
|
||||||
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
|
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
|
||||||
}
|
}
|
||||||
|
@ -1250,24 +1251,24 @@ fn compute_object_lifetime_defaults(
|
||||||
let object_lifetime_default_reprs: String = result
|
let object_lifetime_default_reprs: String = result
|
||||||
.iter()
|
.iter()
|
||||||
.map(|set| match *set {
|
.map(|set| match *set {
|
||||||
Set1::Empty => "BaseDefault".to_string(),
|
Set1::Empty => "BaseDefault".into(),
|
||||||
Set1::One(Region::Static) => "'static".to_string(),
|
Set1::One(Region::Static) => "'static".into(),
|
||||||
Set1::One(Region::EarlyBound(mut i, _, _)) => {
|
Set1::One(Region::EarlyBound(mut i, _, _)) => {
|
||||||
generics.params.iter().find_map(|param| match param.kind {
|
generics.params.iter().find_map(|param| match param.kind {
|
||||||
GenericParamKind::Lifetime { .. } => {
|
GenericParamKind::Lifetime { .. } => {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return Some(param.name.ident().to_string());
|
return Some(param.name.ident().to_string().into());
|
||||||
}
|
|
||||||
i -= 1;
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
_ => None,
|
i -= 1;
|
||||||
}).unwrap()
|
None
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}).unwrap()
|
||||||
}
|
}
|
||||||
Set1::One(_) => bug!(),
|
Set1::One(_) => bug!(),
|
||||||
Set1::Many => "Ambiguous".to_string(),
|
Set1::Many => "Ambiguous".into(),
|
||||||
})
|
})
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<Cow<'static, str>>>()
|
||||||
.join(",");
|
.join(",");
|
||||||
tcx.sess.span_err(item.span, &object_lifetime_default_reprs);
|
tcx.sess.span_err(item.span, &object_lifetime_default_reprs);
|
||||||
}
|
}
|
||||||
|
@ -1420,16 +1421,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
def_ids.sort_by_key(|&def_id| self.tcx.def_path_hash(def_id));
|
def_ids.sort_by_key(|&def_id| self.tcx.def_path_hash(def_id));
|
||||||
|
|
||||||
for def_id in def_ids {
|
for def_id in def_ids {
|
||||||
debug!(
|
debug!("check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", def_id);
|
||||||
"check_uses_for_lifetimes_defined_by_scope: def_id = {:?}",
|
|
||||||
def_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
let lifetimeuseset = self.lifetime_uses.remove(&def_id);
|
let lifetimeuseset = self.lifetime_uses.remove(&def_id);
|
||||||
debug!(
|
|
||||||
"check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}",
|
debug!("check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}",
|
||||||
lifetimeuseset
|
lifetimeuseset);
|
||||||
);
|
|
||||||
match lifetimeuseset {
|
match lifetimeuseset {
|
||||||
Some(LifetimeUseSet::One(lifetime)) => {
|
Some(LifetimeUseSet::One(lifetime)) => {
|
||||||
let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
|
let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
|
||||||
|
@ -1669,7 +1667,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
"lifetimes used in `fn` or `Fn` syntax must be \
|
"lifetimes used in `fn` or `Fn` syntax must be \
|
||||||
explicitly declared using `<...>` binders"
|
explicitly declared using `<...>` binders"
|
||||||
).span_label(lifetime_ref.span, "in-band lifetime definition")
|
).span_label(lifetime_ref.span, "in-band lifetime definition")
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Region::Static
|
Region::Static
|
||||||
|
@ -1689,7 +1687,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
"use of undeclared lifetime name `{}`",
|
"use of undeclared lifetime name `{}`",
|
||||||
lifetime_ref
|
lifetime_ref
|
||||||
).span_label(lifetime_ref.span, "undeclared lifetime")
|
).span_label(lifetime_ref.span, "undeclared lifetime")
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1872,18 +1870,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
node: hir::TraitItemKind::Method(_, ref m),
|
node: hir::TraitItemKind::Method(_, ref m),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
match self.tcx
|
if let hir::ItemKind::Trait(.., ref trait_items) = self.tcx
|
||||||
.hir
|
.hir
|
||||||
.expect_item(self.tcx.hir.get_parent(parent))
|
.expect_item(self.tcx.hir.get_parent(parent))
|
||||||
.node
|
.node
|
||||||
{
|
{
|
||||||
hir::ItemKind::Trait(.., ref trait_items) => {
|
assoc_item_kind = trait_items
|
||||||
assoc_item_kind = trait_items
|
.iter()
|
||||||
.iter()
|
.find(|ti| ti.id.node_id == parent)
|
||||||
.find(|ti| ti.id.node_id == parent)
|
.map(|ti| ti.kind);
|
||||||
.map(|ti| ti.kind);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
match *m {
|
match *m {
|
||||||
hir::TraitMethod::Required(_) => None,
|
hir::TraitMethod::Required(_) => None,
|
||||||
|
@ -1895,19 +1890,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
node: hir::ImplItemKind::Method(_, body),
|
node: hir::ImplItemKind::Method(_, body),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
match self.tcx
|
if let hir::ItemKind::Impl(.., ref self_ty, ref impl_items) = self.tcx
|
||||||
.hir
|
.hir
|
||||||
.expect_item(self.tcx.hir.get_parent(parent))
|
.expect_item(self.tcx.hir.get_parent(parent))
|
||||||
.node
|
.node
|
||||||
{
|
{
|
||||||
hir::ItemKind::Impl(.., ref self_ty, ref impl_items) => {
|
impl_self = Some(self_ty);
|
||||||
impl_self = Some(self_ty);
|
assoc_item_kind = impl_items
|
||||||
assoc_item_kind = impl_items
|
.iter()
|
||||||
.iter()
|
.find(|ii| ii.id.node_id == parent)
|
||||||
.find(|ii| ii.id.node_id == parent)
|
.map(|ii| ii.kind);
|
||||||
.map(|ii| ii.kind);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
Some(body)
|
Some(body)
|
||||||
}
|
}
|
||||||
|
@ -2255,9 +2247,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
|
|
||||||
Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
|
Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
|
||||||
|
|
||||||
Scope::ObjectLifetimeDefault {
|
Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l,
|
||||||
lifetime: Some(l), ..
|
|
||||||
} => break l,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
|
self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
|
||||||
|
@ -2329,13 +2319,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
lifetime_i.name.ident(),
|
lifetime_i.name.ident(),
|
||||||
),
|
),
|
||||||
).help(&format!(
|
).help(&format!(
|
||||||
"you can use the `'static` lifetime directly, in place \
|
"you can use the `'static` lifetime directly, in place of `{}`",
|
||||||
of `{}`",
|
|
||||||
lifetime_i.name.ident(),
|
lifetime_i.name.ident(),
|
||||||
)).emit();
|
)).emit();
|
||||||
}
|
}
|
||||||
hir::LifetimeName::Param(_)
|
hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
|
||||||
| hir::LifetimeName::Implicit => {
|
|
||||||
self.resolve_lifetime_ref(lt);
|
self.resolve_lifetime_ref(lt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2492,8 +2480,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/// Detects late-bound lifetimes and inserts them into
|
/// Detects late-bound lifetimes and inserts them into
|
||||||
/// `map.late_bound`.
|
/// `map.late_bound`.
|
||||||
///
|
///
|
||||||
|
@ -2509,10 +2495,8 @@ fn insert_late_bound_lifetimes(
|
||||||
decl: &hir::FnDecl,
|
decl: &hir::FnDecl,
|
||||||
generics: &hir::Generics,
|
generics: &hir::Generics,
|
||||||
) {
|
) {
|
||||||
debug!(
|
debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})",
|
||||||
"insert_late_bound_lifetimes(decl={:?}, generics={:?})",
|
decl, generics);
|
||||||
decl, generics
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut constrained_by_input = ConstrainedCollector {
|
let mut constrained_by_input = ConstrainedCollector {
|
||||||
regions: FxHashSet(),
|
regions: FxHashSet(),
|
||||||
|
@ -2526,10 +2510,8 @@ fn insert_late_bound_lifetimes(
|
||||||
};
|
};
|
||||||
intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output);
|
intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output);
|
||||||
|
|
||||||
debug!(
|
debug!("insert_late_bound_lifetimes: constrained_by_input={:?}",
|
||||||
"insert_late_bound_lifetimes: constrained_by_input={:?}",
|
constrained_by_input.regions);
|
||||||
constrained_by_input.regions
|
|
||||||
);
|
|
||||||
|
|
||||||
// Walk the lifetimes that appear in where clauses.
|
// Walk the lifetimes that appear in where clauses.
|
||||||
//
|
//
|
||||||
|
@ -2541,15 +2523,12 @@ fn insert_late_bound_lifetimes(
|
||||||
appears_in_where_clause.visit_generics(generics);
|
appears_in_where_clause.visit_generics(generics);
|
||||||
|
|
||||||
for param in &generics.params {
|
for param in &generics.params {
|
||||||
match param.kind {
|
if let hir::GenericParamKind::Lifetime { .. } = param.kind {
|
||||||
hir::GenericParamKind::Lifetime { .. } => {
|
if !param.bounds.is_empty() {
|
||||||
if !param.bounds.is_empty() {
|
// `'a: 'b` means both `'a` and `'b` are referenced
|
||||||
// `'a: 'b` means both `'a` and `'b` are referenced
|
appears_in_where_clause
|
||||||
appears_in_where_clause
|
.regions.insert(hir::LifetimeName::Param(param.name.modern()));
|
||||||
.regions.insert(hir::LifetimeName::Param(param.name.modern()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
hir::GenericParamKind::Type { .. } => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2661,10 +2640,10 @@ pub fn report_missing_lifetime_specifiers(
|
||||||
if count > 1 { "s" } else { "" }
|
if count > 1 { "s" } else { "" }
|
||||||
);
|
);
|
||||||
|
|
||||||
let msg = if count > 1 {
|
let msg: Cow<'static, str> = if count > 1 {
|
||||||
format!("expected {} lifetime parameters", count)
|
format!("expected {} lifetime parameters", count).into()
|
||||||
} else {
|
} else {
|
||||||
"expected lifetime parameter".to_string()
|
"expected lifetime parameter".into()
|
||||||
};
|
};
|
||||||
|
|
||||||
err.span_label(span, msg);
|
err.span_label(span, msg);
|
||||||
|
|
|
@ -164,8 +164,10 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
|
||||||
if let (&Some(attr::RustcDeprecation {since: dep_since, ..}),
|
if let (&Some(attr::RustcDeprecation {since: dep_since, ..}),
|
||||||
&attr::Stable {since: stab_since}) = (&stab.rustc_depr, &stab.level) {
|
&attr::Stable {since: stab_since}) = (&stab.rustc_depr, &stab.level) {
|
||||||
// Explicit version of iter::order::lt to handle parse errors properly
|
// Explicit version of iter::order::lt to handle parse errors properly
|
||||||
for (dep_v, stab_v) in
|
for (dep_v, stab_v) in dep_since.as_str()
|
||||||
dep_since.as_str().split('.').zip(stab_since.as_str().split('.')) {
|
.split('.')
|
||||||
|
.zip(stab_since.as_str().split('.'))
|
||||||
|
{
|
||||||
if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::<u64>(), stab_v.parse()) {
|
if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::<u64>(), stab_v.parse()) {
|
||||||
match dep_v.cmp(&stab_v) {
|
match dep_v.cmp(&stab_v) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
|
@ -523,15 +525,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
Some(Def::Method(_)) |
|
Some(Def::Method(_)) |
|
||||||
Some(Def::AssociatedTy(_)) |
|
Some(Def::AssociatedTy(_)) |
|
||||||
Some(Def::AssociatedConst(_)) => {
|
Some(Def::AssociatedConst(_)) => {
|
||||||
match self.associated_item(def_id).container {
|
if let ty::TraitContainer(trait_def_id) = self.associated_item(def_id).container {
|
||||||
ty::TraitContainer(trait_def_id) => {
|
// Trait methods do not declare visibility (even
|
||||||
// Trait methods do not declare visibility (even
|
// for visibility info in cstore). Use containing
|
||||||
// for visibility info in cstore). Use containing
|
// trait instead, so methods of pub traits are
|
||||||
// trait instead, so methods of pub traits are
|
// themselves considered pub.
|
||||||
// themselves considered pub.
|
def_id = trait_def_id;
|
||||||
def_id = trait_def_id;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -561,8 +560,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
/// `id`.
|
/// `id`.
|
||||||
pub fn eval_stability(self, def_id: DefId, id: Option<NodeId>, span: Span) -> EvalResult {
|
pub fn eval_stability(self, def_id: DefId, id: Option<NodeId>, span: Span) -> EvalResult {
|
||||||
if span.allows_unstable() {
|
if span.allows_unstable() {
|
||||||
debug!("stability: \
|
debug!("stability: skipping span={:?} since it is internal", span);
|
||||||
skipping span={:?} since it is internal", span);
|
|
||||||
return EvalResult::Allow;
|
return EvalResult::Allow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,8 +768,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
||||||
let param_env = self.tcx.param_env(def_id);
|
let param_env = self.tcx.param_env(def_id);
|
||||||
if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
|
if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
|
||||||
emit_feature_err(&self.tcx.sess.parse_sess,
|
emit_feature_err(&self.tcx.sess.parse_sess,
|
||||||
"untagged_unions", item.span, GateIssue::Language,
|
"untagged_unions", item.span, GateIssue::Language,
|
||||||
"unions with non-`Copy` fields are unstable");
|
"unions with non-`Copy` fields are unstable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,13 +113,13 @@ fn verify<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
items.$name().is_none() {
|
items.$name().is_none() {
|
||||||
if lang_items::$item == lang_items::PanicImplLangItem {
|
if lang_items::$item == lang_items::PanicImplLangItem {
|
||||||
tcx.sess.err(&format!("`#[panic_handler]` function required, \
|
tcx.sess.err(&format!("`#[panic_handler]` function required, \
|
||||||
but not found"));
|
but not found"));
|
||||||
} else if lang_items::$item == lang_items::OomLangItem {
|
} else if lang_items::$item == lang_items::OomLangItem {
|
||||||
tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \
|
tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \
|
||||||
but not found"));
|
but not found"));
|
||||||
} else {
|
} else {
|
||||||
tcx.sess.err(&format!("language item required, but not found: `{}`",
|
tcx.sess.err(&format!("language item required, but not found: `{}`",
|
||||||
stringify!($name)));
|
stringify!($name)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
|
|
@ -38,6 +38,7 @@ use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
|
||||||
use rustc_mir::util::suggest_ref_mut;
|
use rustc_mir::util::suggest_ref_mut;
|
||||||
use rustc::util::nodemap::FxHashSet;
|
use rustc::util::nodemap::FxHashSet;
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -808,34 +809,34 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
match err.code {
|
match err.code {
|
||||||
err_mutbl => {
|
err_mutbl => {
|
||||||
let descr = match err.cmt.note {
|
let descr: Cow<'static, str> = match err.cmt.note {
|
||||||
mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
|
mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => {
|
||||||
self.cmt_to_string(&err.cmt)
|
self.cmt_to_cow_str(&err.cmt)
|
||||||
}
|
}
|
||||||
_ => match opt_loan_path_is_field(&err.cmt) {
|
_ => match opt_loan_path_is_field(&err.cmt) {
|
||||||
(None, true) => {
|
(None, true) => {
|
||||||
format!("{} of {} binding",
|
format!("{} of {} binding",
|
||||||
self.cmt_to_string(&err.cmt),
|
self.cmt_to_cow_str(&err.cmt),
|
||||||
err.cmt.mutbl.to_user_str())
|
err.cmt.mutbl.to_user_str()).into()
|
||||||
|
|
||||||
}
|
}
|
||||||
(None, false) => {
|
(None, false) => {
|
||||||
format!("{} {}",
|
format!("{} {}",
|
||||||
err.cmt.mutbl.to_user_str(),
|
err.cmt.mutbl.to_user_str(),
|
||||||
self.cmt_to_string(&err.cmt))
|
self.cmt_to_cow_str(&err.cmt)).into()
|
||||||
|
|
||||||
}
|
}
|
||||||
(Some(lp), true) => {
|
(Some(lp), true) => {
|
||||||
format!("{} `{}` of {} binding",
|
format!("{} `{}` of {} binding",
|
||||||
self.cmt_to_string(&err.cmt),
|
self.cmt_to_cow_str(&err.cmt),
|
||||||
self.loan_path_to_string(&lp),
|
self.loan_path_to_string(&lp),
|
||||||
err.cmt.mutbl.to_user_str())
|
err.cmt.mutbl.to_user_str()).into()
|
||||||
}
|
}
|
||||||
(Some(lp), false) => {
|
(Some(lp), false) => {
|
||||||
format!("{} {} `{}`",
|
format!("{} {} `{}`",
|
||||||
err.cmt.mutbl.to_user_str(),
|
err.cmt.mutbl.to_user_str(),
|
||||||
self.cmt_to_string(&err.cmt),
|
self.cmt_to_cow_str(&err.cmt),
|
||||||
self.loan_path_to_string(&lp))
|
self.loan_path_to_string(&lp)).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1058,11 +1059,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
|
err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
|
||||||
let descr = self.cmt_to_path_or_string(err.cmt);
|
let descr = self.cmt_to_path_or_string(err.cmt);
|
||||||
let mut db = self.lifetime_too_short_for_reborrow(error_span, &descr, Origin::Ast);
|
let mut db = self.lifetime_too_short_for_reborrow(error_span, &descr, Origin::Ast);
|
||||||
let descr = match opt_loan_path(&err.cmt) {
|
let descr: Cow<'static, str> = match opt_loan_path(&err.cmt) {
|
||||||
Some(lp) => {
|
Some(lp) => {
|
||||||
format!("`{}`", self.loan_path_to_string(&lp))
|
format!("`{}`", self.loan_path_to_string(&lp)).into()
|
||||||
}
|
}
|
||||||
None => self.cmt_to_string(&err.cmt),
|
None => self.cmt_to_cow_str(&err.cmt)
|
||||||
};
|
};
|
||||||
self.tcx.note_and_explain_region(
|
self.tcx.note_and_explain_region(
|
||||||
&self.region_scope_tree,
|
&self.region_scope_tree,
|
||||||
|
@ -1477,14 +1478,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cmt_to_string(&self, cmt: &mc::cmt_<'tcx>) -> String {
|
pub fn cmt_to_cow_str(&self, cmt: &mc::cmt_<'tcx>) -> Cow<'static, str> {
|
||||||
cmt.descriptive_string(self.tcx)
|
cmt.descriptive_string(self.tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt_<'tcx>) -> String {
|
pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt_<'tcx>) -> String {
|
||||||
match opt_loan_path(cmt) {
|
match opt_loan_path(cmt) {
|
||||||
Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)),
|
Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)),
|
||||||
None => self.cmt_to_string(cmt),
|
None => self.cmt_to_cow_str(cmt).into_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue