Skip to content

Fix various issues with control-flow statements inside anonymous constants #51967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 5, 2018
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 @@ -3440,13 +3441,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