Skip to content

Commit 5d4e017

Browse files
committed
Rollup merge of rust-lang#22803 - huonw:field-stability, r=alexcrichton
We were recording stability attributes applied to fields in the compiler, and even annotating it in the libs, but the compiler didn't actually do the checks to give errors/warnings in user crates. Details in the commit messages.
2 parents bd0d8e4 + 060661d commit 5d4e017

File tree

12 files changed

+575
-12
lines changed

12 files changed

+575
-12
lines changed

src/libcore/str/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitStr<'a, P> {
939939
type Item = &'a str;
940940

941941
#[inline]
942+
#[allow(deprecated)]
942943
fn next(&mut self) -> Option<&'a str> {
943944
Iterator::next(&mut self.0)
944945
}

src/librustc/lint/builtin.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,11 @@ impl LintPass for Stability {
17711771
stability::check_path(cx.tcx, path, id,
17721772
&mut |id, sp, stab| self.lint(cx, id, sp, stab));
17731773
}
1774+
1775+
fn check_pat(&mut self, cx: &Context, pat: &ast::Pat) {
1776+
stability::check_pat(cx.tcx, pat,
1777+
&mut |id, sp, stab| self.lint(cx, id, sp, stab))
1778+
}
17741779
}
17751780

17761781
declare_lint! {

src/librustc/middle/stability.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ impl<'a> Annotator<'a> {
5858
attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
5959
F: FnOnce(&mut Annotator),
6060
{
61+
debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
6162
match attr::find_stability(self.sess.diagnostic(), attrs, item_sp) {
6263
Some(stab) => {
64+
debug!("annotate: found {:?}", stab);
6365
self.index.local.insert(id, stab.clone());
6466

6567
// Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
@@ -72,6 +74,8 @@ impl<'a> Annotator<'a> {
7274
}
7375
}
7476
None => {
77+
debug!("annotate: not found, use_parent = {:?}, parent = {:?}",
78+
use_parent, self.parent);
7579
if use_parent {
7680
if let Some(stab) = self.parent.clone() {
7781
self.index.local.insert(id, stab);
@@ -299,6 +303,12 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
299303
&mut |id, sp, stab| self.check(id, sp, stab));
300304
visit::walk_path(self, path)
301305
}
306+
307+
fn visit_pat(&mut self, pat: &ast::Pat) {
308+
check_pat(self.tcx, pat,
309+
&mut |id, sp, stab| self.check(id, sp, stab));
310+
visit::walk_pat(self, pat)
311+
}
302312
}
303313

304314
/// Helper for discovering nodes to check for stability
@@ -385,6 +395,76 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
385395
None => return
386396
}
387397
}
398+
ast::ExprField(ref base_e, ref field) => {
399+
span = field.span;
400+
match ty::expr_ty_adjusted(tcx, base_e).sty {
401+
ty::ty_struct(did, _) => {
402+
ty::lookup_struct_fields(tcx, did)
403+
.iter()
404+
.find(|f| f.name == field.node.name)
405+
.unwrap_or_else(|| {
406+
tcx.sess.span_bug(field.span,
407+
"stability::check_expr: unknown named field access")
408+
})
409+
.id
410+
}
411+
_ => tcx.sess.span_bug(e.span,
412+
"stability::check_expr: named field access on non-struct")
413+
}
414+
}
415+
ast::ExprTupField(ref base_e, ref field) => {
416+
span = field.span;
417+
match ty::expr_ty_adjusted(tcx, base_e).sty {
418+
ty::ty_struct(did, _) => {
419+
ty::lookup_struct_fields(tcx, did)
420+
.get(field.node)
421+
.unwrap_or_else(|| {
422+
tcx.sess.span_bug(field.span,
423+
"stability::check_expr: unknown unnamed field access")
424+
})
425+
.id
426+
}
427+
ty::ty_tup(..) => return,
428+
_ => tcx.sess.span_bug(e.span,
429+
"stability::check_expr: unnamed field access on \
430+
something other than a tuple or struct")
431+
}
432+
}
433+
ast::ExprStruct(_, ref expr_fields, _) => {
434+
let type_ = ty::expr_ty(tcx, e);
435+
match type_.sty {
436+
ty::ty_struct(did, _) => {
437+
let struct_fields = ty::lookup_struct_fields(tcx, did);
438+
// check the stability of each field that appears
439+
// in the construction expression.
440+
for field in expr_fields {
441+
let did = struct_fields
442+
.iter()
443+
.find(|f| f.name == field.ident.node.name)
444+
.unwrap_or_else(|| {
445+
tcx.sess.span_bug(field.span,
446+
"stability::check_expr: unknown named \
447+
field access")
448+
})
449+
.id;
450+
maybe_do_stability_check(tcx, did, field.span, cb);
451+
}
452+
453+
// we're done.
454+
return
455+
}
456+
// we don't look at stability attributes on
457+
// struct-like enums (yet...), but it's definitely not
458+
// a bug to have construct one.
459+
ty::ty_enum(..) => return,
460+
_ => {
461+
tcx.sess.span_bug(e.span,
462+
&format!("stability::check_expr: struct construction \
463+
of non-struct, type {:?}",
464+
type_.repr(tcx)));
465+
}
466+
}
467+
}
388468
_ => return
389469
};
390470

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

404484
}
405485

486+
pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
487+
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
488+
debug!("check_pat(pat = {:?})", pat);
489+
if is_internal(tcx, pat.span) { return; }
490+
491+
let did = match ty::pat_ty_opt(tcx, pat) {
492+
Some(&ty::TyS { sty: ty::ty_struct(did, _), .. }) => did,
493+
Some(_) | None => return,
494+
};
495+
let struct_fields = ty::lookup_struct_fields(tcx, did);
496+
match pat.node {
497+
// Foo(a, b, c)
498+
ast::PatEnum(_, Some(ref pat_fields)) => {
499+
for (field, struct_field) in pat_fields.iter().zip(struct_fields.iter()) {
500+
// a .. pattern is fine, but anything positional is
501+
// not.
502+
if let ast::PatWild(ast::PatWildMulti) = field.node {
503+
continue
504+
}
505+
maybe_do_stability_check(tcx, struct_field.id, field.span, cb)
506+
}
507+
}
508+
// Foo { a, b, c }
509+
ast::PatStruct(_, ref pat_fields, _) => {
510+
for field in pat_fields {
511+
let did = struct_fields
512+
.iter()
513+
.find(|f| f.name == field.node.ident.name)
514+
.unwrap_or_else(|| {
515+
tcx.sess.span_bug(field.span,
516+
"stability::check_pat: unknown named field access")
517+
})
518+
.id;
519+
maybe_do_stability_check(tcx, did, field.span, cb);
520+
}
521+
}
522+
// everything else is fine.
523+
_ => {}
524+
}
525+
}
526+
406527
fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
407528
cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
408529
if !is_staged_api(tcx, id) { return }

src/librustc/middle/ty.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4298,6 +4298,9 @@ pub fn free_region_from_def(outlives_extent: region::DestructionScopeData,
42984298
pub fn pat_ty<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Ty<'tcx> {
42994299
return node_id_to_type(cx, pat.id);
43004300
}
4301+
pub fn pat_ty_opt<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Option<Ty<'tcx>> {
4302+
return node_id_to_type_opt(cx, pat.id);
4303+
}
43014304

