From fa8fd3daa7efefd4036a377f48f755be0b6952ee Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Thu, 14 Mar 2019 15:05:49 -0700 Subject: [PATCH 1/2] Add support for comma-separated option lists --- src/librustc/session/config.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 55c4b0e54b822..d39057cbf92ed 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -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`"); @@ -926,6 +927,18 @@ macro_rules! options { } } + fn parse_opt_comma_list(slot: &mut Option>, v: Option<&str>) + -> bool { + match v { + Some(s) => { + let v = s.split(',').map(|s| s.to_string()).collect(); + *slot = Some(v); + 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 }, From 7c59ce9f5db9cb7dbfbd07fab625e2b67aa042f5 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 13 Mar 2019 16:29:24 -0700 Subject: [PATCH 2/2] Add `-Z allow_features=...` flag --- src/librustc/session/config.rs | 6 ++++++ src/librustc_interface/passes.rs | 1 + src/libsyntax/config.rs | 6 +++--- src/libsyntax/diagnostic_list.rs | 15 +++++++++++++ src/libsyntax/feature_gate.rs | 11 +++++++++- .../ui/feature-gate/allow-features-empty.rs | 10 +++++++++ .../feature-gate/allow-features-empty.stderr | 21 +++++++++++++++++++ src/test/ui/feature-gate/allow-features.rs | 10 +++++++++ .../ui/feature-gate/allow-features.stderr | 9 ++++++++ 9 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/feature-gate/allow-features-empty.rs create mode 100644 src/test/ui/feature-gate/allow-features-empty.stderr create mode 100644 src/test/ui/feature-gate/allow-features.rs create mode 100644 src/test/ui/feature-gate/allow-features.stderr diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index d39057cbf92ed..ff18678f091b9 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1440,6 +1440,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, merge_functions: Option = (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> = (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 { @@ -3286,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] diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 5bb47bda17b33..0c710fd283be8 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -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); diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 4e4432a3f334d..2abb7e407eb02 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -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>) -> (ast::Crate, Features) { let features; { let mut strip_unconfigured = StripUnconfigured { @@ -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() { diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 2c367f1f40242..ac24475cab89f 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -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! { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 279e2089f5d71..77e8e75d8321b 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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>) -> 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 { @@ -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 diff --git a/src/test/ui/feature-gate/allow-features-empty.rs b/src/test/ui/feature-gate/allow-features-empty.rs new file mode 100644 index 0000000000000..83250052cb506 --- /dev/null +++ b/src/test/ui/feature-gate/allow-features-empty.rs @@ -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() {} diff --git a/src/test/ui/feature-gate/allow-features-empty.stderr b/src/test/ui/feature-gate/allow-features-empty.stderr new file mode 100644 index 0000000000000..cce2c4078c242 --- /dev/null +++ b/src/test/ui/feature-gate/allow-features-empty.stderr @@ -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`. diff --git a/src/test/ui/feature-gate/allow-features.rs b/src/test/ui/feature-gate/allow-features.rs new file mode 100644 index 0000000000000..1cebc8f34f26f --- /dev/null +++ b/src/test/ui/feature-gate/allow-features.rs @@ -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() {} diff --git a/src/test/ui/feature-gate/allow-features.stderr b/src/test/ui/feature-gate/allow-features.stderr new file mode 100644 index 0000000000000..b13560fb81c6a --- /dev/null +++ b/src/test/ui/feature-gate/allow-features.stderr @@ -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`.