Skip to content

Commit d0029a4

Browse files
committed
rollup merge of rust-lang#21910: Manishearth/missing_stability
Currently, if a `#![staged_api]` crate contains an exported item without a stability marker (or inherited stability), the item is useless. This change introduces a check to ensure that all exported items have a defined stability. it also introduces the `unmarked_api` feature, which lets users import unmarked features. While this PR should in theory forbid these from existing, in practice we can't be so sure; so this lets users bypass this check instead of having to wait for the library and/or compiler to be fixed (since otherwise this is a hard error). r? @aturon
2 parents 9db593c + a5ddacf commit d0029a4

File tree

9 files changed

+114
-75
lines changed

9 files changed

+114
-75
lines changed

src/doc/reference.md

+7
Original file line numberDiff line numberDiff line change
@@ -2432,6 +2432,8 @@ The currently implemented features of the reference compiler are:
24322432
* `simd` - Allows use of the `#[simd]` attribute, which is overly simple and
24332433
not the SIMD interface we want to expose in the long term.
24342434

2435+
* `staged_api` - Allows usage of stability markers and `#![staged_api]` in a crate
2436+
24352437
* `struct_inherit` - Allows using struct inheritance, which is barely
24362438
implemented and will probably be removed. Don't use this.
24372439

@@ -2459,6 +2461,11 @@ The currently implemented features of the reference compiler are:
24592461
which is considered wildly unsafe and will be
24602462
obsoleted by language improvements.
24612463

2464+
* `unmarked_api` - Allows use of items within a `#![staged_api]` crate
2465+
which have not been marked with a stability marker.
2466+
Such items should not be allowed by the compiler to exist,
2467+
so if you need this there probably is a compiler bug.
2468+
24622469
* `associated_types` - Allows type aliases in traits. Experimental.
24632470

24642471
If a feature is promoted to a language feature, then all existing programs will

src/librustc/middle/stability.rs

+57-28
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use session::Session;
1515
use lint;
1616
use middle::ty;
17+
use middle::privacy::PublicItems;
1718
use metadata::csearch;
1819
use syntax::parse::token::InternedString;
1920
use syntax::codemap::{Span, DUMMY_SP};
@@ -44,15 +45,16 @@ pub struct Index {
4445
// A private tree-walker for producing an Index.
4546
struct Annotator<'a> {
4647
sess: &'a Session,
47-
index: Index,
48-
parent: Option<Stability>
48+
index: &'a mut Index,
49+
parent: Option<Stability>,
50+
export_map: &'a PublicItems,
4951
}
5052

