Skip to content

Commit 99f629a

Browse files
committed
rustc: Add a new -Z force-unstable-if-unmarked flag
This commit adds a new `-Z` flag to the compiler for use when bootstrapping the compiler itself. We want to be able to use crates.io crates, but we also want the usage of such crates to be as ergonomic as possible! To that end compiler crates are a little tricky in that the crates.io crates are not annotated as unstable, nor do they expect to pull in unstable dependencies. To cover all these situations it's intended that the compiler will forever now bootstrap with `-Z force-unstable-if-unmarked`. This flags serves a dual purpose of forcing crates.io crates to themselves be unstable while also allowing them to use other "unstable" crates.io crates. This should mean that adding a dependency to compiler no longer requires upstream modification with unstable/staged_api attributes for inclusion!
1 parent 25a1617 commit 99f629a

File tree

7 files changed

+62
-41
lines changed

7 files changed

+62
-41
lines changed

src/librustc/middle/cstore.rs

-2
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,6 @@ pub trait CrateStore {
239239
fn export_macros(&self, cnum: CrateNum);
240240
fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>;
241241
fn missing_lang_items(&self, cnum: CrateNum) -> Vec<lang_items::LangItem>;
242-
fn is_staged_api(&self, cnum: CrateNum) -> bool;
243242
fn is_allocator(&self, cnum: CrateNum) -> bool;
244243
fn is_panic_runtime(&self, cnum: CrateNum) -> bool;
245244
fn is_compiler_builtins(&self, cnum: CrateNum) -> bool;
@@ -368,7 +367,6 @@ impl CrateStore for DummyCrateStore {
368367
{ bug!("lang_items") }
369368
fn missing_lang_items(&self, cnum: CrateNum) -> Vec<lang_items::LangItem>
370369
{ bug!("missing_lang_items") }
371-
fn is_staged_api(&self, cnum: CrateNum) -> bool { bug!("is_staged_api") }
372370
fn dep_kind(&self, cnum: CrateNum) -> DepKind { bug!("is_explicitly_linked") }
373371
fn export_macros(&self, cnum: CrateNum) { bug!("export_macros") }
374372
fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") }

src/librustc/middle/stability.rs

+58-23
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
1414
pub use self::StabilityLevel::*;
1515

16-
use hir::map as hir_map;
1716
use lint;
1817
use hir::def::Def;
1918
use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, LOCAL_CRATE};
2019
use ty::{self, TyCtxt};
2120
use middle::privacy::AccessLevels;
21+
use session::Session;
2222
use syntax::symbol::Symbol;
2323
use syntax_pos::{Span, DUMMY_SP};
2424
use syntax::ast;
@@ -123,7 +123,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
123123
item_sp: Span, kind: AnnotationKind, visit_children: F)
124124
where F: FnOnce(&mut Self)
125125
{
126-
if self.index.staged_api[&LOCAL_CRATE] && self.tcx.sess.features.borrow().staged_api {
126+
if self.index.staged_api[&LOCAL_CRATE] {
127127
debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
128128
if let Some(..) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) {
129129
self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged api, \
@@ -390,20 +390,36 @@ impl<'a, 'tcx> Index<'tcx> {
390390
parent_depr: None,
391391
in_trait_impl: false,
392392
};
393+
394+
// If the `-Z force-unstable-if-unmarked` flag is passed then we provide
395+
// a parent stability annotation which indicates that this is private
396+
// with the `rustc_private` feature. This is intended for use when
397+
// compiling librustc crates themselves so we can leverage crates.io
398+
// while maintaining the invariant that all sysroot crates are unstable
399+
// by default and are unable to be used.
400+
if tcx.sess.opts.debugging_opts.force_unstable_if_unmarked {
401+
let reason = "this crate is being loaded from the sysroot, and \
402+
unstable location; did you mean to load this crate \
403+
from crates.io via `Cargo.toml` instead?";
404+
let stability = tcx.intern_stability(Stability {
405+
level: attr::StabilityLevel::Unstable {
406+
reason: Some(Symbol::intern(reason)),
407+
issue: 27812,
408+
},
409+
feature: Symbol::intern("rustc_private"),
410+
rustc_depr: None,
411+
});
412+
annotator.parent_stab = Some(stability);
413+
}
414+
393415
annotator.annotate(ast::CRATE_NODE_ID, &krate.attrs, krate.span, AnnotationKind::Required,
394416
|v| intravisit::walk_crate(v, krate));
395417
}
396418

397-
pub fn new(hir_map: &hir_map::Map) -> Index<'tcx> {
398-
let krate = hir_map.krate();
399-
400-
let mut is_staged_api = false;
401-
for attr in &krate.attrs {
402-
if attr.path == "stable" || attr.path == "unstable" {
403-
is_staged_api = true;
404-
break
405-
}
406-
}
419+
pub fn new(sess: &Session) -> Index<'tcx> {
420+
let is_staged_api =
421+
sess.opts.debugging_opts.force_unstable_if_unmarked ||
422+
sess.features.borrow().staged_api;
407423

408424
let mut staged_api = FxHashMap();
409425
staged_api.insert(LOCAL_CRATE, is_staged_api);
@@ -496,8 +512,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
496512
}
497513
}
498514

