Skip to content

Commit 6908fb7

Browse files
authored
Rollup merge of #48014 - Manishearth:stealing-chickens-on-the-internet, r=nikomatsakis
Implement RFC 2052 (Epochs) This adds -Zepochs and uses it for tyvar_behind_raw_pointer (#46906) When we move this to --epoch=XXX, we'll need to gate the 2018 epoch on nightly, but not the 2015 one. I can make these changes here itself though it's kinda pointless given that the entire flag is nightly-only. r? @nikomatsakis @aturon cc #44581 (epoch tracking) cc #46906 (tyvar_behind_raw_pointer)
2 parents da6dcbc + b8aa8ca commit 6908fb7

File tree

7 files changed

+156
-9
lines changed

7 files changed

+156
-9
lines changed

src/librustc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#![feature(macro_vis_matcher)]
5959
#![feature(match_default_bindings)]
6060
#![feature(never_type)]
61+
#![feature(non_exhaustive)]
6162
#![feature(nonzero)]
6263
#![feature(quote)]
6364
#![feature(refcell_replace_swap)]

src/librustc/session/config.rs

+43-2
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,31 @@ pub enum OutputType {
112112
DepInfo,
113113
}
114114

115+
/// The epoch of the compiler (RFC 2052)
116+
#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq)]
117+
#[non_exhaustive]
118+
pub enum Epoch {
119+
// epochs must be kept in order, newest to oldest
120+
121+
/// The 2015 epoch
122+
Epoch2015,
123+
/// The 2018 epoch
124+
Epoch2018,
125+
126+
// when adding new epochs, be sure to update:
127+
//
128+
// - the list in the `parse_epoch` static
129+
// - the match in the `parse_epoch` function
130+
// - add a `rust_####()` function to the session
131+
// - update the enum in Cargo's sources as well
132+
//
133+
// When -Zepoch becomes --epoch, there will
134+
// also be a check for the epoch being nightly-only
135+
// somewhere. That will need to be updated
136+
// whenever we're stabilizing/introducing a new epoch
137+
// as well as changing the default Cargo template.
138+
}
139+
115140
impl_stable_hash_for!(enum self::OutputType {
116141
Bitcode,
117142
Assembly,
@@ -783,11 +808,13 @@ macro_rules! options {
783808
Some("`string` or `string=string`");
784809
pub const parse_lto: Option<&'static str> =
785810
Some("one of `thin`, `fat`, or omitted");
811+
pub const parse_epoch: Option<&'static str> =
812+
Some("one of: `2015`, `2018`");
786813
}
787814

788815
#[allow(dead_code)]
789816
mod $mod_set {
790-
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
817+
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto, Epoch};
791818
use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel};
792819
use std::path::PathBuf;
793820

@@ -991,6 +1018,15 @@ macro_rules! options {
9911018
};
9921019
true
9931020
}
1021+
1022+
fn parse_epoch(slot: &mut Epoch, v: Option<&str>) -> bool {
1023+
match v {
1024+
Some("2015") => *slot = Epoch::Epoch2015,
1025+
Some("2018") => *slot = Epoch::Epoch2018,
1026+
_ => return false,
1027+
}
1028+
true
1029+
}
9941030
}
9951031
) }
9961032

@@ -1278,6 +1314,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
12781314
`everybody_loops` (all function bodies replaced with `loop {}`),
12791315
`hir` (the HIR), `hir,identified`, or
12801316
`hir,typed` (HIR with types for each node)."),
1317+
epoch: Epoch = (Epoch::Epoch2015, parse_epoch, [TRACKED],
1318+
"The epoch to build Rust with. Newer epochs may include features
1319+
that require breaking changes. The default epoch is 2015 (the first
1320+
epoch). Crates compiled with different epochs can be linked together."),
12811321
}
12821322

