]> git.lizzy.rs Git - rust.git/commitdiff
Run feature-gating on the final AST passed to the compiler.
authorHuon Wilson <dbau.pp+github@gmail.com>
Wed, 4 Mar 2015 07:05:38 +0000 (18:05 +1100)
committerHuon Wilson <dbau.pp+github@gmail.com>
Thu, 5 Mar 2015 13:18:29 +0000 (00:18 +1100)
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
src/libsyntax/feature_gate.rs
src/test/compile-fail/cfg-attr-unknown-attribute-macro-expansion.rs [new file with mode: 0644]

index 73682faf1a77b3ffccac90846ca5da07e52cea20..6ec36886252f0b250eb170da77ed9eec96132caa 100644 (file)
@@ -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)
 }
 
index bc955259ab5e0961a8f26fd33334b7d541a2de50..fcfc14604843b07b3af67cc26174d0f78eef8d98 100644 (file)
@@ -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 @@ fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
     }
 
     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 @@ fn visit_fn(&mut self,
 }
 
 fn check_crate_inner<F>(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<F>(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<F>(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 (file)
index 0000000..afcb896
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {}