diff options
| author | bors <bors@rust-lang.org> | 2018-04-13 01:43:09 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-04-13 01:43:09 +0000 |
| commit | defcfe7142fca424f7e34aa5c789239e9e9fcfe8 (patch) | |
| tree | 8b6e479ea80191563607ff243cd46699c53ce56e /src | |
| parent | c4a03283cd17c86c9bcdc3fdc76d924ab5eaff2a (diff) | |
| parent | fcf48520a0d63828190217ea59849f9098177427 (diff) | |
| download | rust-defcfe7142fca424f7e34aa5c789239e9e9fcfe8.tar.gz rust-defcfe7142fca424f7e34aa5c789239e9e9fcfe8.zip | |
Auto merge of #49718 - petrochenkov:fieldcmp, r=eddyb
Hygiene 2.0: Avoid comparing fields by name
There are two separate commits here (not counting tests):
- The first one unifies named (`obj.name`) and numeric (`obj.0`) field access expressions in AST and HIR. Before field references in these expressions are resolved it doesn't matter whether the field is named or numeric (it's just a symbol) and 99% of code is common. After field references are resolved we work with
them by index for all fields (see the second commit), so it's again not important whether the field was named or numeric (this includes MIR where all fields were already by index).
(This refactoring actually fixed some bugs in HIR-based borrow checker where borrows through names (`S {
0: ref x }`) and indices (`&s.0`) weren't considered overlapping.)
- The second commit removes all by-name field comparison and instead resolves field references to their indices once, and then uses those resolutions. (There are still a few name comparisons in save-analysis, because save-analysis is weird, but they are made correctly hygienic).
Thus we are fixing a bunch of "secondary" field hygiene bugs (in borrow checker, lints).
Fixes https://github.com/rust-lang/rust/issues/46314
Diffstat (limited to 'src')
87 files changed, 759 insertions, 676 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..be9f8b8dac5 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 fdeb41a8770..fee076acb20 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<hir::Expr>, 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 be8cceb6118..e6080fad91d 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<Name>, pub expr: P<Expr>, 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<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..4a001802eac 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -420,11 +420,23 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Pat { } impl_stable_hash_for_spanned!(hir::FieldPat); -impl_stable_hash_for!(struct hir::FieldPat { - name, - pat, - is_shorthand -}); + +impl<'a> HashStable<StableHashingContext<'a>> for hir::FieldPat { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher<W>) { + 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<StableHashingContext<'a>> for hir::Field { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher<W>) { + 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 a0cd231bb70..9ec3d2e2460 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<hir::Field>) { - 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<hir::Field>) { + 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 28524678e99..2cc5a4a8fe6 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); @@ -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 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..6f41f07dce8 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<H: Hasher>(&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<ImmutabilityBlame<'tcx>> { @@ -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<N:ast_node>(&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<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 +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 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/ty/context.rs b/src/librustc/ty/context.rs index 1e5d0753e69..76ec8c21743 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<Def>, + /// 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<usize>, + /// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in /// MIR. user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>, @@ -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<usize> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.field_indices + } + } + + pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<usize> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.field_indices + } + } + pub fn user_provided_tys(&self) -> LocalTableInContext<CanonicalTy<'tcx>> { LocalTableInContext { local_id_root: self.local_id_root, @@ -706,6 +727,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> 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<StableHashingContext<'a>> 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 fccba1e6aa7..6618f9bc2f5 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}; @@ -2107,32 +2107,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<usize> { - 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) @@ -2399,6 +2373,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<usize> { + 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 c170c2a63e8..77eff49d19f 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<DefId>) -> Option<Ty<'tcx>> { - 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<DefId>) -> Option<Ty<'tcx>> { - 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 5cfbe49f77f..e3adb51433b 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 2049a146a0f..6d832d4060a 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 a90dcd1072f..1f4050a5b36 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 48e9cc498dc..6f2c51b0f18 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 5b373908480..c0d28280946 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<FieldExprRef<'tcx>> { +fn field_refs<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, + fields: &'tcx [hir::Field]) + -> Vec<FieldExprRef<'tcx>> { 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 c3f41e8ac48..8d2b73d6ba0 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 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_privacy/lib.rs b/src/librustc_privacy/lib.rs index ef710ff7a7e..ee08e622390 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 607701b056b..abaa02a856e 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 fefedd4e1c8..ca19ed0df67 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<Ref> { - 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 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/_match.rs b/src/librustc_typeck/check/_match.rs index ae373fbad22..7b4dc60409b 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::<FxHashMap<_, _>>(); // 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::<Vec<_>>(); 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 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/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 2dbc590bbf7..d8907866467 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 da0b616b173..ca35153d571 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::<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(); + + 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<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, @@ -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 bbd04e0b19a..6e0d7dd8508 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 e2e6a2d7aac..3939c3a0627 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -514,11 +514,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<ast::Name, Span> = FxHashMap(); + let mut seen_fields: FxHashMap<ast::Ident, Span> = 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", @@ -527,7 +527,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 063d83780d8..ae3b2b22ea1 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) E0627, // yield statement outside of generator literal E0632, // cannot provide explicit type parameters when `impl Trait` is used in 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..36244f0a3c4 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 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<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..a7a9ce74512 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,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::<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 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 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/borrowck/borrowck-uninit-field-access.rs b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs index a214e3c126e..eec7df84c82 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 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/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index 83425a72f45..9c939d0d2fb 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<std::option::Option<&'35_0rs S<'35_0rs>>>; -// let mut _4: std::option::Option<&'35_0rs S<'35_0rs>>; +// let mut _3: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>; +// let mut _4: std::option::Option<&'36_0rs S<'36_0rs>>; // let mut _5: (); -// let mut _6: &'16s std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>; -// 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<std::option::Option<&'36_0rs S<'36_0rs>>>; +// 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<std::option::Option<&'35_0rs S<'35_0rs>>>; -// 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<std::option::Option<&'36_0rs S<'36_0rs>>>; +// 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 <std::cell::Cell<T>>::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<std::option::Option<&'35_0rs S<'35_0rs>>>); +// _6 = &'17s (_2.0: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>); // 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 <std::cell::Cell<T>>::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<std::option::Option<&'35_0rs S<'35_0rs>>>); +// _14 = &'34s (_2.0: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>); // 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 <std::cell::Cell<T>>::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 80e75fcee8a..79645bd3600 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 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/compile-fail/hygiene/assoc_item_ctxt.rs b/src/test/ui/hygiene/assoc_item_ctxt.rs index e336b0df13f..e336b0df13f 100644 --- a/src/test/compile-fail/hygiene/assoc_item_ctxt.rs +++ b/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 00000000000..8b410405ae5 --- /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 index 46a138749ff..46a138749ff 100644 --- a/src/test/compile-fail/hygiene/assoc_ty_bindings.rs +++ b/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 00000000000..0adf80994f7 --- /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 index aa67e5c5f4d..aa67e5c5f4d 100644 --- a/src/test/compile-fail/hygiene/auxiliary/intercrate.rs +++ b/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 00000000000..c92bf55a723 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![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 00000000000..73f524b7d2a --- /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 00000000000..a6e3b2b2d8b --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// 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 00000000000..ba9de09f9d2 --- /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 00000000000..50ace39e709 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +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 00000000000..ccd898fff27 --- /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 index 64217770b13..64217770b13 100644 --- a/src/test/compile-fail/hygiene/fields.rs +++ b/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 00000000000..c4be1834c04 --- /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 index d9386421970..d9386421970 100644 --- a/src/test/compile-fail/for-loop-hygiene.rs +++ b/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 00000000000..7e606b2358c --- /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 index 7ba217061c6..7ba217061c6 100644 --- a/src/test/compile-fail/hygiene/globs.rs +++ b/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 00000000000..d77242e135d --- /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 index cdba559445d..cdba559445d 100644 --- a/src/test/compile-fail/hygiene/impl_items.rs +++ b/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 00000000000..dbcf53554cf --- /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 index 50fc985ba34..50fc985ba34 100644 --- a/src/test/compile-fail/hygiene/intercrate.rs +++ b/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 00000000000..ecbc6e7b147 --- /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 index 6612359649c..6612359649c 100644 --- a/src/test/compile-fail/hygiene/nested_macro_privacy.rs +++ b/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 00000000000..1179065b94c --- /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 index c90c7b3093c..c90c7b3093c 100644 --- a/src/test/compile-fail/hygiene/no_implicit_prelude.rs +++ b/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 00000000000..5753d1a32f7 --- /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 index 26d411c9154..26d411c9154 100644 --- a/src/test/compile-fail/pattern-macro-hygiene.rs +++ b/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 00000000000..b26084db02e --- /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 index 987cad187d4..987cad187d4 100644 --- a/src/test/compile-fail/hygiene/privacy.rs +++ b/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 00000000000..808d244e9cd --- /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 index 3bd19cbc0ac..3bd19cbc0ac 100644 --- a/src/test/compile-fail/hygiene/trait_items.rs +++ b/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 00000000000..56d9c585d6f --- /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 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`. |