12831323
pub fn default_lib_output() -> CrateType {
@@ -2069,7 +2109,7 @@ mod dep_tracking {
20692109
use std::path::PathBuf;
20702110
use std::collections::hash_map::DefaultHasher;
20712111
use super::{Passes, CrateType, OptLevel, DebugInfoLevel, Lto,
2072-
OutputTypes, Externs, ErrorOutputType, Sanitizer};
2112+
OutputTypes, Externs, ErrorOutputType, Sanitizer, Epoch};
20732113
use syntax::feature_gate::UnstableFeatures;
20742114
use rustc_back::{PanicStrategy, RelroLevel};
20752115

@@ -2131,6 +2171,7 @@ mod dep_tracking {
21312171
impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
21322172
impl_dep_tracking_hash_via_hash!(Sanitizer);
21332173
impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2174+
impl_dep_tracking_hash_via_hash!(Epoch);
21342175

21352176
impl_dep_tracking_hash_for_sortable_vec_of!(String);
21362177
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);

src/librustc/session/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use lint;
1919
use middle::allocator::AllocatorKind;
2020
use middle::dependency_format;
2121
use session::search_paths::PathKind;
22-
use session::config::{BorrowckMode, DebugInfoLevel, OutputType};
22+
use session::config::{BorrowckMode, DebugInfoLevel, OutputType, Epoch};
2323
use ty::tls;
2424
use util::nodemap::{FxHashMap, FxHashSet};
2525
use util::common::{duration_to_secs_str, ErrorReported};
@@ -864,6 +864,11 @@ impl Session {
864864
pub fn teach(&self, code: &DiagnosticId) -> bool {
865865
self.opts.debugging_opts.teach && !self.parse_sess.span_diagnostic.code_emitted(code)
866866
}
867+
868+
/// Are we allowed to use features from the Rust 2018 epoch?
869+
pub fn rust_2018(&self) -> bool {
870+
self.opts.debugging_opts.epoch >= Epoch::Epoch2018
871+
}
867872
}
868873

869874
pub fn build_session(sopts: config::Options,

src/librustc_typeck/check/method/probe.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -326,13 +326,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
326326
if reached_raw_pointer
327327
&& !self.tcx.sess.features.borrow().arbitrary_self_types {
328328
// this case used to be allowed by the compiler,
329-
// so we do a future-compat lint here
329+
// so we do a future-compat lint here for the 2015 epoch
330330
// (see https://github.com/rust-lang/rust/issues/46906)
331-
self.tcx.lint_node(
332-
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
333-
scope_expr_id,
334-
span,
335-
&format!("the type of this value must be known in this context"));
331+
if self.tcx.sess.rust_2018() {
332+
span_err!(self.tcx.sess, span, E0908,
333+
"the type of this value must be known \
334+
to call a method on a raw pointer on it");
335+
} else {
336+
self.tcx.lint_node(
337+
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
338+
scope_expr_id,
339+
span,
340+
&format!("the type of this value must be known in this context"));
341+
}
336342
} else {
337343
let t = self.structurally_resolved_type(span, final_ty);
338344
assert_eq!(t, self.tcx.types.err);

src/librustc_typeck/diagnostics.rs

+49
Original file line numberDiff line numberDiff line change
@@ -4698,6 +4698,55 @@ element type `T`. Also note that the error is conservatively reported even when
46984698
the alignment of the zero-sized type is less than or equal to the data field's
46994699
alignment.
47004700
"##,
4701+
4702+
4703+
E0908: r##"
4704+
A method was called on a raw pointer whose inner type wasn't completely known.
4705+
4706+
For example, you may have done something like:
4707+
4708+
```compile_fail
4709+
# #![deny(warnings)]
4710+
let foo = &1;
4711+
let bar = foo as *const _;
4712+
if bar.is_null() {
4713+
// ...
4714+
}
4715+
```
4716+
4717+
Here, the type of `bar` isn't known; it could be a pointer to anything. Instead,
4718+
specify a type for the pointer (preferably something that makes sense for the
4719+
thing you're pointing to):
4720+
4721+
```
4722+
let foo = &1;
4723+
let bar = foo as *const i32;
4724+
if bar.is_null() {
4725+
// ...
4726+
}
4727+
```
4728+
4729+
Even though `is_null()` exists as a method on any raw pointer, Rust shows this
4730+
error because Rust allows for `self` to have arbitrary types (behind the
4731+
arbitrary_self_types feature flag).
4732+
4733+
This means that someone can specify such a function:
4734+
4735+
```ignore (cannot-doctest-feature-doesnt-exist-yet)
4736+
impl Foo {
4737+
fn is_null(self: *const Self) -> bool {
4738+
// do something else
4739+
}
4740+
}
4741+
```
4742+
4743+
and now when you call `.is_null()` on a raw pointer to `Foo`, there's ambiguity.
4744+
4745+
Given that we don't know what type the pointer is, and there's potential
4746+
ambiguity for some types, we disallow calling methods on raw pointers when
4747+
the type is unknown.
4748+
"##,
4749+
47014750
}
47024751

47034752
register_diagnostics! {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2012 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+
// ignore-tidy-linelength
12+
// compile-flags: -Zepoch=2015 -Zunstable-options
13+
14+
// tests that epochs work with the tyvar warning-turned-error
15+
16+
#[deny(warnings)]
17+
fn main() {
18+
let x = 0;
19+
let y = &x as *const _;
20+
let _ = y.is_null();
21+
//~^ error: the type of this value must be known in this context [tyvar_behind_raw_pointer]
22+
//~^^ warning: this was previously accepted
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2012 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+
// ignore-tidy-linelength
12+
// compile-flags: -Zepoch=2018 -Zunstable-options
13+
14+
// tests that epochs work with the tyvar warning-turned-error
15+
16+
#[deny(warnings)]
17+
fn main() {
18+
let x = 0;
19+
let y = &x as *const _;
20+
let _ = y.is_null();
21+
//~^ error: the type of this value must be known to call a method on a raw pointer on it [E0908]
22+
}

0 commit comments

Comments
 (0)