Auto merge of #71539 - Dylan-DPC:rollup-a2vbfh9, r=Dylan-DPC

Rollup of 8 pull requests

Successful merges:

 - #69456 (fix misleading type annotation diagonstics)
 - #71330 (Only run dataflow for const qualification if type-based check would fail)
 - #71480 (Improve PanicInfo examples readability)
 - #71485 (Add BinaryHeap::retain as suggested in #42849)
 - #71512 (Remove useless "" args)
 - #71527 (Miscellaneous cleanup in `check_consts`)
 - #71534 (Avoid unused Option::map results)
 - #71535 (Fix typos in docs for keyword "in")

Failed merges:

r? @ghost
This commit is contained in:
bors 2020-04-24 23:36:52 +00:00
commit 40008dcb49
36 changed files with 456 additions and 192 deletions

View File

@ -93,12 +93,12 @@ static NIGHTLY_TOOLS: &[(&str, &str)] = &[
];
fn print_error(tool: &str, submodule: &str) {
eprintln!("");
eprintln!();
eprintln!("We detected that this PR updated '{}', but its tests failed.", tool);
eprintln!("");
eprintln!();
eprintln!("If you do intend to update '{}', please check the error messages above and", tool);
eprintln!("commit another update.");
eprintln!("");
eprintln!();
eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool);
eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule);
eprintln!("proper steps.");

View File

@ -665,6 +665,34 @@ impl<T: Ord> BinaryHeap<T> {
pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> {
DrainSorted { inner: self }
}
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all elements `e` such that `f(&e)` returns
/// `false`. The elements are visited in unsorted (and unspecified) order.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(binary_heap_retain)]
/// use std::collections::BinaryHeap;
///
/// let mut heap = BinaryHeap::from(vec![-10, -5, 1, 2, 4, 13]);
///
/// heap.retain(|x| x % 2 == 0); // only keep even numbers
///
/// assert_eq!(heap.into_sorted_vec(), [-10, 2, 4])
/// ```
#[unstable(feature = "binary_heap_retain", issue = "71503")]
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&T) -> bool,
{
self.data.retain(f);
self.rebuild();
}
}
impl<T> BinaryHeap<T> {

View File

@ -372,6 +372,14 @@ fn assert_covariance() {
}
}
#[test]
fn test_retain() {
let mut a = BinaryHeap::from(vec![-10, -5, 1, 2, 4, 13]);
a.retain(|x| x % 2 == 0);
assert_eq!(a.into_sorted_vec(), [-10, 2, 4])
}
// old binaryheap failed this test
//
// Integrity means that all elements are present after a comparison panics,

View File

@ -14,6 +14,7 @@
#![feature(binary_heap_drain_sorted)]
#![feature(vec_remove_item)]
#![feature(split_inclusive)]
#![feature(binary_heap_retain)]
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

View File

@ -77,7 +77,11 @@ impl<'a> PanicInfo<'a> {
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
/// if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
/// println!("panic occurred: {:?}", s);
/// } else {
/// println!("panic occurred");
/// }
/// }));
///
/// panic!("Normal panic");
@ -112,8 +116,10 @@ impl<'a> PanicInfo<'a> {
///
/// panic::set_hook(Box::new(|panic_info| {
/// if let Some(location) = panic_info.location() {
/// println!("panic occurred in file '{}' at line {}", location.file(),
/// location.line());
/// println!("panic occurred in file '{}' at line {}",
/// location.file(),
/// location.line(),
/// );
/// } else {
/// println!("panic occurred but can't get location information...");
/// }

View File

@ -98,7 +98,7 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
}
}
diagnostic.map(|d| {
if let Some(d) = diagnostic {
struct_span_err!(d, attr.span, E0633, "malformed `unwind` attribute input")
.span_label(attr.span, "invalid argument")
.span_suggestions(
@ -110,7 +110,7 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
Applicability::MachineApplicable,
)
.emit();
});
};
}
}
}

View File

