Skip to content

Commit 076be4d

Browse files
authored
Rollup merge of #59169 - tmandry:allow-features-flag, r=cramertj
Add `-Z allow_features=...` flag Adds a compiler option to allow only whitelisted features. For projects on nightly that want to prevent feature-creep (and maybe, someday, move off of nightly). Not being able to enforce this has been a problem on Fuchsia and at other big companies. This doesn't support filtering edition feature flags, but someone is welcome to add that if they need it.
2 parents 14ba4d5 + 7c59ce9 commit 076be4d

File tree

9 files changed

+98
-4
lines changed

9 files changed

+98
-4
lines changed

src/librustc/session/config.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,7 @@ macro_rules! options {
800800
pub const parse_opt_pathbuf: Option<&str> = Some("a path");
801801
pub const parse_list: Option<&str> = Some("a space-separated list of strings");
802802
pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
803+
pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
803804
pub const parse_uint: Option<&str> = Some("a number");
804805
pub const parse_passes: Option<&str> =
805806
Some("a space-separated list of passes, or `all`");
@@ -926,6 +927,18 @@ macro_rules! options {
926927
}
927928
}
928929

930+
fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
931+
-> bool {
932+
match v {
933+
Some(s) => {
934+
let v = s.split(',').map(|s| s.to_string()).collect();
935+
*slot = Some(v);
936+
true
937+
},
938+
None => false,
939+
}
940+
}
941+
929942
fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
930943
match v.and_then(|s| s.parse().ok()) {
931944
Some(i) => { *slot = i; true },
@@ -1427,6 +1440,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
14271440
merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
14281441
"control the operation of the MergeFunctions LLVM pass, taking
14291442
the same values as the target option of the same name"),
1443+
allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1444+
"only allow the listed language features to be enabled in code (space separated)"),
14301445
}
14311446

14321447
pub fn default_lib_output() -> CrateType {
@@ -3273,6 +3288,10 @@ mod tests {
32733288
opts = reference.clone();
32743289
opts.debugging_opts.merge_functions = Some(MergeFunctions::Disabled);
32753290
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
3291+
3292+
opts = reference.clone();
3293+
opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]);
3294+
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
32763295
}
32773296

32783297
#[test]

src/librustc_interface/passes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ pub fn register_plugins<'a>(
243243
krate,
244244
&sess.parse_sess,
245245
sess.edition(),
246+
&sess.opts.debugging_opts.allow_features,
246247
);
247248
// these need to be set "early" so that expansion sees `quote` if enabled.
248249
sess.init_features(features);

src/libsyntax/config.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ pub struct StripUnconfigured<'a> {
2424
}
2525

2626
// `cfg_attr`-process the crate's attributes and compute the crate's features.
27-
pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition)
28-
-> (ast::Crate, Features) {
27+
pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition,
28+
allow_features: &Option<Vec<String>>) -> (ast::Crate, Features) {
2929
let features;
3030
{
3131
let mut strip_unconfigured = StripUnconfigured {
@@ -43,7 +43,7 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition)
4343
return (krate, Features::new());
4444
}
4545

46-
features = get_features(&sess.span_diagnostic, &krate.attrs, edition);
46+
features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features);
4747

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

src/libsyntax/diagnostic_list.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,21 @@ Erroneous code example:
378378
379379
"##,
380380

381+
E0725: r##"
382+
A feature attribute named a feature that was disallowed in the compiler
383+
command line flags.
384+
385+
Erroneous code example:
386+
387+
```ignore (can't specify compiler flags from doctests)
388+
#![feature(never_type)] // error: the feature `never_type` is not in
389+
// the list of allowed features
390+
```
391+
392+
Delete the offending feature attribute, or add it to the list of allowed
393+
features in the `-Z allow_features` flag.
394+
"##,
395+
381396
}
382397

383398
register_diagnostics! {

src/libsyntax/feature_gate.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2008,7 +2008,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
20082008
}
20092009

20102010
pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
2011-
crate_edition: Edition) -> Features {
2011+
crate_edition: Edition, allow_features: &Option<Vec<String>>) -> Features {
20122012
fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
20132013
let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
20142014
if let Some(reason) = reason {
@@ -2127,6 +2127,15 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
21272127
}
21282128

21292129
if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
2130+
if let Some(allowed) = allow_features.as_ref() {
2131+
if allowed.iter().find(|f| *f == name.as_str()).is_none() {
2132+
span_err!(span_handler, mi.span, E0725,
2133+
"the feature `{}` is not in the list of allowed features",
2134+
name);
2135+
continue;
2136+
}
2137+
}
2138+
21302139
set(&mut features, mi.span);
21312140
features.declared_lang_features.push((name, mi.span, None));
21322141
continue
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags: -Z allow_features=
2+
// Note: This test uses rustc internal flags because they will never stabilize.
3+
4+
#![feature(rustc_diagnostic_macros)] //~ ERROR
5+
6+
#![feature(rustc_const_unstable)] //~ ERROR
7+
8+
#![feature(lang_items)] //~ ERROR
9+
10+
fn main() {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0725]: the feature `rustc_diagnostic_macros` is not in the list of allowed features
2+
--> $DIR/allow-features-empty.rs:4:12
3+
|
4+
LL | #![feature(rustc_diagnostic_macros)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features
8+
--> $DIR/allow-features-empty.rs:6:12
9+
|
10+
LL | #![feature(rustc_const_unstable)]
11+
| ^^^^^^^^^^^^^^^^^^^^
12+
13+
error[E0725]: the feature `lang_items` is not in the list of allowed features
14+
--> $DIR/allow-features-empty.rs:8:12
15+
|
16+
LL | #![feature(lang_items)]
17+
| ^^^^^^^^^^
18+
19+
error: aborting due to 3 previous errors
20+
21+
For more information about this error, try `rustc --explain E0725`.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-flags: -Z allow_features=rustc_diagnostic_macros,lang_items
2+
// Note: This test uses rustc internal flags because they will never stabilize.
3+
4+
#![feature(rustc_diagnostic_macros)]
5+
6+
#![feature(rustc_const_unstable)] //~ ERROR
7+
8+
#![feature(lang_items)]
9+
10+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features
2+
--> $DIR/allow-features.rs:6:12
3+
|
4+
LL | #![feature(rustc_const_unstable)]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0725`.

0 commit comments

Comments
 (0)