Auto merge of #51967 - varkor:const-body-break-continue, r=estebank
Fix various issues with control-flow statements inside anonymous constants Fixes #51761. Fixes #51963 (and the host of other reported issues there). (Might be easiest to review per commit, as they should be standalone.) r? @estebank
This commit is contained in:
commit
69b9e1e8f9
|
@ -103,6 +103,7 @@ pub struct LoweringContext<'a> {
|
|||
loop_scopes: Vec<NodeId>,
|
||||
is_in_loop_condition: bool,
|
||||
is_in_trait_impl: bool,
|
||||
is_in_anon_const: bool,
|
||||
|
||||
/// What to do when we encounter either an "anonymous lifetime
|
||||
/// reference". The term "anonymous" is meant to encompass both
|
||||
|
@ -230,6 +231,7 @@ pub fn lower_crate(
|
|||
node_id_to_hir_id: IndexVec::new(),
|
||||
is_generator: false,
|
||||
is_in_trait_impl: false,
|
||||
is_in_anon_const: false,
|
||||
lifetimes_to_define: Vec::new(),
|
||||
is_collecting_in_band_lifetimes: false,
|
||||
in_scope_lifetimes: Vec::new(),
|
||||
|
@ -968,31 +970,30 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
|
||||
match destination {
|
||||
Some((id, label)) => {
|
||||
let target_id = if let Def::Label(loop_id) = self.expect_full_def(id) {
|
||||
Ok(self.lower_node_id(loop_id).node_id)
|
||||
} else {
|
||||
Err(hir::LoopIdError::UnresolvedLabel)
|
||||
};
|
||||
hir::Destination {
|
||||
label: self.lower_label(Some(label)),
|
||||
target_id,
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let target_id = self.loop_scopes
|
||||
.last()
|
||||
.map(|innermost_loop_id| *innermost_loop_id)
|
||||
.map(|id| Ok(self.lower_node_id(id).node_id))
|
||||
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
|
||||
.into();
|
||||
|
||||
hir::Destination {
|
||||
label: None,
|
||||
target_id,
|
||||
let target_id = if self.is_in_anon_const {
|
||||
Err(hir::LoopIdError::OutsideLoopScope)
|
||||
} else {
|
||||
match destination {
|
||||
Some((id, _)) => {
|
||||
if let Def::Label(loop_id) = self.expect_full_def(id) {
|
||||
Ok(self.lower_node_id(loop_id).node_id)
|
||||
} else {
|
||||
Err(hir::LoopIdError::UnresolvedLabel)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
self.loop_scopes
|
||||
.last()
|
||||
.map(|innermost_loop_id| *innermost_loop_id)
|
||||
.map(|id| Ok(self.lower_node_id(id).node_id))
|
||||
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
|
||||
.into()
|
||||
}
|
||||
}
|
||||
};
|
||||
hir::Destination {
|
||||
label: self.lower_label(destination.map(|(_, label)| label)),
|
||||
target_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3447,13 +3448,22 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
|
||||
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(c.id);
|
||||
let was_in_loop_condition = self.is_in_loop_condition;
|
||||
self.is_in_loop_condition = false;
|
||||
let was_in_anon_const = self.is_in_anon_const;
|
||||
self.is_in_anon_const = true;
|
||||
|
||||
hir::AnonConst {
|
||||
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(c.id);
|
||||
let anon_const = hir::AnonConst {
|
||||
id: node_id,
|
||||
hir_id,
|
||||
body: self.lower_body(None, |this| this.lower_expr(&c.value)),
|
||||
}
|
||||
};
|
||||
|
||||
self.is_in_anon_const = was_in_anon_const;
|
||||
self.is_in_loop_condition = was_in_loop_condition;
|
||||
|
||||
anon_const
|
||||
}
|
||||
|
||||
fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
|
||||
|
|
|
@ -840,6 +840,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) {
|
||||
debug!("walk_pat(cmt_discr={:?}, pat={:?})", cmt_discr, pat);
|
||||
|
||||
let tcx = self.tcx();
|
||||
let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self;
|
||||
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| {
|
||||
if let PatKind::Binding(_, canonical_id, ..) = pat.node {
|
||||
|
@ -849,34 +850,36 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
|||
pat,
|
||||
match_mode,
|
||||
);
|
||||
let bm = *mc.tables.pat_binding_modes().get(pat.hir_id)
|
||||
.expect("missing binding mode");
|
||||
debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
|
||||
if let Some(&bm) = mc.tables.pat_binding_modes().get(pat.hir_id) {
|
||||
debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
|
||||
|
||||
// pat_ty: the type of the binding being produced.
|
||||
let pat_ty = return_if_err!(mc.node_ty(pat.hir_id));
|
||||
debug!("walk_pat: pat_ty={:?}", pat_ty);
|
||||
// pat_ty: the type of the binding being produced.
|
||||
let pat_ty = return_if_err!(mc.node_ty(pat.hir_id));
|
||||
debug!("walk_pat: pat_ty={:?}", pat_ty);
|
||||
|
||||
// Each match binding is effectively an assignment to the
|
||||
// binding being produced.
|
||||
let def = Def::Local(canonical_id);
|
||||
if let Ok(ref binding_cmt) = mc.cat_def(pat.hir_id, pat.span, pat_ty, def) {
|
||||
delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
|
||||
}
|
||||
// Each match binding is effectively an assignment to the
|
||||
// binding being produced.
|
||||
let def = Def::Local(canonical_id);
|
||||
if let Ok(ref binding_cmt) = mc.cat_def(pat.hir_id, pat.span, pat_ty, def) {
|
||||
delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
|
||||
}
|
||||
|
||||
// It is also a borrow or copy/move of the value being matched.
|
||||
match bm {
|
||||
ty::BindByReference(m) => {
|
||||
if let ty::TyRef(r, _, _) = pat_ty.sty {
|
||||
let bk = ty::BorrowKind::from_mutbl(m);
|
||||
delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding);
|
||||
// It is also a borrow or copy/move of the value being matched.
|
||||
match bm {
|
||||
ty::BindByReference(m) => {
|
||||
if let ty::TyRef(r, _, _) = pat_ty.sty {
|
||||
let bk = ty::BorrowKind::from_mutbl(m);
|
||||
delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding);
|
||||
}
|
||||
}
|
||||
ty::BindByValue(..) => {
|
||||
let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove);
|
||||
debug!("walk_pat binding consuming pat");
|
||||
delegate.consume_pat(pat, &cmt_pat, mode);
|
||||
}
|
||||
}
|
||||
ty::BindByValue(..) => {
|
||||
let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove);
|
||||
debug!("walk_pat binding consuming pat");
|
||||
delegate.consume_pat(pat, &cmt_pat, mode);
|
||||
}
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(pat.span, "missing binding mode");
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
|
|
@ -1115,12 +1115,12 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
|||
}
|
||||
tcx.layout_raw(param_env.and(normalized))?
|
||||
}
|
||||
ty::TyParam(_) => {
|
||||
return Err(LayoutError::Unknown(ty));
|
||||
}
|
||||
ty::TyGeneratorWitness(..) | ty::TyInfer(_) | ty::TyError => {
|
||||
ty::TyGeneratorWitness(..) | ty::TyInfer(_) => {
|
||||
bug!("LayoutDetails::compute: unexpected type `{}`", ty)
|
||||
}
|
||||
ty::TyParam(_) | ty::TyError => {
|
||||
return Err(LayoutError::Unknown(ty));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -54,16 +54,16 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
|
|||
|
||||
// Skip anything that looks like `&foo` or `&mut foo`, only look
|
||||
// for by-value bindings
|
||||
let bm = match self.bccx.tables.pat_binding_modes().get(hir_id) {
|
||||
Some(&bm) => bm,
|
||||
None => span_bug!(span, "missing binding mode"),
|
||||
};
|
||||
match bm {
|
||||
ty::BindByValue(hir::MutMutable) => {}
|
||||
_ => return,
|
||||
}
|
||||
if let Some(&bm) = self.bccx.tables.pat_binding_modes().get(hir_id) {
|
||||
match bm {
|
||||
ty::BindByValue(hir::MutMutable) => {}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
mutables.entry(ident.name).or_insert(Vec::new()).push((hir_id, span));
|
||||
mutables.entry(ident.name).or_insert(Vec::new()).push((hir_id, span));
|
||||
} else {
|
||||
tcx.sess.delay_span_bug(span, "missing binding mode");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -541,13 +541,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
|
|||
if let hir::PatKind::Binding(_, _, ident, _) = pat.node {
|
||||
decl.debug_name = ident.name;
|
||||
|
||||
let bm = *hir.tables.pat_binding_modes()
|
||||
.get(pat.hir_id)
|
||||
.expect("missing binding mode");
|
||||
if bm == ty::BindByValue(hir::MutMutable) {
|
||||
decl.mutability = Mutability::Mut;
|
||||
if let Some(&bm) = hir.tables.pat_binding_modes().get(pat.hir_id) {
|
||||
if bm == ty::BindByValue(hir::MutMutable) {
|
||||
decl.mutability = Mutability::Mut;
|
||||
} else {
|
||||
decl.mutability = Mutability::Not;
|
||||
}
|
||||
} else {
|
||||
decl.mutability = Mutability::Not;
|
||||
tcx.sess.delay_span_bug(pat.span, "missing binding mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -541,9 +541,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
/// Finds the breakable scope for a given label. This is used for
|
||||
/// resolving `break` and `continue`.
|
||||
pub fn find_breakable_scope(&self,
|
||||
span: Span,
|
||||
label: region::Scope)
|
||||
-> &BreakableScope<'tcx> {
|
||||
span: Span,
|
||||
label: region::Scope)
|
||||
-> &BreakableScope<'tcx> {
|
||||
// find the loop-scope with the correct id
|
||||
self.breakable_scopes.iter()
|
||||
.rev()
|
||||
|
|
|
@ -309,33 +309,32 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
|||
fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
|
||||
pat.walk(|p| {
|
||||
if let PatKind::Binding(_, _, ident, None) = p.node {
|
||||
let bm = *cx.tables
|
||||
.pat_binding_modes()
|
||||
.get(p.hir_id)
|
||||
.expect("missing binding mode");
|
||||
|
||||
if bm != ty::BindByValue(hir::MutImmutable) {
|
||||
// Nothing to check.
|
||||
return true;
|
||||
}
|
||||
let pat_ty = cx.tables.pat_ty(p);
|
||||
if let ty::TyAdt(edef, _) = pat_ty.sty {
|
||||
if edef.is_enum() && edef.variants.iter().any(|variant| {
|
||||
variant.name == ident.name && variant.ctor_kind == CtorKind::Const
|
||||
}) {
|
||||
let ty_path = cx.tcx.item_path_str(edef.did);
|
||||
let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
|
||||
"pattern binding `{}` is named the same as one \
|
||||
of the variants of the type `{}`",
|
||||
ident, ty_path);
|
||||
err.span_suggestion_with_applicability(
|
||||
p.span,
|
||||
"to match on the variant, qualify the path",
|
||||
format!("{}::{}", ty_path, ident),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
err.emit();
|
||||
if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) {
|
||||
if bm != ty::BindByValue(hir::MutImmutable) {
|
||||
// Nothing to check.
|
||||
return true;
|
||||
}
|
||||
let pat_ty = cx.tables.pat_ty(p);
|
||||
if let ty::TyAdt(edef, _) = pat_ty.sty {
|
||||
if edef.is_enum() && edef.variants.iter().any(|variant| {
|
||||
variant.name == ident.name && variant.ctor_kind == CtorKind::Const
|
||||
}) {
|
||||
let ty_path = cx.tcx.item_path_str(edef.did);
|
||||
let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
|
||||
"pattern binding `{}` is named the same as one \
|
||||
of the variants of the type `{}`",
|
||||
ident, ty_path);
|
||||
err.span_suggestion_with_applicability(
|
||||
p.span,
|
||||
"to match on the variant, qualify the path",
|
||||
format!("{}::{}", ty_path, ident),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cx.tcx.sess.delay_span_bug(p.span, "missing binding mode");
|
||||
}
|
||||
}
|
||||
true
|
||||
|
@ -517,12 +516,12 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
|||
let mut by_ref_span = None;
|
||||
for pat in pats {
|
||||
pat.each_binding(|_, hir_id, span, _path| {
|
||||
let bm = *cx.tables
|
||||
.pat_binding_modes()
|
||||
.get(hir_id)
|
||||
.expect("missing binding mode");
|
||||
if let ty::BindByReference(..) = bm {
|
||||
by_ref_span = Some(span);
|
||||
if let Some(&bm) = cx.tables.pat_binding_modes().get(hir_id) {
|
||||
if let ty::BindByReference(..) = bm {
|
||||
by_ref_span = Some(span);
|
||||
}
|
||||
} else {
|
||||
cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -553,18 +552,18 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
|||
for pat in pats {
|
||||
pat.walk(|p| {
|
||||
if let PatKind::Binding(_, _, _, ref sub) = p.node {
|
||||
let bm = *cx.tables
|
||||
.pat_binding_modes()
|
||||
.get(p.hir_id)
|
||||
.expect("missing binding mode");
|
||||
match bm {
|
||||
ty::BindByValue(..) => {
|
||||
let pat_ty = cx.tables.node_id_to_type(p.hir_id);
|
||||
if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
|
||||
check_move(p, sub.as_ref().map(|p| &**p));
|
||||
if let Some(&bm) = cx.tables.pat_binding_modes().get(p.hir_id) {
|
||||
match bm {
|
||||
ty::BindByValue(..) => {
|
||||
let pat_ty = cx.tables.node_id_to_type(p.hir_id);
|
||||
if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) {
|
||||
check_move(p, sub.as_ref().map(|p| &**p));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
} else {
|
||||
cx.tcx.sess.delay_span_bug(pat.span, "missing binding mode");
|
||||
}
|
||||
}
|
||||
true
|
||||
|
|
|
@ -743,8 +743,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
);
|
||||
*self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
|
||||
},
|
||||
Err(()) => {
|
||||
self.errors.push(PatternError::FloatBug);
|
||||
Err(e) => {
|
||||
if e == LitToConstError::UnparseableFloat {
|
||||
self.errors.push(PatternError::FloatBug);
|
||||
}
|
||||
PatternKind::Wild
|
||||
},
|
||||
}
|
||||
|
@ -764,8 +766,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
);
|
||||
*self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
|
||||
},
|
||||
Err(()) => {
|
||||
self.errors.push(PatternError::FloatBug);
|
||||
Err(e) => {
|
||||
if e == LitToConstError::UnparseableFloat {
|
||||
self.errors.push(PatternError::FloatBug);
|
||||
}
|
||||
PatternKind::Wild
|
||||
},
|
||||
}
|
||||
|
@ -1118,12 +1122,18 @@ pub fn compare_const_vals<'a, 'tcx>(
|
|||
fallback()
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum LitToConstError {
|
||||
UnparseableFloat,
|
||||
Propagated,
|
||||
}
|
||||
|
||||
// FIXME: Combine with rustc_mir::hair::cx::const_eval_literal
|
||||
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
neg: bool)
|
||||
-> Result<&'tcx ty::Const<'tcx>, ()> {
|
||||
-> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
|
||||
use syntax::ast::*;
|
||||
|
||||
use rustc::mir::interpret::*;
|
||||
|
@ -1152,7 +1162,10 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
|||
ty::TyInt(other) => Int::Signed(other),
|
||||
ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty),
|
||||
ty::TyUint(other) => Int::Unsigned(other),
|
||||
_ => bug!(),
|
||||
ty::TyError => { // Avoid ICE (#51963)
|
||||
return Err(LitToConstError::Propagated);
|
||||
}
|
||||
_ => bug!("literal integer type with bad type ({:?})", ty.sty),
|
||||
};
|
||||
// This converts from LitKind::Int (which is sign extended) to
|
||||
// Scalar::Bytes (which is zero extended)
|
||||
|
@ -1182,14 +1195,14 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
|||
})
|
||||
},
|
||||
LitKind::Float(n, fty) => {
|
||||
parse_float(n, fty, neg)?
|
||||
parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
|
||||
}
|
||||
LitKind::FloatUnsuffixed(n) => {
|
||||
let fty = match ty.sty {
|
||||
ty::TyFloat(fty) => fty,
|
||||
_ => bug!()
|
||||
};
|
||||
parse_float(n, fty, neg)?
|
||||
parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
|
||||
}
|
||||
LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits {
|
||||
bits: b as u128,
|
||||
|
|
|
@ -17,7 +17,7 @@ use rustc::hir::{self, Destination};
|
|||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum LoopKind {
|
||||
Loop(hir::LoopSource),
|
||||
WhileLoop,
|
||||
|
@ -34,12 +34,13 @@ impl LoopKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum Context {
|
||||
Normal,
|
||||
Loop(LoopKind),
|
||||
Closure,
|
||||
LabeledBlock,
|
||||
AnonConst,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -71,6 +72,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
|
|||
self.with_context(Normal, |v| intravisit::walk_impl_item(v, i));
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
|
||||
self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c));
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &'hir hir::Expr) {
|
||||
match e.node {
|
||||
hir::ExprWhile(ref e, ref b, _) => {
|
||||
|
@ -194,7 +199,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
|
|||
.span_label(span, "cannot break inside of a closure")
|
||||
.emit();
|
||||
}
|
||||
Normal => {
|
||||
Normal | AnonConst => {
|
||||
struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name)
|
||||
.span_label(span, "cannot break outside of a loop")
|
||||
.emit();
|
||||
|
|
|
@ -3827,7 +3827,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// this can only happen if the `break` was not
|
||||
// inside a loop at all, which is caught by the
|
||||
// loop-checking pass.
|
||||
assert!(self.tcx.sess.err_count() > 0);
|
||||
if self.tcx.sess.err_count() == 0 {
|
||||
self.tcx.sess.delay_span_bug(expr.span,
|
||||
"break was outside loop, but no error was emitted");
|
||||
}
|
||||
|
||||
// We still need to assign a type to the inner expression to
|
||||
// prevent the ICE in #43162.
|
||||
|
@ -3960,7 +3963,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
// is nil. This makes sense because infinite loops
|
||||
// (which would have type !) are only possible iff we
|
||||
// permit break with a value [1].
|
||||
assert!(ctxt.coerce.is_some() || ctxt.may_break); // [1]
|
||||
if ctxt.coerce.is_none() && !ctxt.may_break {
|
||||
// [1]
|
||||
self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break");
|
||||
}
|
||||
ctxt.coerce.map(|c| c.complete(self)).unwrap_or(self.tcx.mk_nil())
|
||||
}
|
||||
hir::ExprMatch(ref discrim, ref arms, match_src) => {
|
||||
|
|
|
@ -1039,11 +1039,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
|||
match sub_pat.node {
|
||||
// `ref x` pattern
|
||||
PatKind::Binding(..) => {
|
||||
let bm = *mc.tables.pat_binding_modes().get(sub_pat.hir_id)
|
||||
.expect("missing binding mode");
|
||||
if let ty::BindByReference(mutbl) = bm {
|
||||
self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id,
|
||||
mutbl, &sub_cmt);
|
||||
if let Some(&bm) = mc.tables.pat_binding_modes().get(sub_pat.hir_id) {
|
||||
if let ty::BindByReference(mutbl) = bm {
|
||||
self.link_region_from_node_type(sub_pat.span, sub_pat.hir_id,
|
||||
mutbl, &sub_cmt);
|
||||
}
|
||||
} else {
|
||||
self.tcx.sess.delay_span_bug(sub_pat.span, "missing binding mode");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -257,13 +257,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
|
|||
fn visit_pat(&mut self, p: &'gcx hir::Pat) {
|
||||
match p.node {
|
||||
hir::PatKind::Binding(..) => {
|
||||
let bm = *self.fcx
|
||||
.tables
|
||||
.borrow()
|
||||
.pat_binding_modes()
|
||||
.get(p.hir_id)
|
||||
.expect("missing binding mode");
|
||||
self.tables.pat_binding_modes_mut().insert(p.hir_id, bm);
|
||||
if let Some(&bm) = self.fcx.tables.borrow().pat_binding_modes().get(p.hir_id) {
|
||||
self.tables.pat_binding_modes_mut().insert(p.hir_id, bm);
|
||||
} else {
|
||||
self.tcx().sess.delay_span_bug(p.span, "missing binding mode");
|
||||
}
|
||||
}
|
||||
hir::PatKind::Struct(_, ref fields, _) => {
|
||||
for field in fields {
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
loop {
|
||||
|_: [_; break]| {} //~ ERROR: `break` outside of loop
|
||||
}
|
||||
|
||||
loop {
|
||||
|_: [_; continue]| {} //~ ERROR: `continue` outside of loop
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
error[E0268]: `break` outside of loop
|
||||
--> $DIR/array-break-length.rs:13:17
|
||||
|
|
||||
LL | |_: [_; break]| {} //~ ERROR: `break` outside of loop
|
||||
| ^^^^^ cannot break outside of a loop
|
||||
|
||||
error[E0268]: `continue` outside of loop
|
||||
--> $DIR/array-break-length.rs:17:17
|
||||
|
|
||||
LL | |_: [_; continue]| {} //~ ERROR: `continue` outside of loop
|
||||
| ^^^^^^^^ cannot break outside of a loop
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0268`.
|
|
@ -11,7 +11,7 @@
|
|||
fn main() {
|
||||
|_: [_; continue]| {}; //~ ERROR: `continue` outside of loop
|
||||
|
||||
while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label
|
||||
while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop
|
||||
|
||||
while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label
|
||||
while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop
|
||||
}
|
||||
|
|
|
@ -4,19 +4,18 @@ error[E0268]: `continue` outside of loop
|
|||
LL | |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop
|
||||
| ^^^^^^^^ cannot break outside of a loop
|
||||
|
||||
error[E0590]: `break` or `continue` with no label in the condition of a `while` loop
|
||||
error[E0268]: `continue` outside of loop
|
||||
--> $DIR/closure-array-break-length.rs:14:19
|
||||
|
|
||||
LL | while |_: [_; continue]| {} {} //~ ERROR: `break` or `continue` with no label
|
||||
| ^^^^^^^^ unlabeled `continue` in the condition of a `while` loop
|
||||
LL | while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop
|
||||
| ^^^^^^^^ cannot break outside of a loop
|
||||
|
||||
error[E0590]: `break` or `continue` with no label in the condition of a `while` loop
|
||||
error[E0268]: `break` outside of loop
|
||||
--> $DIR/closure-array-break-length.rs:16:19
|
||||
|
|
||||
LL | while |_: [_; break]| {} {} //~ ERROR: `break` or `continue` with no label
|
||||
| ^^^^^ unlabeled `break` in the condition of a `while` loop
|
||||
LL | while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop
|
||||
| ^^^^^ cannot break outside of a loop
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors occurred: E0268, E0590.
|
||||
For more information about an error, try `rustc --explain E0268`.
|
||||
For more information about this error, try `rustc --explain E0268`.
|
||||
|
|
|
@ -9,11 +9,16 @@
|
|||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
|_: [_; return || {}] | {}
|
||||
|_: [_; return || {}] | {};
|
||||
//~^ ERROR return statement outside of function body
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
[(); return || {}];
|
||||
//~^ ERROR return statement outside of function body
|
||||
|
||||
[(); return |ice| {}];
|
||||
//~^ ERROR return statement outside of function body
|
||||
|
||||
[(); return while let Some(n) = Some(0) {}];
|
||||
//~^ ERROR return statement outside of function body
|
||||
//~^^ ERROR irrefutable while-let pattern
|
||||
}
|
||||
|
|
|
@ -1,15 +1,34 @@
|
|||
error[E0572]: return statement outside of function body
|
||||
--> $DIR/issue-51714.rs:12:14
|
||||
|
|
||||
LL | |_: [_; return || {}] | {}
|
||||
LL | |_: [_; return || {}] | {};
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0572]: return statement outside of function body
|
||||
--> $DIR/issue-51714.rs:17:10
|
||||
--> $DIR/issue-51714.rs:15:10
|
||||
|
|
||||
LL | [(); return || {}];
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0572]: return statement outside of function body
|
||||
--> $DIR/issue-51714.rs:18:10
|
||||
|
|
||||
LL | [(); return |ice| {}];
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
For more information about this error, try `rustc --explain E0572`.
|
||||
error[E0572]: return statement outside of function body
|
||||
--> $DIR/issue-51714.rs:21:10
|
||||
|
|
||||
LL | [(); return while let Some(n) = Some(0) {}];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0165]: irrefutable while-let pattern
|
||||
--> $DIR/issue-51714.rs:21:27
|
||||
|
|
||||
LL | [(); return while let Some(n) = Some(0) {}];
|
||||
| ^^^^^^^ irrefutable pattern
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors occurred: E0165, E0572.
|
||||
For more information about an error, try `rustc --explain E0165`.
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
[(); return match 0 { n => n }]; //~ ERROR: return statement outside of function body
|
||||
|
||||
[(); return match 0 { 0 => 0 }]; //~ ERROR: return statement outside of function body
|
||||
|
||||
[(); return match () { 'a' => 0, _ => 0 }]; //~ ERROR: return statement outside of function body
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
error[E0572]: return statement outside of function body
|
||||
--> $DIR/return-match-array-const.rs:12:10
|
||||
|
|
||||
LL | [(); return match 0 { n => n }]; //~ ERROR: return statement outside of function body
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0572]: return statement outside of function body
|
||||
--> $DIR/return-match-array-const.rs:14:10
|
||||
|
|
||||
LL | [(); return match 0 { 0 => 0 }]; //~ ERROR: return statement outside of function body
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0572]: return statement outside of function body
|
||||
--> $DIR/return-match-array-const.rs:16:10
|
||||
|
|
||||
LL | [(); return match () { 'a' => 0, _ => 0 }]; //~ ERROR: return statement outside of function body
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0572`.
|
Loading…
Reference in New Issue