@ -1172,10 +1172,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
// ignore derives so they remain unused
let (attr, after_derive) = self.classify_nonitem(&mut expr);
if attr.is_some() {
if let Some(ref attr_value) = attr {
// Collect the invoc regardless of whether or not attributes are permitted here
// expansion will eat the attribute so it won't error later.
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
self.cfg.maybe_emit_expr_attr_err(attr_value);
// AstFragmentKind::Expr requires the macro to emit an expression.
return self
@ -1322,8 +1322,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
// Ignore derives so they remain unused.
let (attr, after_derive) = self.classify_nonitem(&mut expr);
if attr.is_some() {
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
if let Some(ref attr_value) = attr {
self.cfg.maybe_emit_expr_attr_err(attr_value);
return self
.collect_attr(

View File

@ -246,7 +246,7 @@ impl DefPath {
let mut opt_delimiter = None;
for component in &self.data {
opt_delimiter.map(|d| s.push(d));
s.extend(opt_delimiter);
opt_delimiter = Some('-');
if component.disambiguator == 0 {
write!(s, "{}", component.data.as_symbol()).unwrap();

View File

@ -755,7 +755,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
},
ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => {
err.span_label(then, "expected because of this");
outer.map(|sp| err.span_label(sp, "`if` and `else` have incompatible types"));
if let Some(sp) = outer {
err.span_label(sp, "`if` and `else` have incompatible types");
}
if let Some(sp) = semicolon {
err.span_suggestion_short(
sp,

View File

@ -17,23 +17,27 @@ use std::borrow::Cow;
struct FindHirNodeVisitor<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
target: GenericArg<'tcx>,
target_span: Span,
found_node_ty: Option<Ty<'tcx>>,
found_local_pattern: Option<&'tcx Pat<'tcx>>,
found_arg_pattern: Option<&'tcx Pat<'tcx>>,
found_closure: Option<&'tcx Expr<'tcx>>,
found_method_call: Option<&'tcx Expr<'tcx>>,
found_exact_method_call: Option<&'tcx Expr<'tcx>>,
}
impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>) -> Self {
fn new(infcx: &'a InferCtxt<'a, 'tcx>, target: GenericArg<'tcx>, target_span: Span) -> Self {
Self {
infcx,
target,
target_span,
found_node_ty: None,
found_local_pattern: None,
found_arg_pattern: None,
found_closure: None,
found_method_call: None,
found_exact_method_call: None,
}
}
@ -103,6 +107,17 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
}
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
if let ExprKind::MethodCall(_, call_span, exprs) = expr.kind {
if call_span == self.target_span
&& Some(self.target)
== self.infcx.in_progress_tables.and_then(|tables| {
tables.borrow().node_type_opt(exprs.first().unwrap().hir_id).map(Into::into)
})
{
self.found_exact_method_call = Some(&expr);
return;
}
}
if self.node_ty_contains_target(expr.hir_id).is_some() {
match expr.kind {
ExprKind::Closure(..) => self.found_closure = Some(&expr),
@ -234,7 +249,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let ty = self.resolve_vars_if_possible(&ty);
let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None);
let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into());
let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span);
let ty_to_string = |ty: Ty<'tcx>| -> String {
let mut s = String::new();
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
@ -287,14 +302,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
(!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings)
};
let ty_msg = match local_visitor.found_node_ty {
Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => {
let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
(_, Some(_)) => String::new(),
(Some(ty::TyS { kind: ty::Closure(_, substs), .. }), _) => {
let fn_sig = substs.as_closure().sig();
let args = closure_args(&fn_sig);
let ret = fn_sig.output().skip_binder().to_string();
format!(" for the closure `fn({}) -> {}`", args, ret)
}
Some(ty) if is_named_and_not_impl_trait(ty) => {
(Some(ty), _) if is_named_and_not_impl_trait(ty) => {
let ty = ty_to_string(ty);
format!(" for `{}`", ty)
}
@ -370,7 +386,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => "a type".to_string(),
};
if let Some(pattern) = local_visitor.found_arg_pattern {
if let Some(e) = local_visitor.found_exact_method_call {
if let ExprKind::MethodCall(segment, ..) = &e.kind {
// Suggest specifying type params or point out the return type of the call:
//
// error[E0282]: type annotations needed
// --> $DIR/type-annotations-needed-expr.rs:2:39
// |
// LL | let _ = x.into_iter().sum() as f64;
// | ^^^
// | |
// | cannot infer type for `S`
// | help: consider specifying the type argument in
// | the method call: `sum::<S>`
// |
// = note: type must be known at this point
//
// or
//
// error[E0282]: type annotations needed
// --> $DIR/issue-65611.rs:59:20
// |
// LL | let x = buffer.last().unwrap().0.clone();
// | -------^^^^--
// | | |
// | | cannot infer type for `T`
// | this method call resolves to `std::option::Option<&T>`
// |
// = note: type must be known at this point
self.annotate_method_call(segment, e, &mut err);
}
} else if let Some(pattern) = local_visitor.found_arg_pattern {
// We don't want to show the default label for closures.
//
// So, before clearing, the output would look something like this:

View File

@ -101,9 +101,15 @@ fn dump_crates(cstore: &CStore) {
info!(" hash: {}", data.hash());
info!(" reqd: {:?}", data.dep_kind());
let CrateSource { dylib, rlib, rmeta } = data.source();
dylib.as_ref().map(|dl| info!(" dylib: {}", dl.0.display()));
rlib.as_ref().map(|rl| info!(" rlib: {}", rl.0.display()));
rmeta.as_ref().map(|rl| info!(" rmeta: {}", rl.0.display()));
if let Some(dylib) = dylib {
info!(" dylib: {}", dylib.0.display());
}
if let Some(rlib) = rlib {
info!(" rlib: {}", rlib.0.display());
}
if let Some(rmeta) = rmeta {
info!(" rmeta: {}", rmeta.0.display());
}
});
}

View File

@ -3,7 +3,6 @@
use rustc_errors::struct_span_err;
use rustc_hir::lang_items;
use rustc_hir::{def_id::DefId, HirId};
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
@ -28,70 +27,100 @@ use crate::dataflow::{self, Analysis};
// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
pub type IndirectlyMutableResults<'mir, 'tcx> =
type IndirectlyMutableResults<'mir, 'tcx> =
dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
struct QualifCursor<'a, 'mir, 'tcx, Q: Qualif> {
cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>,
in_any_value_of_ty: BitSet<Local>,
type QualifResults<'mir, 'tcx, Q> =
dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
#[derive(Default)]
pub struct Qualifs<'mir, 'tcx> {
has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
}
impl<Q: Qualif> QualifCursor<'a, 'mir, 'tcx, Q> {
pub fn new(q: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self {
let cursor = FlowSensitiveAnalysis::new(q, ccx)
.into_engine(ccx.tcx, ccx.body, ccx.def_id)
.iterate_to_fixpoint()
.into_results_cursor(ccx.body);
impl Qualifs<'mir, 'tcx> {
fn indirectly_mutable(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
location: Location,
) -> bool {
let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
let ConstCx { tcx, body, def_id, param_env, .. } = *ccx;
let mut in_any_value_of_ty = BitSet::new_empty(ccx.body.local_decls.len());
for (local, decl) in ccx.body.local_decls.iter_enumerated() {
if Q::in_any_value_of_ty(ccx, decl.ty) {
in_any_value_of_ty.insert(local);
}
}
// We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
// allowed in a const.
//
// FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
// without breaking stable code?
MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
.unsound_ignore_borrow_on_drop()
.into_engine(tcx, &body, def_id)
.iterate_to_fixpoint()
.into_results_cursor(&body)
});
QualifCursor { cursor, in_any_value_of_ty }
}
}
pub struct Qualifs<'a, 'mir, 'tcx> {
has_mut_interior: QualifCursor<'a, 'mir, 'tcx, HasMutInterior>,
needs_drop: QualifCursor<'a, 'mir, 'tcx, NeedsDrop>,
indirectly_mutable: IndirectlyMutableResults<'mir, 'tcx>,
}
impl Qualifs<'a, 'mir, 'tcx> {
fn indirectly_mutable(&mut self, local: Local, location: Location) -> bool {
self.indirectly_mutable.seek_before(location);
self.indirectly_mutable.get().contains(local)
indirectly_mutable.seek_before(location);
indirectly_mutable.get().contains(local)
}
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
///
/// Only updates the cursor if absolutely necessary
fn needs_drop(&mut self, local: Local, location: Location) -> bool {
if !self.needs_drop.in_any_value_of_ty.contains(local) {
fn needs_drop(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
location: Location,
) -> bool {
let ty = ccx.body.local_decls[local].ty;
if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
return false;
}
self.needs_drop.cursor.seek_before(location);
self.needs_drop.cursor.get().contains(local) || self.indirectly_mutable(local, location)
let needs_drop = self.needs_drop.get_or_insert_with(|| {
let ConstCx { tcx, body, def_id, .. } = *ccx;
FlowSensitiveAnalysis::new(NeedsDrop, ccx)
.into_engine(tcx, &body, def_id)
.iterate_to_fixpoint()
.into_results_cursor(&body)
});
needs_drop.seek_before(location);
needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
}
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
///
/// Only updates the cursor if absolutely necessary.
fn has_mut_interior(&mut self, local: Local, location: Location) -> bool {
if !self.has_mut_interior.in_any_value_of_ty.contains(local) {
fn has_mut_interior(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
location: Location,
) -> bool {
let ty = ccx.body.local_decls[local].ty;
if !HasMutInterior::in_any_value_of_ty(ccx, ty) {
return false;
}
self.has_mut_interior.cursor.seek_before(location);
self.has_mut_interior.cursor.get().contains(local)
|| self.indirectly_mutable(local, location)
let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| {
let ConstCx { tcx, body, def_id, .. } = *ccx;
FlowSensitiveAnalysis::new(HasMutInterior, ccx)
.into_engine(tcx, &body, def_id)
.iterate_to_fixpoint()
.into_results_cursor(&body)
});
has_mut_interior.seek_before(location);
has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location)
}
fn in_return_place(&mut self, ccx: &ConstCx<'_, 'tcx>) -> ConstQualifs {
fn in_return_place(&mut self, ccx: &'mir ConstCx<'mir, 'tcx>) -> ConstQualifs {
// Find the `Return` terminator if one exists.
//
// If no `Return` terminator exists, this MIR is divergent. Just return the conservative
@ -114,21 +143,21 @@ impl Qualifs<'a, 'mir, 'tcx> {
let return_loc = ccx.body.terminator_loc(return_block);
ConstQualifs {
needs_drop: self.needs_drop(RETURN_PLACE, return_loc),
has_mut_interior: self.has_mut_interior(RETURN_PLACE, return_loc),
needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
}
}
}
pub struct Validator<'a, 'mir, 'tcx> {
ccx: &'a ConstCx<'mir, 'tcx>,
qualifs: Qualifs<'a, 'mir, 'tcx>,
pub struct Validator<'mir, 'tcx> {
ccx: &'mir ConstCx<'mir, 'tcx>,
qualifs: Qualifs<'mir, 'tcx>,
/// The span of the current statement.
span: Span,
}
impl Deref for Validator<'_, 'mir, 'tcx> {
impl Deref for Validator<'mir, 'tcx> {
type Target = ConstCx<'mir, 'tcx>;
fn deref(&self) -> &Self::Target {
@ -136,27 +165,9 @@ impl Deref for Validator<'_, 'mir, 'tcx> {
}
}
impl Validator<'a, 'mir, 'tcx> {
pub fn new(ccx: &'a ConstCx<'mir, 'tcx>) -> Self {
let ConstCx { tcx, body, def_id, param_env, .. } = *ccx;
let needs_drop = QualifCursor::new(NeedsDrop, ccx);
let has_mut_interior = QualifCursor::new(HasMutInterior, ccx);
// We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
// allowed in a const.
//
// FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
// without breaking stable code?
let indirectly_mutable = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
.unsound_ignore_borrow_on_drop()
.into_engine(tcx, body, def_id)
.iterate_to_fixpoint()
.into_results_cursor(body);
let qualifs = Qualifs { needs_drop, has_mut_interior, indirectly_mutable };
Validator { span: ccx.body.span, ccx, qualifs }
impl Validator<'mir, 'tcx> {
pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
Validator { span: ccx.body.span, ccx, qualifs: Default::default() }
}
pub fn check_body(&mut self) {
@ -205,7 +216,7 @@ impl Validator<'a, 'mir, 'tcx> {
where
O: NonConstOp,
{
trace!("check_op: op={:?}", op);
debug!("check_op: op={:?}", op);
if op.is_allowed_in_item(self) {
return;
@ -239,7 +250,7 @@ impl Validator<'a, 'mir, 'tcx> {
}
}
impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
impl Visitor<'tcx> for Validator<'mir, 'tcx> {
fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) {
trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
@ -345,7 +356,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
| Rvalue::AddressOf(Mutability::Not, ref place) => {
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
&self.ccx,
&mut |local| self.qualifs.has_mut_interior(local, location),
&mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
place.as_ref(),
);
@ -386,15 +397,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
}
}
fn visit_local(&mut self, place_local: &Local, context: PlaceContext, location: Location) {
trace!(
"visit_local: place_local={:?} context={:?} location={:?}",
place_local,
context,
location,
);
}
fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
self.super_operand(op, location);
if let Operand::Constant(c) = op {
@ -571,7 +573,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
let needs_drop = if let Some(local) = dropped_place.as_local() {
// Use the span where the local was declared as the span of the drop error.
err_span = self.body.local_decls[local].source_info.span;
self.qualifs.needs_drop(local, location)
self.qualifs.needs_drop(self.ccx, local, location)
} else {
true
};

View File

@ -1388,7 +1388,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
// Insert a Shallow borrow of any places that is switched on.
fake_borrows.as_mut().map(|fb| fb.insert(match_place));
if let Some(fb) = fake_borrows {
fb.insert(match_place);
}
// perform the test, branching to one of N blocks. For each of
// those N possible outcomes, create a (initially empty)

View File

@ -1206,8 +1206,8 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, sess: &Pa
*sess.reached_eof.borrow_mut() |=
unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none());
for unmatched in unclosed_delims.drain(..) {
make_unclosed_delims_error(unmatched, sess).map(|mut e| {
if let Some(mut e) = make_unclosed_delims_error(unmatched, sess) {
e.emit();
});
}
}
}

View File

@ -68,7 +68,9 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
self.with_context(LabeledBlock, |v| v.visit_block(&b));
}
hir::ExprKind::Break(label, ref opt_expr) => {
opt_expr.as_ref().map(|e| self.visit_expr(e));
if let Some(e) = opt_expr {
self.visit_expr(e);
}
if self.require_label_in_labeled_block(e.span, &label, "break") {
// If we emitted an error about an unlabeled break in a labeled

View File

@ -133,7 +133,11 @@ impl<CTX: QueryContext> QueryJob<CTX> {
/// as there are no concurrent jobs which could be waiting on us
pub fn signal_complete(self) {
#[cfg(parallel_compiler)]
self.latch.map(|latch| latch.set());
{
if let Some(latch) = self.latch {
latch.set();
}
}
}
}

View File

@ -1996,7 +1996,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
this.visit_expr(cond);
this.visit_block(then);
});
opt_else.as_ref().map(|expr| self.visit_expr(expr));
if let Some(expr) = opt_else {
self.visit_expr(expr);
}
}
ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),

View File

@ -499,7 +499,9 @@ impl<'a> ModuleData<'a> {
F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>),
{
for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
name_resolution.borrow().binding.map(|binding| f(resolver, key.ident, key.ns, binding));
if let Some(binding) = name_resolution.borrow().binding {
f(resolver, key.ident, key.ns, binding);
}
}
}

View File

@ -979,20 +979,21 @@ impl Target {
macro_rules! key {
($key_name:ident) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.find(&name[..]).map(|o| o.as_string()
.map(|s| base.options.$key_name = s.to_string()));
if let Some(s) = obj.find(&name).and_then(Json::as_string) {
base.options.$key_name = s.to_string();
}
} );
($key_name:ident, bool) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.find(&name[..])
.map(|o| o.as_boolean()
.map(|s| base.options.$key_name = s));
if let Some(s) = obj.find(&name).and_then(Json::as_boolean) {
base.options.$key_name = s;
}
} );
($key_name:ident, Option<u64>) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.find(&name[..])
.map(|o| o.as_u64()
.map(|s| base.options.$key_name = Some(s)));
if let Some(s) = obj.find(&name).and_then(Json::as_u64) {
base.options.$key_name = Some(s);
}
} );
($key_name:ident, MergeFunctions) => ( {
let name = (stringify!($key_name)).replace("_", "-");
@ -1034,19 +1035,19 @@ impl Target {
} );
($key_name:ident, list) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.find(&name[..]).map(|o| o.as_array()
.map(|v| base.options.$key_name = v.iter()
.map(|a| a.as_string().unwrap().to_string()).collect()
)
);
if let Some(v) = obj.find(&name).and_then(Json::as_array) {
base.options.$key_name = v.iter()
.map(|a| a.as_string().unwrap().to_string())
.collect();
}
} );
($key_name:ident, opt_list) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.find(&name[..]).map(|o| o.as_array()
.map(|v| base.options.$key_name = Some(v.iter()
.map(|a| a.as_string().unwrap().to_string()).collect())
)
);
if let Some(v) = obj.find(&name).and_then(Json::as_array) {
base.options.$key_name = Some(v.iter()
.map(|a| a.as_string().unwrap().to_string())
.collect());
}
} );
($key_name:ident, optional) => ( {
let name = (stringify!($key_name)).replace("_", "-");

View File

@ -213,7 +213,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
None,
);
assoc_bindings.first().map(|b| Self::prohibit_assoc_ty_binding(self.tcx(), b.span));
if let Some(b) = assoc_bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
substs
}
@ -1095,7 +1097,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) -> ty::TraitRef<'tcx> {
let (substs, assoc_bindings, _) =
self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment);
assoc_bindings.first().map(|b| AstConv::prohibit_assoc_ty_binding(self.tcx(), b.span));
if let Some(b) = assoc_bindings.first() {
AstConv::prohibit_assoc_ty_binding(self.tcx(), b.span);
}
ty::TraitRef::new(trait_def_id, substs)
}

