Skip to content

Commit 24529d9

Browse files
committed
don't ask what edition we are in; ask what edition a span is in
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).
1 parent 1962a70 commit 24529d9

File tree

9 files changed

+84
-15
lines changed

9 files changed

+84
-15
lines changed

src/librustc/lint/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,13 @@ impl Lint {
8989

9090
pub fn default_level(&self, session: &Session) -> Level {
9191
if let Some(edition_deny) = self.edition_deny {
92-
if session.edition() >= edition_deny {
92+
// Ideally, we would get the edition for the actual span,
93+
// but that is kind of a pain in the neck to do right
94+
// now. Also, lints are not breaking things anyway (due to
95+
// `-Acap-lints`), and the lint itself should probably be
96+
// checking the span to see if the code was injected via
97+
// macro etc, so for now we'll just use the local level.
98+
if session.local_edition() >= edition_deny {
9399
return Level::Deny
94100
}
95101
}

src/librustc/session/mod.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -948,12 +948,14 @@ impl Session {
948948
self.opts.debugging_opts.teach && self.parse_sess.span_diagnostic.must_teach(code)
949949
}
950950

951-
/// Are we allowed to use features from the Rust 2018 edition?
952-
pub fn rust_2018(&self) -> bool {
953-
self.opts.edition >= Edition::Edition2018
954-
}
955-
956-
pub fn edition(&self) -> Edition {
951+
/// What is the edition of the "local crate" being compiled?
952+
///
953+
/// You should not call this except as a last resort. It is better
954+
/// to do `span.edition()` instead, which gives the edition for a
955+
/// particular span: that way, when you are looking at code
956+
/// creating a macro from a Rust 2015 crate, you will use the Rust
957+
/// 2015 Edition rules.
958+
pub fn local_edition(&self) -> Edition {
957959
self.opts.edition
958960
}
959961
}

src/librustc_driver/driver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ where
736736
krate,
737737
&sess.parse_sess,
738738
sess.opts.test,
739-
sess.edition(),
739+
sess.local_edition(),
740740
);
741741
// these need to be set "early" so that expansion sees `quote` if enabled.
742742
sess.init_features(features);

src/librustc_resolve/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3276,7 +3276,7 @@ impl<'a> Resolver<'a> {
32763276
if prev_name == keywords::Extern.name() ||
32773277
prev_name == keywords::CrateRoot.name() &&
32783278
self.session.features_untracked().extern_absolute_paths &&
3279-
self.session.rust_2018() {
3279+
path_span.edition().rust_2018() {
32803280
// `::extern_crate::a::b`
32813281
let crate_id = self.crate_loader.process_path_extern(name, ident.span);
32823282
let crate_root =
@@ -3446,7 +3446,7 @@ impl<'a> Resolver<'a> {
34463446

34473447
fn lint_path_starts_with_module(&self, id: NodeId, span: Span) {
34483448
// In the 2018 edition this lint is a hard error, so nothing to do
3449-
if self.session.rust_2018() {
3449+
if span.edition().rust_2018() {
34503450
return
34513451
}
34523452
// In the 2015 edition there's no use in emitting lints unless the

src/librustc_resolve/resolve_imports.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
677677
module_path[0].name == keywords::Extern.name()) {
678678
let is_extern = module_path[0].name == keywords::Extern.name() ||
679679
(self.session.features_untracked().extern_absolute_paths &&
680-
self.session.rust_2018());
680+
span.edition().rust_2018());
681681
match directive.subclass {
682682
GlobImport { .. } if is_extern => {
683683
return Some((directive.span,

src/librustc_typeck/check/method/probe.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
334334
// this case used to be allowed by the compiler,
335335
// so we do a future-compat lint here for the 2015 edition
336336
// (see https://github.com/rust-lang/rust/issues/46906)
337-
if self.tcx.sess.rust_2018() {
338-
span_err!(self.tcx.sess, span, E0908,
339-
"the type of this value must be known \
340-
to call a method on a raw pointer on it");
337+
if span.edition().rust_2018() {
338+
span_err!(self.tcx.sess, span, E0908,
339+
"the type of this value must be known \
340+
to call a method on a raw pointer on it");
341341
} else {
342342
self.tcx.lint_node(
343343
lint::builtin::TYVAR_BEHIND_RAW_POINTER,

src/libsyntax_pos/edition.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ impl Edition {
6868
Edition::Edition2018 => false,
6969
}
7070
}
71+
72+
/// Is this at least 2018?
73+
pub fn rust_2018(self) -> bool {
74+
self >= Edition::Edition2018
75+
}
7176
}
7277

7378
impl FromStr for Edition {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// this is a rust 2015 crate
12+
13+
#[macro_export]
14+
macro_rules! inject_me_at_the_root {
15+
($name1:ident, $name2:ident) => {
16+
mod $name1 {
17+
pub(crate) const THE_CONSTANT: u32 = 22;
18+
}
19+
20+
fn $name2() -> u32 {
21+
// Key point: this `use` statement -- in Rust 2018 --
22+
// would be an error. But because this crate is in Rust
23+
// 2015, it works, even when executed from a Rust 2018
24+
// environment.
25+
use $name1::THE_CONSTANT;
26+
THE_CONSTANT
27+
}
28+
}
29+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:--edition 2018
12+
// aux-build:inject-2015-use-root-module-lib.rs
13+
// run-pass
14+
15+
// The macro `inject_me_at_the_root!` generates some code that uses
16+
// `use x::y` to name the global item `x`. In Rust 2018, that should
17+
// be `use crate::x::y`, but we test here that we still accept it,
18+
// as `inject_2015_lib` is in the 2015 edition.
19+
20+
#[macro_use]
21+
extern crate inject_2015_use_root_module_lib;
22+
23+
inject_me_at_the_root!(x, y);
24+
25+
fn main() {
26+
println!("Hello, world: {}", y());
27+
}

0 commit comments

Comments
 (0)