43024305

43034306
// Returns the type of an expression as a monotype.

src/librustc_privacy/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
233233
ast::ItemEnum(ref def, _) if public_first => {
234234
for variant in &def.variants {
235235
self.exported_items.insert(variant.node.id);
236+
self.public_items.insert(variant.node.id);
236237
}
237238
}
238239

@@ -321,6 +322,15 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
321322
Some(id) => { self.exported_items.insert(id); }
322323
None => {}
323324
}
325+
// fields can be public or private, so lets check
326+
for field in &def.fields {
327+
let vis = match field.node.kind {
328+
ast::NamedField(_, vis) | ast::UnnamedField(vis) => vis
329+
};
330+
if vis == ast::Public {
331+
self.public_items.insert(field.node.id);
332+
}
333+
}
324334
}
325335

326336
ast::ItemTy(ref ty, _) if public_first => {

src/libstd/old_io/mem.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ impl MemWriter {
102102

103103
impl Writer for MemWriter {
104104
#[inline]
105+
#[allow(deprecated)]
105106
fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
106107
self.buf.push_all(buf);
107108
Ok(())

src/libstd/sync/mpsc/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ impl<T> !Sync for SyncSender<T> {}
384384
/// contains the data being sent as a payload so it can be recovered.
385385
#[stable(feature = "rust1", since = "1.0.0")]
386386
#[derive(PartialEq, Eq, Clone, Copy)]
387-
pub struct SendError<T>(pub T);
387+
pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
388388

389389
/// An error returned from the `recv` function on a `Receiver`.
390390
///

src/libstd/thread_local/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,12 @@ pub struct Key<T> {
105105
// This is trivially devirtualizable by LLVM because we never store anything
106106
// to this field and rustc can declare the `static` as constant as well.
107107
#[doc(hidden)]
108+
#[unstable(feature = "thread_local_internals")]
108109
pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
109110

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

src/test/auxiliary/lint_stability.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,22 @@ pub trait UnstableTrait { fn dummy(&self) { } }
100100

101101
#[stable(feature = "test_feature", since = "1.0.0")]
102102
#[deprecated(since = "1.0.0")]
103-
pub struct DeprecatedStruct { pub i: int }
103+
pub struct DeprecatedStruct {
104+
#[stable(feature = "test_feature", since = "1.0.0")] pub i: int
105+
}
104106
#[unstable(feature = "test_feature")]
105107
#[deprecated(since = "1.0.0")]
106-
pub struct DeprecatedUnstableStruct { pub i: int }
108+
pub struct DeprecatedUnstableStruct {
109+
#[stable(feature = "test_feature", since = "1.0.0")] pub i: int
110+
}
107111
#[unstable(feature = "test_feature")]
108-
pub struct UnstableStruct { pub i: int }
112+
pub struct UnstableStruct {
113+
#[stable(feature = "test_feature", since = "1.0.0")] pub i: int
114+
}
109115
#[stable(feature = "rust1", since = "1.0.0")]
110-
pub struct StableStruct { pub i: int }
116+
pub struct StableStruct {
117+
#[stable(feature = "test_feature", since = "1.0.0")] pub i: int
118+
}
111119

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

138146
#[stable(feature = "test_feature", since = "1.0.0")]
139147
#[deprecated(since = "1.0.0")]
140-
pub struct DeprecatedTupleStruct(pub int);
148+
pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
141149
#[unstable(feature = "test_feature")]
142150
#[deprecated(since = "1.0.0")]
143-
pub struct DeprecatedUnstableTupleStruct(pub int);
151+
pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
144152
#[unstable(feature = "test_feature")]
145-
pub struct UnstableTupleStruct(pub int);
153+
pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
146154
#[stable(feature = "rust1", since = "1.0.0")]
147-
pub struct StableTupleStruct(pub int);
155+
pub struct StableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int);
148156

149157
#[macro_export]
150158
macro_rules! macro_test {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
#![feature(staged_api)]
12+
#![staged_api]
13+
#![stable(feature = "rust1", since = "1.0.0")]
14+
15+
#[stable(feature = "rust1", since = "1.0.0")]
16+
pub struct Stable {
17+
#[stable(feature = "rust1", since = "1.0.0")]
18+
pub inherit: u8, // it's a lie (stable doesn't inherit)
19+
#[unstable(feature = "test_feature")]
20+
pub override1: u8,
21+
#[deprecated(since = "1.0.0")]
22+
#[unstable(feature = "test_feature")]
23+
pub override2: u8,
24+
}
25+
26+
#[stable(feature = "rust1", since = "1.0.0")]
27+
pub struct Stable2(#[stable(feature = "rust1", since = "1.0.0")] pub u8,
28+
#[unstable(feature = "test_feature")] pub u8,
29+
#[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8);
30+
31+
#[unstable(feature = "test_feature")]
32+
pub struct Unstable {
33+
pub inherit: u8,
34+
#[stable(feature = "rust1", since = "1.0.0")]
35+
pub override1: u8,
36+
#[deprecated(since = "1.0.0")]
37+
#[unstable(feature = "test_feature")]
38+
pub override2: u8,
39+
}
40+
41+
#[unstable(feature = "test_feature")]
42+
pub struct Unstable2(pub u8,
43+
#[stable(feature = "rust1", since = "1.0.0")] pub u8,
44+
#[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8);
45+
46+
#[unstable(feature = "test_feature")]
47+
#[deprecated(feature = "rust1", since = "1.0.0")]
48+
pub struct Deprecated {
49+
pub inherit: u8,
50+
#[stable(feature = "rust1", since = "1.0.0")]
51+
pub override1: u8,
52+
#[unstable(feature = "test_feature")]
53+
pub override2: u8,
54+
}
55+
56+
#[unstable(feature = "test_feature")]
57+
#[deprecated(feature = "rust1", since = "1.0.0")]
58+
pub struct Deprecated2(pub u8,
59+
#[stable(feature = "rust1", since = "1.0.0")] pub u8,
60+
#[unstable(feature = "test_feature")] pub u8);

0 commit comments

Comments
 (0)