Skip to content

Handle stability of struct fields #22803

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

Merged
merged 3 commits into from
Feb 28, 2015
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
1 change: 1 addition & 0 deletions src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitStr<'a, P> {
type Item = &'a str;

#[inline]
#[allow(deprecated)]
fn next(&mut self) -> Option<&'a str> {
Iterator::next(&mut self.0)
}
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,11 @@ impl LintPass for Stability {
stability::check_path(cx.tcx, path, id,
&mut |id, sp, stab| self.lint(cx, id, sp, stab));
}

fn check_pat(&mut self, cx: &Context, pat: &ast::Pat) {
stability::check_pat(cx.tcx, pat,
&mut |id, sp, stab| self.lint(cx, id, sp, stab))
}
}

declare_lint! {
Expand Down
121 changes: 121 additions & 0 deletions src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ impl<'a> Annotator<'a> {
attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
F: FnOnce(&mut Annotator),
{
debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
match attr::find_stability(self.sess.diagnostic(), attrs, item_sp) {
Some(stab) => {
debug!("annotate: found {:?}", stab);
self.index.local.insert(id, stab.clone());

// Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
Expand All @@ -72,6 +74,8 @@ impl<'a> Annotator<'a> {
}
}
None => {
debug!("annotate: not found, use_parent = {:?}, parent = {:?}",
use_parent, self.parent);
if use_parent {
if let Some(stab) = self.parent.clone() {
self.index.local.insert(id, stab);
Expand Down Expand Up @@ -299,6 +303,12 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
&mut |id, sp, stab| self.check(id, sp, stab));
visit::walk_path(self, path)
}

fn visit_pat(&mut self, pat: &ast::Pat) {
check_pat(self.tcx, pat,
&mut |id, sp, stab| self.check(id, sp, stab));
visit::walk_pat(self, pat)
}
}

/// Helper for discovering nodes to check for stability
Expand Down Expand Up @@ -385,6 +395,76 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
None => return
}
}
ast::ExprField(ref base_e, ref field) => {
span = field.span;
match ty::expr_ty_adjusted(tcx, base_e).sty {
ty::ty_struct(did, _) => {
ty::lookup_struct_fields(tcx, did)
.iter()
.find(|f| f.name == field.node.name)
.unwrap_or_else(|| {
tcx.sess.span_bug(field.span,
"stability::check_expr: unknown named field access")
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this sort of lookup would be candidate for a good helper in middle::ty

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think how we handle structs in the compiler will be changing with #22564, so I'll leave it for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, this can wait then. r=me with patterns handled as well

.id
}
_ => tcx.sess.span_bug(e.span,
"stability::check_expr: named field access on non-struct")
}
}
ast::ExprTupField(ref base_e, ref field) => {
span = field.span;
match ty::expr_ty_adjusted(tcx, base_e).sty {
ty::ty_struct(did, _) => {
ty::lookup_struct_fields(tcx, did)
.get(field.node)
.unwrap_or_else(|| {
tcx.sess.span_bug(field.span,
"stability::check_expr: unknown unnamed field access")
})
.id
}
ty::ty_tup(..) => return,
_ => tcx.sess.span_bug(e.span,
"stability::check_expr: unnamed field access on \
something other than a tuple or struct")
}
}
ast::ExprStruct(_, ref expr_fields, _) => {
let type_ = ty::expr_ty(tcx, e);
match type_.sty {
ty::ty_struct(did, _) => {
let struct_fields = ty::lookup_struct_fields(tcx, did);
// check the stability of each field that appears
// in the construction expression.
for field in expr_fields {
let did = struct_fields
.iter()
.find(|f| f.name == field.ident.node.name)
.unwrap_or_else(|| {
tcx.sess.span_bug(field.span,
"stability::check_expr: unknown named \
field access")
})
.id;
maybe_do_stability_check(tcx, did, field.span, cb);
}

// we're done.
return
}
// we don't look at stability attributes on
// struct-like enums (yet...), but it's definitely not
// a bug to have construct one.
ty::ty_enum(..) => return,
_ => {
tcx.sess.span_bug(e.span,
&format!("stability::check_expr: struct construction \
of non-struct, type {:?}",
type_.repr(tcx)));
}
}
}
_ => return
};

Expand All @@ -403,6 +483,47 @@ pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,

}

pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
debug!("check_pat(pat = {:?})", pat);
if is_internal(tcx, pat.span) { return; }

let did = match ty::pat_ty_opt(tcx, pat) {
Some(&ty::TyS { sty: ty::ty_struct(did, _), .. }) => did,
Some(_) | None => return,
};
let struct_fields = ty::lookup_struct_fields(tcx, did);
match pat.node {
// Foo(a, b, c)
ast::PatEnum(_, Some(ref pat_fields)) => {
for (field, struct_field) in pat_fields.iter().zip(struct_fields.iter()) {
// a .. pattern is fine, but anything positional is
// not.
if let ast::PatWild(ast::PatWildMulti) = field.node {
continue
}
maybe_do_stability_check(tcx, struct_field.id, field.span, cb)
}
}
// Foo { a, b, c }
ast::PatStruct(_, ref pat_fields, _) => {
for field in pat_fields {
let did = struct_fields
.iter()
.find(|f| f.name == field.node.ident.name)
.unwrap_or_else(|| {
tcx.sess.span_bug(field.span,
"stability::check_pat: unknown named field access")
})
.id;
maybe_do_stability_check(tcx, did, field.span, cb);
}
}
// everything else is fine.
_ => {}
}
}

fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
if !is_staged_api(tcx, id) { return }
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4298,6 +4298,9 @@ pub fn free_region_from_def(outlives_extent: region::DestructionScopeData,
pub fn pat_ty<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Ty<'tcx> {
return node_id_to_type(cx, pat.id);
}
pub fn pat_ty_opt<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Option<Ty<'tcx>> {
return node_id_to_type_opt(cx, pat.id);
}


// Returns the type of an expression as a monotype.
Expand Down
10 changes: 10 additions & 0 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
ast::ItemEnum(ref def, _) if public_first => {
for variant in &def.variants {
self.exported_items.insert(variant.node.id);
self.public_items.insert(variant.node.id);
}
}

Expand Down Expand Up @@ -321,6 +322,15 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
Some(id) => { self.exported_items.insert(id); }
None => {}
}
// fields can be public or private, so lets check
for field in &def.fields {
let vis = match field.node.kind {
ast::NamedField(_, vis) | ast::UnnamedField(vis) => vis
};
if vis == ast::Public {
self.public_items.insert(field.node.id);
}
}
}

ast::ItemTy(ref ty, _) if public_first => {
Expand Down
1 change: 1 addition & 0 deletions src/libstd/old_io/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ impl MemWriter {

impl Writer for MemWriter {
#[inline]
#[allow(deprecated)]
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
self.buf.push_all(buf);
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/sync/mpsc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ impl<T> !Sync for SyncSender<T> {}
/// contains the data being sent as a payload so it can be recovered.
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct SendError<T>(pub T);
pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);

/// An error returned from the `recv` function on a `Receiver`.
///
Expand Down
2 changes: 2 additions & 0 deletions src/libstd/thread_local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,12 @@ pub struct Key<T> {
// This is trivially devirtualizable by LLVM because we never store anything
// to this field and rustc can declare the `static` as constant as well.
#[doc(hidden)]
#[unstable(feature = "thread_local_internals")]
pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,

// initialization routine to invoke to create a value
#[doc(hidden)]
#[unstable(feature = "thread_local_internals")]
pub init: fn() -> T,
}

Expand Down
24 changes: 16 additions & 8 deletions src/test/auxiliary/lint_stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,22 @@ pub trait UnstableTrait { fn dummy(&self) { } }

#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
pub struct DeprecatedStruct { pub i: int }
pub struct DeprecatedStruct {
#[stable(feature = "test_feature", since = "1.0.0")] pub i: int
}
#[unstable(feature = "test_feature")]
#[deprecated(since = "1.0.0")]
pub struct DeprecatedUnstableStruct { pub i: int }
pub struct DeprecatedUnstableStruct {
#[stable(feature = "test_feature", since = "1.0.0")] pub i: int
}
#[unstable(feature = "test_feature")]
pub struct UnstableStruct { pub i: int }
pub struct UnstableStruct {
#[stable(feature = "test_feature", since = "1.0.0")] pub i: int
}
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StableStruct { pub i: int }
pub struct StableStruct {
#[stable(feature = "test_feature", since = "1.0.0")] pub i: int
}

#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
Expand Down Expand Up @@ -137,14 +145,14 @@ pub enum Enum {

#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0")]
pub struct DeprecatedTupleStruct(pub int);
pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
#[unstable(feature = "test_feature")]
#[deprecated(since = "1.0.0")]
pub struct DeprecatedUnstableTupleStruct(pub int);
pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
#[unstable(feature = "test_feature")]
pub struct UnstableTupleStruct(pub int);
pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StableTupleStruct(pub int);
pub struct StableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);

#[macro_export]
macro_rules! macro_test {
Expand Down
60 changes: 60 additions & 0 deletions src/test/auxiliary/lint_stability_fields.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2015 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.

#![feature(staged_api)]
#![staged_api]
#![stable(feature = "rust1", since = "1.0.0")]

#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stable {
#[stable(feature = "rust1", since = "1.0.0")]
pub inherit: u8, // it's a lie (stable doesn't inherit)
#[unstable(feature = "test_feature")]
pub override1: u8,
#[deprecated(since = "1.0.0")]
#[unstable(feature = "test_feature")]
pub override2: u8,
}

#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stable2(#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "test_feature")] pub u8,
#[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8);

#[unstable(feature = "test_feature")]
pub struct Unstable {
pub inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
pub override1: u8,
#[deprecated(since = "1.0.0")]
#[unstable(feature = "test_feature")]
pub override2: u8,
}

#[unstable(feature = "test_feature")]
pub struct Unstable2(pub u8,
#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8);

#[unstable(feature = "test_feature")]
#[deprecated(feature = "rust1", since = "1.0.0")]
pub struct Deprecated {
pub inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
pub override1: u8,
#[unstable(feature = "test_feature")]
pub override2: u8,
}

#[unstable(feature = "test_feature")]
#[deprecated(feature = "rust1", since = "1.0.0")]
pub struct Deprecated2(pub u8,
#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "test_feature")] pub u8);
Loading