diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 7645d3486c2f8..10f5bad5265e4 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -89,7 +89,13 @@ impl Lint { pub fn default_level(&self, session: &Session) -> Level { if let Some(edition_deny) = self.edition_deny { - if session.edition() >= edition_deny { + // Ideally, we would get the edition for the actual span, + // but that is kind of a pain in the neck to do right + // now. Also, lints are not breaking things anyway (due to + // `-Acap-lints`), and the lint itself should probably be + // checking the span to see if the code was injected via + // macro etc, so for now we'll just use the local level. + if session.local_edition() >= edition_deny { return Level::Deny } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 8df66d8d68855..bd5c528824eb2 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -948,12 +948,14 @@ impl Session { self.opts.debugging_opts.teach && self.parse_sess.span_diagnostic.must_teach(code) } - /// Are we allowed to use features from the Rust 2018 edition? - pub fn rust_2018(&self) -> bool { - self.opts.edition >= Edition::Edition2018 - } - - pub fn edition(&self) -> Edition { + /// What is the edition of the "local crate" being compiled? + /// + /// You should not call this except as a last resort. It is better + /// to do `span.edition()` instead, which gives the edition for a + /// particular span: that way, when you are looking at code + /// creating a macro from a Rust 2015 crate, you will use the Rust + /// 2015 Edition rules. + pub fn local_edition(&self) -> Edition { self.opts.edition } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ed28b05c12551..6a43f0c6f04ed 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -736,7 +736,7 @@ where krate, &sess.parse_sess, sess.opts.test, - sess.edition(), + sess.local_edition(), ); // these need to be set "early" so that expansion sees `quote` if enabled. sess.init_features(features); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5f277d03c5238..f2292a737b454 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3276,7 +3276,7 @@ impl<'a> Resolver<'a> { if prev_name == keywords::Extern.name() || prev_name == keywords::CrateRoot.name() && self.session.features_untracked().extern_absolute_paths && - self.session.rust_2018() { + path_span.edition().rust_2018() { // `::extern_crate::a::b` let crate_id = self.crate_loader.process_path_extern(name, ident.span); let crate_root = @@ -3446,7 +3446,7 @@ impl<'a> Resolver<'a> { fn lint_path_starts_with_module(&self, id: NodeId, span: Span) { // In the 2018 edition this lint is a hard error, so nothing to do - if self.session.rust_2018() { + if span.edition().rust_2018() { return } // In the 2015 edition there's no use in emitting lints unless the diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 91de3a34cc84a..42d33d6d07a9a 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -677,7 +677,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { module_path[0].name == keywords::Extern.name()) { let is_extern = module_path[0].name == keywords::Extern.name() || (self.session.features_untracked().extern_absolute_paths && - self.session.rust_2018()); + span.edition().rust_2018()); match directive.subclass { GlobImport { .. } if is_extern => { return Some((directive.span, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 6cdfb0bccc986..2df8420e957ac 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -334,10 +334,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) - if self.tcx.sess.rust_2018() { - span_err!(self.tcx.sess, span, E0908, - "the type of this value must be known \ - to call a method on a raw pointer on it"); + if span.edition().rust_2018() { + span_err!(self.tcx.sess, span, E0908, + "the type of this value must be known \ + to call a method on a raw pointer on it"); } else { self.tcx.lint_node( lint::builtin::TYVAR_BEHIND_RAW_POINTER, diff --git a/src/libsyntax_pos/edition.rs b/src/libsyntax_pos/edition.rs index 18446c109964d..20ee11c5ec3f9 100644 --- a/src/libsyntax_pos/edition.rs +++ b/src/libsyntax_pos/edition.rs @@ -68,6 +68,11 @@ impl Edition { Edition::Edition2018 => false, } } + + /// Is this at least 2018? + pub fn rust_2018(self) -> bool { + self >= Edition::Edition2018 + } } impl FromStr for Edition { diff --git a/src/test/ui/rust-2018/auxiliary/inject-2015-use-root-module-lib.rs b/src/test/ui/rust-2018/auxiliary/inject-2015-use-root-module-lib.rs new file mode 100644 index 0000000000000..4126f9e925ce8 --- /dev/null +++ b/src/test/ui/rust-2018/auxiliary/inject-2015-use-root-module-lib.rs @@ -0,0 +1,39 @@ +// Copyright 2018 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. + +// this is a rust 2015 crate + +#[macro_export] +macro_rules! inject_me_at_the_root { + ($name1:ident, $name2:ident) => { + mod $name1 { + pub(crate) const THE_CONSTANT: u32 = 22; + } + + fn $name2() -> u32 { + // Key point: this `use` statement -- in Rust 2018 -- + // would be an error. But because this crate is in Rust + // 2015, it works, even when executed from a Rust 2018 + // environment. + use $name1::THE_CONSTANT; + THE_CONSTANT + } + } +} + +#[macro_export] +macro_rules! print_me { + ($p:path) => { + { + use $p as V; + println!("{}", V); + } + } +} diff --git a/src/test/ui/rust-2018/inject-2015-use-root-module-path.rs b/src/test/ui/rust-2018/inject-2015-use-root-module-path.rs new file mode 100644 index 0000000000000..33a643708b251 --- /dev/null +++ b/src/test/ui/rust-2018/inject-2015-use-root-module-path.rs @@ -0,0 +1,29 @@ +// Copyright 2018 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. + +// compile-flags:--edition 2018 +// aux-build:inject-2015-use-root-module-lib.rs + +// The macro `inject_me_at_the_root!` generates some code that uses +// `use x::y` to name the global item `x`. In Rust 2018, that should +// be `use crate::x::y`, but we test here that we still accept it, +// as `inject_2015_lib` is in the 2015 edition. + +#[macro_use] +extern crate inject_2015_use_root_module_lib; + +inject_me_at_the_root!(x, y); + +fn main() { + println!("Hello, world: {}", y()); + + // This path comes out as an error, because `x::y` comes from Rust 2018 + print_me!(x::y); //~ ERROR unresolved import `x::y` +} diff --git a/src/test/ui/rust-2018/inject-2015-use-root-module.rs b/src/test/ui/rust-2018/inject-2015-use-root-module.rs new file mode 100644 index 0000000000000..60031596c5538 --- /dev/null +++ b/src/test/ui/rust-2018/inject-2015-use-root-module.rs @@ -0,0 +1,29 @@ +// Copyright 2018 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. + +// compile-flags:--edition 2018 +// aux-build:inject-2015-use-root-module-lib.rs +// run-pass + +// The macro `inject_me_at_the_root!` generates some code that uses +// `use x::y` to name the global item `x`. In Rust 2018, that should +// be `use crate::x::y`, but we test here that we still accept it, +// as `inject_2015_lib` is in the 2015 edition. + +#[macro_use] +extern crate inject_2015_use_root_module_lib; + +inject_me_at_the_root!(x, y); + +fn main() { + println!("Hello, world: {}", y()); + + print_me!(crate::x::y); +}