5153
impl<'a> Annotator<'a> {
5254
// Determine the stability for a node based on its attributes and inherited
5355
// stability. The stability is recorded in the index and used as the parent.
5456
fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
55-
attrs: &Vec<Attribute>, item_sp: Span, f: F) where
57+
attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
5658
F: FnOnce(&mut Annotator),
5759
{
5860
match attr::find_stability(self.sess.diagnostic(), attrs.as_slice(), item_sp) {
@@ -70,7 +72,14 @@ impl<'a> Annotator<'a> {
7072
}
7173
None => {
7274
if use_parent {
73-
self.parent.clone().map(|stab| self.index.local.insert(id, stab));
75+
if let Some(stab) = self.parent.clone() {
76+
self.index.local.insert(id, stab);
77+
} else if self.index.staged_api && required
78+
&& self.export_map.contains(&id)
79+
&& !self.sess.opts.test {
80+
self.sess.span_err(item_sp,
81+
"This node does not have a stability attribute");
82+
}
7483
}
7584
f(self);
7685
}
@@ -93,11 +102,19 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
93102
_ => true,
94103
};
95104

96-
self.annotate(i.id, use_parent, &i.attrs, i.span, |v| visit::walk_item(v, i));
105+
// In case of a `pub use <mod>;`, we should not error since the stability
106+
// is inherited from the module itself
107+
let required = match i.node {
108+
ast::ItemUse(_) => i.vis != ast::Public,
109+
_ => true
110+
};
111+
112+
self.annotate(i.id, use_parent, &i.attrs, i.span,
113+
|v| visit::walk_item(v, i), required);
97114

98115
if let ast::ItemStruct(ref sd, _) = i.node {
99116
sd.ctor_id.map(|id| {
100-
self.annotate(id, true, &i.attrs, i.span, |_| {})
117+
self.annotate(id, true, &i.attrs, i.span, |_| {}, true)
101118
});
102119
}
103120
}
@@ -106,7 +123,7 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
106123
_: &'v Block, sp: Span, _: NodeId) {
107124
if let FkMethod(_, _, meth) = fk {
108125
// Methods are not already annotated, so we annotate it
109-
self.annotate(meth.id, true, &meth.attrs, sp, |_| {});
126+
self.annotate(meth.id, true, &meth.attrs, sp, |_| {}, true);
110127
}
111128
// Items defined in a function body have no reason to have
112129
// a stability attribute, so we don't recurse.
@@ -126,27 +143,41 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> {
126143
TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs,
127144
typedef.ty_param.span),
128145
};
129-
self.annotate(id, true, attrs, sp, |v| visit::walk_trait_item(v, t));
146+
self.annotate(id, true, attrs, sp, |v| visit::walk_trait_item(v, t), true);
130147
}
131148

132149
fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
133150
self.annotate(var.node.id, true, &var.node.attrs, var.span,
134-
|v| visit::walk_variant(v, var, g))
151+
|v| visit::walk_variant(v, var, g), true)
135152
}
136153

137154
fn visit_struct_field(&mut self, s: &StructField) {
138155
self.annotate(s.node.id, true, &s.node.attrs, s.span,
139-
|v| visit::walk_struct_field(v, s));
156+
|v| visit::walk_struct_field(v, s), true);
140157
}
141158

142159
fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
143-
self.annotate(i.id, true, &i.attrs, i.span, |_| {});
160+
self.annotate(i.id, true, &i.attrs, i.span, |_| {}, true);
144161
}
145162
}
146163

147164
impl Index {
148165
/// Construct the stability index for a crate being compiled.
149-
pub fn build(sess: &Session, krate: &Crate) -> Index {
166+
pub fn build(&mut self, sess: &Session, krate: &Crate, export_map: &PublicItems) {
167+
if !self.staged_api {
168+
return;
169+
}
170+
let mut annotator = Annotator {
171+
sess: sess,
172+
index: self,
173+
parent: None,
174+
export_map: export_map,
175+
};
176+
annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs, krate.span,
177+
|v| visit::walk_crate(v, krate), true);
178+
}
179+
180+
pub fn new(krate: &Crate) -> Index {
150181
let mut staged_api = false;
151182
for attr in &krate.attrs {
152183
if attr.name().get() == "staged_api" {
@@ -159,22 +190,11 @@ impl Index {
159190
}
160191
}
161192
}
162-
let index = Index {
193+
Index {
163194
staged_api: staged_api,
164195
local: NodeMap(),
165196
extern_cache: DefIdMap()
166-
};
167-
if !staged_api {
168-
return index;
169197
}
170-
let mut annotator = Annotator {
171-
sess: sess,
172-
index: index,
173-
parent: None
174-
};
175-
annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs, krate.span,
176-
|v| visit::walk_crate(v, krate));
177-
annotator.index
178198
}
179199
}
180200

