Skip to content

Commit 4a70e27

Browse files
committed
Auto merge of #48082 - jseyfried:improve_struct_field_hygiene, r=petrochenkov
macros: improve struct constructor field hygiene, fix span bug Fixes #47311. r? @nrc
2 parents 322d7f7 + 1e037f4 commit 4a70e27

15 files changed

+62
-24
lines changed

src/librustc_privacy/lib.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use rustc::util::nodemap::NodeSet;
3434
use syntax::ast::{self, CRATE_NODE_ID, Ident};
3535
use syntax::symbol::keywords;
3636
use syntax_pos::Span;
37+
use syntax_pos::hygiene::SyntaxContext;
3738

3839
use std::cmp;
3940
use std::mem::replace;
@@ -491,9 +492,13 @@ struct NamePrivacyVisitor<'a, 'tcx: 'a> {
491492
}
492493

493494
impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> {
494-
// Checks that a field is accessible.
495-
fn check_field(&mut self, span: Span, def: &'tcx ty::AdtDef, field: &'tcx ty::FieldDef) {
496-
let ident = Ident { ctxt: span.ctxt().modern(), ..keywords::Invalid.ident() };
495+
// Checks that a field in a struct constructor (expression or pattern) is accessible.
496+
fn check_field(&mut self,
497+
use_ctxt: SyntaxContext, // Syntax context of the field name at the use site
498+
span: Span, // Span of the field pattern, e.g. `x: 0`
499+
def: &'tcx ty::AdtDef, // Definition of the struct or enum
500+
field: &'tcx ty::FieldDef) { // Definition of the field
501+
let ident = Ident { ctxt: use_ctxt.modern(), ..keywords::Invalid.ident() };
497502
let def_id = self.tcx.adjust_ident(ident, def.did, self.current_item).1;
498503
if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) {
499504
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> {
566571
// unmentioned fields, just check them all.
567572
for variant_field in &variant.fields {
568573
let field = fields.iter().find(|f| f.name.node == variant_field.name);
569-
let span = if let Some(f) = field { f.span } else { base.span };
570-
self.check_field(span, adt, variant_field);
574+
let (use_ctxt, span) = match field {
575+
Some(field) => (field.name.node.to_ident().ctxt, field.span),
576+
None => (base.span.ctxt(), base.span),
577+
};
578+
self.check_field(use_ctxt, span, adt, variant_field);
571579
}
572580
} else {
573581
for field in fields {
574-
self.check_field(field.span, adt, variant.field_named(field.name.node));
582+
let use_ctxt = field.name.node.to_ident().ctxt;
583+
let field_def = variant.field_named(field.name.node);
584+
self.check_field(use_ctxt, field.span, adt, field_def);
575585
}
576586
}
577587
}
@@ -588,7 +598,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
588598
let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap();
589599
let variant = adt.variant_of_def(def);
590600
for field in fields {
591-
self.check_field(field.span, adt, variant.field_named(field.node.name));
601+
let use_ctxt = field.node.name.to_ident().ctxt;
602+
let field_def = variant.field_named(field.node.name);
603+
self.check_field(use_ctxt, field.span, adt, field_def);
592604
}
593605
}
594606
_ => {}

src/libsyntax/parse/parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2125,8 +2125,8 @@ impl<'a> Parser<'a> {
21252125
// Check if a colon exists one ahead. This means we're parsing a fieldname.
21262126
let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
21272127
let fieldname = self.parse_field_name()?;
2128-
self.bump();
21292128
hi = self.prev_span;
2129+
self.bump();
21302130
(fieldname, self.parse_expr()?, false)
21312131
} else {
21322132
let fieldname = self.parse_ident_common(false)?;
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ignore-pretty pretty-printing is unhygienic
12+
13+
#![feature(decl_macro)]
14+
#![allow(unused)]
15+
16+
macro m($S:ident, $x:ident) {
17+
$S { $x: 0 }
18+
}
19+
20+
mod foo {
21+
struct S { x: i32 }
22+
23+
fn f() { ::m!(S, x); }
24+
}
25+
26+
fn main() {}

src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ error[E0560]: struct `submodule::Demo` has no field named `inocently_mispellable
22
--> $DIR/issue-42599_available_fields_note.rs:26:39
33
|
44
26 | Self { secret_integer: 2, inocently_mispellable: () }
5-
| ^^^^^^^^^^^^^^^^^^^^^^ field does not exist - did you mean `innocently_misspellable`?
5+
| ^^^^^^^^^^^^^^^^^^^^^ field does not exist - did you mean `innocently_misspellable`?
66

77
error[E0560]: struct `submodule::Demo` has no field named `egregiously_nonexistent_field`
88
--> $DIR/issue-42599_available_fields_note.rs:31:39
99
|
1010
31 | Self { secret_integer: 3, egregiously_nonexistent_field: () }
11-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `submodule::Demo` does not have this field
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `submodule::Demo` does not have this field
1212
|
1313
= note: available fields are: `favorite_integer`, `secret_integer`, `innocently_misspellable`, `another_field`, `yet_another_field` ... and 2 others
1414

src/test/ui/error-codes/E0062.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0062]: field `x` specified more than once
44
17 | x: 0,
55
| ---- first use of `x`
66
18 | x: 0,
7-
| ^^ used more than once
7+
| ^ used more than once
88

99
error: aborting due to previous error
1010

src/test/ui/error-codes/E0559.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0559]: variant `Field::Fool` has no field named `joke`
22
--> $DIR/E0559.rs:16:27
33
|
44
16 | let s = Field::Fool { joke: 0 };
5-
| ^^^^^ `Field::Fool` does not have this field
5+
| ^^^^ `Field::Fool` does not have this field
66
|
77
= note: available fields are: `x`
88

src/test/ui/error-codes/E0560.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0560]: struct `Simba` has no field named `father`
22
--> $DIR/E0560.rs:16:32
33
|
44
16 | let s = Simba { mother: 1, father: 0 };
5-
| ^^^^^^^ `Simba` does not have this field
5+
| ^^^^^^ `Simba` does not have this field
66
|
77
= note: available fields are: `mother`
88

src/test/ui/issue-19922.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0559]: variant `Homura::Akemi` has no field named `kaname`
22
--> $DIR/issue-19922.rs:16:34
33
|
44
16 | let homura = Homura::Akemi { kaname: () };
5-
| ^^^^^^^ `Homura::Akemi` does not have this field
5+
| ^^^^^^ `Homura::Akemi` does not have this field
66
|
77
= note: available fields are: `madoka`
88

src/test/ui/numeric-fields.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0560]: struct `S` has no field named `0b1`
22
--> $DIR/numeric-fields.rs:14:15
33
|
44
14 | let s = S{0b1: 10, 0: 11};
5-
| ^^^^ `S` does not have this field
5+
| ^^^ `S` does not have this field
66
|
77
= note: available fields are: `0`, `1`
88

src/test/ui/struct-fields-hints-no-dupe.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0560]: struct `A` has no field named `bar`
22
--> $DIR/struct-fields-hints-no-dupe.rs:20:9
33
|
44
20 | bar : 42,
5-
| ^^^^^ field does not exist - did you mean `barr`?
5+
| ^^^ field does not exist - did you mean `barr`?
66

77
error: aborting due to previous error
88

src/test/ui/struct-fields-hints.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0560]: struct `A` has no field named `bar`
22
--> $DIR/struct-fields-hints.rs:20:9
33
|
44
20 | bar : 42,
5-
| ^^^^^ field does not exist - did you mean `car`?
5+
| ^^^ field does not exist - did you mean `car`?
66

77
error: aborting due to previous error
88

src/test/ui/struct-fields-too-many.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0560]: struct `BuildData` has no field named `bar`
22
--> $DIR/struct-fields-too-many.rs:18:9
33
|
44
18 | bar: 0
5-
| ^^^^ `BuildData` does not have this field
5+
| ^^^ `BuildData` does not have this field
66
|
77
= note: available fields are: `foo`
88

src/test/ui/suggest-private-fields.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@ error[E0560]: struct `xc::B` has no field named `aa`
22
--> $DIR/suggest-private-fields.rs:25:9
33
|
44
25 | aa: 20,
5-
| ^^^ field does not exist - did you mean `a`?
5+
| ^^ field does not exist - did you mean `a`?
66

77
error[E0560]: struct `xc::B` has no field named `bb`
88
--> $DIR/suggest-private-fields.rs:27:9
99
|
1010
27 | bb: 20,
11-
| ^^^ `xc::B` does not have this field
11+
| ^^ `xc::B` does not have this field
1212
|
1313
= note: available fields are: `a`
1414

1515
error[E0560]: struct `A` has no field named `aa`
1616
--> $DIR/suggest-private-fields.rs:32:9
1717
|
1818
32 | aa: 20,
19-
| ^^^ field does not exist - did you mean `a`?
19+
| ^^ field does not exist - did you mean `a`?
2020

2121
error[E0560]: struct `A` has no field named `bb`
2222
--> $DIR/suggest-private-fields.rs:34:9
2323
|
2424
34 | bb: 20,
25-
| ^^^ field does not exist - did you mean `b`?
25+
| ^^ field does not exist - did you mean `b`?
2626

2727
error: aborting due to 4 previous errors
2828

src/test/ui/union/union-fields-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ error[E0560]: union `U` has no field named `c`
1414
--> $DIR/union-fields-2.rs:20:29
1515
|
1616
20 | let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field
17-
| ^^ `U` does not have this field
17+
| ^ `U` does not have this field
1818
|
1919
= note: available fields are: `a`, `b`
2020

src/test/ui/union/union-suggest-field.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0560]: union `U` has no field named `principle`
22
--> $DIR/union-suggest-field.rs:20:17
33
|
44
20 | let u = U { principle: 0 };
5-
| ^^^^^^^^^^ field does not exist - did you mean `principal`?
5+
| ^^^^^^^^^ field does not exist - did you mean `principal`?
66

77
error[E0609]: no field `principial` on type `U`
88
--> $DIR/union-suggest-field.rs:22:15

0 commit comments

Comments
 (0)