Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -Z allow_features=... flag #59169

Merged
merged 2 commits into from
Mar 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ macro_rules! options {
pub const parse_opt_pathbuf: Option<&str> = Some("a path");
pub const parse_list: Option<&str> = Some("a space-separated list of strings");
pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
pub const parse_uint: Option<&str> = Some("a number");
pub const parse_passes: Option<&str> =
Some("a space-separated list of passes, or `all`");
Expand Down Expand Up @@ -926,6 +927,18 @@ macro_rules! options {
}
}

fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
-> bool {
match v {
Some(s) => {
let v = s.split(',').map(|s| s.to_string()).collect();
*slot = Some(v);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will this do if we see the flag multiple times?

I think we have this sort of problem all over the place, I would prefer if -Z allow_features=foo -Z allow_features=bar worked like -Z allow_features=foo,bar.

cc @rust-lang/compiler Should we do an audit? It's plausible fixing some of the other flags to do "the right thing" when provided multiple times may be a breaking change.

At least this one is unstable though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the flag is supplied multiple times the last invocation will override the previous ones. This is (afaict) the behavior of all the -Z flags that take a list of arguments.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and I'm saying it's not intentional most of the time, it just arises from how the CLI arguments are parsed.

I wonder what would happen were we to try to switch to e.g. structopt.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, was responding in answer to your original "What will this do if we see the flag multiple times?"-- I agree that trying to shift everything over to a different behavior would be a worthwhile thing to investigate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #59219

true
},
None => false,
}
}

fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
match v.and_then(|s| s.parse().ok()) {
Some(i) => { *slot = i; true },
Expand Down Expand Up @@ -1427,6 +1440,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
"control the operation of the MergeFunctions LLVM pass, taking
the same values as the target option of the same name"),
allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
"only allow the listed language features to be enabled in code (space separated)"),
}

pub fn default_lib_output() -> CrateType {
Expand Down Expand Up @@ -3273,6 +3288,10 @@ mod tests {
opts = reference.clone();
opts.debugging_opts.merge_functions = Some(MergeFunctions::Disabled);
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());

opts = reference.clone();
opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]);
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions src/librustc_interface/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ pub fn register_plugins<'a>(
krate,
&sess.parse_sess,
sess.edition(),
&sess.opts.debugging_opts.allow_features,
);
// these need to be set "early" so that expansion sees `quote` if enabled.
sess.init_features(features);
Expand Down
6 changes: 3 additions & 3 deletions src/libsyntax/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ pub struct StripUnconfigured<'a> {
}

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

features = get_features(&sess.span_diagnostic, &krate.attrs, edition);
features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features);

// Avoid reconfiguring malformed `cfg_attr`s
if err_count == sess.span_diagnostic.err_count() {
Expand Down
15 changes: 15 additions & 0 deletions src/libsyntax/diagnostic_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,21 @@ Erroneous code example:

"##,

E0725: r##"
A feature attribute named a feature that was disallowed in the compiler
command line flags.

Erroneous code example:

```ignore (can't specify compiler flags from doctests)
#![feature(never_type)] // error: the feature `never_type` is not in
// the list of allowed features
```

Delete the offending feature attribute, or add it to the list of allowed
features in the `-Z allow_features` flag.
"##,

}

register_diagnostics! {
Expand Down
11 changes: 10 additions & 1 deletion src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2008,7 +2008,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}

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

if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
if let Some(allowed) = allow_features.as_ref() {
if allowed.iter().find(|f| *f == name.as_str()).is_none() {
span_err!(span_handler, mi.span, E0725,
"the feature `{}` is not in the list of allowed features",
name);
continue;
}
}

set(&mut features, mi.span);
features.declared_lang_features.push((name, mi.span, None));
continue
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/feature-gate/allow-features-empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// compile-flags: -Z allow_features=
// Note: This test uses rustc internal flags because they will never stabilize.

#![feature(rustc_diagnostic_macros)] //~ ERROR

#![feature(rustc_const_unstable)] //~ ERROR

#![feature(lang_items)] //~ ERROR

fn main() {}
21 changes: 21 additions & 0 deletions src/test/ui/feature-gate/allow-features-empty.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0725]: the feature `rustc_diagnostic_macros` is not in the list of allowed features
--> $DIR/allow-features-empty.rs:4:12
|
LL | #![feature(rustc_diagnostic_macros)]
| ^^^^^^^^^^^^^^^^^^^^^^^

error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features
--> $DIR/allow-features-empty.rs:6:12
|
LL | #![feature(rustc_const_unstable)]
| ^^^^^^^^^^^^^^^^^^^^

error[E0725]: the feature `lang_items` is not in the list of allowed features
--> $DIR/allow-features-empty.rs:8:12
|
LL | #![feature(lang_items)]
| ^^^^^^^^^^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0725`.
10 changes: 10 additions & 0 deletions src/test/ui/feature-gate/allow-features.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// compile-flags: -Z allow_features=rustc_diagnostic_macros,lang_items
// Note: This test uses rustc internal flags because they will never stabilize.

#![feature(rustc_diagnostic_macros)]

#![feature(rustc_const_unstable)] //~ ERROR

#![feature(lang_items)]

fn main() {}
9 changes: 9 additions & 0 deletions src/test/ui/feature-gate/allow-features.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features
--> $DIR/allow-features.rs:6:12
|
LL | #![feature(rustc_const_unstable)]
| ^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0725`.