@@ -234,10 +254,19 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
234254
None => {
235255
// This is an 'unmarked' API, which should not exist
236256
// in the standard library.
237-
self.tcx.sess.span_err(span, "use of unmarked library feature");
238-
self.tcx.sess.span_note(span, "this is either a bug in the library you are \
239-
using or a bug in the compiler - there is \
240-
no way to use this feature");
257+
if self.tcx.sess.features.borrow().unmarked_api {
258+
self.tcx.sess.span_warn(span, "use of unmarked library feature");
259+
self.tcx.sess.span_note(span, "this is either a bug in the library you are \
260+
using and a bug in the compiler - please \
261+
report it in both places");
262+
} else {
263+
self.tcx.sess.span_err(span, "use of unmarked library feature");
264+
self.tcx.sess.span_note(span, "this is either a bug in the library you are \
265+
using and a bug in the compiler - please \
266+
report it in both places");
267+
self.tcx.sess.span_note(span, "use #![feature(unmarked_api)] in the \
268+
crate attributes to override this");
269+
}
241270
}
242271
}
243272
}

src/librustc_driver/driver.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -594,9 +594,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
594594
time(time_passes, "loop checking", (), |_|
595595
middle::check_loop::check_crate(&sess, krate));
596596

597-
let stability_index = time(time_passes, "stability index", (), |_|
598-
stability::Index::build(&sess, krate));
599-
600597
time(time_passes, "static item recursion checking", (), |_|
601598
middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
602599

@@ -608,7 +605,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
608605
freevars,
609606
region_map,
610607
lang_items,
611-
stability_index);
608+
stability::Index::new(krate));
612609

613610
// passes are timed inside typeck
614611
typeck::check_crate(&ty_cx, trait_map);
@@ -628,6 +625,10 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
628625
time(time_passes, "privacy checking", maps, |(a, b)|
629626
rustc_privacy::check_crate(&ty_cx, &export_map, a, b));
630627

628+
// Do not move this check past lint
629+
time(time_passes, "stability index", (), |_|
630+
ty_cx.stability.borrow_mut().build(&ty_cx.sess, krate, &public_items));
631+
631632
time(time_passes, "intrinsic checking", (), |_|
632633
middle::intrinsicck::check_crate(&ty_cx));
633634

src/librustc_driver/test.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ fn test_env<F>(source_string: &str,
125125
resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
126126
let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
127127
let region_map = region::resolve_crate(&sess, krate);
128-
let stability_index = stability::Index::build(&sess, krate);
129128
let tcx = ty::mk_ctxt(sess,
130129
&arenas,
131130
def_map,
@@ -134,7 +133,7 @@ fn test_env<F>(source_string: &str,
134133
freevars,
135134
region_map,
136135
lang_items,
137-
stability_index);
136+
stability::Index::new(krate));
138137
let infcx = infer::new_infer_ctxt(&tcx);
139138
body(Env { infcx: &infcx });
140139
infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID);

src/libstd/thread_local/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub mod scoped;
4545

4646
// Sure wish we had macro hygiene, no?
4747
#[doc(hidden)]
48+
#[stable(feature = "rust1", since = "1.0.0")]
4849
pub mod __impl {
4950
pub use super::imp::Key as KeyInner;
5051
pub use super::imp::destroy_value;

src/libsyntax/feature_gate.rs

+6
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
119119

120120
// Allows use of #[staged_api]
121121
("staged_api", "1.0.0", Active),
122+
123+
// Allows using items which are missing stability attributes
124+
("unmarked_api", "1.0.0", Active)
122125
];
123126

124127
enum Status {
@@ -145,6 +148,7 @@ pub struct Features {
145148
pub quote: bool,
146149
pub old_orphan_check: bool,
147150
pub simd_ffi: bool,
151+
pub unmarked_api: bool,
148152
pub lib_features: Vec<(InternedString, Span)>
149153
}
150154

@@ -157,6 +161,7 @@ impl Features {
157161
quote: false,
158162
old_orphan_check: false,
159163
simd_ffi: false,
164+
unmarked_api: false,
160165
lib_features: Vec::new()
161166
}
162167
}
@@ -566,6 +571,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
566571
quote: cx.has_feature("quote"),
567572
old_orphan_check: cx.has_feature("old_orphan_check"),
568573
simd_ffi: cx.has_feature("simd_ffi"),
574+
unmarked_api: cx.has_feature("unmarked_api"),
569575
lib_features: unknown_features
570576
}
571577
}