View File

@ -36,7 +36,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Requires that the two types unify, and prints an error message if
// they don't.
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
self.demand_suptype_diag(sp, expected, actual).map(|mut e| e.emit());
if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) {
e.emit();
}
}
pub fn demand_suptype_diag(

View File

@ -4492,15 +4492,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => Err(ErrorReported),
};
if item_name.name != kw::Invalid {
self.report_method_error(
if let Some(mut e) = self.report_method_error(
span,
ty,
item_name,
SelfSource::QPath(qself),
error,
None,
)
.map(|mut e| e.emit());
) {
e.emit();
}
}
result
});

View File

@ -104,7 +104,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
actual: Ty<'tcx>,
ti: TopInfo<'tcx>,
) {
self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map(|mut err| err.emit());
if let Some(mut err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) {
err.emit();
}
}
}
@ -449,12 +451,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Subtyping doesn't matter here, as the value is some kind of scalar.
let demand_eqtype = |x, y| {
if let Some((_, x_ty, x_span)) = x {
self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti).map(|mut err| {
if let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) {
if let Some((_, y_ty, y_span)) = y {
self.endpoint_has_type(&mut err, y_span, y_ty);
}
err.emit();
});
};
}
};
demand_eqtype(lhs, rhs);
@ -852,8 +854,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Type-check the tuple struct pattern against the expected type.
let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, ti);
let had_err = diag.is_some();
diag.map(|mut err| err.emit());
let had_err = if let Some(mut err) = diag {
err.emit();
true
} else {
false
};
// Type-check subpatterns.
if subpats.len() == variant.fields.len()

