Skip to content

Commit

Permalink
don't ask what edition we are in; ask what edition a span is in
Browse files Browse the repository at this point in the history
We now track the edition of each span. Using that info when gating the
Rust 2018 interpretation means that macros from Rust 2015 crates "just
work" when used in Rust 2018 crates (at least in the case of `use`
paths).
  • Loading branch information
nikomatsakis committed May 23, 2018
1 parent 1962a70 commit 24529d9
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 15 deletions.
8 changes: 7 additions & 1 deletion src/librustc/lint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
14 changes: 8 additions & 6 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_resolve/resolve_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_typeck/check/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions src/libsyntax_pos/edition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
29 changes: 29 additions & 0 deletions src/test/ui/rust-2018/auxiliary/inject-2015-use-root-module-lib.rs
Original file line number Diff line number Diff line change
@@ -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 <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.

// 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
}
}
}
27 changes: 27 additions & 0 deletions src/test/ui/rust-2018/inject-2015-use-root-module.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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 <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.

// 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());
}

0 comments on commit 24529d9

Please sign in to comment.