src/test/auxiliary/lint_stability.rs

+3-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#![crate_type = "lib"]
1212
#![feature(staged_api)]
1313
#![staged_api]
14+
#![stable(feature = "lint_stability", since = "1.0.0")]
1415

1516
#[stable(feature = "test_feature", since = "1.0.0")]
1617
#[deprecated(since = "1.0.0")]
@@ -31,8 +32,6 @@ pub fn unstable() {}
3132
#[unstable(feature = "test_feature", reason = "text")]
3233
pub fn unstable_text() {}
3334

34-
pub fn unmarked() {}
35-
3635
#[stable(feature = "rust1", since = "1.0.0")]
3736
pub fn stable() {}
3837
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -61,8 +60,6 @@ impl MethodTester {
6160
#[unstable(feature = "test_feature", reason = "text")]
6261
pub fn method_unstable_text(&self) {}
6362

64-
pub fn method_unmarked(&self) {}
65-
6663
#[stable(feature = "rust1", since = "1.0.0")]
6764
pub fn method_stable(&self) {}
6865
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -79,6 +76,7 @@ impl MethodTester {
7976
pub fn method_frozen_text(&self) {}
8077
}
8178

79+
#[stable(feature = "test_feature", since = "1.0.0")]
8280
pub trait Trait {
8381
#[stable(feature = "test_feature", since = "1.0.0")]
8482
#[deprecated(since = "1.0.0")]
@@ -99,8 +97,6 @@ pub trait Trait {
9997
#[unstable(feature = "test_feature", reason = "text")]
10098
fn trait_unstable_text(&self) {}
10199

102-
fn trait_unmarked(&self) {}
103-
104100
#[stable(feature = "rust1", since = "1.0.0")]
105101
fn trait_stable(&self) {}
106102
#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -130,7 +126,6 @@ pub struct DeprecatedStruct { pub i: int }
130126
pub struct DeprecatedUnstableStruct { pub i: int }
131127
#[unstable(feature = "test_feature")]
132128
pub struct UnstableStruct { pub i: int }
133-
pub struct UnmarkedStruct { pub i: int }
134129
#[stable(feature = "rust1", since = "1.0.0")]
135130
pub struct StableStruct { pub i: int }
136131

@@ -142,10 +137,10 @@ pub struct DeprecatedUnitStruct;
142137
pub struct DeprecatedUnstableUnitStruct;
143138
#[unstable(feature = "test_feature")]
144139
pub struct UnstableUnitStruct;
145-
pub struct UnmarkedUnitStruct;
146140
#[stable(feature = "rust1", since = "1.0.0")]
147141
pub struct StableUnitStruct;
148142

143+
#[stable(feature = "test_feature", since = "1.0.0")]
149144
pub enum Enum {
150145
#[stable(feature = "test_feature", since = "1.0.0")]
151146
#[deprecated(since = "1.0.0")]
@@ -156,7 +151,6 @@ pub enum Enum {
156151
#[unstable(feature = "test_feature")]
157152
UnstableVariant,
158153

159-
UnmarkedVariant,
160154
#[stable(feature = "rust1", since = "1.0.0")]
161155
StableVariant,
162156
}
@@ -169,7 +163,6 @@ pub struct DeprecatedTupleStruct(pub int);
169163
pub struct DeprecatedUnstableTupleStruct(pub int);
170164
#[unstable(feature = "test_feature")]
171165
pub struct UnstableTupleStruct(pub int);
172-
pub struct UnmarkedTupleStruct(pub int);
173166
#[stable(feature = "rust1", since = "1.0.0")]
174167
pub struct StableTupleStruct(pub int);
175168

0 commit comments

Comments
 (0)