Skip to content

Commit 90620b7

Browse files
committed
Autoderef privacy for fields
1 parent d5880ff commit 90620b7

File tree

1 file changed

+48
-35
lines changed
  • src/librustc_typeck/check

1 file changed

+48
-35
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2893,25 +2893,26 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
28932893
base: &'tcx hir::Expr,
28942894
field: &Spanned<ast::Name>) {
28952895
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
2896-
let expr_t = structurally_resolved_type(fcx, expr.span,
2897-
fcx.expr_ty(base));
2898-
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
2896+
let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base));
2897+
let mut private_candidate = None;
28992898
let (_, autoderefs, field_ty) = autoderef(fcx,
29002899
expr.span,
29012900
expr_t,
29022901
|| Some(base),
29032902
UnresolvedTypeAction::Error,
29042903
lvalue_pref,
29052904
|base_t, _| {
2906-
match base_t.sty {
2907-
ty::TyStruct(base_def, substs) => {
2908-
debug!("struct named {:?}", base_t);
2909-
base_def.struct_variant()
2910-
.find_field_named(field.node)
2911-
.map(|f| fcx.field_ty(expr.span, f, substs))
2905+
if let ty::TyStruct(base_def, substs) = base_t.sty {
2906+
debug!("struct named {:?}", base_t);
2907+
if let Some(field) = base_def.struct_variant().find_field_named(field.node) {
2908+
let field_ty = fcx.field_ty(expr.span, field, substs);
2909+
if field.vis == hir::Public || fcx.private_item_is_visible(base_def.did) {
2910+
return Some(field_ty);
2911+
}
2912+
private_candidate = Some((base_def.did, field_ty));
29122913
}
2913-
_ => None
29142914
}
2915+
None
29152916
});
29162917
match field_ty {
29172918
Some(field_ty) => {
@@ -2922,12 +2923,14 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
29222923
None => {}
29232924
}
29242925

2925-
if field.node == special_idents::invalid.name {
2926+
if let Some((did, field_ty)) = private_candidate {
2927+
let struct_path = fcx.tcx().item_path_str(did);
2928+
let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
2929+
fcx.tcx().sess.span_err(expr.span, &msg);
2930+
fcx.write_ty(expr.id, field_ty);
2931+
} else if field.node == special_idents::invalid.name {
29262932
fcx.write_error(expr.id);
2927-
return;
2928-
}
2929-
2930-
if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
2933+
} else if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
29312934
fcx.type_error_struct(field.span,
29322935
|actual| {
29332936
format!("attempted to take value of method `{}` on type \
@@ -2938,6 +2941,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
29382941
"maybe a `()` to call it is missing? \
29392942
If not, try an anonymous function")
29402943
.emit();
2944+
fcx.write_error(expr.id);
29412945
} else {
29422946
let mut err = fcx.type_error_struct(
29432947
expr.span,
@@ -2953,9 +2957,8 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
29532957
suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
29542958
}
29552959
err.emit();
2960+
fcx.write_error(expr.id);
29562961
}
2957-
2958-
fcx.write_error(expr.id);
29592962
}
29602963

29612964
// displays hints about the closest matches in field names
@@ -2990,36 +2993,37 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
29902993
base: &'tcx hir::Expr,
29912994
idx: codemap::Spanned<usize>) {
29922995
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
2993-
let expr_t = structurally_resolved_type(fcx, expr.span,
2994-
fcx.expr_ty(base));
2996+
let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base));
2997+
let mut private_candidate = None;
29952998
let mut tuple_like = false;
2996-
// FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
29972999
let (_, autoderefs, field_ty) = autoderef(fcx,
29983000
expr.span,
29993001
expr_t,
30003002
|| Some(base),
30013003
UnresolvedTypeAction::Error,
30023004
lvalue_pref,
30033005
|base_t, _| {
3004-
match base_t.sty {
3005-
ty::TyStruct(base_def, substs) => {
3006-
tuple_like = base_def.struct_variant().is_tuple_struct();
3007-
if tuple_like {
3008-
debug!("tuple struct named {:?}", base_t);
3009-
base_def.struct_variant()
3010-
.fields
3011-
.get(idx.node)
3012-
.map(|f| fcx.field_ty(expr.span, f, substs))
3013-
} else {
3014-
None
3015-
}
3016-
}
3006+
let (base_def, substs) = match base_t.sty {
3007+
ty::TyStruct(base_def, substs) => (base_def, substs),
30173008
ty::TyTuple(ref v) => {
30183009
tuple_like = true;
3019-
if idx.node < v.len() { Some(v[idx.node]) } else { None }
3010+
return if idx.node < v.len() { Some(v[idx.node]) } else { None }
30203011
}
3021-
_ => None
3012+
_ => return None,
3013+
};
3014+
3015+
tuple_like = base_def.struct_variant().is_tuple_struct();
3016+
if !tuple_like { return None }
3017+
3018+
debug!("tuple struct named {:?}", base_t);
3019+
if let Some(field) = base_def.struct_variant().fields.get(idx.node) {
3020+
let field_ty = fcx.field_ty(expr.span, field, substs);
3021+
if field.vis == hir::Public || fcx.private_item_is_visible(base_def.did) {
3022+
return Some(field_ty);
3023+
}
3024+
private_candidate = Some((base_def.did, field_ty));
30223025
}
3026+
None
30233027
});
30243028
match field_ty {
30253029
Some(field_ty) => {
@@ -3029,6 +3033,15 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
30293033
}
30303034
None => {}
30313035
}
3036+
3037+
if let Some((did, field_ty)) = private_candidate {
3038+
let struct_path = fcx.tcx().item_path_str(did);
3039+
let msg = format!("field #{} of struct `{}` is private", idx.node, struct_path);
3040+
fcx.tcx().sess.span_err(expr.span, &msg);
3041+
fcx.write_ty(expr.id, field_ty);
3042+
return;
3043+
}
3044+
30323045
fcx.type_error_message(
30333046
expr.span,
30343047
|actual| {

0 commit comments

Comments
 (0)