View File

@ -165,12 +165,18 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
hir::ExprKind::Binary(..) => {
if !op.node.is_by_value() {
let mut adjustments = tables.adjustments_mut();
adjustments.get_mut(lhs.hir_id).map(|a| a.pop());
adjustments.get_mut(rhs.hir_id).map(|a| a.pop());
if let Some(a) = adjustments.get_mut(lhs.hir_id) {
a.pop();
}
if let Some(a) = adjustments.get_mut(rhs.hir_id) {
a.pop();
}
}
}
hir::ExprKind::AssignOp(..) => {
tables.adjustments_mut().get_mut(lhs.hir_id).map(|a| a.pop());
if let Some(a) = tables.adjustments_mut().get_mut(lhs.hir_id) {
a.pop();
}
}
_ => {}
}
@ -215,7 +221,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
tables.type_dependent_defs_mut().remove(e.hir_id);
tables.node_substs_mut().remove(e.hir_id);
tables.adjustments_mut().get_mut(base.hir_id).map(|a| {
if let Some(a) = tables.adjustments_mut().get_mut(base.hir_id) {
// Discard the need for a mutable borrow
// Extra adjustment made when indexing causes a drop
@ -229,7 +235,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// So the borrow discard actually happens here
a.pop();
}
});
}
}
}
}