499-
let is_staged_api = *self.stability.borrow_mut().staged_api.entry(def_id.krate)
500-
.or_insert_with(|| self.sess.cstore.is_staged_api(def_id.krate));
515+
let is_staged_api = self.lookup_stability(DefId {
516+
index: CRATE_DEF_INDEX,
517+
..def_id
518+
}).is_some();
501519
if !is_staged_api {
502520
return;
503521
}
@@ -530,15 +548,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
530548

531549
match stability {
532550
Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => {
533-
if !self.stability.borrow().active_features.contains(feature) {
534-
let msg = match *reason {
535-
Some(ref r) => format!("use of unstable library feature '{}': {}",
536-
feature.as_str(), &r),
537-
None => format!("use of unstable library feature '{}'", &feature)
538-
};
539-
emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span,
540-
GateIssue::Library(Some(issue)), &msg);
551+
if self.stability.borrow().active_features.contains(feature) {
552+
return
541553
}
554+
555+
// When we're compiling the compiler itself we may pull in
556+
// crates from crates.io, but those crates may depend on other
557+
// crates also pulled in from crates.io. We want to ideally be
558+
// able to compile everything without requiring upstream
559+
// modifications, so in the case that this looks like a
560+
// rustc_private crate (e.g. a compiler crate) and we also have
561+
// the `-Z force-unstable-if-unmarked` flag present (we're
562+
// compiling a compiler crate), then let this missing feature
563+
// annotation slide.
564+
if *feature == "rustc_private" && issue == 27812 {
565+
if self.sess.opts.debugging_opts.force_unstable_if_unmarked {
566+
return
567+
}
568+
}
569+
570+
let msg = match *reason {
571+
Some(ref r) => format!("use of unstable library feature '{}': {}",
572+
feature.as_str(), &r),
573+
None => format!("use of unstable library feature '{}'", &feature)
574+
};
575+
emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span,
576+
GateIssue::Library(Some(issue)), &msg);
542577
}
543578
Some(_) => {
544579
// Stable APIs are always ok to call and deprecated APIs are
@@ -658,7 +693,7 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
658693

659694
let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
660695

661-
if tcx.stability.borrow().staged_api[&LOCAL_CRATE] && tcx.sess.features.borrow().staged_api {
696+
if tcx.stability.borrow().staged_api[&LOCAL_CRATE] {
662697
let krate = tcx.hir.krate();
663698
let mut missing = MissingStabilityAnnotations {
664699
tcx: tcx,

src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
10271027
"add a source pattern to the file path remapping config"),
10281028
remap_path_prefix_to: Vec<String> = (vec![], parse_string_push, [TRACKED],
10291029
"add a mapping target to the file path remapping config"),
1030+
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1031+
"force all crates to be `rustc_private` unstable"),
10301032
}
10311033

10321034
pub fn default_lib_output() -> CrateType {

src/librustc_driver/driver.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
882882
"static item recursion checking",
883883
|| static_recursion::check_crate(sess, &hir_map))?;
884884

885-
let index = stability::Index::new(&hir_map);
885+
let index = stability::Index::new(&sess);
886886

887887
let mut local_providers = ty::maps::Providers::default();
888888
borrowck::provide(&mut local_providers);

src/librustc_driver/test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ fn test_env<F>(source_string: &str,
138138
// run just enough stuff to build a tcx:
139139
let lang_items = lang_items::collect_language_items(&sess, &hir_map);
140140
let named_region_map = resolve_lifetime::krate(&sess, &hir_map);
141-
let index = stability::Index::new(&hir_map);
141+
let index = stability::Index::new(&sess);
142142
TyCtxt::create_and_enter(&sess,
143143
ty::maps::Providers::default(),
144144
ty::maps::Providers::default(),

src/librustc_metadata/cstore.rs

-9
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,6 @@ impl CrateMetadata {
269269
self.root.disambiguator
270270
}
271271

272-
pub fn is_staged_api(&self, dep_graph: &DepGraph) -> bool {
273-
for attr in self.get_item_attrs(CRATE_DEF_INDEX, dep_graph).iter() {
274-
if attr.path == "stable" || attr.path == "unstable" {
275-
return true;
276-
}
277-
}
278-
false
279-
}
280-
281272
pub fn is_allocator(&self, dep_graph: &DepGraph) -> bool {
282273
let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph);
283274
attr::contains_name(&attrs, "allocator")

src/librustc_metadata/cstore_impl.rs

-5
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,6 @@ impl CrateStore for cstore::CStore {
267267
self.get_crate_data(cnum).get_missing_lang_items(&self.dep_graph)
268268
}
269269

270-
fn is_staged_api(&self, cnum: CrateNum) -> bool
271-
{
272-
self.get_crate_data(cnum).is_staged_api(&self.dep_graph)
273-
}
274-
275270
fn is_allocator(&self, cnum: CrateNum) -> bool
276271
{
277272
self.get_crate_data(cnum).is_allocator(&self.dep_graph)

0 commit comments

Comments
 (0)