Skip to content

Commit

Permalink
Rollup merge of rust-lang#48082 - jseyfried:improve_struct_field_hygi…
Browse files Browse the repository at this point in the history
…ene, r=jseyfried

macros: improve struct constructor field hygiene, fix span bug

Fixes rust-lang#47311.
r? @nrc
  • Loading branch information
Manishearth committed Feb 19, 2018
2 parents 27a046e + 169643d commit face16b
Show file tree
Hide file tree
Showing 15 changed files with 60 additions and 24 deletions.
26 changes: 19 additions & 7 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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);
}
}
}
Expand All @@ -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);
}
}
_ => {}
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down
24 changes: 24 additions & 0 deletions src/test/run-pass/hygiene/issue-47311.rs
Original file line number Diff line number Diff line change
@@ -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 <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)]
#![allow(unused)]

macro m($S:ident, $x:ident) {
$S { $x: 0 }
}

mod foo {
struct S { x: i32 }

fn f() { ::m!(S, x); }
}

fn main() {}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/error-codes/E0062.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

2 changes: 1 addition & 1 deletion src/test/ui/error-codes/E0559.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/error-codes/E0560.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issue-19922.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/numeric-fields.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/struct-fields-hints-no-dupe.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

2 changes: 1 addition & 1 deletion src/test/ui/struct-fields-hints.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

2 changes: 1 addition & 1 deletion src/test/ui/struct-fields-too-many.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/suggest-private-fields.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@ 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`

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

2 changes: 1 addition & 1 deletion src/test/ui/union/union-fields-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/union/union-suggest-field.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit face16b

Please sign in to comment.