View File

@ -1599,7 +1599,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
inline::record_extern_fqn(cx, did, TypeKind::Trait);
let mut param_names = vec![];
reg.clean(cx).map(|b| param_names.push(GenericBound::Outlives(b)));
if let Some(b) = reg.clean(cx) {
param_names.push(GenericBound::Outlives(b));
}
for did in dids {
let empty = cx.tcx.intern_substs(&[]);
let path =
@ -1662,10 +1664,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
tr
} else if let ty::Predicate::TypeOutlives(pred) = *predicate {
// these should turn up at the end
pred.skip_binder()
.1
.clean(cx)
.map(|r| regions.push(GenericBound::Outlives(r)));
if let Some(r) = pred.skip_binder().1.clean(cx) {
regions.push(GenericBound::Outlives(r));
}
return None;
} else {
return None;

View File

@ -94,7 +94,7 @@ impl TocBuilder {
loop {
match self.chain.pop() {
Some(mut next) => {
this.map(|e| next.children.entries.push(e));
next.children.entries.extend(this);
if next.level < level {
// this is the parent we want, so return it to
// its rightful place.
@ -105,7 +105,7 @@ impl TocBuilder {
}
}
None => {
this.map(|e| self.top_level.entries.push(e));
self.top_level.entries.extend(this);
return;
}
}

View File

@ -685,12 +685,12 @@ mod impl_keyword {}
/// ## Literal Examples:
///
/// * `for _ **in** 1..3 {}` - Iterate over an exclusive range up to but excluding 3.
/// * `for _ **in** 1..=3 {}` - Iterate over an inclusive range up to and includeing 3.
/// * `for _ **in** 1..=3 {}` - Iterate over an inclusive range up to and including 3.
///
/// (Read more about [range patterns])
///
/// [`Iterator`]: ../book/ch13-04-performance.html
/// [`range patterns`]: ../reference/patterns.html?highlight=range#range-patterns
/// [range patterns]: ../reference/patterns.html?highlight=range#range-patterns
/// [`for`]: keyword.for.html
mod in_keyword {}

View File

@ -91,7 +91,7 @@ impl<T> Packet<T> {
//
// This can only be called at channel-creation time
pub fn inherit_blocker(&self, token: Option<SignalToken>, guard: MutexGuard<'_, ()>) {
token.map(|token| {
if let Some(token) = token {
assert_eq!(self.cnt.load(Ordering::SeqCst), 0);
assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
self.to_wake.store(unsafe { token.cast_to_usize() }, Ordering::SeqCst);
@ -118,7 +118,7 @@ impl<T> Packet<T> {
unsafe {
*self.steals.get() = -1;
}
});
}
// When the shared packet is constructed, we grabbed this lock. The
// purpose of this lock is to ensure that abort_selection() doesn't

View File

@ -343,8 +343,12 @@ impl<T> Packet<T> {
mem::drop(guard);
// only outside of the lock do we wake up the pending threads
pending_sender1.map(|t| t.signal());
pending_sender2.map(|t| t.signal());
if let Some(token) = pending_sender1 {
token.signal();
}
if let Some(token) = pending_sender2 {
token.signal();
}
}
// Prepares this shared packet for a channel clone, essentially just bumping
@ -410,7 +414,9 @@ impl<T> Packet<T> {
while let Some(token) = queue.dequeue() {
token.signal();
}
waiter.map(|t| t.signal());
if let Some(token) = waiter {
token.signal();
}
}
}

View File

@ -1,11 +1,22 @@
error[E0391]: cycle detected when const checking `FOO`
--> $DIR/issue-17252.rs:1:20
error[E0391]: cycle detected when normalizing `FOO`
|
note: ...which requires const-evaluating + checking `FOO`...
--> $DIR/issue-17252.rs:1:1
|
LL | const FOO: usize = FOO;
| ^^^
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `FOO`...
--> $DIR/issue-17252.rs:1:1
|
= note: ...which again requires const checking `FOO`, completing the cycle
note: cycle used when const checking `main::{{constant}}#0`
LL | const FOO: usize = FOO;
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating `FOO`...
--> $DIR/issue-17252.rs:1:1
|
LL | const FOO: usize = FOO;
| ^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires normalizing `FOO`, completing the cycle
note: cycle used when const-evaluating `main::{{constant}}#0`
--> $DIR/issue-17252.rs:4:18
|
LL | let _x: [u8; FOO]; // caused stack overflow prior to fix

View File

@ -1,15 +1,26 @@
error[E0391]: cycle detected when const checking `X::A::{{constant}}#0`
error[E0391]: cycle detected when const-evaluating + checking `X::A::{{constant}}#0`
--> $DIR/issue-23302-1.rs:4:9
|
LL | A = X::A as isize,
| ^^^^^^^^^^^^^
|
= note: ...which again requires const checking `X::A::{{constant}}#0`, completing the cycle
note: cycle used when processing `X::A::{{constant}}#0`
note: ...which requires const-evaluating + checking `X::A::{{constant}}#0`...
--> $DIR/issue-23302-1.rs:4:9
|
LL | A = X::A as isize,
| ^^^^^^^^^^^^^
note: ...which requires const-evaluating `X::A::{{constant}}#0`...
--> $DIR/issue-23302-1.rs:4:9
|
LL | A = X::A as isize,
| ^^^^^^^^^^^^^
= note: ...which requires normalizing `X::A as isize`...
= note: ...which again requires const-evaluating + checking `X::A::{{constant}}#0`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/issue-23302-1.rs:3:1
|
LL | enum X {
| ^^^^^^
error: aborting due to previous error

View File

@ -1,15 +1,26 @@
error[E0391]: cycle detected when const checking `Y::A::{{constant}}#0`
error[E0391]: cycle detected when const-evaluating + checking `Y::A::{{constant}}#0`
--> $DIR/issue-23302-2.rs:4:9
|
LL | A = Y::B as isize,
| ^^^^^^^^^^^^^
|
= note: ...which again requires const checking `Y::A::{{constant}}#0`, completing the cycle
note: cycle used when processing `Y::A::{{constant}}#0`
note: ...which requires const-evaluating + checking `Y::A::{{constant}}#0`...
--> $DIR/issue-23302-2.rs:4:9
|
LL | A = Y::B as isize,
| ^^^^^^^^^^^^^
note: ...which requires const-evaluating `Y::A::{{constant}}#0`...
--> $DIR/issue-23302-2.rs:4:9
|
LL | A = Y::B as isize,
| ^^^^^^^^^^^^^
= note: ...which requires normalizing `Y::B as isize`...
= note: ...which again requires const-evaluating + checking `Y::A::{{constant}}#0`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/issue-23302-2.rs:3:1
|
LL | enum Y {
| ^^^^^^
error: aborting due to previous error

View File

@ -1,20 +1,38 @@
error[E0391]: cycle detected when const checking `A`
--> $DIR/issue-23302-3.rs:1:16
|
LL | const A: i32 = B;
| ^
|
note: ...which requires const checking `B`...
--> $DIR/issue-23302-3.rs:3:16
|
LL | const B: i32 = A;
| ^
= note: ...which again requires const checking `A`, completing the cycle
note: cycle used when processing `A`
error[E0391]: cycle detected when const-evaluating + checking `A`
--> $DIR/issue-23302-3.rs:1:1
|
LL | const A: i32 = B;
| ^^^^^^^^^^^^^^^^^
|
note: ...which requires const-evaluating + checking `A`...
--> $DIR/issue-23302-3.rs:1:1
|
LL | const A: i32 = B;
| ^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating `A`...
--> $DIR/issue-23302-3.rs:1:1
|
LL | const A: i32 = B;
| ^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `B`...
note: ...which requires const-evaluating + checking `B`...
--> $DIR/issue-23302-3.rs:3:1
|
LL | const B: i32 = A;
| ^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `B`...
--> $DIR/issue-23302-3.rs:3:1
|
LL | const B: i32 = A;
| ^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating `B`...
--> $DIR/issue-23302-3.rs:3:1
|
LL | const B: i32 = A;
| ^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `A`...
= note: ...which again requires const-evaluating + checking `A`, completing the cycle
= note: cycle used when running analysis passes on this crate
error: aborting due to previous error

View File

@ -1,20 +1,48 @@
error[E0391]: cycle detected when const checking `Foo::B::{{constant}}#0`
error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{{constant}}#0`
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
|
note: ...which requires const checking `A`...
--> $DIR/issue-36163.rs:1:18
note: ...which requires const-evaluating + checking `Foo::B::{{constant}}#0`...
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
note: ...which requires const-evaluating `Foo::B::{{constant}}#0`...
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
= note: ...which requires normalizing `A`...
note: ...which requires const-evaluating + checking `A`...
--> $DIR/issue-36163.rs:1:1
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^
= note: ...which again requires const checking `Foo::B::{{constant}}#0`, completing the cycle
note: cycle used when processing `Foo::B::{{constant}}#0`
--> $DIR/issue-36163.rs:4:9
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `A`...
--> $DIR/issue-36163.rs:1:1
|
LL | B = A,
| ^
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating `A`...
--> $DIR/issue-36163.rs:1:1
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `A`...
= note: ...which again requires const-evaluating + checking `Foo::B::{{constant}}#0`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/issue-36163.rs:1:1
|
LL | / const A: isize = Foo::B as isize;
LL | |
LL | | enum Foo {
LL | | B = A,
LL | | }
LL | |
LL | | fn main() {}
| |____________^
error: aborting due to previous error

View File

@ -0,0 +1,30 @@
// Regression test for #69455: projection predicate was not satisfied.
// Compiler should indicate the correct location of the
// unsatisfied projection predicate
pub trait Test<Rhs = Self> {
type Output;
fn test(self, rhs: Rhs) -> Self::Output;
}
impl Test<u32> for u64 {
type Output = u64;
fn test(self, other: u32) -> u64 {
self + (other as u64)
}
}
impl Test<u64> for u64 {
type Output = u64;
fn test(self, other: u64) -> u64 {
(self + other) as u64
}
}
fn main() {
let xs: Vec<u64> = vec![1, 2, 3];
println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed [E0284]
}

View File

@ -0,0 +1,17 @@
error[E0284]: type annotations needed
--> $DIR/issue-69455.rs:29:26
|
LL | type Output;
| ------------ `<Self as Test<Rhs>>::Output` defined here
...
LL | println!("{}", 23u64.test(xs.iter().sum()));
| ------^^^^-----------------
| | |
| | cannot infer type for type `u64`
| this method call resolves to `<Self as Test<Rhs>>::Output`
|
= note: cannot satisfy `<u64 as Test<_>>::Output == _`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0284`.