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)
This commit is contained in:
Manish Goregaokar 2018-02-07 08:30:54 -08:00 committed by GitHub
commit 6908fb762d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 156 additions and 9 deletions

View File

@ -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)]

View File

@ -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,
@ -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;
@ -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
}
}
) }
@ -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 {
@ -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};
@ -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);

View File

@ -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};
@ -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,

View File

@ -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);

View File

@ -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! {

View File

@ -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
}

View File

@ -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]
}