diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 1247db55f5850..118125a19ddef 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -389,7 +389,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprType(ref e, _) | hir::ExprUnary(_, ref e) | hir::ExprField(ref e, _) | - hir::ExprTupField(ref e, _) | hir::ExprYield(ref e) | hir::ExprRepeat(ref e, _) => { self.straightline(expr, pred, Some(&**e).into_iter()) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 9f51eb8c35a82..be9f8b8dac5c0 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -658,6 +658,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { PatKind::Struct(ref qpath, ref fields, _) => { visitor.visit_qpath(qpath, pattern.id, pattern.span); for field in fields { + visitor.visit_id(field.node.id); visitor.visit_name(field.span, field.node.name); visitor.visit_pat(&field.node.pat) } @@ -959,6 +960,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { ExprStruct(ref qpath, ref fields, ref optional_base) => { visitor.visit_qpath(qpath, expression.id, expression.span); for field in fields { + visitor.visit_id(field.id); visitor.visit_name(field.name.span, field.name.node); visitor.visit_expr(&field.expr) } @@ -1025,9 +1027,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(subexpression); visitor.visit_name(name.span, name.node); } - ExprTupField(ref subexpression, _) => { - visitor.visit_expr(subexpression); - } ExprIndex(ref main_expression, ref index_expression) => { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index fdeb41a8770f1..fee076acb207e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2100,6 +2100,7 @@ impl<'a> LoweringContext<'a> { fn lower_field(&mut self, f: &Field) -> hir::Field { hir::Field { + id: self.next_id().node_id, name: respan(f.ident.span, self.lower_ident(f.ident)), expr: P(self.lower_expr(&f.expr)), span: f.span, @@ -2863,6 +2864,7 @@ impl<'a> LoweringContext<'a> { .map(|f| Spanned { span: f.span, node: hir::FieldPat { + id: self.next_id().node_id, name: self.lower_ident(f.node.ident), pat: self.lower_pat(&f.node.pat), is_shorthand: f.node.is_shorthand, @@ -3095,7 +3097,6 @@ impl<'a> LoweringContext<'a> { P(self.lower_expr(el)), respan(ident.span, self.lower_ident(ident)), ), - ExprKind::TupField(ref el, ident) => hir::ExprTupField(P(self.lower_expr(el)), ident), ExprKind::Index(ref el, ref er) => { hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) } @@ -3742,6 +3743,7 @@ impl<'a> LoweringContext<'a> { fn field(&mut self, name: Name, expr: P, span: Span) -> hir::Field { hir::Field { + id: self.next_id().node_id, name: Spanned { node: name, span }, span, expr, diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index be8cceb611896..e6080fad91d59 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -827,6 +827,7 @@ impl Pat { /// except is_shorthand is true #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct FieldPat { + pub id: NodeId, /// The identifier for the field pub name: Name, /// The pattern the field is destructured to @@ -1172,6 +1173,7 @@ pub struct Arm { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Field { + pub id: NodeId, pub name: Spanned, pub expr: P, pub span: Span, @@ -1276,7 +1278,6 @@ impl Expr { ExprAssign(..) => ExprPrecedence::Assign, ExprAssignOp(..) => ExprPrecedence::AssignOp, ExprField(..) => ExprPrecedence::Field, - ExprTupField(..) => ExprPrecedence::TupField, ExprIndex(..) => ExprPrecedence::Index, ExprPath(..) => ExprPrecedence::Path, ExprAddrOf(..) => ExprPrecedence::AddrOf, @@ -1363,12 +1364,8 @@ pub enum Expr_ { /// /// For example, `a += 1`. ExprAssignOp(BinOp, P, P), - /// Access of a named struct field (`obj.foo`) + /// Access of a named (`obj.foo`) or unnamed (`obj.0`) struct or tuple field ExprField(P, Spanned), - /// Access of an unnamed field of a struct or tuple-struct - /// - /// For example, `foo.0`. - ExprTupField(P, Spanned), /// An indexing operation (`foo[2]`) ExprIndex(P, P), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index ff501f30c891a..d3f2458ef87c7 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1201,8 +1201,7 @@ impl<'a> State<'a> { fn print_expr_call(&mut self, func: &hir::Expr, args: &[hir::Expr]) -> io::Result<()> { let prec = match func.node { - hir::ExprField(..) | - hir::ExprTupField(..) => parser::PREC_FORCE_PAREN, + hir::ExprField(..) => parser::PREC_FORCE_PAREN, _ => parser::PREC_POSTFIX, }; @@ -1405,11 +1404,6 @@ impl<'a> State<'a> { self.s.word(".")?; self.print_name(name.node)?; } - hir::ExprTupField(ref expr, id) => { - self.print_expr_maybe_paren(&expr, parser::PREC_POSTFIX)?; - self.s.word(".")?; - self.print_usize(id.node)?; - } hir::ExprIndex(ref expr, ref index) => { self.print_expr_maybe_paren(&expr, parser::PREC_POSTFIX)?; self.s.word("[")?; @@ -2376,7 +2370,6 @@ fn contains_exterior_struct_lit(value: &hir::Expr) -> bool { hir::ExprCast(ref x, _) | hir::ExprType(ref x, _) | hir::ExprField(ref x, _) | - hir::ExprTupField(ref x, _) | hir::ExprIndex(ref x, _) => { // &X { y: 1 }, X { y: 1 }.y contains_exterior_struct_lit(&x) diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 38b284fd64637..4a001802eacb4 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -420,11 +420,23 @@ impl<'a> HashStable> for hir::Pat { } impl_stable_hash_for_spanned!(hir::FieldPat); -impl_stable_hash_for!(struct hir::FieldPat { - name, - pat, - is_shorthand -}); + +impl<'a> HashStable> for hir::FieldPat { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + let hir::FieldPat { + id: _, + name, + ref pat, + is_shorthand, + } = *self; + + name.hash_stable(hcx, hasher); + pat.hash_stable(hcx, hasher); + is_shorthand.hash_stable(hcx, hasher); + } +} impl_stable_hash_for!(enum hir::BindingAnnotation { Unannotated, @@ -507,12 +519,24 @@ impl_stable_hash_for!(struct hir::Arm { body }); -impl_stable_hash_for!(struct hir::Field { - name, - expr, - span, - is_shorthand -}); +impl<'a> HashStable> for hir::Field { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + let hir::Field { + id: _, + name, + ref expr, + span, + is_shorthand, + } = *self; + + name.hash_stable(hcx, hasher); + expr.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + is_shorthand.hash_stable(hcx, hasher); + } +} impl_stable_hash_for_spanned!(ast::Name); @@ -569,7 +593,6 @@ impl_stable_hash_for!(enum hir::Expr_ { ExprAssign(lhs, rhs), ExprAssignOp(op, lhs, rhs), ExprField(owner, field_name), - ExprTupField(owner, idx), ExprIndex(lhs, rhs), ExprPath(path), ExprAddrOf(mutability, sub), diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index a0cd231bb704d..9ec3d2e2460e9 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -13,7 +13,7 @@ // from live codes are live, and everything else is dead. use hir::map as hir_map; -use hir::{self, Item_, PatKind}; +use hir::{self, PatKind}; use hir::intravisit::{self, Visitor, NestedVisitorMap}; use hir::itemlikevisit::ItemLikeVisitor; @@ -99,22 +99,14 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.check_def_id(self.tables.type_dependent_defs()[id].def_id()); } - fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { + fn handle_field_access(&mut self, lhs: &hir::Expr, node_id: ast::NodeId) { match self.tables.expr_ty_adjusted(lhs).sty { ty::TyAdt(def, _) => { - self.insert_def_id(def.non_enum_variant().field_named(name).did); - } - _ => span_bug!(lhs.span, "named field access on non-ADT"), - } - } - - fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) { - match self.tables.expr_ty_adjusted(lhs).sty { - ty::TyAdt(def, _) => { - self.insert_def_id(def.non_enum_variant().fields[idx].did); + let index = self.tcx.field_index(node_id, self.tables); + self.insert_def_id(def.non_enum_variant().fields[index].did); } ty::TyTuple(..) => {} - _ => span_bug!(lhs.span, "numeric field access on non-ADT"), + _ => span_bug!(lhs.span, "named field access on non-ADT"), } } @@ -128,7 +120,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { if let PatKind::Wild = pat.node.pat.node { continue; } - self.insert_def_id(variant.field_named(pat.node.name).did); + let index = self.tcx.field_index(pat.node.id, self.tables); + self.insert_def_id(variant.fields[index].did); } } @@ -191,18 +184,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.inherited_pub_visibility = had_inherited_pub_visibility; } - fn mark_as_used_if_union(&mut self, did: DefId, fields: &hir::HirVec) { - if let Some(node_id) = self.tcx.hir.as_local_node_id(did) { - if let Some(hir_map::NodeItem(item)) = self.tcx.hir.find(node_id) { - if let Item_::ItemUnion(ref variant, _) = item.node { - if variant.fields().len() > 1 { - for field in variant.fields() { - if fields.iter().find(|x| x.name.node == field.name).is_some() { - self.live_symbols.insert(field.id); - } - } - } - } + fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &hir::HirVec) { + if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did.is_local() { + for field in fields { + let index = self.tcx.field_index(field.id, self.tables); + self.insert_def_id(adt.non_enum_variant().fields[index].did); } } } @@ -242,17 +228,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { hir::ExprMethodCall(..) => { self.lookup_and_handle_method(expr.hir_id); } - hir::ExprField(ref lhs, ref name) => { - self.handle_field_access(&lhs, name.node); - } - hir::ExprTupField(ref lhs, idx) => { - self.handle_tup_field_access(&lhs, idx.node); + hir::ExprField(ref lhs, ..) => { + self.handle_field_access(&lhs, expr.id); } hir::ExprStruct(_, ref fields, _) => { - if let ty::TypeVariants::TyAdt(ref def, _) = self.tables.expr_ty(expr).sty { - if def.is_union() { - self.mark_as_used_if_union(def.did, fields); - } + if let ty::TypeVariants::TyAdt(ref adt, _) = self.tables.expr_ty(expr).sty { + self.mark_as_used_if_union(adt, fields); } } _ => () diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 28524678e9916..2cc5a4a8fe639 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -404,10 +404,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.select_from_expr(&base); } - hir::ExprTupField(ref base, _) => { // base. - self.select_from_expr(&base); - } - hir::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] self.select_from_expr(&lhs); self.consume_expr(&rhs); @@ -663,11 +659,15 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { match with_cmt.ty.sty { ty::TyAdt(adt, substs) if adt.is_struct() => { // Consume those fields of the with expression that are needed. - for with_field in &adt.non_enum_variant().fields { - if !contains_field_named(with_field, fields) { + for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() { + let is_mentioned = fields.iter().any(|f| { + self.tcx().field_index(f.id, self.mc.tables) == f_index + }); + if !is_mentioned { let cmt_field = self.mc.cat_field( &*with_expr, with_cmt.clone(), + f_index, with_field.name, with_field.ty(self.tcx(), substs) ); @@ -691,14 +691,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // walk the with expression so that complex expressions // are properly handled. self.walk_expr(with_expr); - - fn contains_field_named(field: &ty::FieldDef, - fields: &[hir::Field]) - -> bool - { - fields.iter().any( - |f| f.name.node == field.name) - } } // Invoke the appropriate delegate calls for anything that gets diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 966353b53a95a..11dc2a8188505 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -476,7 +476,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { } // otherwise, live nodes are not required: - hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) | + hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprArray(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprAddrOf(..) | hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprBreak(..) | @@ -912,10 +912,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&e, succ) } - hir::ExprTupField(ref e, _) => { - self.propagate_through_expr(&e, succ) - } - hir::ExprClosure(.., blk_id, _, _) => { debug!("{} is an ExprClosure", self.ir.tcx.hir.node_to_pretty_string(expr.id)); @@ -1226,7 +1222,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match expr.node { hir::ExprPath(_) => succ, hir::ExprField(ref e, _) => self.propagate_through_expr(&e, succ), - hir::ExprTupField(ref e, _) => self.propagate_through_expr(&e, succ), _ => self.propagate_through_expr(expr, succ) } } @@ -1419,7 +1414,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { // no correctness conditions related to liveness hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprIf(..) | hir::ExprMatch(..) | hir::ExprWhile(..) | hir::ExprLoop(..) | - hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) | + hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprRet(..) | hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) | diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 5875e5e4097af..6f41f07dce8a7 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -62,7 +62,6 @@ pub use self::PointerKind::*; pub use self::InteriorKind::*; -pub use self::FieldName::*; pub use self::MutabilityCategory::*; pub use self::AliasableReason::*; pub use self::Note::*; @@ -81,10 +80,11 @@ use ty::fold::TypeFoldable; use hir::{MutImmutable, MutMutable, PatKind}; use hir::pat_util::EnumerateAndAdjustIterator; use hir; -use syntax::ast; +use syntax::ast::{self, Name}; use syntax_pos::Span; use std::fmt; +use std::hash::{Hash, Hasher}; use rustc_data_structures::sync::Lrc; use std::rc::Rc; use util::nodemap::ItemLocalSet; @@ -129,14 +129,25 @@ pub enum PointerKind<'tcx> { // base without a pointer dereference", e.g. a field #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum InteriorKind { - InteriorField(FieldName), + InteriorField(FieldIndex), InteriorElement(InteriorOffsetKind), } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum FieldName { - NamedField(ast::Name), - PositionalField(usize) +// Contains index of a field that is actually used for loan path comparisons and +// string representation of the field that should be used only for diagnostics. +#[derive(Clone, Copy, Eq)] +pub struct FieldIndex(pub usize, pub Name); + +impl PartialEq for FieldIndex { + fn eq(&self, rhs: &Self) -> bool { + self.0 == rhs.0 + } +} + +impl Hash for FieldIndex { + fn hash(&self, h: &mut H) { + self.0.hash(h) + } } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] @@ -198,7 +209,7 @@ pub enum ImmutabilityBlame<'tcx> { } impl<'tcx> cmt_<'tcx> { - fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)> + fn resolve_field(&self, field_index: usize) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)> { let adt_def = match self.ty.sty { ty::TyAdt(def, _) => def, @@ -215,11 +226,7 @@ impl<'tcx> cmt_<'tcx> { &adt_def.variants[0] } }; - let field_def = match field_name { - NamedField(name) => variant_def.field_named(name), - PositionalField(idx) => &variant_def.fields[idx] - }; - Some((adt_def, field_def)) + Some((adt_def, &variant_def.fields[field_index])) } pub fn immutability_blame(&self) -> Option> { @@ -230,8 +237,8 @@ impl<'tcx> cmt_<'tcx> { match base_cmt.cat { Categorization::Local(node_id) => Some(ImmutabilityBlame::LocalDeref(node_id)), - Categorization::Interior(ref base_cmt, InteriorField(field_name)) => { - base_cmt.resolve_field(field_name).map(|(adt_def, field_def)| { + Categorization::Interior(ref base_cmt, InteriorField(field_index)) => { + base_cmt.resolve_field(field_index.0).map(|(adt_def, field_def)| { ImmutabilityBlame::AdtFieldDeref(adt_def, field_def) }) } @@ -646,12 +653,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { expr.id, expr, base_cmt); - Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty)) - } - - hir::ExprTupField(ref base, idx) => { - let base_cmt = self.cat_expr(&base)?; - Ok(self.cat_tup_field(expr, base_cmt, idx.node, expr_ty)) + let f_index = self.tcx.field_index(expr.id, self.tables); + Ok(self.cat_field(expr, base_cmt, f_index, f_name.node, expr_ty)) } hir::ExprIndex(ref base, _) => { @@ -979,14 +982,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn cat_field(&self, node: &N, base_cmt: cmt<'tcx>, - f_name: ast::Name, + f_index: usize, + f_name: Name, f_ty: Ty<'tcx>) -> cmt<'tcx> { let ret = Rc::new(cmt_ { id: node.id(), span: node.span(), mutbl: base_cmt.mutbl.inherit(), - cat: Categorization::Interior(base_cmt, InteriorField(NamedField(f_name))), + cat: Categorization::Interior(base_cmt, InteriorField(FieldIndex(f_index, f_name))), ty: f_ty, note: NoteNone }); @@ -994,24 +998,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - pub fn cat_tup_field(&self, - node: &N, - base_cmt: cmt<'tcx>, - f_idx: usize, - f_ty: Ty<'tcx>) - -> cmt<'tcx> { - let ret = Rc::new(cmt_ { - id: node.id(), - span: node.span(), - mutbl: base_cmt.mutbl.inherit(), - cat: Categorization::Interior(base_cmt, InteriorField(PositionalField(f_idx))), - ty: f_ty, - note: NoteNone - }); - debug!("cat_tup_field ret {:?}", ret); - ret - } - fn cat_overloaded_place(&self, expr: &hir::Expr, base: &hir::Expr, @@ -1292,8 +1278,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) - let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string()))); + let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior); self.cat_pattern_(subcmt, &subpat, op)?; } } @@ -1315,7 +1301,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { 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); + let f_index = self.tcx.field_index(fp.node.id, self.tables); + let cmt_field = self.cat_field(pat, cmt.clone(), f_index, fp.node.name, field_ty); self.cat_pattern_(cmt_field, &fp.node.pat, op)?; } } @@ -1332,8 +1319,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) - let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string()))); + let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior); self.cat_pattern_(subcmt, &subpat, op)?; } } @@ -1516,12 +1503,9 @@ impl<'tcx> cmt_<'tcx> { } } } - Categorization::Interior(_, InteriorField(NamedField(_))) => { + Categorization::Interior(_, InteriorField(..)) => { "field".to_string() } - Categorization::Interior(_, InteriorField(PositionalField(_))) => { - "anonymous field".to_string() - } Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index)) => { "indexed content".to_string() } @@ -1554,8 +1538,7 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str { impl fmt::Debug for InteriorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - InteriorField(NamedField(fld)) => write!(f, "{}", fld), - InteriorField(PositionalField(i)) => write!(f, "#{}", i), + InteriorField(FieldIndex(_, info)) => write!(f, "{}", info), InteriorElement(..) => write!(f, "[]"), } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 7e1b7c08c3dad..42483c83f4ba2 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1307,7 +1307,6 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, hir::ExprAddrOf(_, ref subexpr) | hir::ExprUnary(hir::UnDeref, ref subexpr) | hir::ExprField(ref subexpr, _) | - hir::ExprTupField(ref subexpr, _) | hir::ExprIndex(ref subexpr, _) => { expr = &subexpr; } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 1e5d0753e6932..76ec8c21743e0 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -346,6 +346,12 @@ pub struct TypeckTables<'tcx> { /// method calls, including those of overloaded operators. type_dependent_defs: ItemLocalMap, + /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`) + /// or patterns (`S { field }`). The index is often useful by itself, but to learn more + /// about the field you also need definition of the variant to which the field + /// belongs, but it may not exist if it's a tuple field (`tuple.0`). + field_indices: ItemLocalMap, + /// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in /// MIR. user_provided_tys: ItemLocalMap>, @@ -426,6 +432,7 @@ impl<'tcx> TypeckTables<'tcx> { TypeckTables { local_id_root, type_dependent_defs: ItemLocalMap(), + field_indices: ItemLocalMap(), user_provided_tys: ItemLocalMap(), node_types: ItemLocalMap(), node_substs: ItemLocalMap(), @@ -468,6 +475,20 @@ impl<'tcx> TypeckTables<'tcx> { } } + pub fn field_indices(&self) -> LocalTableInContext { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.field_indices + } + } + + pub fn field_indices_mut(&mut self) -> LocalTableInContextMut { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.field_indices + } + } + pub fn user_provided_tys(&self) -> LocalTableInContext> { LocalTableInContext { local_id_root: self.local_id_root, @@ -706,6 +727,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { let ty::TypeckTables { local_id_root, ref type_dependent_defs, + ref field_indices, ref user_provided_tys, ref node_types, ref node_substs, @@ -726,6 +748,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { type_dependent_defs.hash_stable(hcx, hasher); + field_indices.hash_stable(hcx, hasher); user_provided_tys.hash_stable(hcx, hasher); node_types.hash_stable(hcx, hasher); node_substs.hash_stable(hcx, hasher); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 33b59eda7ce2c..d0850f5ba6e9a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -50,7 +50,7 @@ use std::vec::IntoIter; use std::mem; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; -use syntax::ext::hygiene::{Mark, SyntaxContext}; +use syntax::ext::hygiene::Mark; use syntax::symbol::{Symbol, InternedString}; use syntax_pos::{DUMMY_SP, Span}; @@ -2091,32 +2091,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } -impl<'a, 'gcx, 'tcx> VariantDef { - #[inline] - pub fn find_field_named(&self, name: ast::Name) -> Option<&FieldDef> { - self.index_of_field_named(name).map(|index| &self.fields[index]) - } - - pub fn index_of_field_named(&self, name: ast::Name) -> Option { - if let Some(index) = self.fields.iter().position(|f| f.name == name) { - return Some(index); - } - let mut ident = name.to_ident(); - while ident.span.ctxt() != SyntaxContext::empty() { - ident.span.remove_mark(); - if let Some(field) = self.fields.iter().position(|f| f.name.to_ident() == ident) { - return Some(field); - } - } - None - } - - #[inline] - pub fn field_named(&self, name: ast::Name) -> &FieldDef { - self.find_field_named(name).unwrap() - } -} - impl<'a, 'gcx, 'tcx> FieldDef { pub fn ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { tcx.type_of(self.did).subst(tcx, subst) @@ -2383,6 +2357,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + pub fn field_index(self, node_id: NodeId, tables: &TypeckTables) -> usize { + let hir_id = self.hir.node_to_hir_id(node_id); + tables.field_indices().get(hir_id).cloned().expect("no index for a field") + } + + pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option { + variant.fields.iter().position(|field| { + self.adjust_ident(ident.modern(), variant.did, DUMMY_NODE_ID).0 == field.name.to_ident() + }) + } + pub fn associated_items( self, def_id: DefId, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c170c2a63e829..77eff49d19ff6 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -33,7 +33,7 @@ use rustc_data_structures::fx::FxHashMap; use std::{cmp, fmt}; use std::hash::Hash; use std::intrinsics; -use syntax::ast::{self, Name}; +use syntax::ast; use syntax::attr::{self, SignedInt, UnsignedInt}; use syntax_pos::{Span, DUMMY_SP}; @@ -270,42 +270,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { false } - /// Returns the type of element at index `i` in tuple or tuple-like type `t`. - /// For an enum `t`, `variant` is None only if `t` is a univariant enum. - pub fn positional_element_ty(self, - ty: Ty<'tcx>, - i: usize, - variant: Option) -> Option> { - match (&ty.sty, variant) { - (&TyAdt(adt, substs), Some(vid)) => { - adt.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyAdt(adt, substs), None) => { - // Don't use `non_enum_variant`, this may be a univariant enum. - adt.variants[0].fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyTuple(ref v), None) => v.get(i).cloned(), - _ => None, - } - } - - /// Returns the type of element at field `n` in struct or struct-like type `t`. - /// For an enum `t`, `variant` must be some def id. - pub fn named_element_ty(self, - ty: Ty<'tcx>, - n: Name, - variant: Option) -> Option> { - match (&ty.sty, variant) { - (&TyAdt(adt, substs), Some(vid)) => { - adt.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) - } - (&TyAdt(adt, substs), None) => { - adt.non_enum_variant().find_field_named(n).map(|f| f.ty(self, substs)) - } - _ => return None - } - } - /// Returns the deeply last field of nested structures, or the same type, /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 5cfbe49f77f11..e3adb51433b25 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -107,8 +107,9 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { ty::TyAdt(adt_def, _) if adt_def.is_union() => match result { RestrictionResult::Safe => RestrictionResult::Safe, RestrictionResult::SafeIf(base_lp, mut base_vec) => { - for field in &adt_def.non_enum_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { + let field = + InteriorKind::InteriorField(mc::FieldIndex(i, field.name)); let field_ty = if field == interior { cmt.ty } else { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 2049a146a0f02..6d832d4060a1f 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -370,7 +370,7 @@ const DOWNCAST_PRINTED_OPERATOR: &'static str = " as "; // is tracked is irrelevant here.) #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum InteriorKind { - InteriorField(mc::FieldName), + InteriorField(mc::FieldIndex), InteriorElement, } @@ -1336,18 +1336,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { out.push(')'); } - LpExtend(ref lp_base, _, LpInterior(_, InteriorField(fname))) => { + LpExtend(ref lp_base, _, LpInterior(_, InteriorField(mc::FieldIndex(_, info)))) => { self.append_autoderefd_loan_path_to_string(&lp_base, out); - match fname { - mc::NamedField(fname) => { - out.push('.'); - out.push_str(&fname.as_str()); - } - mc::PositionalField(idx) => { - out.push('.'); - out.push_str(&idx.to_string()); - } - } + out.push('.'); + out.push_str(&info.as_str()); } LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => { @@ -1422,8 +1414,7 @@ impl DataFlowOperator for LoanDataFlowOperator { impl<'tcx> fmt::Debug for InteriorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - InteriorField(mc::NamedField(fld)) => write!(f, "{}", fld), - InteriorField(mc::PositionalField(i)) => write!(f, "#{}", i), + InteriorField(mc::FieldIndex(_, info)) => write!(f, "{}", info), InteriorElement => write!(f, "[]"), } } diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index a90dcd1072f95..1f4050a5b3624 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -21,7 +21,6 @@ use rustc::middle::dataflow::DataFlowOperator; use rustc::middle::dataflow::KillFrom; use rustc::middle::expr_use_visitor as euv; use rustc::middle::expr_use_visitor::MutateMode; -use rustc::middle::mem_categorization as mc; use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; @@ -343,8 +342,8 @@ impl<'a, 'tcx> MoveData<'tcx> { if let (&ty::TyAdt(adt_def, _), LpInterior(opt_variant_id, interior)) = (&base_lp.ty.sty, lp_elem) { if adt_def.is_union() { - for field in &adt_def.non_enum_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { + let field = InteriorKind::InteriorField(mc::FieldIndex(i, field.name)); if field != interior { let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field)); @@ -395,8 +394,8 @@ impl<'a, 'tcx> MoveData<'tcx> { if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { if adt_def.is_union() { - for field in &adt_def.non_enum_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { + let field = InteriorKind::InteriorField(mc::FieldIndex(i, field.name)); let field_ty = if field == interior { lp.ty } else { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 48e9cc498dceb..6f2c51b0f1899 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -166,19 +166,24 @@ impl LintPass for NonShorthandFieldPatterns { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns { fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { - if let PatKind::Struct(_, ref field_pats, _) = pat.node { + if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.node { + let variant = cx.tables.pat_ty(pat).ty_adt_def() + .expect("struct pattern type is not an ADT") + .variant_of_def(cx.tables.qpath_def(qpath, pat.hir_id)); for fieldpat in field_pats { if fieldpat.node.is_shorthand { continue; } + if fieldpat.span.ctxt().outer().expn_info().is_some() { + // Don't lint if this is a macro expansion: macro authors + // shouldn't have to worry about this kind of style issue + // (Issue #49588) + continue; + } if let PatKind::Binding(_, _, name, None) = fieldpat.node.pat.node { - if name.node == fieldpat.node.name { - if let Some(_) = fieldpat.span.ctxt().outer().expn_info() { - // Don't lint if this is a macro expansion: macro authors - // shouldn't have to worry about this kind of style issue - // (Issue #49588) - return; - } + let binding_ident = ast::Ident::new(name.node, name.span); + if cx.tcx.find_field_index(binding_ident, &variant) == + Some(cx.tcx.field_index(fieldpat.node.id, cx.tables)) { let mut err = cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, &format!("the `{}:` in this pattern is redundant", diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 5b3739084801f..c0d2828094695 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -16,7 +16,7 @@ use hair::cx::to_ref::ToRef; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; use rustc::mir::interpret::{GlobalId, Value, PrimVal}; -use rustc::ty::{self, AdtKind, VariantDef, Ty}; +use rustc::ty::{self, AdtKind, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; @@ -420,12 +420,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty::TyAdt(adt, substs) => { match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { - let field_refs = field_refs(&adt.variants[0], fields); ExprKind::Adt { adt_def: adt, variant_index: 0, substs, - fields: field_refs, + fields: field_refs(cx, fields), base: base.as_ref().map(|base| { FruInfo { base: base.to_ref(), @@ -446,12 +445,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, assert!(base.is_none()); let index = adt.variant_index_with_id(variant_id); - let field_refs = field_refs(&adt.variants[index], fields); ExprKind::Adt { adt_def: adt, variant_index: index, substs, - fields: field_refs, + fields: field_refs(cx, fields), base: None, } } @@ -581,24 +579,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, body: block::to_expr_ref(cx, body), } } - hir::ExprField(ref source, name) => { - let index = match cx.tables().expr_ty_adjusted(source).sty { - ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node), - ref ty => span_bug!(expr.span, "field of non-ADT: {:?}", ty), - }; - let index = - index.unwrap_or_else(|| { - span_bug!(expr.span, "no index found for field `{}`", name.node) - }); - ExprKind::Field { - lhs: source.to_ref(), - name: Field::new(index), - } - } - hir::ExprTupField(ref source, index) => { + hir::ExprField(ref source, ..) => { ExprKind::Field { lhs: source.to_ref(), - name: Field::new(index.node as usize), + name: Field::new(cx.tcx.field_index(expr.id, cx.tables)), } } hir::ExprCast(ref source, _) => { @@ -999,13 +983,13 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } /// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef. -fn field_refs<'tcx>(variant: &'tcx VariantDef, - fields: &'tcx [hir::Field]) - -> Vec> { +fn field_refs<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, + fields: &'tcx [hir::Field]) + -> Vec> { fields.iter() .map(|field| { FieldExprRef { - name: Field::new(variant.index_of_field_named(field.name.node).unwrap()), + name: Field::new(cx.tcx.field_index(field.id, cx.tables)), expr: field.expr.to_ref(), } }) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index c3f41e8ac4827..8d2b73d6ba033 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -528,28 +528,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatKind::Struct(ref qpath, ref fields, _) => { let def = self.tables.qpath_def(qpath, pat.hir_id); - let adt_def = match ty.sty { - ty::TyAdt(adt_def, _) => adt_def, - _ => { - span_bug!( - pat.span, - "struct pattern not applied to an ADT"); - } - }; - let variant_def = adt_def.variant_of_def(def); - let subpatterns = fields.iter() .map(|field| { - let index = variant_def.index_of_field_named(field.node.name); - let index = index.unwrap_or_else(|| { - span_bug!( - pat.span, - "no field with name {:?}", - field.node.name); - }); FieldPattern { - field: Field::new(index), + field: Field::new(self.tcx.field_index(field.node.id, + self.tables)), pattern: self.lower_pattern(&field.node.pat), } }) diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 76cbc67096988..c5d2f0041a0f2 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -407,7 +407,6 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node hir::ExprBlock(_) | hir::ExprIndex(..) | hir::ExprField(..) | - hir::ExprTupField(..) | hir::ExprArray(_) | hir::ExprType(..) | hir::ExprTup(..) => {} diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index ef710ff7a7e4b..ee08e6223903e 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -568,8 +568,10 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { // If the expression uses FRU we need to make sure all the unmentioned fields // are checked for privacy (RFC 736). Rather than computing the set of // unmentioned fields, just check them all. - for variant_field in &variant.fields { - let field = fields.iter().find(|f| f.name.node == variant_field.name); + for (vf_index, variant_field) in variant.fields.iter().enumerate() { + let field = fields.iter().find(|f| { + self.tcx.field_index(f.id, self.tables) == vf_index + }); let (use_ctxt, span) = match field { Some(field) => (field.name.node.to_ident().span, field.span), None => (base.span, base.span), @@ -579,8 +581,8 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { } else { for field in fields { let use_ctxt = field.name.node.to_ident().span; - let field_def = variant.field_named(field.name.node); - self.check_field(use_ctxt, field.span, adt, field_def); + let index = self.tcx.field_index(field.id, self.tables); + self.check_field(use_ctxt, field.span, adt, &variant.fields[index]); } } } @@ -598,8 +600,8 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { let variant = adt.variant_of_def(def); for field in fields { let use_ctxt = field.node.name.to_ident().span; - let field_def = variant.field_named(field.node.name); - self.check_field(use_ctxt, field.span, adt, field_def); + let index = self.tcx.field_index(field.node.id, self.tables); + self.check_field(use_ctxt, field.span, adt, &variant.fields[index]); } } _ => {} diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 607701b056bab..abaa02a856e9c 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -25,7 +25,6 @@ use rustc::hir::def::Def as HirDef; use rustc::hir::def_id::DefId; -use rustc::hir::map::Node; use rustc::ty::{self, TyCtxt}; use rustc_data_structures::fx::FxHashSet; @@ -1006,20 +1005,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { }; let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id)); - for &Spanned { - node: ref field, - span, - } in fields - { + for &Spanned { node: ref field, span } in fields { let sub_span = self.span.span_for_first_ident(span); - if let Some(f) = variant.find_field_named(field.ident.name) { + if let Some(index) = self.tcx.find_field_index(field.ident, variant) { if !self.span.filter_generated(sub_span, span) { let span = self.span_from_span(sub_span.expect("No span fund for var ref")); self.dumper.dump_ref(Ref { kind: RefKind::Variable, span, - ref_id: ::id_from_def_id(f.did), + ref_id: ::id_from_def_id(variant.fields[index].did), }); } } @@ -1638,52 +1633,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc } } } - ast::ExprKind::TupField(ref sub_ex, idx) => { - self.visit_expr(&sub_ex); - - let hir_node = match self.save_ctxt.tcx.hir.find(sub_ex.id) { - Some(Node::NodeExpr(expr)) => expr, - _ => { - debug!( - "Missing or weird node for sub-expression {} in {:?}", - sub_ex.id, - ex - ); - return; - } - }; - let ty = match self.save_ctxt.tables.expr_ty_adjusted_opt(&hir_node) { - Some(ty) => &ty.sty, - None => { - visit::walk_expr(self, ex); - return; - } - }; - match *ty { - ty::TyAdt(def, _) => { - let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); - if !self.span.filter_generated(sub_span, ex.span) { - let span = - self.span_from_span(sub_span.expect("No span found for var ref")); - if let Some(field) = def.non_enum_variant().fields.get(idx.node) { - let ref_id = ::id_from_def_id(field.did); - self.dumper.dump_ref(Ref { - kind: RefKind::Variable, - span, - ref_id, - }); - } else { - return; - } - } - } - ty::TyTuple(..) => {} - _ => { - debug!("Expected struct or tuple type, found {:?}", ty); - return; - } - } - } ast::ExprKind::Closure(_, _, ref decl, ref body, _fn_decl_span) => { let mut id = String::from("$"); id.push_str(&ex.id.to_string()); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index fefedd4e1c819..ca19ed0df67d1 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -553,16 +553,18 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }; match self.tables.expr_ty_adjusted(&hir_node).sty { ty::TyAdt(def, _) if !def.is_enum() => { - let f = def.non_enum_variant().field_named(ident.name); + let variant = &def.non_enum_variant(); + let index = self.tcx.find_field_index(ident, variant).unwrap(); let sub_span = self.span_utils.span_for_last_ident(expr.span); filter!(self.span_utils, sub_span, expr.span, None); let span = self.span_from_span(sub_span.unwrap()); return Some(Data::RefData(Ref { kind: RefKind::Variable, span, - ref_id: id_from_def_id(f.did), + ref_id: id_from_def_id(variant.fields[index].did), })); } + ty::TyTuple(..) => None, _ => { debug!("Expected struct or union type, found {:?}", ty); None @@ -816,7 +818,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { field_ref: &ast::Field, variant: &ty::VariantDef, ) -> Option { - let f = variant.find_field_named(field_ref.ident.name)?; + let index = self.tcx.find_field_index(field_ref.ident, variant).unwrap(); // We don't really need a sub-span here, but no harm done let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span); filter!(self.span_utils, sub_span, field_ref.ident.span, None); @@ -824,7 +826,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(Ref { kind: RefKind::Variable, span, - ref_id: id_from_def_id(f.did), + ref_id: id_from_def_id(variant.fields[index].did), }) } diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index d5a58c08cbe5a..4d93e81a78fa1 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -202,10 +202,6 @@ impl<'a> SpanUtils<'a> { self.sub_span_after(span, |t| t.is_keyword(keyword)) } - pub fn sub_span_after_token(&self, span: Span, tok: Token) -> Option { - self.sub_span_after(span, |t| t == tok) - } - fn sub_span_after bool>(&self, span: Span, f: F) -> Option { let mut toks = self.retokenise_span(span); loop { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ae373fbad2246..7b4dc60409b12 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -860,7 +860,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); // Index the struct fields' types. let field_map = variant.fields .iter() - .map(|field| (field.name, field)) + .enumerate() + .map(|(i, field)| (field.name.to_ident(), (i, field))) .collect::>(); // Keep track of which fields have already appeared in the pattern. @@ -869,7 +870,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let mut inexistent_fields = vec![]; // Typecheck each field. for &Spanned { node: ref field, span } in fields { - let field_ty = match used_fields.entry(field.name) { + let ident = tcx.adjust(field.name, variant.did, self.body_id).0; + let field_ty = match used_fields.entry(ident) { Occupied(occupied) => { struct_span_err!(tcx.sess, span, E0025, "field `{}` bound multiple times \ @@ -883,10 +885,10 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } Vacant(vacant) => { vacant.insert(span); - field_map.get(&field.name) - .map(|f| { + field_map.get(&ident) + .map(|(i, f)| { + self.write_field_index(field.id, *i); self.tcx.check_stability(f.did, Some(pat_id), span); - self.field_ty(span, f, substs) }) .unwrap_or_else(|| { @@ -958,8 +960,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } else if !etc { let unmentioned_fields = variant.fields .iter() - .map(|field| field.name) - .filter(|field| !used_fields.contains_key(&field)) + .map(|field| field.name.to_ident()) + .filter(|ident| !used_fields.contains_key(&ident)) .collect::>(); if unmentioned_fields.len() > 0 { let field_names = if unmentioned_fields.len() == 1 { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 3705c53a76fa0..7569bdccd5a10 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -433,7 +433,6 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let last = exprs[exprs.len() - 1]; match last.node { hir::ExprField(ref expr, _) | - hir::ExprTupField(ref expr, _) | hir::ExprIndex(ref expr, _) | hir::ExprUnary(hir::UnDeref, ref expr) => exprs.push(&expr), _ => break, diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 2dbc590bbf727..d8907866467ba 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -304,8 +304,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for (ty, _) in self.autoderef(span, rcvr_ty) { match ty.sty { ty::TyAdt(def, substs) if !def.is_enum() => { - if let Some(field) = def.non_enum_variant() - .find_field_named(item_name) { + let variant = &def.non_enum_variant(); + if let Some(index) = + self.tcx.find_field_index(item_name.to_ident(), variant) { + let field = &variant.fields[index]; let snippet = tcx.sess.codemap().span_to_snippet(expr.span); let expr_string = match snippet { Ok(expr_string) => expr_string, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index da0b616b17373..ca35153d571db 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -85,7 +85,7 @@ use self::method::MethodCallee; use self::TupleArgumentsFlag::*; use astconv::AstConv; -use hir::def::{Def, CtorKind}; +use hir::def::Def; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use std::slice; use namespace::Namespace; @@ -121,7 +121,7 @@ use std::ops::{self, Deref}; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::codemap::{self, original_sp, Spanned}; +use syntax::codemap::{original_sp, Spanned}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; use syntax::symbol::{Symbol, InternedString, keywords}; @@ -1938,6 +1938,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + pub fn write_field_index(&self, node_id: ast::NodeId, index: usize) { + let hir_id = self.tcx.hir.node_to_hir_id(node_id); + self.tables.borrow_mut().field_indices_mut().insert(hir_id, index); + } + // The NodeId and the ItemLocalId must identify the same item. We just pass // both of them for consistency checking. pub fn write_method_call(&self, @@ -2266,7 +2271,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprUnary(hir::UnDeref, _) | hir::ExprField(..) | - hir::ExprTupField(..) | hir::ExprIndex(..) => { true } @@ -3070,20 +3074,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let (ident, def_scope) = self.tcx.adjust(field.node, base_def.did, self.body_id); let fields = &base_def.non_enum_variant().fields; - if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) { + if let Some(index) = fields.iter().position(|f| f.name.to_ident() == ident) { + let field = &fields[index]; let field_ty = self.field_ty(expr.span, field, substs); if field.vis.is_accessible_from(def_scope, self.tcx) { let adjustments = autoderef.adjust_steps(needs); self.apply_adjustments(base, adjustments); autoderef.finalize(); + self.write_field_index(expr.id, index); self.tcx.check_stability(field.did, Some(expr.id), expr.span); - return field_ty; } private_candidate = Some((base_def.did, field_ty)); } } + ty::TyTuple(ref tys) => { + let fstr = field.node.as_str(); + if let Ok(index) = fstr.parse::() { + if fstr == index.to_string() { + if let Some(field_ty) = tys.get(index) { + let adjustments = autoderef.adjust_steps(needs); + self.apply_adjustments(base, adjustments); + autoderef.finalize(); + + self.write_field_index(expr.id, index); + return field_ty; + } + } + } + } _ => {} } } @@ -3189,78 +3209,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { display } - // Check tuple index expressions - fn check_tup_field(&self, - expr: &'gcx hir::Expr, - needs: Needs, - base: &'gcx hir::Expr, - idx: codemap::Spanned) -> Ty<'tcx> { - let expr_t = self.check_expr_with_needs(base, needs); - let expr_t = self.structurally_resolved_type(expr.span, - expr_t); - let mut private_candidate = None; - let mut tuple_like = false; - let mut autoderef = self.autoderef(expr.span, expr_t); - while let Some((base_t, _)) = autoderef.next() { - let field = match base_t.sty { - ty::TyAdt(base_def, substs) if base_def.is_struct() => { - tuple_like = base_def.non_enum_variant().ctor_kind == CtorKind::Fn; - if !tuple_like { continue } - - debug!("tuple struct named {:?}", base_t); - let ident = - ast::Ident::new(Symbol::intern(&idx.node.to_string()), idx.span.modern()); - let (ident, def_scope) = - self.tcx.adjust_ident(ident, base_def.did, self.body_id); - let fields = &base_def.non_enum_variant().fields; - if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) { - let field_ty = self.field_ty(expr.span, field, substs); - if field.vis.is_accessible_from(def_scope, self.tcx) { - self.tcx.check_stability(field.did, Some(expr.id), expr.span); - Some(field_ty) - } else { - private_candidate = Some((base_def.did, field_ty)); - None - } - } else { - None - } - } - ty::TyTuple(ref v) => { - tuple_like = true; - v.get(idx.node).cloned() - } - _ => continue - }; - - if let Some(field_ty) = field { - let adjustments = autoderef.adjust_steps(needs); - self.apply_adjustments(base, adjustments); - autoderef.finalize(); - return field_ty; - } - } - autoderef.unambiguous_final_ty(); - - if let Some((did, field_ty)) = private_candidate { - let struct_path = self.tcx().item_path_str(did); - struct_span_err!(self.tcx().sess, expr.span, E0611, - "field `{}` of tuple-struct `{}` is private", - idx.node, struct_path).emit(); - return field_ty; - } - - if tuple_like { - type_error_struct!(self.tcx().sess, expr.span, expr_t, E0612, - "attempted out-of-bounds tuple index `{}` on type `{}`", - idx.node, expr_t).emit(); - } else { - self.no_such_field_err(expr.span, idx.node, expr_t).emit(); - } - - self.tcx().types.err - } - fn no_such_field_err(&self, span: Span, field: T, expr_t: &ty::TyS) -> DiagnosticBuilder { type_error_struct!(self.tcx().sess, span, expr_t, E0609, @@ -3343,8 +3291,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; let mut remaining_fields = FxHashMap(); - for field in &variant.fields { - remaining_fields.insert(field.name.to_ident(), field); + for (i, field) in variant.fields.iter().enumerate() { + remaining_fields.insert(field.name.to_ident(), (i, field)); } let mut seen_fields = FxHashMap(); @@ -3354,8 +3302,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Typecheck each field. for field in ast_fields { let ident = tcx.adjust(field.name.node, variant.did, self.body_id).0; - let field_type = if let Some(v_field) = remaining_fields.remove(&ident) { - seen_fields.insert(field.name.node, field.span); + let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) { + seen_fields.insert(ident, field.span); + self.write_field_index(field.id, i); // we don't look at stability attributes on // struct-like enums (yet...), but it's definitely not @@ -3367,18 +3316,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.field_ty(field.span, v_field, substs) } else { error_happened = true; - if let Some(_) = variant.find_field_named(field.name.node) { + if let Some(prev_span) = seen_fields.get(&ident) { let mut err = struct_span_err!(self.tcx.sess, field.name.span, E0062, "field `{}` specified more than once", - field.name.node); + ident); err.span_label(field.name.span, "used more than once"); - - if let Some(prev_span) = seen_fields.get(&field.name.node) { - err.span_label(*prev_span, format!("first use of `{}`", field.name.node)); - } + err.span_label(*prev_span, format!("first use of `{}`", ident)); err.emit(); } else { @@ -4121,9 +4067,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprField(ref base, ref field) => { self.check_field(expr, needs, &base, field) } - hir::ExprTupField(ref base, idx) => { - self.check_tup_field(expr, needs, &base, idx) - } hir::ExprIndex(ref base, ref idx) => { let base_t = self.check_expr_with_needs(&base, needs); let idx_t = self.check_expr(&idx); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index bbd04e0b19ae1..6e0d7dd850877 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -226,13 +226,24 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { self.visit_node_id(e.span, e.hir_id); - if let hir::ExprClosure(_, _, body, _, _) = e.node { - let body = self.fcx.tcx.hir.body(body); - for arg in &body.arguments { - self.visit_node_id(e.span, arg.hir_id); - } + match e.node { + hir::ExprClosure(_, _, body, _, _) => { + let body = self.fcx.tcx.hir.body(body); + for arg in &body.arguments { + self.visit_node_id(e.span, arg.hir_id); + } - self.visit_body(body); + self.visit_body(body); + } + hir::ExprStruct(_, ref fields, _) => { + for field in fields { + self.visit_field_id(field.id); + } + } + hir::ExprField(..) => { + self.visit_field_id(e.id); + } + _ => {} } intravisit::walk_expr(self, e); @@ -254,6 +265,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { .expect("missing binding mode"); self.tables.pat_binding_modes_mut().insert(p.hir_id, bm); } + hir::PatKind::Struct(_, ref fields, _) => { + for field in fields { + self.visit_field_id(field.node.id); + } + } _ => {} }; @@ -384,6 +400,13 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } + fn visit_field_id(&mut self, node_id: ast::NodeId) { + let hir_id = self.tcx().hir.node_to_hir_id(node_id); + if let Some(index) = self.fcx.tables.borrow_mut().field_indices_mut().remove(hir_id) { + self.tables.field_indices_mut().insert(hir_id, index); + } + } + fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) { // Export associated path extensions and method resultions. if let Some(def) = self.fcx diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a4f820d1fdcf9..640e648886278 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -513,11 +513,11 @@ fn convert_struct_variant<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, discr: ty::VariantDiscr, def: &hir::VariantData) -> ty::VariantDef { - let mut seen_fields: FxHashMap = FxHashMap(); + let mut seen_fields: FxHashMap = FxHashMap(); let node_id = tcx.hir.as_local_node_id(did).unwrap(); let fields = def.fields().iter().map(|f| { let fid = tcx.hir.local_def_id(f.id); - let dup_span = seen_fields.get(&f.name).cloned(); + let dup_span = seen_fields.get(&f.name.to_ident()).cloned(); if let Some(prev_span) = dup_span { struct_span_err!(tcx.sess, f.span, E0124, "field `{}` is already declared", @@ -526,7 +526,7 @@ fn convert_struct_variant<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .span_label(prev_span, format!("`{}` first declared here", f.name)) .emit(); } else { - seen_fields.insert(f.name, f.span); + seen_fields.insert(f.name.to_ident(), f.span); } ty::FieldDef { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 5a53c008f6c31..946fbfd82a48a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4138,86 +4138,6 @@ https://doc.rust-lang.org/book/first-edition/primitive-types.html https://doc.rust-lang.org/book/first-edition/structs.html "##, -E0611: r##" -Attempted to access a private field on a tuple-struct. - -Erroneous code example: - -```compile_fail,E0611 -mod some_module { - pub struct Foo(u32); - - impl Foo { - pub fn new() -> Foo { Foo(0) } - } -} - -let y = some_module::Foo::new(); -println!("{}", y.0); // error: field `0` of tuple-struct `some_module::Foo` - // is private -``` - -Since the field is private, you have two solutions: - -1) Make the field public: - -``` -mod some_module { - pub struct Foo(pub u32); // The field is now public. - - impl Foo { - pub fn new() -> Foo { Foo(0) } - } -} - -let y = some_module::Foo::new(); -println!("{}", y.0); // So we can access it directly. -``` - -2) Add a getter function to keep the field private but allow for accessing its -value: - -``` -mod some_module { - pub struct Foo(u32); - - impl Foo { - pub fn new() -> Foo { Foo(0) } - - // We add the getter function. - pub fn get(&self) -> &u32 { &self.0 } - } -} - -let y = some_module::Foo::new(); -println!("{}", y.get()); // So we can get the value through the function. -``` -"##, - -E0612: r##" -Attempted out-of-bounds tuple index. - -Erroneous code example: - -```compile_fail,E0612 -struct Foo(u32); - -let y = Foo(0); -println!("{}", y.1); // error: attempted out-of-bounds tuple index `1` - // on type `Foo` -``` - -If a tuple/tuple-struct type has n fields, you can only try to access these n -fields from 0 to (n - 1). So in this case, you can only index `0`. Example: - -``` -struct Foo(u32); - -let y = Foo(0); -println!("{}", y.0); // ok! -``` -"##, - E0614: r##" Attempted to dereference a variable which cannot be dereferenced. @@ -4839,6 +4759,8 @@ register_diagnostics! { E0587, // type has conflicting packed and align representation hints E0588, // packed type cannot transitively contain a `[repr(align)]` type E0592, // duplicate definitions with name `{}` +// E0611, // merged into E0616 +// E0612, // merged into E0609 // E0613, // Removed (merged with E0609) E0640, // infer outlives E0627, // yield statement outside of generator literal diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e7900af7f121d..91c9a1524e144 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1018,7 +1018,6 @@ impl Expr { ExprKind::Assign(..) => ExprPrecedence::Assign, ExprKind::AssignOp(..) => ExprPrecedence::AssignOp, ExprKind::Field(..) => ExprPrecedence::Field, - ExprKind::TupField(..) => ExprPrecedence::TupField, ExprKind::Index(..) => ExprPrecedence::Index, ExprKind::Range(..) => ExprPrecedence::Range, ExprKind::Path(..) => ExprPrecedence::Path, @@ -1133,12 +1132,8 @@ pub enum ExprKind { /// /// For example, `a += 1`. AssignOp(BinOp, P, P), - /// Access of a named struct field (`obj.foo`) + /// Access of a named (`obj.foo`) or unnamed (`obj.0`) struct field Field(P, Ident), - /// Access of an unnamed field of a struct or tuple-struct - /// - /// For example, `foo.0`. - TupField(P, Spanned), /// An indexing operation (`foo[2]`) Index(P, P), /// A range (`1..2`, `1..`, `..2`, `1...2`, `1...`, `...2`) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 062f3ce112752..36244f0a3c438 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -636,8 +636,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(sp, ast::ExprKind::Field(expr, ident.with_span_pos(sp))) } fn expr_tup_field_access(&self, sp: Span, expr: P, idx: usize) -> P { - let id = Spanned { node: idx, span: sp }; - self.expr(sp, ast::ExprKind::TupField(expr, id)) + let ident = Ident::from_str(&idx.to_string()).with_span_pos(sp); + self.expr(sp, ast::ExprKind::Field(expr, ident)) } fn expr_addr_of(&self, sp: Span, e: P) -> P { self.expr(sp, ast::ExprKind::AddrOf(ast::Mutability::Immutable, e)) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index ba6703b9c7440..a0cd831a9ba08 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1267,11 +1267,6 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Field(el, ident) => { ExprKind::Field(folder.fold_expr(el), folder.fold_ident(ident)) } - ExprKind::TupField(el, index) => { - ExprKind::TupField(folder.fold_expr(el), - respan(folder.new_span(index.span), - folder.fold_usize(index.node))) - } ExprKind::Index(el, er) => { ExprKind::Index(folder.fold_expr(el), folder.fold_expr(er)) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 027b24cbbdcd6..a7a9ce745122c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2144,10 +2144,6 @@ impl<'a> Parser<'a> { } } - pub fn mk_tup_field(&mut self, expr: P, idx: codemap::Spanned) -> ast::ExprKind { - ExprKind::TupField(expr, idx) - } - pub fn mk_assign_op(&mut self, binop: ast::BinOp, lhs: P, rhs: P) -> ast::ExprKind { ExprKind::AssignOp(binop, lhs, rhs) @@ -2605,35 +2601,11 @@ impl<'a> Parser<'a> { token::Ident(..) => { e = self.parse_dot_suffix(e, lo)?; } - token::Literal(token::Integer(index_ident), suf) => { - let sp = self.span; - - // A tuple index may not have a suffix - self.expect_no_suffix(sp, "tuple index", suf); - - let idx_span = self.span; + token::Literal(token::Integer(name), _) => { + let span = self.span; self.bump(); - - let invalid_msg = "invalid tuple or struct index"; - - let index = index_ident.as_str().parse::().ok(); - match index { - Some(n) => { - if n.to_string() != index_ident.as_str() { - let mut err = self.struct_span_err(self.prev_span, invalid_msg); - err.span_suggestion(self.prev_span, - "try simplifying the index", - n.to_string()); - err.emit(); - } - let field = self.mk_tup_field(e, respan(idx_span, n)); - e = self.mk_expr(lo.to(idx_span), field, ThinVec::new()); - } - None => { - let prev_span = self.prev_span; - self.span_err(prev_span, invalid_msg); - } - } + let field = ExprKind::Field(e, Ident::new(name, span)); + e = self.mk_expr(lo.to(span), field, ThinVec::new()); } token::Literal(token::Float(n), _suf) => { self.bump(); @@ -7058,7 +7030,7 @@ impl<'a> Parser<'a> { match self.token { token::Ident(ident, false) if ident.name == keywords::Underscore.name() => { self.bump(); // `_` - Ok(Some(Ident { name: ident.name.gensymed(), ..ident })) + Ok(Some(Ident::new(ident.name.gensymed(), ident.span))) } _ => self.parse_ident().map(Some), } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8168db1905876..3741850b8a974 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1966,8 +1966,7 @@ impl<'a> State<'a> { args: &[P]) -> io::Result<()> { let prec = match func.node { - ast::ExprKind::Field(..) | - ast::ExprKind::TupField(..) => parser::PREC_FORCE_PAREN, + ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, _ => parser::PREC_POSTFIX, }; @@ -2203,11 +2202,6 @@ impl<'a> State<'a> { self.s.word(".")?; self.print_ident(ident)?; } - ast::ExprKind::TupField(ref expr, id) => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX)?; - self.s.word(".")?; - self.print_usize(id.node)?; - } ast::ExprKind::Index(ref expr, ref index) => { self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX)?; self.s.word("[")?; diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 4770273e8c4a7..524f9f127f57b 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -251,7 +251,6 @@ pub enum ExprPrecedence { Call, MethodCall, Field, - TupField, Index, Try, InlineAsm, @@ -320,7 +319,6 @@ impl ExprPrecedence { ExprPrecedence::Call | ExprPrecedence::MethodCall | ExprPrecedence::Field | - ExprPrecedence::TupField | ExprPrecedence::Index | ExprPrecedence::Try | ExprPrecedence::InlineAsm | @@ -365,7 +363,6 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { ast::ExprKind::Cast(ref x, _) | ast::ExprKind::Type(ref x, _) | ast::ExprKind::Field(ref x, _) | - ast::ExprKind::TupField(ref x, _) | ast::ExprKind::Index(ref x, _) => { // &X { y: 1 }, X { y: 1 }.y contains_exterior_struct_lit(&x) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index fdb3e2c5f31db..8743840e44393 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -749,9 +749,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); visitor.visit_ident(ident); } - ExprKind::TupField(ref subexpression, _) => { - visitor.visit_expr(subexpression); - } ExprKind::Index(ref main_expression, ref index_expression) => { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) diff --git a/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs index a214e3c126e8d..eec7df84c82f7 100644 --- a/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs +++ b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs @@ -36,7 +36,7 @@ fn main() { let mut line1 = Line::default(); let _moved = line1.origin; - let _ = line1.origin.x + 1; //[ast]~ ERROR use of collaterally moved value: `line1.origin.x` + let _ = line1.origin.x + 1; //[ast]~ ERROR use of moved value: `line1.origin.x` //[mir]~^ [E0382] let mut line2 = Line::default(); diff --git a/src/test/compile-fail/issue-19244-1.rs b/src/test/compile-fail/issue-19244-1.rs index 0fa1a15477209..df34aab4b8f66 100644 --- a/src/test/compile-fail/issue-19244-1.rs +++ b/src/test/compile-fail/issue-19244-1.rs @@ -12,5 +12,5 @@ const TUP: (usize,) = (42,); fn main() { let a: [isize; TUP.1]; - //~^ ERROR attempted out-of-bounds tuple index + //~^ ERROR no field `1` on type `(usize,)` } diff --git a/src/test/compile-fail/struct-field-privacy.rs b/src/test/compile-fail/struct-field-privacy.rs index 5b2e04e25a93d..f487ef62aa435 100644 --- a/src/test/compile-fail/struct-field-privacy.rs +++ b/src/test/compile-fail/struct-field-privacy.rs @@ -42,7 +42,7 @@ fn test(a: A, b: inner::A, c: inner::B, d: xc::A, e: xc::B, z: inner::Z) { e.b; //~ ERROR: field `b` of struct `xc::B` is private z.0; - z.1; //~ ERROR: field `1` of tuple-struct `inner::Z` is private + z.1; //~ ERROR: field `1` of struct `inner::Z` is private } fn main() {} diff --git a/src/test/compile-fail/tuple-index-out-of-bounds.rs b/src/test/compile-fail/tuple-index-out-of-bounds.rs index 4597cf3d350c4..35b843676b4f1 100644 --- a/src/test/compile-fail/tuple-index-out-of-bounds.rs +++ b/src/test/compile-fail/tuple-index-out-of-bounds.rs @@ -15,10 +15,10 @@ fn main() { origin.0; origin.1; origin.2; - //~^ ERROR attempted out-of-bounds tuple index `2` on type `Point` + //~^ ERROR no field `2` on type `Point` let tuple = (0, 0); tuple.0; tuple.1; tuple.2; - //~^ ERROR attempted out-of-bounds tuple index `2` on type `({integer}, {integer})` + //~^ ERROR no field `2` on type `({integer}, {integer})` } diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index 83425a72f4598..9c939d0d2fbad 100644 --- a/src/test/mir-opt/end_region_cyclic.rs +++ b/src/test/mir-opt/end_region_cyclic.rs @@ -40,29 +40,29 @@ fn query() -> bool { true } // END RUST SOURCE // START rustc.main.SimplifyCfg-qualify-consts.after.mir -// fn main() -> () { +// fn main() -> (){ // let mut _0: (); // scope 1 { -// let _2: S<'35_0rs>; +// let _2: S<'36_0rs>; +// } +// scope 2 { // } -// ... // let mut _1: (); -// let mut _3: std::cell::Cell>>; -// let mut _4: std::option::Option<&'35_0rs S<'35_0rs>>; +// let mut _3: std::cell::Cell>>; +// let mut _4: std::option::Option<&'36_0rs S<'36_0rs>>; // let mut _5: (); -// let mut _6: &'16s std::cell::Cell>>; -// let mut _7: std::option::Option<&'35_0rs S<'35_0rs>>; -// let mut _8: &'35_0rs S<'35_0rs>; -// let mut _9: &'35_0rs S<'35_0rs>; +// let mut _6: &'17s std::cell::Cell>>; +// let mut _7: std::option::Option<&'36_0rs S<'36_0rs>>; +// let mut _8: &'36_0rs S<'36_0rs>; +// let mut _9: &'36_0rs S<'36_0rs>; // let mut _10: (); // let mut _11: bool; // let mut _12: !; // let mut _13: (); -// let mut _14: &'33s std::cell::Cell>>; -// let mut _15: std::option::Option<&'35_0rs S<'35_0rs>>; -// let mut _16: &'35_0rs S<'35_0rs>; -// let mut _17: &'35_0rs S<'35_0rs>; -// +// let mut _14: &'34s std::cell::Cell>>; +// let mut _15: std::option::Option<&'36_0rs S<'36_0rs>>; +// let mut _16: &'36_0rs S<'36_0rs>; +// let mut _17: &'36_0rs S<'36_0rs>; // bb0: { // goto -> bb1; // } @@ -73,7 +73,7 @@ fn query() -> bool { true } // StorageLive(_2); // StorageLive(_3); // StorageLive(_4); -// _4 = std::option::Option<&'35_0rs S<'35_0rs>>::None; +// _4 = std::option::Option<&'36_0rs S<'36_0rs>>::None; // _3 = const >::new(move _4) -> [return: bb4, unwind: bb3]; // } // bb3: { @@ -81,21 +81,21 @@ fn query() -> bool { true } // } // bb4: { // StorageDead(_4); -// _2 = S<'35_0rs> { r: move _3 }; +// _2 = S<'36_0rs> { r: move _3 }; // StorageDead(_3); // StorageLive(_6); -// _6 = &'16s (_2.0: std::cell::Cell>>); +// _6 = &'17s (_2.0: std::cell::Cell>>); // StorageLive(_7); // StorageLive(_8); // StorageLive(_9); -// _9 = &'35_0rs _2; -// _8 = &'35_0rs (*_9); -// _7 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _8,); +// _9 = &'36_0rs _2; +// _8 = &'36_0rs (*_9); +// _7 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _8,); // StorageDead(_8); // _5 = const >::set(move _6, move _7) -> [return: bb5, unwind: bb3]; // } // bb5: { -// EndRegion('16s); +// EndRegion('17s); // StorageDead(_7); // StorageDead(_6); // StorageDead(_9); @@ -108,7 +108,7 @@ fn query() -> bool { true } // bb7: { // _0 = (); // StorageDead(_11); -// EndRegion('35_0rs); +// EndRegion('36_0rs); // StorageDead(_2); // return; // } @@ -116,23 +116,23 @@ fn query() -> bool { true } // _10 = (); // StorageDead(_11); // StorageLive(_14); -// _14 = &'33s (_2.0: std::cell::Cell>>); +// _14 = &'34s (_2.0: std::cell::Cell>>); // StorageLive(_15); // StorageLive(_16); // StorageLive(_17); -// _17 = &'35_0rs _2; -// _16 = &'35_0rs (*_17); -// _15 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _16,); +// _17 = &'36_0rs _2; +// _16 = &'36_0rs (*_17); +// _15 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _16,); // StorageDead(_16); // _13 = const >::set(move _14, move _15) -> [return: bb9, unwind: bb3]; // } // bb9: { -// EndRegion('33s); +// EndRegion('34s); // StorageDead(_15); // StorageDead(_14); // StorageDead(_17); // _1 = (); -// EndRegion('35_0rs); +// EndRegion('36_0rs); // StorageDead(_2); // goto -> bb1; // } diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs index 80e75fcee8ac4..79645bd36000a 100644 --- a/src/test/mir-opt/validate_3.rs +++ b/src/test/mir-opt/validate_3.rs @@ -29,34 +29,46 @@ fn main() { // END RUST SOURCE // START rustc.main.EraseRegions.after.mir -// fn main() -> () { -// ... +// fn main() -> (){ +// let mut _0: (); +// scope 1 { +// let _1: Test; +// scope 3 { +// let _2: &ReErased Test; +// } +// scope 4 { +// } +// } +// scope 2 { +// } +// let mut _3: (); +// let mut _4: &ReErased i32; // let mut _5: &ReErased i32; // bb0: { // StorageLive(_1); // _1 = Test { x: const 0i32 }; // StorageLive(_2); -// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 }))), [_1: Test]); +// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 }))), [_1: Test]); // _2 = &ReErased _1; -// Validate(Acquire, [(*_2): Test/ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })) (imm)]); +// Validate(Acquire, [(*_2): Test/ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 })) (imm)]); // StorageLive(_4); // StorageLive(_5); -// Validate(Suspend(ReScope(Node(ItemLocalId(17)))), [((*_2).0: i32): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })) (imm)]); +// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 })) (imm)]); // _5 = &ReErased ((*_2).0: i32); -// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(17))) (imm)]); -// Validate(Suspend(ReScope(Node(ItemLocalId(17)))), [(*_5): i32/ReScope(Node(ItemLocalId(17))) (imm)]); +// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]); +// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]); // _4 = &ReErased (*_5); -// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(17))) (imm)]); -// Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(17))) i32]); +// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(18))) (imm)]); +// Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(18))) i32]); // _3 = const foo(move _4) -> bb1; // } // bb1: { // Validate(Acquire, [_3: ()]); -// EndRegion(ReScope(Node(ItemLocalId(17)))); +// EndRegion(ReScope(Node(ItemLocalId(18)))); // StorageDead(_4); // StorageDead(_5); // _0 = (); -// EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 }))); +// EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 }))); // StorageDead(_2); // StorageDead(_1); // return; diff --git a/src/test/ui/error-codes/E0609.stderr b/src/test/ui/error-codes/E0609.stderr index 24581889ae954..dd793b29febef 100644 --- a/src/test/ui/error-codes/E0609.stderr +++ b/src/test/ui/error-codes/E0609.stderr @@ -7,10 +7,10 @@ LL | let _ = x.foo; //~ ERROR E0609 = note: available fields are: `x` error[E0609]: no field `1` on type `Bar` - --> $DIR/E0609.rs:21:5 + --> $DIR/E0609.rs:21:7 | LL | y.1; //~ ERROR E0609 - | ^^^ + | ^ unknown field error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0611.stderr b/src/test/ui/error-codes/E0611.stderr deleted file mode 100644 index c4b86e76c14e4..0000000000000 --- a/src/test/ui/error-codes/E0611.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0611]: field `0` of tuple-struct `a::Foo` is private - --> $DIR/E0611.rs:21:4 - | -LL | y.0; //~ ERROR E0611 - | ^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0611`. diff --git a/src/test/ui/error-codes/E0612.stderr b/src/test/ui/error-codes/E0612.stderr deleted file mode 100644 index 18013697a8338..0000000000000 --- a/src/test/ui/error-codes/E0612.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0612]: attempted out-of-bounds tuple index `1` on type `Foo` - --> $DIR/E0612.rs:15:4 - | -LL | y.1; //~ ERROR E0612 - | ^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0612`. diff --git a/src/test/ui/error-codes/E0611.rs b/src/test/ui/error-codes/ex-E0611.rs similarity index 91% rename from src/test/ui/error-codes/E0611.rs rename to src/test/ui/error-codes/ex-E0611.rs index 1e392d194b1d8..4e580242e641e 100644 --- a/src/test/ui/error-codes/E0611.rs +++ b/src/test/ui/error-codes/ex-E0611.rs @@ -18,5 +18,5 @@ mod a { fn main() { let y = a::Foo::new(); - y.0; //~ ERROR E0611 + y.0; //~ ERROR field `0` of struct `a::Foo` is private } diff --git a/src/test/ui/error-codes/ex-E0611.stderr b/src/test/ui/error-codes/ex-E0611.stderr new file mode 100644 index 0000000000000..2f5066542db76 --- /dev/null +++ b/src/test/ui/error-codes/ex-E0611.stderr @@ -0,0 +1,9 @@ +error[E0616]: field `0` of struct `a::Foo` is private + --> $DIR/ex-E0611.rs:21:4 + | +LL | y.0; //~ ERROR field `0` of struct `a::Foo` is private + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0616`. diff --git a/src/test/ui/error-codes/E0612.rs b/src/test/ui/error-codes/ex-E0612.rs similarity index 92% rename from src/test/ui/error-codes/E0612.rs rename to src/test/ui/error-codes/ex-E0612.rs index 429a8bb7eb7b2..46e26c87e5f34 100644 --- a/src/test/ui/error-codes/E0612.rs +++ b/src/test/ui/error-codes/ex-E0612.rs @@ -12,5 +12,5 @@ struct Foo(u32); fn main() { let y = Foo(0); - y.1; //~ ERROR E0612 + y.1; //~ ERROR no field `1` on type `Foo` } diff --git a/src/test/ui/error-codes/ex-E0612.stderr b/src/test/ui/error-codes/ex-E0612.stderr new file mode 100644 index 0000000000000..a07efc939ab47 --- /dev/null +++ b/src/test/ui/error-codes/ex-E0612.stderr @@ -0,0 +1,9 @@ +error[E0609]: no field `1` on type `Foo` + --> $DIR/ex-E0612.rs:15:6 + | +LL | y.1; //~ ERROR no field `1` on type `Foo` + | ^ did you mean `0`? + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/compile-fail/hygiene/assoc_item_ctxt.rs b/src/test/ui/hygiene/assoc_item_ctxt.rs similarity index 100% rename from src/test/compile-fail/hygiene/assoc_item_ctxt.rs rename to src/test/ui/hygiene/assoc_item_ctxt.rs diff --git a/src/test/ui/hygiene/assoc_item_ctxt.stderr b/src/test/ui/hygiene/assoc_item_ctxt.stderr new file mode 100644 index 0000000000000..8b410405ae5ca --- /dev/null +++ b/src/test/ui/hygiene/assoc_item_ctxt.stderr @@ -0,0 +1,25 @@ +error[E0407]: method `method` is not a member of trait `Tr` + --> $DIR/assoc_item_ctxt.rs:45:13 + | +LL | fn method() {} //~ ERROR method `method` is not a member of trait `Tr` + | ^^^^^^^^^^^^^^ not a member of trait `Tr` +... +LL | mac_trait_impl!(); + | ------------------ in this macro invocation + +error[E0046]: not all trait items implemented, missing: `method` + --> $DIR/assoc_item_ctxt.rs:44:9 + | +LL | fn method(); + | ------------ `method` from trait +... +LL | impl Tr for u8 { //~ ERROR not all trait items implemented, missing: `method` + | ^^^^^^^^^^^^^^ missing `method` in implementation +... +LL | mac_trait_impl!(); + | ------------------ in this macro invocation + +error: aborting due to 2 previous errors + +Some errors occurred: E0046, E0407. +For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/compile-fail/hygiene/assoc_ty_bindings.rs b/src/test/ui/hygiene/assoc_ty_bindings.rs similarity index 100% rename from src/test/compile-fail/hygiene/assoc_ty_bindings.rs rename to src/test/ui/hygiene/assoc_ty_bindings.rs diff --git a/src/test/ui/hygiene/assoc_ty_bindings.stderr b/src/test/ui/hygiene/assoc_ty_bindings.stderr new file mode 100644 index 0000000000000..0adf80994f7fc --- /dev/null +++ b/src/test/ui/hygiene/assoc_ty_bindings.stderr @@ -0,0 +1,8 @@ +error: compilation successful + --> $DIR/assoc_ty_bindings.rs:49:1 + | +LL | fn main() {} //~ ERROR compilation successful + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/compile-fail/hygiene/auxiliary/intercrate.rs b/src/test/ui/hygiene/auxiliary/intercrate.rs similarity index 100% rename from src/test/compile-fail/hygiene/auxiliary/intercrate.rs rename to src/test/ui/hygiene/auxiliary/intercrate.rs diff --git a/src/test/ui/hygiene/fields-definition.rs b/src/test/ui/hygiene/fields-definition.rs new file mode 100644 index 0000000000000..c92bf55a72381 --- /dev/null +++ b/src/test/ui/hygiene/fields-definition.rs @@ -0,0 +1,32 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(decl_macro)] + +macro modern($a: ident) { + struct Modern { + a: u8, + $a: u8, // OK + } +} + +macro_rules! legacy { + ($a: ident) => { + struct Legacy { + a: u8, + $a: u8, //~ ERROR field `a` is already declared + } + } +} + +modern!(a); +legacy!(a); + +fn main() {} diff --git a/src/test/ui/hygiene/fields-definition.stderr b/src/test/ui/hygiene/fields-definition.stderr new file mode 100644 index 0000000000000..73f524b7d2a7f --- /dev/null +++ b/src/test/ui/hygiene/fields-definition.stderr @@ -0,0 +1,14 @@ +error[E0124]: field `a` is already declared + --> $DIR/fields-definition.rs:24:17 + | +LL | a: u8, + | ----- `a` first declared here +LL | $a: u8, //~ ERROR field `a` is already declared + | ^^ field already declared +... +LL | legacy!(a); + | ----------- in this macro invocation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0124`. diff --git a/src/test/ui/hygiene/fields-move.rs b/src/test/ui/hygiene/fields-move.rs new file mode 100644 index 0000000000000..a6e3b2b2d8b47 --- /dev/null +++ b/src/test/ui/hygiene/fields-move.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// issue #46314 + +#![feature(decl_macro)] + +#[derive(Debug)] +struct NonCopy(String); + +struct Foo { + x: NonCopy, +} + +macro copy_modern($foo: ident) { + $foo.x +} + +macro_rules! copy_legacy { + ($foo: ident) => { + $foo.x //~ ERROR use of moved value: `foo.x` + } +} + +fn assert_two_copies(a: NonCopy, b: NonCopy) { + println!("Got two copies: {:?}, {:?}", a, b); +} + +fn main() { + let foo = Foo { x: NonCopy("foo".into()) }; + assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` +} diff --git a/src/test/ui/hygiene/fields-move.stderr b/src/test/ui/hygiene/fields-move.stderr new file mode 100644 index 0000000000000..ba9de09f9d2f1 --- /dev/null +++ b/src/test/ui/hygiene/fields-move.stderr @@ -0,0 +1,39 @@ +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:38:42 + | +LL | $foo.x + | ------ value moved here +... +LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ^^^^^ value used here after move + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:28:9 + | +LL | $foo.x + | ------ value moved here +... +LL | $foo.x //~ ERROR use of moved value: `foo.x` + | ^^^^^^ value used here after move +... +LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ----------------- in this macro invocation + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:39:42 + | +LL | $foo.x + | ------ value moved here +... +LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ^^^^^ value used here after move + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/hygiene/fields-numeric-borrowck.rs b/src/test/ui/hygiene/fields-numeric-borrowck.rs new file mode 100644 index 0000000000000..50ace39e70939 --- /dev/null +++ b/src/test/ui/hygiene/fields-numeric-borrowck.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S(u8); + +fn main() { + let mut s = S(0); + let borrow1 = &mut s.0; + let S { 0: ref mut borrow2 } = s; + //~^ ERROR cannot borrow `s.0` as mutable more than once at a time +} diff --git a/src/test/ui/hygiene/fields-numeric-borrowck.stderr b/src/test/ui/hygiene/fields-numeric-borrowck.stderr new file mode 100644 index 0000000000000..ccd898fff27b7 --- /dev/null +++ b/src/test/ui/hygiene/fields-numeric-borrowck.stderr @@ -0,0 +1,14 @@ +error[E0499]: cannot borrow `s.0` as mutable more than once at a time + --> $DIR/fields-numeric-borrowck.rs:16:16 + | +LL | let borrow1 = &mut s.0; + | --- first mutable borrow occurs here +LL | let S { 0: ref mut borrow2 } = s; + | ^^^^^^^^^^^^^^^ second mutable borrow occurs here +LL | //~^ ERROR cannot borrow `s.0` as mutable more than once at a time +LL | } + | - first borrow ends here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/compile-fail/hygiene/fields.rs b/src/test/ui/hygiene/fields.rs similarity index 100% rename from src/test/compile-fail/hygiene/fields.rs rename to src/test/ui/hygiene/fields.rs diff --git a/src/test/ui/hygiene/fields.stderr b/src/test/ui/hygiene/fields.stderr new file mode 100644 index 0000000000000..c4be1834c04f8 --- /dev/null +++ b/src/test/ui/hygiene/fields.stderr @@ -0,0 +1,38 @@ +error: type `foo::S` is private + --> $DIR/fields.rs:25:17 + | +LL | let s = S { x: 0 }; //~ ERROR type `foo::S` is private + | ^^^^^^^^^^ +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + +error: type `foo::S` is private + --> $DIR/fields.rs:26:17 + | +LL | let _ = s.x; //~ ERROR type `foo::S` is private + | ^ +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + +error: type `foo::T` is private + --> $DIR/fields.rs:28:17 + | +LL | let t = T(0); //~ ERROR type `foo::T` is private + | ^^^^ +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + +error: type `foo::T` is private + --> $DIR/fields.rs:29:17 + | +LL | let _ = t.0; //~ ERROR type `foo::T` is private + | ^ +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + +error: aborting due to 4 previous errors + diff --git a/src/test/compile-fail/for-loop-hygiene.rs b/src/test/ui/hygiene/for-loop.rs similarity index 100% rename from src/test/compile-fail/for-loop-hygiene.rs rename to src/test/ui/hygiene/for-loop.rs diff --git a/src/test/ui/hygiene/for-loop.stderr b/src/test/ui/hygiene/for-loop.stderr new file mode 100644 index 0000000000000..7e606b2358c14 --- /dev/null +++ b/src/test/ui/hygiene/for-loop.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `iter` in this scope + --> $DIR/for-loop.rs:16:9 + | +LL | iter.next(); //~ ERROR cannot find value `iter` in this scope + | ^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/compile-fail/hygiene/globs.rs b/src/test/ui/hygiene/globs.rs similarity index 100% rename from src/test/compile-fail/hygiene/globs.rs rename to src/test/ui/hygiene/globs.rs diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr new file mode 100644 index 0000000000000..d77242e135dde --- /dev/null +++ b/src/test/ui/hygiene/globs.stderr @@ -0,0 +1,49 @@ +error[E0425]: cannot find function `f` in this scope + --> $DIR/globs.rs:32:9 + | +LL | f(); //~ ERROR cannot find function `f` in this scope + | ^ not found in this scope +help: possible candidates are found in other modules, you can import them into scope + | +LL | use foo::f; + | +LL | use foo::f; + | +LL | use foo::f; + | + +error[E0425]: cannot find function `g` in this scope + --> $DIR/globs.rs:25:5 + | +LL | g(); //~ ERROR cannot find function `g` in this scope + | ^ not found in this scope +... +LL | / m! { +LL | | use bar::*; +LL | | g(); +LL | | f(); //~ ERROR cannot find function `f` in this scope +LL | | } + | |_____- in this macro invocation +help: possible candidates are found in other modules, you can import them into scope + | +LL | use bar::g; + | +LL | use foo::test2::test::g; + | +LL | use foo::test::g; + | +LL | use foo::test::g; + | + +error[E0425]: cannot find function `f` in this scope + --> $DIR/globs.rs:64:17 + | +LL | n!(f); + | ------ in this macro invocation +... +LL | f //~ ERROR cannot find function `f` in this scope + | ^ not found in this scope + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/compile-fail/hygiene/impl_items.rs b/src/test/ui/hygiene/impl_items.rs similarity index 100% rename from src/test/compile-fail/hygiene/impl_items.rs rename to src/test/ui/hygiene/impl_items.rs diff --git a/src/test/ui/hygiene/impl_items.stderr b/src/test/ui/hygiene/impl_items.stderr new file mode 100644 index 0000000000000..dbcf53554cf25 --- /dev/null +++ b/src/test/ui/hygiene/impl_items.stderr @@ -0,0 +1,11 @@ +error: type `for<'r> fn(&'r foo::S) {foo::S::f}` is private + --> $DIR/impl_items.rs:22:23 + | +LL | let _: () = S.f(); //~ ERROR type `for<'r> fn(&'r foo::S) {foo::S::f}` is private + | ^ +... +LL | foo::m!(); + | ---------- in this macro invocation + +error: aborting due to previous error + diff --git a/src/test/compile-fail/hygiene/intercrate.rs b/src/test/ui/hygiene/intercrate.rs similarity index 100% rename from src/test/compile-fail/hygiene/intercrate.rs rename to src/test/ui/hygiene/intercrate.rs diff --git a/src/test/ui/hygiene/intercrate.stderr b/src/test/ui/hygiene/intercrate.stderr new file mode 100644 index 0000000000000..ecbc6e7b1472c --- /dev/null +++ b/src/test/ui/hygiene/intercrate.stderr @@ -0,0 +1,10 @@ +error: type `fn() -> u32 {intercrate::foo::bar::f}` is private + --> $DIR/intercrate.rs:22:16 + | +LL | assert_eq!(intercrate::foo::m!(), 1); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/compile-fail/hygiene/nested_macro_privacy.rs b/src/test/ui/hygiene/nested_macro_privacy.rs similarity index 100% rename from src/test/compile-fail/hygiene/nested_macro_privacy.rs rename to src/test/ui/hygiene/nested_macro_privacy.rs diff --git a/src/test/ui/hygiene/nested_macro_privacy.stderr b/src/test/ui/hygiene/nested_macro_privacy.stderr new file mode 100644 index 0000000000000..1179065b94cd8 --- /dev/null +++ b/src/test/ui/hygiene/nested_macro_privacy.stderr @@ -0,0 +1,9 @@ +error[E0616]: field `i` of struct `foo::S` is private + --> $DIR/nested_macro_privacy.rs:25:5 + | +LL | S::default().i; //~ ERROR field `i` of struct `foo::S` is private + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0616`. diff --git a/src/test/compile-fail/hygiene/no_implicit_prelude.rs b/src/test/ui/hygiene/no_implicit_prelude.rs similarity index 100% rename from src/test/compile-fail/hygiene/no_implicit_prelude.rs rename to src/test/ui/hygiene/no_implicit_prelude.rs diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr new file mode 100644 index 0000000000000..5753d1a32f74f --- /dev/null +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -0,0 +1,30 @@ +error[E0433]: failed to resolve. Use of undeclared type or module `Vec` + --> $DIR/no_implicit_prelude.rs:21:9 + | +LL | fn f() { ::bar::m!(); } + | ------------ in this macro invocation +... +LL | Vec::new(); //~ ERROR failed to resolve + | ^^^ Use of undeclared type or module `Vec` + +error[E0601]: `main` function not found in crate `no_implicit_prelude` + | + = note: consider adding a `main` function to `$DIR/no_implicit_prelude.rs` + +error[E0599]: no method named `clone` found for type `()` in the current scope + --> $DIR/no_implicit_prelude.rs:22:12 + | +LL | fn f() { ::bar::m!(); } + | ------------ in this macro invocation +... +LL | ().clone() //~ ERROR no method named `clone` found + | ^^^^^ + | + = help: items from traits can only be used if the trait is in scope + = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + candidate #1: `use std::clone::Clone;` + +error: aborting due to 3 previous errors + +Some errors occurred: E0433, E0599, E0601. +For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/compile-fail/pattern-macro-hygiene.rs b/src/test/ui/hygiene/pattern-macro.rs similarity index 100% rename from src/test/compile-fail/pattern-macro-hygiene.rs rename to src/test/ui/hygiene/pattern-macro.rs diff --git a/src/test/ui/hygiene/pattern-macro.stderr b/src/test/ui/hygiene/pattern-macro.stderr new file mode 100644 index 0000000000000..b26084db02e96 --- /dev/null +++ b/src/test/ui/hygiene/pattern-macro.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/pattern-macro.rs:15:5 + | +LL | x + 1; //~ ERROR cannot find value `x` in this scope + | ^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/compile-fail/hygiene/privacy.rs b/src/test/ui/hygiene/privacy.rs similarity index 100% rename from src/test/compile-fail/hygiene/privacy.rs rename to src/test/ui/hygiene/privacy.rs diff --git a/src/test/ui/hygiene/privacy.stderr b/src/test/ui/hygiene/privacy.stderr new file mode 100644 index 0000000000000..808d244e9cdb6 --- /dev/null +++ b/src/test/ui/hygiene/privacy.stderr @@ -0,0 +1,9 @@ +error[E0603]: function `f` is private + --> $DIR/privacy.rs:26:9 + | +LL | foo::f() //~ ERROR `f` is private + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/compile-fail/hygiene/trait_items.rs b/src/test/ui/hygiene/trait_items.rs similarity index 100% rename from src/test/compile-fail/hygiene/trait_items.rs rename to src/test/ui/hygiene/trait_items.rs diff --git a/src/test/ui/hygiene/trait_items.stderr b/src/test/ui/hygiene/trait_items.stderr new file mode 100644 index 0000000000000..56d9c585d6f85 --- /dev/null +++ b/src/test/ui/hygiene/trait_items.stderr @@ -0,0 +1,16 @@ +error[E0599]: no method named `f` found for type `()` in the current scope + --> $DIR/trait_items.rs:27:24 + | +LL | fn f() { ::baz::m!(); } + | ------------ in this macro invocation +... +LL | pub macro m() { ().f() } //~ ERROR no method named `f` found for type `()` in the current scope + | ^ + | + = help: items from traits can only be used if the trait is in scope + = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + candidate #1: `use foo::T;` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.rs b/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.rs index e339716289c6b..c59a9bc4170bd 100644 --- a/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.rs +++ b/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.rs @@ -16,7 +16,7 @@ struct Verdict(Guilty, Option); fn main() { let justice = Verdict(true, Some(2718)); let _condemned = justice.00; - //~^ ERROR invalid tuple or struct index + //~^ ERROR no field `00` on type `Verdict` let _punishment = justice.001; - //~^ ERROR invalid tuple or struct index + //~^ ERROR no field `001` on type `Verdict` } diff --git a/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.stderr b/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.stderr index 9603ac01fefb9..4a1c9b554a931 100644 --- a/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.stderr +++ b/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.stderr @@ -1,14 +1,17 @@ -error: invalid tuple or struct index +error[E0609]: no field `00` on type `Verdict` --> $DIR/issue-47073-zero-padded-tuple-struct-indices.rs:18:30 | LL | let _condemned = justice.00; - | ^^ help: try simplifying the index: `0` + | ^^ did you mean `0`? -error: invalid tuple or struct index +error[E0609]: no field `001` on type `Verdict` --> $DIR/issue-47073-zero-padded-tuple-struct-indices.rs:20:31 | LL | let _punishment = justice.001; - | ^^^ help: try simplifying the index: `1` + | ^^^ unknown field + | + = note: available fields are: `0`, `1` error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs index 58a30e86f222b..bff64ad489210 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.rs +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.rs @@ -24,7 +24,7 @@ macro_rules! fake_field_stmt { macro_rules! fake_anon_field_stmt { () => { - (1).0 //~ ERROR no field + (1).0 //~ ERROR doesn't have fields } } @@ -42,7 +42,7 @@ macro_rules! fake_field_expr { macro_rules! fake_anon_field_expr { () => { - (1).0 //~ ERROR no field + (1).0 //~ ERROR doesn't have fields } } diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index eab6cd23748cd..cb7d422b7f3ed 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -16,11 +16,11 @@ LL | 1.fake //~ ERROR doesn't have fields LL | fake_field_stmt!(); | ------------------- in this macro invocation -error[E0609]: no field `0` on type `{integer}` - --> $DIR/macro-backtrace-invalid-internals.rs:27:11 +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/macro-backtrace-invalid-internals.rs:27:15 | -LL | (1).0 //~ ERROR no field - | ^^^^^ +LL | (1).0 //~ ERROR doesn't have fields + | ^ ... LL | fake_anon_field_stmt!(); | ------------------------ in this macro invocation @@ -56,11 +56,11 @@ LL | 1.fake //~ ERROR doesn't have fields LL | let _ = fake_field_expr!(); | ------------------ in this macro invocation -error[E0609]: no field `0` on type `{integer}` - --> $DIR/macro-backtrace-invalid-internals.rs:45:11 +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/macro-backtrace-invalid-internals.rs:45:15 | -LL | (1).0 //~ ERROR no field - | ^^^^^ +LL | (1).0 //~ ERROR doesn't have fields + | ^ ... LL | let _ = fake_anon_field_expr!(); | ----------------------- in this macro invocation @@ -80,5 +80,5 @@ LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous n error: aborting due to 8 previous errors -Some errors occurred: E0599, E0609, E0610, E0689. +Some errors occurred: E0599, E0610, E0689. For more information about an error, try `rustc --explain E0599`.