diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c5a0657594e..294ebb9915b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2938,9 +2938,8 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, base: &'tcx hir::Expr, field: &Spanned) { check_expr_with_lvalue_pref(fcx, base, lvalue_pref); - let expr_t = structurally_resolved_type(fcx, expr.span, - fcx.expr_ty(base)); - // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop. + let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base)); + let mut private_candidate = None; let (_, autoderefs, field_ty) = autoderef(fcx, expr.span, expr_t, @@ -2948,15 +2947,17 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, UnresolvedTypeAction::Error, lvalue_pref, |base_t, _| { - match base_t.sty { - ty::TyStruct(base_def, substs) => { - debug!("struct named {:?}", base_t); - base_def.struct_variant() - .find_field_named(field.node) - .map(|f| fcx.field_ty(expr.span, f, substs)) + if let ty::TyStruct(base_def, substs) = base_t.sty { + debug!("struct named {:?}", base_t); + if let Some(field) = base_def.struct_variant().find_field_named(field.node) { + let field_ty = fcx.field_ty(expr.span, field, substs); + if field.vis == hir::Public || fcx.private_item_is_visible(base_def.did) { + return Some(field_ty); + } + private_candidate = Some((base_def.did, field_ty)); } - _ => None } + None }); match field_ty { Some(field_ty) => { @@ -2967,12 +2968,14 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, None => {} } - if field.node == special_idents::invalid.name { + if let Some((did, field_ty)) = private_candidate { + let struct_path = fcx.tcx().item_path_str(did); + let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path); + fcx.tcx().sess.span_err(expr.span, &msg); + fcx.write_ty(expr.id, field_ty); + } else if field.node == special_idents::invalid.name { fcx.write_error(expr.id); - return; - } - - if method::exists(fcx, field.span, field.node, expr_t, expr.id) { + } else if method::exists(fcx, field.span, field.node, expr_t, expr.id) { fcx.type_error_struct(field.span, |actual| { format!("attempted to take value of method `{}` on type \ @@ -2983,6 +2986,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, "maybe a `()` to call it is missing? \ If not, try an anonymous function") .emit(); + fcx.write_error(expr.id); } else { let mut err = fcx.type_error_struct( expr.span, @@ -2998,9 +3002,8 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, suggest_field_names(&mut err, def.struct_variant(), field, vec![]); } err.emit(); + fcx.write_error(expr.id); } - - fcx.write_error(expr.id); } // displays hints about the closest matches in field names @@ -3035,10 +3038,9 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, base: &'tcx hir::Expr, idx: codemap::Spanned) { check_expr_with_lvalue_pref(fcx, base, lvalue_pref); - let expr_t = structurally_resolved_type(fcx, expr.span, - fcx.expr_ty(base)); + let expr_t = structurally_resolved_type(fcx, expr.span, fcx.expr_ty(base)); + let mut private_candidate = None; let mut tuple_like = false; - // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop. let (_, autoderefs, field_ty) = autoderef(fcx, expr.span, expr_t, @@ -3046,25 +3048,27 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, UnresolvedTypeAction::Error, lvalue_pref, |base_t, _| { - match base_t.sty { - ty::TyStruct(base_def, substs) => { - tuple_like = base_def.struct_variant().is_tuple_struct(); - if tuple_like { - debug!("tuple struct named {:?}", base_t); - base_def.struct_variant() - .fields - .get(idx.node) - .map(|f| fcx.field_ty(expr.span, f, substs)) - } else { - None - } - } + let (base_def, substs) = match base_t.sty { + ty::TyStruct(base_def, substs) => (base_def, substs), ty::TyTuple(ref v) => { tuple_like = true; - if idx.node < v.len() { Some(v[idx.node]) } else { None } + return if idx.node < v.len() { Some(v[idx.node]) } else { None } } - _ => None + _ => return None, + }; + + tuple_like = base_def.struct_variant().is_tuple_struct(); + if !tuple_like { return None } + + debug!("tuple struct named {:?}", base_t); + if let Some(field) = base_def.struct_variant().fields.get(idx.node) { + let field_ty = fcx.field_ty(expr.span, field, substs); + if field.vis == hir::Public || fcx.private_item_is_visible(base_def.did) { + return Some(field_ty); + } + private_candidate = Some((base_def.did, field_ty)); } + None }); match field_ty { Some(field_ty) => { @@ -3074,6 +3078,15 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } None => {} } + + if let Some((did, field_ty)) = private_candidate { + let struct_path = fcx.tcx().item_path_str(did); + let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path); + fcx.tcx().sess.span_err(expr.span, &msg); + fcx.write_ty(expr.id, field_ty); + return; + } + fcx.type_error_message( expr.span, |actual| {