Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macros: improve struct constructor field hygiene, fix span bug #48082

Merged
merged 4 commits into from
Feb 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
26 changes: 26 additions & 0 deletions src/test/run-pass/hygiene/issue-47311.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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.

// ignore-pretty pretty-printing is unhygienic

#![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