about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2018-04-01 21:48:39 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2018-04-12 23:02:09 +0300
commit44acea4d880b646caa00a7237ea1a17031dd2116 (patch)
treef109f2beda49e7972c2c6e562944c1a2c810c3d2 /src
parent6c537493d01694cc6e0a614dff12c475055aa2b4 (diff)
downloadrust-44acea4d880b646caa00a7237ea1a17031dd2116.tar.gz
rust-44acea4d880b646caa00a7237ea1a17031dd2116.zip
AST/HIR: Merge field access expressions for named and numeric fields
Diffstat (limited to 'src')
-rw-r--r--src/librustc/cfg/construct.rs1
-rw-r--r--src/librustc/hir/intravisit.rs3
-rw-r--r--src/librustc/hir/lowering.rs1
-rw-r--r--src/librustc/hir/mod.rs7
-rw-r--r--src/librustc/hir/print.rs9
-rw-r--r--src/librustc/ich/impls_hir.rs1
-rw-r--r--src/librustc/middle/dead.rs14
-rw-r--r--src/librustc/middle/expr_use_visitor.rs4
-rw-r--r--src/librustc/middle/liveness.rs9
-rw-r--r--src/librustc/middle/mem_categorization.rs68
-rw-r--r--src/librustc/middle/region.rs1
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/restrictions.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs19
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs5
-rw-r--r--src/librustc_mir/hair/cx/expr.rs7
-rw-r--r--src/librustc_passes/rvalue_promotion.rs1
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs47
-rw-r--r--src/librustc_save_analysis/lib.rs1
-rw-r--r--src/librustc_save_analysis/span_utils.rs4
-rw-r--r--src/librustc_typeck/check/method/confirm.rs1
-rw-r--r--src/librustc_typeck/check/mod.rs94
-rw-r--r--src/librustc_typeck/diagnostics.rs82
-rw-r--r--src/libsyntax/ast.rs7
-rw-r--r--src/libsyntax/ext/build.rs4
-rw-r--r--src/libsyntax/fold.rs5
-rw-r--r--src/libsyntax/parse/parser.rs37
-rw-r--r--src/libsyntax/print/pprust.rs8
-rw-r--r--src/libsyntax/util/parser.rs3
-rw-r--r--src/libsyntax/visit.rs3
-rw-r--r--src/test/compile-fail/issue-19244-1.rs2
-rw-r--r--src/test/compile-fail/struct-field-privacy.rs2
-rw-r--r--src/test/compile-fail/tuple-index-out-of-bounds.rs4
-rw-r--r--src/test/ui/error-codes/E0609.stderr4
-rw-r--r--src/test/ui/error-codes/E0611.stderr9
-rw-r--r--src/test/ui/error-codes/E0612.stderr9
-rw-r--r--src/test/ui/error-codes/ex-E0611.rs (renamed from src/test/ui/error-codes/E0611.rs)2
-rw-r--r--src/test/ui/error-codes/ex-E0611.stderr9
-rw-r--r--src/test/ui/error-codes/ex-E0612.rs (renamed from src/test/ui/error-codes/E0612.rs)2
-rw-r--r--src/test/ui/error-codes/ex-E0612.stderr9
-rw-r--r--src/test/ui/issue-47073-zero-padded-tuple-struct-indices.rs4
-rw-r--r--src/test/ui/issue-47073-zero-padded-tuple-struct-indices.stderr11
-rw-r--r--src/test/ui/macros/macro-backtrace-invalid-internals.rs4
-rw-r--r--src/test/ui/macros/macro-backtrace-invalid-internals.stderr18
43 files changed, 105 insertions, 432 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 1247db55f58..118125a19dd 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 9f51eb8c35a..0a7f0e4dc4c 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -1025,9 +1025,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 fdeb41a8770..262c307feed 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -3095,7 +3095,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)))
             }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index be8cceb6118..79b39be3eb2 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1276,7 +1276,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 +1362,8 @@ pub enum Expr_ {
     ///
     /// For example, `a += 1`.
     ExprAssignOp(BinOp, P<Expr>, P<Expr>),
-    /// Access of a named struct field (`obj.foo`)
+    /// Access of a named (`obj.foo`) or unnamed (`obj.0`) struct or tuple field
     ExprField(P<Expr>, Spanned<Name>),
-    /// Access of an unnamed field of a struct or tuple-struct
-    ///
-    /// For example, `foo.0`.
-    ExprTupField(P<Expr>, Spanned<usize>),
     /// An indexing operation (`foo[2]`)
     ExprIndex(P<Expr>, P<Expr>),
 
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index ff501f30c89..d3f2458ef87 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 38b284fd646..ec573e3d681 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -569,7 +569,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 a0cd231bb70..5800988344a 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -104,17 +104,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             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);
-            }
             ty::TyTuple(..) => {}
