Skip to content

Commit 0b1d5f0

Browse files
committed
Make FRU respect privacy of all struct fields, mentioned or unmentioned.
This is RFC 736. Fix #21407.
1 parent 94c06a1 commit 0b1d5f0

File tree

2 files changed

+57
-14
lines changed

2 files changed

+57
-14
lines changed

src/librustc_privacy/lib.rs

+15-14
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,8 @@ enum PrivacyResult {
390390

391391
enum FieldName {
392392
UnnamedField(uint), // index
393-
// FIXME #6993: change type (and name) from Ident to Name
394-
NamedField(ast::Ident),
393+
// (Name, not Ident, because struct fields are not macro-hygienic)
394+
NamedField(ast::Name),
395395
}
396396

397397
impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
@@ -665,9 +665,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
665665
name: FieldName) {
666666
let fields = ty::lookup_struct_fields(self.tcx, id);
667667
let field = match name {
668-
NamedField(ident) => {
669-
debug!("privacy - check named field {} in struct {:?}", ident.name, id);
670-
fields.iter().find(|f| f.name == ident.name).unwrap()
668+
NamedField(f_name) => {
669+
debug!("privacy - check named field {} in struct {:?}", f_name, id);
670+
fields.iter().find(|f| f.name == f_name).unwrap()
671671
}
672672
UnnamedField(idx) => &fields[idx]
673673
};
@@ -686,7 +686,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
686686
};
687687
let msg = match name {
688688
NamedField(name) => format!("field `{}` of {} is private",
689-
token::get_ident(name), struct_desc),
689+
token::get_name(name), struct_desc),
690690
UnnamedField(idx) => format!("field #{} of {} is private",
691691
idx + 1, struct_desc),
692692
};
@@ -873,7 +873,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
873873
match expr.node {
874874
ast::ExprField(ref base, ident) => {
875875
if let ty::ty_struct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty {
876-
self.check_field(expr.span, id, NamedField(ident.node));
876+
self.check_field(expr.span, id, NamedField(ident.node.name));
877877
}
878878
}
879879
ast::ExprTupField(ref base, idx) => {
@@ -897,18 +897,19 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
897897
}
898898
ast::ExprStruct(_, ref fields, _) => {
899899
match ty::expr_ty(self.tcx, expr).sty {
900-
ty::ty_struct(id, _) => {
901-
for field in &(*fields) {
902-
self.check_field(expr.span, id,
903-
NamedField(field.ident.node));
900+
ty::ty_struct(ctor_id, _) => {
901+
let all_fields = ty::lookup_struct_fields(self.tcx, ctor_id);
902+
for field in all_fields {
903+
self.check_field(expr.span, ctor_id,
904+
NamedField(field.name));
904905
}
905906
}
906907
ty::ty_enum(_, _) => {
907908
match self.tcx.def_map.borrow()[expr.id].clone() {
908909
def::DefVariant(_, variant_id, _) => {
909910
for field in fields {
910911
self.check_field(expr.span, variant_id,
911-
NamedField(field.ident.node));
912+
NamedField(field.ident.node.name));
912913
}
913914
}
914915
_ => self.tcx.sess.span_bug(expr.span,
@@ -973,15 +974,15 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
973974
ty::ty_struct(id, _) => {
974975
for field in fields {
975976
self.check_field(pattern.span, id,
976-
NamedField(field.node.ident));
977+
NamedField(field.node.ident.name));
977978
}
978979
}
979980
ty::ty_enum(_, _) => {
980981
match self.tcx.def_map.borrow().get(&pattern.id) {
981982
Some(&def::DefVariant(_, variant_id, _)) => {
982983
for field in fields {
983984
self.check_field(pattern.span, variant_id,
984-
NamedField(field.node.ident));
985+
NamedField(field.node.ident.name));
985986
}
986987
}
987988
_ => self.tcx.sess.span_bug(pattern.span,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2015 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+
// RFC 736 (and Issue 21407): functional struct update should respect privacy.
12+
13+
// The `foo` module attempts to maintains an invariant that each `S`
14+
// has a unique `u64` id.
15+
use self::foo::S;
16+
mod foo {
17+
use std::cell::{UnsafeCell};
18+
19+
static mut count : UnsafeCell<u64> = UnsafeCell { value: 1 };
20+
21+
pub struct S { pub a: u8, pub b: String, secret_uid: u64 }
22+
23+
pub fn make_secrets(a: u8, b: String) -> S {
24+
let val = unsafe { let p = count.get(); let val = *p; *p = val + 1; val };
25+
println!("creating {}, uid {}", b, val);
26+
S { a: a, b: b, secret_uid: val }
27+
}
28+
29+
impl Drop for S {
30+
fn drop(&mut self) {
31+
println!("dropping {}, uid {}", self.b, self.secret_uid);
32+
}
33+
}
34+
}
35+
36+
fn main() {
37+
let s_1 = foo::make_secrets(3, format!("ess one"));
38+
let s_2 = foo::S { b: format!("ess two"), ..s_1 }; // FRU ...
39+
40+
println!("main forged an S named: {}", s_2.b);
41+
// at end of scope, ... both s_1 *and* s_2 get dropped. Boom!
42+
}

0 commit comments

Comments
 (0)