Skip to content

Commit

Permalink
Rollup merge of rust-lang#48014 - Manishearth:stealing-chickens-on-th…
Browse files Browse the repository at this point in the history
…e-internet, r=nikomatsakis

Implement RFC 2052 (Epochs)

This adds -Zepochs and uses it for tyvar_behind_raw_pointer (rust-lang#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 rust-lang#44581 (epoch tracking)
cc rust-lang#46906 (tyvar_behind_raw_pointer)
  • Loading branch information
Manishearth authored Feb 7, 2018
2 parents da6dcbc + b8aa8ca commit 6908fb7
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#![feature(macro_vis_matcher)]
#![feature(match_default_bindings)]
#![feature(never_type)]
#![feature(non_exhaustive)]
#![feature(nonzero)]
#![feature(quote)]
#![feature(refcell_replace_swap)]
Expand Down
45 changes: 43 additions & 2 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,31 @@ pub enum OutputType {
DepInfo,
}

/// The epoch of the compiler (RFC 2052)
#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq)]
#[non_exhaustive]
pub enum Epoch {
// epochs must be kept in order, newest to oldest

/// The 2015 epoch
Epoch2015,
/// The 2018 epoch
Epoch2018,

// when adding new epochs, be sure to update:
//
// - the list in the `parse_epoch` static
// - the match in the `parse_epoch` function
// - add a `rust_####()` function to the session
// - update the enum in Cargo's sources as well
//
// When -Zepoch becomes --epoch, there will
// also be a check for the epoch being nightly-only
// somewhere. That will need to be updated
// whenever we're stabilizing/introducing a new epoch
// as well as changing the default Cargo template.
}

impl_stable_hash_for!(enum self::OutputType {
Bitcode,
Assembly,
Expand Down Expand Up @@ -783,11 +808,13 @@ macro_rules! options {
Some("`string` or `string=string`");
pub const parse_lto: Option<&'static str> =
Some("one of `thin`, `fat`, or omitted");
pub const parse_epoch: Option<&'static str> =
Some("one of: `2015`, `2018`");
}

#[allow(dead_code)]
mod $mod_set {
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto, Epoch};
use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel};
use std::path::PathBuf;

Expand Down Expand Up @@ -991,6 +1018,15 @@ macro_rules! options {
};
true
}

fn parse_epoch(slot: &mut Epoch, v: Option<&str>) -> bool {
match v {
Some("2015") => *slot = Epoch::Epoch2015,
Some("2018") => *slot = Epoch::Epoch2018,
_ => return false,
}
true
}
}
) }

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

pub fn default_lib_output() -> CrateType {
Expand Down Expand Up @@ -2069,7 +2109,7 @@ mod dep_tracking {
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
use super::{Passes, CrateType, OptLevel, DebugInfoLevel, Lto,
OutputTypes, Externs, ErrorOutputType, Sanitizer};
OutputTypes, Externs, ErrorOutputType, Sanitizer, Epoch};
use syntax::feature_gate::UnstableFeatures;
use rustc_back::{PanicStrategy, RelroLevel};

Expand Down Expand Up @@ -2131,6 +2171,7 @@ mod dep_tracking {
impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
impl_dep_tracking_hash_via_hash!(Sanitizer);
impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
impl_dep_tracking_hash_via_hash!(Epoch);

impl_dep_tracking_hash_for_sortable_vec_of!(String);
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
Expand Down
7 changes: 6 additions & 1 deletion src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use lint;
use middle::allocator::AllocatorKind;
use middle::dependency_format;
use session::search_paths::PathKind;
use session::config::{BorrowckMode, DebugInfoLevel, OutputType};
use session::config::{BorrowckMode, DebugInfoLevel, OutputType, Epoch};
use ty::tls;
use util::nodemap::{FxHashMap, FxHashSet};
use util::common::{duration_to_secs_str, ErrorReported};
Expand Down Expand Up @@ -864,6 +864,11 @@ impl Session {
pub fn teach(&self, code: &DiagnosticId) -> bool {
self.opts.debugging_opts.teach && !self.parse_sess.span_diagnostic.code_emitted(code)
}

/// Are we allowed to use features from the Rust 2018 epoch?
pub fn rust_2018(&self) -> bool {
self.opts.debugging_opts.epoch >= Epoch::Epoch2018
}
}

pub fn build_session(sopts: config::Options,
Expand Down
18 changes: 12 additions & 6 deletions src/librustc_typeck/check/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,13 +326,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if reached_raw_pointer
&& !self.tcx.sess.features.borrow().arbitrary_self_types {
// this case used to be allowed by the compiler,
// so we do a future-compat lint here
// so we do a future-compat lint here for the 2015 epoch
// (see https://github.com/rust-lang/rust/issues/46906)
self.tcx.lint_node(
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
scope_expr_id,
span,
&format!("the type of this value must be known in this context"));
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");
} else {
self.tcx.lint_node(
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
scope_expr_id,
span,
&format!("the type of this value must be known in this context"));
}
} else {
let t = self.structurally_resolved_type(span, final_ty);
assert_eq!(t, self.tcx.types.err);
Expand Down
49 changes: 49 additions & 0 deletions src/librustc_typeck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4698,6 +4698,55 @@ element type `T`. Also note that the error is conservatively reported even when
the alignment of the zero-sized type is less than or equal to the data field's
alignment.
"##,


E0908: r##"
A method was called on a raw pointer whose inner type wasn't completely known.
For example, you may have done something like:
```compile_fail
# #![deny(warnings)]
let foo = &1;
let bar = foo as *const _;
if bar.is_null() {
// ...
}
```
Here, the type of `bar` isn't known; it could be a pointer to anything. Instead,
specify a type for the pointer (preferably something that makes sense for the
thing you're pointing to):
```
let foo = &1;
let bar = foo as *const i32;
if bar.is_null() {
// ...
}
```
Even though `is_null()` exists as a method on any raw pointer, Rust shows this
error because Rust allows for `self` to have arbitrary types (behind the
arbitrary_self_types feature flag).
This means that someone can specify such a function:
```ignore (cannot-doctest-feature-doesnt-exist-yet)
impl Foo {
fn is_null(self: *const Self) -> bool {
// do something else
}
}
```
and now when you call `.is_null()` on a raw pointer to `Foo`, there's ambiguity.
Given that we don't know what type the pointer is, and there's potential
ambiguity for some types, we disallow calling methods on raw pointers when
the type is unknown.
"##,

}

register_diagnostics! {
Expand Down
23 changes: 23 additions & 0 deletions src/test/compile-fail/epoch-raw-pointer-method-2015.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2012 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.

// ignore-tidy-linelength
// compile-flags: -Zepoch=2015 -Zunstable-options

// tests that epochs work with the tyvar warning-turned-error

#[deny(warnings)]
fn main() {
let x = 0;
let y = &x as *const _;
let _ = y.is_null();
//~^ error: the type of this value must be known in this context [tyvar_behind_raw_pointer]
//~^^ warning: this was previously accepted
}
22 changes: 22 additions & 0 deletions src/test/compile-fail/epoch-raw-pointer-method-2018.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2012 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.

// ignore-tidy-linelength
// compile-flags: -Zepoch=2018 -Zunstable-options

// tests that epochs work with the tyvar warning-turned-error

#[deny(warnings)]
fn main() {
let x = 0;
let y = &x as *const _;
let _ = y.is_null();
//~^ error: the type of this value must be known to call a method on a raw pointer on it [E0908]
}

0 comments on commit 6908fb7

Please sign in to comment.