Skip to content

Commit 37c9dc8

Browse files
committed
Auto merge of #52355 - pietroalbini:zfeature, r=<try>
Add the -Zfeature=foo unstable rustc option This PR adds a new unstable option to `rustc`: `-Zfeature=foo`. The option can be used to enable nightly features from the CLI, and it's meant to be used by tools like Crater to try enabling features without changing the crate's source code. The exact reason I need this is to implement "edition runs" in Crater: we need to add the preview feature flag to every crate, and editing the crates' source code on the fly might produce unexpected results, while a compiler flag is more reliable. Obviously this won't be stabilized in the future. cc rust-lang/crater#282 @Mark-Simulacrum
2 parents 5ba2184 + bce31ea commit 37c9dc8

File tree

5 files changed

+89
-46
lines changed

5 files changed

+89
-46
lines changed

Diff for: src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
13511351
"generate build artifacts that are compatible with linker-based LTO."),
13521352
no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
13531353
"don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1354+
feature: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1355+
"enable the provided nightly feature (can be used multiple times)"),
13541356
}
13551357

13561358
pub fn default_lib_output() -> CrateType {

Diff for: src/librustc_driver/driver.rs

+1
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ where
812812
let (mut krate, features) = syntax::config::features(
813813
krate,
814814
&sess.parse_sess,
815+
&sess.opts.debugging_opts.feature,
815816
sess.opts.test,
816817
sess.edition(),
817818
);

Diff for: src/libsyntax/config.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ pub struct StripUnconfigured<'a> {
2727
}
2828

2929
// `cfg_attr`-process the crate's attributes and compute the crate's features.
30-
pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool, edition: Edition)
31-
-> (ast::Crate, Features) {
30+
pub fn features(mut krate: ast::Crate, sess: &ParseSess, z_features: &[String], should_test: bool,
31+
edition: Edition) -> (ast::Crate, Features) {
3232
let features;
3333
{
3434
let mut strip_unconfigured = StripUnconfigured {
@@ -47,7 +47,7 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool, edit
4747
return (krate, Features::new());
4848
}
4949

50-
features = get_features(&sess.span_diagnostic, &krate.attrs, edition);
50+
features = get_features(&sess.span_diagnostic, &krate.attrs, &z_features, edition);
5151

5252
// Avoid reconfiguring malformed `cfg_attr`s
5353
if err_count == sess.span_diagnostic.err_count() {

Diff for: src/libsyntax/feature_gate.rs

+62-43
Original file line numberDiff line numberDiff line change
@@ -1874,16 +1874,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
18741874
}
18751875
}
18761876

1877-
pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
1877+
pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], z_features: &[String],
18781878
crate_edition: Edition) -> Features {
1879-
fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
1880-
let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
1881-
if let Some(reason) = reason {
1882-
err.span_note(span, reason);
1883-
}
1884-
err.emit();
1885-
}
1886-
18871879
let mut features = Features::new();
18881880

18891881
let mut feature_checker = FeatureChecker::default();
@@ -1919,49 +1911,76 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
19191911
continue
19201912
};
19211913

1922-
if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
1923-
set(&mut features, mi.span);
1924-
feature_checker.collect(&features, mi.span);
1925-
continue
1926-
}
1927-
1928-
let removed = REMOVED_FEATURES.iter().find(|f| name == f.0);
1929-
let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0);
1930-
if let Some((.., reason)) = removed.or(stable_removed) {
1931-
feature_removed(span_handler, mi.span, *reason);
1932-
continue
1933-
}
1914+
set_feature(
1915+
name,
1916+
mi.span,
1917+
span_handler,
1918+
&mut features,
1919+
&mut feature_checker,
1920+
crate_edition,
1921+
);
1922+
}
1923+
}
19341924

1935-
if ACCEPTED_FEATURES.iter().any(|f| name == f.0) {
1936-
features.declared_stable_lang_features.push((name, mi.span));
1937-
continue
1938-
}
1925+
for z_feature in z_features {
1926+
set_feature(
1927+
Symbol::intern(&z_feature),
1928+
DUMMY_SP,
1929+
span_handler,
1930+
&mut features,
1931+
&mut feature_checker,
1932+
crate_edition,
1933+
);
1934+
}
19391935

1940-
if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
1941-
if *edition <= crate_edition {
1942-
continue
1943-
}
1936+
feature_checker.check(span_handler);
19441937

1945-
for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
1946-
if let Some(f_edition) = f_edition {
1947-
if *edition >= f_edition {
1948-
// FIXME(Manishearth) there is currently no way to set
1949-
// lib features by edition
1950-
set(&mut features, DUMMY_SP);
1951-
}
1952-
}
1953-
}
1938+
features
1939+
}
19541940

1955-
continue
1956-
}
1941+
fn set_feature(name: Symbol, span: Span, span_handler: &Handler, features: &mut Features,
1942+
feature_checker: &mut FeatureChecker, crate_edition: Edition) {
1943+
if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
1944+
set(features, span);
1945+
feature_checker.collect(&features, span);
1946+
return;
1947+
}
19571948

1958-
features.declared_lib_features.push((name, mi.span));
1949+
let removed = REMOVED_FEATURES.iter().find(|f| name == f.0);
1950+
let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0);
1951+
if let Some((.., reason)) = removed.or(stable_removed) {
1952+
let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
1953+
if let Some(reason) = reason {
1954+
err.span_note(span, reason);
19591955
}
1956+
err.emit();
1957+
return;
19601958
}
19611959

1962-
feature_checker.check(span_handler);
1960+
if ACCEPTED_FEATURES.iter().any(|f| name == f.0) {
1961+
features.declared_stable_lang_features.push((name, span));
1962+
return;
1963+
}
19631964

1964-
features
1965+
if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
1966+
if *edition <= crate_edition {
1967+
return;
1968+
}
1969+
1970+
for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
1971+
if let Some(f_edition) = f_edition {
1972+
if *edition >= f_edition {
1973+
// FIXME(Manishearth) there is currently no way to set
1974+
// lib features by edition
1975+
set(features, DUMMY_SP);
1976+
}
1977+
}
1978+
}
1979+
1980+
return;
1981+
}
1982+
1983+
features.declared_lib_features.push((name, span));
19651984
}
19661985

19671986
/// A collector for mutually exclusive and interdependent features and their flag spans.

Diff for: src/test/run-pass/z-feature.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2018 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+
// This test checks if an unstable feature is enabled with the -Zfeature=foo
12+
// flag. If the exact feature used here is causing problems feel free to
13+
// replace it with another perma-unstable feature.
14+
15+
// compile-flags: -Zfeature=abi_unadjusted
16+
17+
#![allow(dead_code)]
18+
19+
extern "unadjusted" fn foo() {}
20+
21+
fn main() {}

0 commit comments

Comments
 (0)