-            _ => span_bug!(lhs.span, "numeric field access on non-ADT"),
+            _ => span_bug!(lhs.span, "named field access on non-ADT"),
         }
     }
 
@@ -245,9 +236,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
             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::ExprStruct(_, ref fields, _) => {
                 if let ty::TypeVariants::TyAdt(ref def, _) = self.tables.expr_ty(expr).sty {
                     if def.is_union() {
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 28524678e99..fb83e563ffc 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.<n>
-                self.select_from_expr(&base);
-            }
-
             hir::ExprIndex(ref lhs, ref rhs) => {       // lhs[rhs]
                 self.select_from_expr(&lhs);
                 self.consume_expr(&rhs);
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 966353b53a9..11dc2a81885 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 5875e5e4097..c7449325f75 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,7 +80,7 @@ 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;
@@ -129,15 +128,13 @@ 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)
-}
+// FIXME: Use actual index instead of `ast::Name` with questionable hygiene
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct FieldIndex(pub ast::Name);
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub enum InteriorOffsetKind {
@@ -198,7 +195,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_name: Name) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
     {
         let adt_def = match self.ty.sty {
             ty::TyAdt(def, _) => def,
@@ -215,11 +212,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.field_named(field_name)))
     }
 
     pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
@@ -230,8 +223,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)
                         })
                     }
@@ -649,11 +642,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             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))
-          }
-
           hir::ExprIndex(ref base, _) => {
             if self.tables.is_method_call(expr) {
                 // If this is an index implemented by a method call, then it
@@ -979,14 +967,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     pub fn cat_field<N:ast_node>(&self,
                                  node: &N,
                                  base_cmt: cmt<'tcx>,
-                                 f_name: ast::Name,
+                                 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_name))),
             ty: f_ty,
             note: NoteNone
         });
@@ -994,24 +982,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         ret
     }
 
-    pub fn cat_tup_field<N:ast_node>(&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 +1262,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(Name::intern(&i.to_string())));
+                let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior);
                 self.cat_pattern_(subcmt, &subpat, op)?;
             }
           }
@@ -1332,8 +1302,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(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 +1486,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 +1521,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(name)) => write!(f, "{}", name),
             InteriorElement(..) => write!(f, "[]"),
         }
     }
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 7e1b7c08c3d..42483c83f4b 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_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
index 5cfbe49f77f..2bd40890ca3 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
@@ -108,7 +108,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
                         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));
+                                let field = InteriorKind::InteriorField(mc::FieldIndex(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 2049a146a0f..12c5fcdf13d 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(fname)))) => {
                 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(&fname.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(name)) => write!(f, "{}", name),
             InteriorElement => write!(f, "[]"),
         }
     }
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index a90dcd1072f..a69b9dc0d4f 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};
 
@@ -344,7 +343,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
                     = (&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));
+                        let field = InteriorKind::InteriorField(mc::FieldIndex(field.name));
                         if field != interior {
                             let sibling_lp_kind =
                                 LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field));
@@ -396,7 +395,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
             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));
+                        let field = InteriorKind::InteriorField(mc::FieldIndex(field.name));
                         let field_ty = if field == interior {
                             lp.ty
                         } else {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 5b373908480..efe88c6789f 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -584,6 +584,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         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),
+                ty::TyTuple(..) => name.node.as_str().parse::<usize>().ok(),
                 ref ty => span_bug!(expr.span, "field of non-ADT: {:?}", ty),
             };
             let index =
@@ -595,12 +596,6 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 name: Field::new(index),
             }
         }
-        hir::ExprTupField(ref source, index) => {
-            ExprKind::Field {
-                lhs: source.to_ref(),
-                name: Field::new(index.node as usize),
-            }
-        }
         hir::ExprCast(ref source, _) => {
             // Check to see if this cast is a "coercion cast", where the cast is actually done
             // using a coercion (or is a no-op).
diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs
index 76cbc670969..c5d2f0041a0 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_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 607701b056b..811ebe57669 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;
 
@@ -1638,52 +1637,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 fefedd4e1c8..9da692851d9 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -563,6 +563,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                             ref_id: id_from_def_id(f.did),
                         }));
                     }
