Skip to content

Commit

Permalink
Auto merge of #42969 - arielb1:struct-err, r=eddyb
Browse files Browse the repository at this point in the history
mem_categorization: handle type-based paths in variant patterns

These can't be used in correct programs, but must be handled in order to
prevent ICEs.

Fixes #42880.

r? @eddyb
  • Loading branch information
bors committed Jun 30, 2017
2 parents e72580c + 1ea6813 commit 37849a0
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 55 deletions.
9 changes: 1 addition & 8 deletions src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,6 @@ 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(bmode, def_id, ..) = pat.node {
Expand Down Expand Up @@ -864,13 +863,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
match def {
Def::Variant(variant_did) |
Def::VariantCtor(variant_did, ..) => {
let enum_did = tcx.parent_def_id(variant_did).unwrap();
let downcast_cmt = if tcx.adt_def(enum_did).is_univariant() {
cmt_pat
} else {
let cmt_pat_ty = cmt_pat.ty;
mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
};
let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did);

debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
delegate.matched_pat(pat, downcast_cmt, match_mode);
Expand Down
92 changes: 45 additions & 47 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1032,22 +1032,29 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
ret
}

pub fn cat_downcast<N:ast_node>(&self,
node: &N,
base_cmt: cmt<'tcx>,
downcast_ty: Ty<'tcx>,
variant_did: DefId)
-> cmt<'tcx> {
let ret = Rc::new(cmt_ {
id: node.id(),
span: node.span(),
mutbl: base_cmt.mutbl.inherit(),
cat: Categorization::Downcast(base_cmt, variant_did),
ty: downcast_ty,
note: NoteNone
});
debug!("cat_downcast ret={:?}", ret);
ret
pub fn cat_downcast_if_needed<N:ast_node>(&self,
node: &N,
base_cmt: cmt<'tcx>,
variant_did: DefId)
-> cmt<'tcx> {
// univariant enums do not need downcasts
let base_did = self.tcx.parent_def_id(variant_did).unwrap();
if !self.tcx.adt_def(base_did).is_univariant() {
let base_ty = base_cmt.ty;
let ret = Rc::new(cmt_ {
id: node.id(),
span: node.span(),
mutbl: base_cmt.mutbl.inherit(),
cat: Categorization::Downcast(base_cmt, variant_did),
ty: base_ty,
note: NoteNone
});
debug!("cat_downcast ret={:?}", ret);
ret
} else {
debug!("cat_downcast univariant={:?}", base_cmt);
base_cmt
}
}

pub fn cat_pattern<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, mut op: F) -> McResult<()>
Expand Down Expand Up @@ -1109,45 +1116,23 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {

op(cmt.clone(), pat);

// Note: This goes up here (rather than within the PatKind::TupleStruct arm
// alone) because PatKind::Struct can also refer to variants.
let cmt = match pat.node {
PatKind::Path(hir::QPath::Resolved(_, ref path)) |
PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
match path.def {
Def::Err => {
debug!("access to unresolvable pattern {:?}", pat);
return Err(())
}
Def::Variant(variant_did) |
Def::VariantCtor(variant_did, ..) => {
// univariant enums do not need downcasts
let enum_did = self.tcx.parent_def_id(variant_did).unwrap();
if !self.tcx.adt_def(enum_did).is_univariant() {
self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
} else {
cmt
}
}
_ => cmt
}
}
_ => cmt
};

match pat.node {
PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => {
let def = self.tables.qpath_def(qpath, pat.id);
let expected_len = match def {
let (cmt, expected_len) = match def {
Def::Err => {
debug!("access to unresolvable pattern {:?}", pat);
return Err(())
}
Def::VariantCtor(def_id, CtorKind::Fn) => {
let enum_def = self.tcx.parent_def_id(def_id).unwrap();
self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len()
(self.cat_downcast_if_needed(pat, cmt, def_id),
self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len())
}
Def::StructCtor(_, CtorKind::Fn) => {
match self.pat_ty(&pat)?.sty {
ty::TyAdt(adt_def, _) => {
adt_def.struct_variant().fields.len()
(cmt, adt_def.struct_variant().fields.len())
}
ref ty => {
span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty);
Expand All @@ -1168,8 +1153,21 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
}
}

PatKind::Struct(_, ref field_pats, _) => {
PatKind::Struct(ref qpath, ref field_pats, _) => {
// {f1: p1, ..., fN: pN}
let def = self.tables.qpath_def(qpath, pat.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(&fp.node.pat)?; // see (*2)
let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.name, field_ty);
Expand Down
18 changes: 18 additions & 0 deletions src/test/compile-fail/issue-42880.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2017 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.

type Value = String;

fn main() {
let f = |&Value::String(_)| (); //~ ERROR no associated item named

let vec: Vec<Value> = Vec::new();
vec.last().map(f);
}

0 comments on commit 37849a0

Please sign in to comment.