diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 83 | ||||
| -rw-r--r-- | src/libsyntax/lib.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/test.rs | 17 |
3 files changed, 75 insertions, 28 deletions
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 71c1f791470..40e210d02ca 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -112,8 +112,8 @@ macro_rules! declare_features { // was set. This is most important for knowing when a particular feature became // stable (active). // -// NB: The featureck.py script parses this information directly out of the source -// so take care when modifying it. +// NB: tools/tidy/src/features.rs parses this information directly out of the +// source, so take care when modifying it. declare_features! ( (active, asm, "1.0.0", Some(29722)), @@ -376,6 +376,9 @@ declare_features! ( // #[doc(cfg(...))] (active, doc_cfg, "1.21.0", Some(43781)), + + // allow `#[must_use]` on functions (RFC 1940) + (active, fn_must_use, "1.21.0", Some(43302)), ); declare_features! ( @@ -919,20 +922,27 @@ struct Context<'a> { } macro_rules! gate_feature_fn { - ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{ - let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain); + ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{ + let (cx, has_feature, span, + name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level); let has_feature: bool = has_feature(&$cx.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); if !has_feature && !span.allows_unstable() { - emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain); + leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level) + .emit(); } }} } macro_rules! gate_feature { ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { - gate_feature_fn!($cx, |x:&Features| x.$feature, $span, stringify!($feature), $explain) - } + gate_feature_fn!($cx, |x:&Features| x.$feature, $span, + stringify!($feature), $explain, GateStrength::Hard) + }; + ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { + gate_feature_fn!($cx, |x:&Features| x.$feature, $span, + stringify!($feature), $explain, $level) + }; } impl<'a> Context<'a> { @@ -942,7 +952,7 @@ impl<'a> Context<'a> { for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES { if name == n { if let Gated(_, name, desc, ref has_feature) = *gateage { - gate_feature_fn!(self, has_feature, attr.span, name, desc); + gate_feature_fn!(self, has_feature, attr.span, name, desc, GateStrength::Hard); } debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); return; @@ -1012,13 +1022,26 @@ pub enum GateIssue { Library(Option<u32>) } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum GateStrength { + /// A hard error. (Most feature gates should use this.) + Hard, + /// Only a warning. (Use this only as backwards-compatibility demands.) + Soft, +} + pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue, explain: &str) { feature_err(sess, feature, span, issue, explain).emit(); } pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue, - explain: &str) -> DiagnosticBuilder<'a> { + explain: &str) -> DiagnosticBuilder<'a> { + leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard) +} + +fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue, + explain: &str, level: GateStrength) -> DiagnosticBuilder<'a> { let diag = &sess.span_diagnostic; let issue = match issue { @@ -1026,10 +1049,15 @@ pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: Ga GateIssue::Library(lib) => lib, }; - let mut err = if let Some(n) = issue { - diag.struct_span_err(span, &format!("{} (see issue #{})", explain, n)) + let explanation = if let Some(n) = issue { + format!("{} (see issue #{})", explain, n) } else { - diag.struct_span_err(span, explain) + explain.to_owned() + }; + + let mut err = match level { + GateStrength::Hard => diag.struct_span_err(span, &explanation), + GateStrength::Soft => diag.struct_span_warn(span, &explanation), }; // #23973: do not suggest `#![feature(...)]` if we are in beta/stable @@ -1039,7 +1067,15 @@ pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: Ga feature)); } + // If we're on stable and only emitting a "soft" warning, add a note to + // clarify that the feature isn't "on" (rather than being on but + // warning-worthy). + if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft { + err.help("a nightly build of the compiler is required to enable this feature"); + } + err + } const EXPLAIN_BOX_SYNTAX: &'static str = @@ -1096,6 +1132,12 @@ macro_rules! gate_feature_post { if !span.allows_unstable() { gate_feature!(cx.context, $feature, span, $explain) } + }}; + ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{ + let (cx, span) = ($cx, $span); + if !span.allows_unstable() { + gate_feature!(cx.context, $feature, span, $explain, $level) + } }} } @@ -1238,6 +1280,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { function may change over time, for now \ a top-level `fn main()` is required"); } + if attr::contains_name(&i.attrs[..], "must_use") { + gate_feature_post!(&self, fn_must_use, i.span, + "`#[must_use]` on functions is experimental", + GateStrength::Soft); + } } ast::ItemKind::Struct(..) => { @@ -1275,7 +1322,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { and possibly buggy"); } - ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { + ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, ref impl_items) => { if polarity == ast::ImplPolarity::Negative { gate_feature_post!(&self, optin_builtin_traits, i.span, @@ -1288,6 +1335,16 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { i.span, "specialization is unstable"); } + + for impl_item in impl_items { + if let ast::ImplItemKind::Method(..) = impl_item.node { + if attr::contains_name(&impl_item.attrs[..], "must_use") { + gate_feature_post!(&self, fn_must_use, impl_item.span, + "`#[must_use]` on methods is experimental", + GateStrength::Soft); + } + } + } } ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 43345b02bf6..e3c9f0a9345 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -14,9 +14,6 @@ //! //! This API is completely unstable and subject to change. -#![crate_name = "syntax"] -#![crate_type = "dylib"] -#![crate_type = "rlib"] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index eeb8bf72144..35dc9819529 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -56,13 +56,12 @@ struct Test { } struct TestCtxt<'a> { - sess: &'a ParseSess, span_diagnostic: &'a errors::Handler, path: Vec<Ident>, ext_cx: ExtCtxt<'a>, testfns: Vec<Test>, reexport_test_harness_main: Option<Symbol>, - is_test_crate: bool, + is_libtest: bool, ctxt: SyntaxContext, // top-level re-export submodule, filled out after folding is finished @@ -272,14 +271,15 @@ fn generate_test_harness(sess: &ParseSess, let krate = cleaner.fold_crate(krate); let mark = Mark::fresh(Mark::root()); + let mut cx: TestCtxt = TestCtxt { - sess, span_diagnostic: sd, ext_cx: ExtCtxt::new(sess, ExpansionConfig::default("test".to_string()), resolver), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main, - is_test_crate: is_test_crate(&krate), + // NB: doesn't consider the value of `--crate-name` passed on the command line. + is_libtest: attr::find_crate_name(&krate.attrs).map(|s| s == "test").unwrap_or(false), toplevel_reexport: None, ctxt: SyntaxContext::empty().apply_mark(mark), }; @@ -454,7 +454,7 @@ mod __test { fn mk_std(cx: &TestCtxt) -> P<ast::Item> { let id_test = Ident::from_str("test"); let sp = ignored_span(cx, DUMMY_SP); - let (vi, vis, ident) = if cx.is_test_crate { + let (vi, vis, ident) = if cx.is_libtest { (ast::ItemKind::Use( P(nospan(ast::ViewPathSimple(id_test, path_node(vec![id_test]))))), @@ -608,13 +608,6 @@ fn mk_tests(cx: &TestCtxt) -> P<ast::Item> { test_descs) } -fn is_test_crate(krate: &ast::Crate) -> bool { - match attr::find_crate_name(&krate.attrs) { - Some(s) if "test" == s.as_str() => true, - _ => false - } -} - fn mk_test_descs(cx: &TestCtxt) -> P<ast::Expr> { debug!("building test vector from {} tests", cx.testfns.len()); |
