Skip to content

Commit

Permalink
Auto merge of #51967 - varkor:const-body-break-continue, r=estebank
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Jul 5, 2018
2 parents 6fc21e5 + adf4ef7 commit 69b9e1e
Show file tree
Hide file tree
Showing 20 changed files with 288 additions and 156 deletions.
60 changes: 35 additions & 25 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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,
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 => {
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,
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,
}
}

Expand Down Expand Up @@ -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 {
Expand Down
53 changes: 28 additions & 25 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);

// 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);
}
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);

// 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");
}
}
}));
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
})
}

Expand Down
18 changes: 9 additions & 9 deletions src/librustc_borrowck/borrowck/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
} else {
tcx.sess.delay_span_bug(span, "missing binding mode");
}

mutables.entry(ident.name).or_insert(Vec::new()).push((hir_id, span));
});
}

Expand Down
13 changes: 7 additions & 6 deletions src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_mir/build/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
83 changes: 41 additions & 42 deletions src/librustc_mir/hair/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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");
}
})
}
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 69b9e1e

Please sign in to comment.