diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 6ae047609535e..40143dc0b35c0 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -34,6 +34,7 @@ use rustc::util::nodemap::NodeSet; use syntax::ast::{self, CRATE_NODE_ID, Ident}; use syntax::symbol::keywords; use syntax_pos::Span; +use syntax_pos::hygiene::SyntaxContext; use std::cmp; use std::mem::replace; @@ -491,9 +492,13 @@ struct NamePrivacyVisitor<'a, 'tcx: 'a> { } impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> { - // Checks that a field is accessible. - fn check_field(&mut self, span: Span, def: &'tcx ty::AdtDef, field: &'tcx ty::FieldDef) { - let ident = Ident { ctxt: span.ctxt().modern(), ..keywords::Invalid.ident() }; + // Checks that a field in a struct constructor (expression or pattern) is accessible. + fn check_field(&mut self, + use_ctxt: SyntaxContext, // Syntax context of the field name at the use site + span: Span, // Span of the field pattern, e.g. `x: 0` + def: &'tcx ty::AdtDef, // Definition of the struct or enum + field: &'tcx ty::FieldDef) { // Definition of the field + let ident = Ident { ctxt: use_ctxt.modern(), ..keywords::Invalid.ident() }; let def_id = self.tcx.adjust_ident(ident, def.did, self.current_item).1; if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) { struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private", @@ -566,12 +571,17 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { // unmentioned fields, just check them all. for variant_field in &variant.fields { let field = fields.iter().find(|f| f.name.node == variant_field.name); - let span = if let Some(f) = field { f.span } else { base.span }; - self.check_field(span, adt, variant_field); + let (use_ctxt, span) = match field { + Some(field) => (field.name.node.to_ident().ctxt, field.span), + None => (base.span.ctxt(), base.span), + }; + self.check_field(use_ctxt, span, adt, variant_field); } } else { for field in fields { - self.check_field(field.span, adt, variant.field_named(field.name.node)); + let use_ctxt = field.name.node.to_ident().ctxt; + let field_def = variant.field_named(field.name.node); + self.check_field(use_ctxt, field.span, adt, field_def); } } } @@ -588,7 +598,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap(); let variant = adt.variant_of_def(def); for field in fields { - self.check_field(field.span, adt, variant.field_named(field.node.name)); + let use_ctxt = field.node.name.to_ident().ctxt; + let field_def = variant.field_named(field.node.name); + self.check_field(use_ctxt, field.span, adt, field_def); } } _ => {} diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7915109ce3af8..ee8a5ff036c32 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2121,8 +2121,8 @@ impl<'a> Parser<'a> { // Check if a colon exists one ahead. This means we're parsing a fieldname. let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { let fieldname = self.parse_field_name()?; - self.bump(); hi = self.prev_span; + self.bump(); (fieldname, self.parse_expr()?, false) } else { let fieldname = self.parse_ident_common(false)?; diff --git a/src/test/run-pass/hygiene/issue-47311.rs b/src/test/run-pass/hygiene/issue-47311.rs new file mode 100644 index 0000000000000..d68d8fc8c7481 --- /dev/null +++ b/src/test/run-pass/hygiene/issue-47311.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(decl_macro)] +#![allow(unused)] + +macro m($S:ident, $x:ident) { + $S { $x: 0 } +} + +mod foo { + struct S { x: i32 } + + fn f() { ::m!(S, x); } +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr b/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr index d5dcef638471e..2c7701e9965db 100644 --- a/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr +++ b/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr @@ -2,13 +2,13 @@ error[E0560]: struct `submodule::Demo` has no field named `inocently_mispellable --> $DIR/issue-42599_available_fields_note.rs:26:39 | 26 | Self { secret_integer: 2, inocently_mispellable: () } - | ^^^^^^^^^^^^^^^^^^^^^^ field does not exist - did you mean `innocently_misspellable`? + | ^^^^^^^^^^^^^^^^^^^^^ field does not exist - did you mean `innocently_misspellable`? error[E0560]: struct `submodule::Demo` has no field named `egregiously_nonexistent_field` --> $DIR/issue-42599_available_fields_note.rs:31:39 | 31 | Self { secret_integer: 3, egregiously_nonexistent_field: () } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `submodule::Demo` does not have this field + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `submodule::Demo` does not have this field | = note: available fields are: `favorite_integer`, `secret_integer`, `innocently_misspellable`, `another_field`, `yet_another_field` ... and 2 others diff --git a/src/test/ui/error-codes/E0062.stderr b/src/test/ui/error-codes/E0062.stderr index 6c5ecf48045b1..462ee2ac50d83 100644 --- a/src/test/ui/error-codes/E0062.stderr +++ b/src/test/ui/error-codes/E0062.stderr @@ -4,7 +4,7 @@ error[E0062]: field `x` specified more than once 17 | x: 0, | ---- first use of `x` 18 | x: 0, - | ^^ used more than once + | ^ used more than once error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0559.stderr b/src/test/ui/error-codes/E0559.stderr index 5d145a9518095..0bdf104ec6b2d 100644 --- a/src/test/ui/error-codes/E0559.stderr +++ b/src/test/ui/error-codes/E0559.stderr @@ -2,7 +2,7 @@ error[E0559]: variant `Field::Fool` has no field named `joke` --> $DIR/E0559.rs:16:27 | 16 | let s = Field::Fool { joke: 0 }; - | ^^^^^ `Field::Fool` does not have this field + | ^^^^ `Field::Fool` does not have this field | = note: available fields are: `x` diff --git a/src/test/ui/error-codes/E0560.stderr b/src/test/ui/error-codes/E0560.stderr index a0185aa8af64b..aedd2d59142a1 100644 --- a/src/test/ui/error-codes/E0560.stderr +++ b/src/test/ui/error-codes/E0560.stderr @@ -2,7 +2,7 @@ error[E0560]: struct `Simba` has no field named `father` --> $DIR/E0560.rs:16:32 | 16 | let s = Simba { mother: 1, father: 0 }; - | ^^^^^^^ `Simba` does not have this field + | ^^^^^^ `Simba` does not have this field | = note: available fields are: `mother` diff --git a/src/test/ui/issue-19922.stderr b/src/test/ui/issue-19922.stderr index f96392441967f..035901abac668 100644 --- a/src/test/ui/issue-19922.stderr +++ b/src/test/ui/issue-19922.stderr @@ -2,7 +2,7 @@ error[E0559]: variant `Homura::Akemi` has no field named `kaname` --> $DIR/issue-19922.rs:16:34 | 16 | let homura = Homura::Akemi { kaname: () }; - | ^^^^^^^ `Homura::Akemi` does not have this field + | ^^^^^^ `Homura::Akemi` does not have this field | = note: available fields are: `madoka` diff --git a/src/test/ui/numeric-fields.stderr b/src/test/ui/numeric-fields.stderr index cdf85d4f9718e..8261e9034a69b 100644 --- a/src/test/ui/numeric-fields.stderr +++ b/src/test/ui/numeric-fields.stderr @@ -2,7 +2,7 @@ error[E0560]: struct `S` has no field named `0b1` --> $DIR/numeric-fields.rs:14:15 | 14 | let s = S{0b1: 10, 0: 11}; - | ^^^^ `S` does not have this field + | ^^^ `S` does not have this field | = note: available fields are: `0`, `1` diff --git a/src/test/ui/struct-fields-hints-no-dupe.stderr b/src/test/ui/struct-fields-hints-no-dupe.stderr index 93cbe1f5afa80..0de22d1a84f7f 100644 --- a/src/test/ui/struct-fields-hints-no-dupe.stderr +++ b/src/test/ui/struct-fields-hints-no-dupe.stderr @@ -2,7 +2,7 @@ error[E0560]: struct `A` has no field named `bar` --> $DIR/struct-fields-hints-no-dupe.rs:20:9 | 20 | bar : 42, - | ^^^^^ field does not exist - did you mean `barr`? + | ^^^ field does not exist - did you mean `barr`? error: aborting due to previous error diff --git a/src/test/ui/struct-fields-hints.stderr b/src/test/ui/struct-fields-hints.stderr index a7c77103e7357..f602f398acd1c 100644 --- a/src/test/ui/struct-fields-hints.stderr +++ b/src/test/ui/struct-fields-hints.stderr @@ -2,7 +2,7 @@ error[E0560]: struct `A` has no field named `bar` --> $DIR/struct-fields-hints.rs:20:9 | 20 | bar : 42, - | ^^^^^ field does not exist - did you mean `car`? + | ^^^ field does not exist - did you mean `car`? error: aborting due to previous error diff --git a/src/test/ui/struct-fields-too-many.stderr b/src/test/ui/struct-fields-too-many.stderr index ec353d00aa7ee..d61dd8da6ece3 100644 --- a/src/test/ui/struct-fields-too-many.stderr +++ b/src/test/ui/struct-fields-too-many.stderr @@ -2,7 +2,7 @@ error[E0560]: struct `BuildData` has no field named `bar` --> $DIR/struct-fields-too-many.rs:18:9 | 18 | bar: 0 - | ^^^^ `BuildData` does not have this field + | ^^^ `BuildData` does not have this field | = note: available fields are: `foo` diff --git a/src/test/ui/suggest-private-fields.stderr b/src/test/ui/suggest-private-fields.stderr index d32d85f6e3fd1..a451f9c8fe7d2 100644 --- a/src/test/ui/suggest-private-fields.stderr +++ b/src/test/ui/suggest-private-fields.stderr @@ -2,13 +2,13 @@ error[E0560]: struct `xc::B` has no field named `aa` --> $DIR/suggest-private-fields.rs:25:9 | 25 | aa: 20, - | ^^^ field does not exist - did you mean `a`? + | ^^ field does not exist - did you mean `a`? error[E0560]: struct `xc::B` has no field named `bb` --> $DIR/suggest-private-fields.rs:27:9 | 27 | bb: 20, - | ^^^ `xc::B` does not have this field + | ^^ `xc::B` does not have this field | = note: available fields are: `a` @@ -16,13 +16,13 @@ error[E0560]: struct `A` has no field named `aa` --> $DIR/suggest-private-fields.rs:32:9 | 32 | aa: 20, - | ^^^ field does not exist - did you mean `a`? + | ^^ field does not exist - did you mean `a`? error[E0560]: struct `A` has no field named `bb` --> $DIR/suggest-private-fields.rs:34:9 | 34 | bb: 20, - | ^^^ field does not exist - did you mean `b`? + | ^^ field does not exist - did you mean `b`? error: aborting due to 4 previous errors diff --git a/src/test/ui/union/union-fields-2.stderr b/src/test/ui/union/union-fields-2.stderr index f6c64dcabd74c..d66ebaa2187eb 100644 --- a/src/test/ui/union/union-fields-2.stderr +++ b/src/test/ui/union/union-fields-2.stderr @@ -14,7 +14,7 @@ error[E0560]: union `U` has no field named `c` --> $DIR/union-fields-2.rs:20:29 | 20 | let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field - | ^^ `U` does not have this field + | ^ `U` does not have this field | = note: available fields are: `a`, `b` diff --git a/src/test/ui/union/union-suggest-field.stderr b/src/test/ui/union/union-suggest-field.stderr index d2ea09553bcc1..e3cb52270ddd6 100644 --- a/src/test/ui/union/union-suggest-field.stderr +++ b/src/test/ui/union/union-suggest-field.stderr @@ -2,7 +2,7 @@ error[E0560]: union `U` has no field named `principle` --> $DIR/union-suggest-field.rs:20:17 | 20 | let u = U { principle: 0 }; - | ^^^^^^^^^^ field does not exist - did you mean `principal`? + | ^^^^^^^^^ field does not exist - did you mean `principal`? error[E0609]: no field `principial` on type `U` --> $DIR/union-suggest-field.rs:22:15