+                    ty::TyTuple(..) => None,
                     _ => {
                         debug!("Expected struct or union type, found {:?}", ty);
                         None
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index d5a58c08cbe..4d93e81a78f 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<Span> {
-        self.sub_span_after(span, |t| t == tok)
-    }
-
     fn sub_span_after<F: Fn(Token) -> bool>(&self, span: Span, f: F) -> Option<Span> {
         let mut toks = self.retokenise_span(span);
         loop {
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 3705c53a76f..7569bdccd5a 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/mod.rs b/src/librustc_typeck/check/mod.rs
index da0b616b173..9d0e0191ffb 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};
@@ -2266,7 +2266,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             hir::ExprUnary(hir::UnDeref, _) |
             hir::ExprField(..) |
-            hir::ExprTupField(..) |
             hir::ExprIndex(..) => {
                 true
             }
@@ -3084,6 +3083,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         private_candidate = Some((base_def.did, field_ty));
                     }
                 }
+                ty::TyTuple(ref tys) => {
+                    let fstr = field.node.as_str();
+                    if let Ok(index) = fstr.parse::<usize>() {
+                        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();
+
+                                return field_ty;
+                            }
+                        }
+                    }
+                }
                 _ => {}
             }
         }
@@ -3189,78 +3202,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<usize>) -> 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<T: Display>(&self, span: Span, field: T, expr_t: &ty::TyS)
         -> DiagnosticBuilder {
         type_error_struct!(self.tcx().sess, span, expr_t, E0609,
@@ -4121,9 +4062,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/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 5a53c008f6c..946fbfd82a4 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 e7900af7f12..91c9a1524e1 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<Expr>, P<Expr>),
-    /// Access of a named struct field (`obj.foo`)
+    /// Access of a named (`obj.foo`) or unnamed (`obj.0`) struct field
     Field(P<Expr>, Ident),
-    /// Access of an unnamed field of a struct or tuple-struct
-    ///
-    /// For example, `foo.0`.
-    TupField(P<Expr>, Spanned<usize>),
     /// An indexing operation (`foo[2]`)
     Index(P<Expr>, P<Expr>),
     /// 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 062f3ce1127..2e1a4ee5851 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<ast::Expr>, idx: usize) -> P<ast::Expr> {
-        let id = Spanned { node: idx, span: sp };
-        self.expr(sp, ast::ExprKind::TupField(expr, id))
+        let id = Spanned { node: Ident::from_str(&idx.to_string()), span: sp };
+        self.expr(sp, ast::ExprKind::Field(expr, id))
     }
     fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::AddrOf(ast::Mutability::Immutable, e))
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index ba6703b9c74..a0cd831a9ba 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1267,11 +1267,6 @@ pub fn noop_fold_expr<T: Folder>(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 027b24cbbdc..33a602a26fc 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<Expr>, idx: codemap::Spanned<usize>) -> ast::ExprKind {
-        ExprKind::TupField(expr, idx)
-    }
-
     pub fn mk_assign_op(&mut self, binop: ast::BinOp,
                         lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind {
         ExprKind::AssignOp(binop, lhs, rhs)
@@ -2605,35 +2601,12 @@ 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::<usize>().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 ident = Ident { name, ctxt: span.ctxt() };
+                    let field = ExprKind::Field(e, respan(span, ident));
+                    e = self.mk_expr(lo.to(span), field, ThinVec::new());
                   }
                   token::Literal(token::Float(n), _suf) => {
                     self.bump();
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 8168db19058..3741850b8a9 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1966,8 +1966,7 @@ impl<'a> State<'a> {
                        args: &[P<ast::Expr>]) -> 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 4770273e8c4..524f9f127f5 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 fdb3e2c5f31..8743840e443 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/issue-19244-1.rs b/src/test/compile-fail/issue-19244-1.rs
index 0fa1a154772..df34aab4b8f 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 5b2e04e25a9..f487ef62aa4 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 4597cf3d350..35b843676b4 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/ui/error-codes/E0609.stderr b/src/test/ui/error-codes/E0609.stderr
index 24581889ae9..dd793b29feb 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 c4b86e76c14..00000000000
--- 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 18013697a83..00000000000
--- 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
index 1e392d194b1..4e580242e64 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 00000000000..2f5066542db
--- /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
index 429a8bb7eb7..46e26c87e5f 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 00000000000..a07efc939ab
--- /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/ui/issue-47073-zero-padded-tuple-struct-indices.rs b/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.rs
index e339716289c..c59a9bc4170 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<FineDollars>);
 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 9603ac01fef..4a1c9b554a9 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 58a30e86f22..bff64ad4892 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 eab6cd23748..cb7d422b7f3 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`.