Auto merge of #42969 - arielb1:struct-err, r=eddyb
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
This commit is contained in:
commit
37849a002e
@ -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 {
|
||||
@ -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);
|
||||
|
@ -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<()>
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
18
src/test/compile-fail/issue-42880.rs
Normal file
18
src/test/compile-fail/issue-42880.rs
Normal file
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user