From b5c6ab20b7d1f4d6b0cc31c2987b2e0f8ea43e0c Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 4 Mar 2015 18:05:38 +1100 Subject: [PATCH] Run feature-gating on the final AST passed to the compiler. This ensures we catch everything; previously, an unknown attribute inserted by #[cfg_attr(...)] in a macro expansion would not be detected. --- src/librustc_driver/driver.rs | 25 ++++++++++++++++--- src/libsyntax/feature_gate.rs | 14 +++++++---- ...-attr-unknown-attribute-macro-expansion.rs | 20 +++++++++++++++ 3 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 src/test/compile-fail/cfg-attr-unknown-attribute-macro-expansion.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 73682faf1a7..6ec36886252 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -493,12 +493,16 @@ pub fn phase_2_configure_and_expand(sess: &Session, } ); - // Needs to go *after* expansion to be able to check the results of macro expansion. - time(time_passes, "complete gated feature checking", (), |_| { + // Needs to go *after* expansion to be able to check the results + // of macro expansion. This runs before #[cfg] to try to catch as + // much as possible (e.g. help the programmer avoid platform + // specific differences) + time(time_passes, "complete gated feature checking 1", (), |_| { let features = syntax::feature_gate::check_crate(sess.codemap(), - &sess.parse_sess.span_diagnostic, - &krate); + &sess.parse_sess.span_diagnostic, + &krate, + true); *sess.features.borrow_mut() = features; sess.abort_if_errors(); }); @@ -521,6 +525,19 @@ pub fn phase_2_configure_and_expand(sess: &Session, time(time_passes, "checking that all macro invocations are gone", &krate, |krate| syntax::ext::expand::check_for_macros(&sess.parse_sess, krate)); + // One final feature gating of the true AST that gets compiled + // later, to make sure we've got everything (e.g. configuration + // can insert new attributes via `cfg_attr`) + time(time_passes, "complete gated feature checking 2", (), |_| { + let features = + syntax::feature_gate::check_crate(sess.codemap(), + &sess.parse_sess.span_diagnostic, + &krate, + false); + *sess.features.borrow_mut() = features; + sess.abort_if_errors(); + }); + Some(krate) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index bc955259ab5..fcfc1460484 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -349,6 +349,7 @@ struct Context<'a> { features: Vec<&'static str>, span_handler: &'a SpanHandler, cm: &'a CodeMap, + do_warnings: bool, } impl<'a> Context<'a> { @@ -361,7 +362,7 @@ impl<'a> Context<'a> { } fn warn_feature(&self, feature: &str, span: Span, explain: &str) { - if !self.has_feature(feature) { + if !self.has_feature(feature) && self.do_warnings { emit_feature_warn(self.span_handler, feature, span, explain); } } @@ -700,6 +701,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate, + do_warnings: bool, check: F) -> Features where F: FnOnce(&mut Context, &ast::Crate) @@ -707,6 +709,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C let mut cx = Context { features: Vec::new(), span_handler: span_handler, + do_warnings: do_warnings, cm: cm, }; @@ -786,13 +789,14 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate) -> Features { - check_crate_inner(cm, span_handler, krate, + check_crate_inner(cm, span_handler, krate, true, |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate)) } -pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate) --> Features { - check_crate_inner(cm, span_handler, krate, +pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate, + do_warnings: bool) -> Features +{ + check_crate_inner(cm, span_handler, krate, do_warnings, |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx }, krate)) } diff --git a/src/test/compile-fail/cfg-attr-unknown-attribute-macro-expansion.rs b/src/test/compile-fail/cfg-attr-unknown-attribute-macro-expansion.rs new file mode 100644 index 00000000000..afcb896b43c --- /dev/null +++ b/src/test/compile-fail/cfg-attr-unknown-attribute-macro-expansion.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! foo { + () => { + #[cfg_attr(all(), unknown)] //~ ERROR `unknown` is currently unknown + fn foo() {} + } +} + +foo!(); + +fn main() {}