mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Auto merge of #36818 - jonathandturner:rollup, r=jonathandturner
Rollup of 12 pull requests - Successful merges: #35286, #35892, #36460, #36704, #36741, #36760, #36787, #36789, #36794, #36803, #36811, #36813 - Failed merges:
This commit is contained in:
commit
91f34c0c70
4
configure
vendored
4
configure
vendored
@ -645,7 +645,6 @@ valopt datadir "${CFG_PREFIX}/share" "install data"
|
||||
valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
|
||||
valopt llvm-root "" "set LLVM root"
|
||||
valopt python "" "set path to python"
|
||||
valopt nodejs "" "set path to nodejs"
|
||||
valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
|
||||
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
|
||||
valopt android-cross-path "" "Android NDK standalone path (deprecated)"
|
||||
@ -762,9 +761,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then
|
||||
err "Found $python_version, but Python 2.7 is required"
|
||||
fi
|
||||
|
||||
# Checking for node, but not required
|
||||
probe CFG_NODEJS nodejs node
|
||||
|
||||
# If we have no git directory then we are probably a tarball distribution
|
||||
# and shouldn't attempt to load submodules
|
||||
if [ ! -e ${CFG_SRC_DIR}.git ]
|
||||
|
@ -104,8 +104,7 @@ fn main() {
|
||||
let is_panic_abort = args.windows(2).any(|a| {
|
||||
&*a[0] == "--crate-name" && &*a[1] == "panic_abort"
|
||||
});
|
||||
// FIXME(stage0): remove this `stage != "0"` condition
|
||||
if is_panic_abort && stage != "0" {
|
||||
if is_panic_abort {
|
||||
cmd.arg("-C").arg("panic=abort");
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ use std::process::Command;
|
||||
use build_helper::output;
|
||||
use filetime::FileTime;
|
||||
|
||||
use util::{exe, staticlib, libdir, mtime, is_dylib, copy};
|
||||
use util::{exe, libdir, mtime, is_dylib, copy};
|
||||
use {Build, Compiler, Mode};
|
||||
|
||||
/// Build the standard library.
|
||||
@ -40,20 +40,6 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
|
||||
let libdir = build.sysroot_libdir(compiler, target);
|
||||
let _ = fs::remove_dir_all(&libdir);
|
||||
t!(fs::create_dir_all(&libdir));
|
||||
// FIXME(stage0) remove this `if` after the next snapshot
|
||||
// The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap`
|
||||
// never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's
|
||||
// `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use
|
||||
// an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make
|
||||
// it to the final binary because now `libcore.rlib` also contains the symbols that
|
||||
// `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its
|
||||
// symbols are used instead of `libcompiler-rt.a`'s.
|
||||
if compiler.stage == 0 {
|
||||
let rtlib = &staticlib("compiler-rt", target);
|
||||
let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib")
|
||||
.join(target).join("lib").join(rtlib);
|
||||
copy(&src, &libdir.join(rtlib));
|
||||
}
|
||||
|
||||
// Some platforms have startup objects that may be required to produce the
|
||||
// libstd dynamic library, for example.
|
||||
|
@ -396,9 +396,6 @@ impl Config {
|
||||
self.rustc = Some(PathBuf::from(value).join("bin/rustc"));
|
||||
self.cargo = Some(PathBuf::from(value).join("bin/cargo"));
|
||||
}
|
||||
"CFG_NODEJS" if value.len() > 0 => {
|
||||
self.nodejs = Some(PathBuf::from(value));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -40,17 +40,23 @@ pub fn check(build: &mut Build) {
|
||||
panic!("PATH contains invalid character '\"'");
|
||||
}
|
||||
}
|
||||
let have_cmd = |cmd: &OsStr| {
|
||||
for path in env::split_paths(&path).map(|p| p.join(cmd)) {
|
||||
if fs::metadata(&path).is_ok() ||
|
||||
fs::metadata(path.with_extension("exe")).is_ok() {
|
||||
return Some(path);
|
||||
}
|
||||
}
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut need_cmd = |cmd: &OsStr| {
|
||||
if !checked.insert(cmd.to_owned()) {
|
||||
return
|
||||
}
|
||||
for path in env::split_paths(&path).map(|p| p.join(cmd)) {
|
||||
if fs::metadata(&path).is_ok() ||
|
||||
fs::metadata(path.with_extension("exe")).is_ok() {
|
||||
return
|
||||
}
|
||||
if have_cmd(cmd).is_none() {
|
||||
panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
|
||||
}
|
||||
panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
|
||||
};
|
||||
|
||||
// If we've got a git directory we're gona need git to update
|
||||
@ -75,8 +81,13 @@ pub fn check(build: &mut Build) {
|
||||
|
||||
need_cmd("python".as_ref());
|
||||
|
||||
// If a manual nodejs was added to the config,
|
||||
// of if a nodejs install is detected through config, use it.
|
||||
// Look for the nodejs command, needed for emscripten testing
|
||||
if let Some(node) = have_cmd("node".as_ref()) {
|
||||
build.config.nodejs = Some(node);
|
||||
} else if let Some(node) = have_cmd("nodejs".as_ref()) {
|
||||
build.config.nodejs = Some(node);
|
||||
}
|
||||
|
||||
if let Some(ref s) = build.config.nodejs {
|
||||
need_cmd(s.as_ref());
|
||||
}
|
||||
|
@ -61,7 +61,6 @@
|
||||
* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`).
|
||||
* `-=` (`var -= expr`): arithmetic subtraction & assignment. Overloadable (`SubAssign`).
|
||||
* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. See [Functions], [Closures].
|
||||
* `-> !` (`fn(…) -> !`, `|…| -> !`): diverging function or closure. See [Diverging Functions].
|
||||
* `.` (`expr.ident`): member access. See [Structs], [Method Syntax].
|
||||
* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal.
|
||||
* `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)].
|
||||
@ -159,6 +158,10 @@
|
||||
* `/*!…*/`: inner block doc comment. See [Comments].
|
||||
* `/**…*/`: outer block doc comment. See [Comments].
|
||||
|
||||
<!-- Special types -->
|
||||
|
||||
* `!`: always empty Never type. See [Diverging Functions].
|
||||
|
||||
<!-- Various things involving parens and tuples -->
|
||||
|
||||
* `()`: empty tuple (*a.k.a.* unit), both literal and type.
|
||||
|
@ -764,6 +764,13 @@ bound-list := bound | bound '+' bound-list
|
||||
bound := path | lifetime
|
||||
```
|
||||
|
||||
### Never type
|
||||
An empty type
|
||||
|
||||
```antlr
|
||||
never_type : "!" ;
|
||||
```
|
||||
|
||||
### Object types
|
||||
|
||||
**FIXME:** grammar?
|
||||
|
@ -127,7 +127,6 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Arc<T: ?Sized> {
|
||||
ptr: Shared<ArcInner<T>>,
|
||||
@ -153,7 +152,6 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
|
||||
/// nodes behind strong `Arc<T>` pointers, and then storing the parent pointers
|
||||
/// as `Weak<T>` pointers.
|
||||
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
#[stable(feature = "arc_weak", since = "1.4.0")]
|
||||
pub struct Weak<T: ?Sized> {
|
||||
ptr: Shared<ArcInner<T>>,
|
||||
|
@ -88,7 +88,6 @@
|
||||
#![feature(staged_api)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unique)]
|
||||
#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
|
||||
#![feature(unsize)]
|
||||
|
||||
#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))]
|
||||
|
@ -44,7 +44,6 @@ use core::cmp;
|
||||
/// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity
|
||||
/// field. This allows zero-sized types to not be special-cased by consumers of
|
||||
/// this type.
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
pub struct RawVec<T> {
|
||||
ptr: Unique<T>,
|
||||
cap: usize,
|
||||
|
@ -252,7 +252,6 @@ struct RcBox<T: ?Sized> {
|
||||
/// that you have to call them as e.g. `Rc::get_mut(&value)` instead of
|
||||
/// `value.get_mut()`. This avoids conflicts with methods of the inner
|
||||
/// type `T`.
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Rc<T: ?Sized> {
|
||||
ptr: Shared<RcBox<T>>,
|
||||
@ -873,7 +872,6 @@ impl<T> From<T> for Rc<T> {
|
||||
///
|
||||
/// [rc]: struct.Rc.html
|
||||
/// [downgrade]: struct.Rc.html#method.downgrade
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
#[stable(feature = "rc_weak", since = "1.4.0")]
|
||||
pub struct Weak<T: ?Sized> {
|
||||
ptr: Shared<RcBox<T>>,
|
||||
|
@ -52,7 +52,6 @@
|
||||
#![feature(step_by)]
|
||||
#![feature(unicode)]
|
||||
#![feature(unique)]
|
||||
#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
|
||||
#![cfg_attr(test, feature(rand, test))]
|
||||
|
||||
#![no_std]
|
||||
|
@ -68,7 +68,9 @@ macro_rules! vec {
|
||||
}
|
||||
|
||||
/// Use the syntax described in `std::fmt` to create a value of type `String`.
|
||||
/// See `std::fmt` for more information.
|
||||
/// See [`std::fmt`][fmt] for more information.
|
||||
///
|
||||
/// [fmt]: ../std/fmt/index.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -268,7 +268,6 @@ use super::range::RangeArgument;
|
||||
/// Vec does not currently guarantee the order in which elements are dropped
|
||||
/// (the order has changed in the past, and may change again).
|
||||
///
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Vec<T> {
|
||||
buf: RawVec<T>,
|
||||
|
@ -8,9 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![cfg_attr(not(stage0), feature(compiler_builtins))]
|
||||
#![feature(compiler_builtins)]
|
||||
#![no_std]
|
||||
#![cfg_attr(not(stage0), compiler_builtins)]
|
||||
#![compiler_builtins]
|
||||
#![unstable(feature = "compiler_builtins_lib",
|
||||
reason = "internal implementation detail of rustc right now",
|
||||
issue = "0")]
|
||||
|
@ -129,13 +129,6 @@ pub struct AssertParamIsClone<T: Clone + ?Sized> { _field: ::marker::PhantomData
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T> }
|
||||
#[cfg(stage0)]
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
#[unstable(feature = "derive_clone_copy",
|
||||
reason = "deriving hack, should not be public",
|
||||
issue = "0")]
|
||||
pub fn assert_receiver_is_clone<T: Clone + ?Sized>(_: &T) {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T: ?Sized> Clone for &'a T {
|
||||
|
@ -194,14 +194,12 @@ extern "rust-intrinsic" {
|
||||
/// own, or if it does not enable any significant optimizations.
|
||||
pub fn assume(b: bool);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
/// Hints to the compiler that branch condition is likely to be true.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
pub fn likely(b: bool) -> bool;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
/// Hints to the compiler that branch condition is likely to be false.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
|
@ -32,7 +32,6 @@ use ty::{self, Ty, TyCtxt};
|
||||
use mir::repr::Mir;
|
||||
use mir::mir_map::MirMap;
|
||||
use session::Session;
|
||||
use session::config::PanicStrategy;
|
||||
use session::search_paths::PathKind;
|
||||
use util::nodemap::{NodeSet, DefIdMap};
|
||||
use std::path::PathBuf;
|
||||
@ -46,6 +45,7 @@ use syntax_pos::Span;
|
||||
use rustc_back::target::Target;
|
||||
use hir;
|
||||
use hir::intravisit::Visitor;
|
||||
use rustc_back::PanicStrategy;
|
||||
|
||||
pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
|
||||
|
||||
|
@ -64,9 +64,10 @@
|
||||
use hir::def_id::CrateNum;
|
||||
|
||||
use session;
|
||||
use session::config::{self, PanicStrategy};
|
||||
use session::config;
|
||||
use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic};
|
||||
use util::nodemap::FnvHashMap;
|
||||
use rustc_back::PanicStrategy;
|
||||
|
||||
/// A list of dependencies for a certain crate type.
|
||||
///
|
||||
@ -357,7 +358,7 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) {
|
||||
// only one, but we perform validation here that all the panic strategy
|
||||
// compilation modes for the whole DAG are valid.
|
||||
if let Some((cnum, found_strategy)) = panic_runtime {
|
||||
let desired_strategy = sess.opts.cg.panic.clone();
|
||||
let desired_strategy = sess.panic_strategy();
|
||||
|
||||
// First up, validate that our selected panic runtime is indeed exactly
|
||||
// our same strategy.
|
||||
|
@ -10,10 +10,11 @@
|
||||
|
||||
//! Validity checking for weak lang items
|
||||
|
||||
use session::config::{self, PanicStrategy};
|
||||
use session::config;
|
||||
use session::Session;
|
||||
use middle::lang_items;
|
||||
|
||||
use rustc_back::PanicStrategy;
|
||||
use syntax::ast;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax_pos::Span;
|
||||
@ -92,7 +93,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
|
||||
// symbols. Other panic runtimes ensure that the relevant symbols are
|
||||
// available to link things together, but they're never exercised.
|
||||
let mut whitelisted = HashSet::new();
|
||||
if sess.opts.cg.panic != PanicStrategy::Unwind {
|
||||
if sess.panic_strategy() != PanicStrategy::Unwind {
|
||||
whitelisted.insert(lang_items::EhPersonalityLangItem);
|
||||
whitelisted.insert(lang_items::EhUnwindResumeLangItem);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ pub use self::DebugInfoLevel::*;
|
||||
use session::{early_error, early_warn, Session};
|
||||
use session::search_paths::SearchPaths;
|
||||
|
||||
use rustc_back::PanicStrategy;
|
||||
use rustc_back::target::Target;
|
||||
use lint;
|
||||
use middle::cstore;
|
||||
@ -492,21 +493,6 @@ impl Passes {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub enum PanicStrategy {
|
||||
Unwind,
|
||||
Abort,
|
||||
}
|
||||
|
||||
impl PanicStrategy {
|
||||
pub fn desc(&self) -> &str {
|
||||
match *self {
|
||||
PanicStrategy::Unwind => "unwind",
|
||||
PanicStrategy::Abort => "abort",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
|
||||
/// at once. The goal of this macro is to define an interface that can be
|
||||
/// programmatically used by the option parser in order to initialize the struct
|
||||
@ -620,7 +606,8 @@ macro_rules! options {
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod $mod_set {
|
||||
use super::{$struct_name, Passes, SomePasses, AllPasses, PanicStrategy};
|
||||
use super::{$struct_name, Passes, SomePasses, AllPasses};
|
||||
use rustc_back::PanicStrategy;
|
||||
|
||||
$(
|
||||
pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
|
||||
@ -732,10 +719,10 @@ macro_rules! options {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
|
||||
fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
|
||||
match v {
|
||||
Some("unwind") => *slot = PanicStrategy::Unwind,
|
||||
Some("abort") => *slot = PanicStrategy::Abort,
|
||||
Some("unwind") => *slot = Some(PanicStrategy::Unwind),
|
||||
Some("abort") => *slot = Some(PanicStrategy::Abort),
|
||||
_ => return false
|
||||
}
|
||||
true
|
||||
@ -809,7 +796,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
|
||||
"explicitly enable the cfg(debug_assertions) directive"),
|
||||
inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
|
||||
"set the inlining threshold for"),
|
||||
panic: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy,
|
||||
panic: Option<PanicStrategy> = (None, parse_panic_strategy,
|
||||
[TRACKED], "panic strategy to compile crate with"),
|
||||
}
|
||||
|
||||
@ -1665,9 +1652,10 @@ mod dep_tracking {
|
||||
use std::collections::BTreeMap;
|
||||
use std::hash::{Hash, SipHasher};
|
||||
use std::path::PathBuf;
|
||||
use super::{Passes, PanicStrategy, CrateType, OptLevel, DebugInfoLevel,
|
||||
use super::{Passes, CrateType, OptLevel, DebugInfoLevel,
|
||||
OutputTypes, Externs, ErrorOutputType};
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use rustc_back::PanicStrategy;
|
||||
|
||||
pub trait DepTrackingHash {
|
||||
fn hash(&self, &mut SipHasher, ErrorOutputType);
|
||||
@ -1706,6 +1694,7 @@ mod dep_tracking {
|
||||
impl_dep_tracking_hash_via_hash!(Option<bool>);
|
||||
impl_dep_tracking_hash_via_hash!(Option<usize>);
|
||||
impl_dep_tracking_hash_via_hash!(Option<String>);
|
||||
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
|
||||
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
|
||||
impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
|
||||
impl_dep_tracking_hash_via_hash!(CrateType);
|
||||
@ -1772,7 +1761,8 @@ mod tests {
|
||||
use std::iter::FromIterator;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use super::{OutputType, OutputTypes, Externs, PanicStrategy};
|
||||
use super::{OutputType, OutputTypes, Externs};
|
||||
use rustc_back::PanicStrategy;
|
||||
use syntax::{ast, attr};
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::codemap::dummy_spanned;
|
||||
@ -2318,7 +2308,7 @@ mod tests {
|
||||
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
|
||||
|
||||
opts = reference.clone();
|
||||
opts.cg.panic = PanicStrategy::Abort;
|
||||
opts.cg.panic = Some(PanicStrategy::Abort);
|
||||
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ use lint;
|
||||
use middle::cstore::CrateStore;
|
||||
use middle::dependency_format;
|
||||
use session::search_paths::PathKind;
|
||||
use session::config::{DebugInfoLevel, PanicStrategy};
|
||||
use session::config::DebugInfoLevel;
|
||||
use ty::tls;
|
||||
use util::nodemap::{NodeMap, FnvHashMap};
|
||||
use util::common::duration_to_secs_str;
|
||||
@ -33,6 +33,7 @@ use syntax::{ast, codemap};
|
||||
use syntax::feature_gate::AttributeType;
|
||||
use syntax_pos::{Span, MultiSpan};
|
||||
|
||||
use rustc_back::PanicStrategy;
|
||||
use rustc_back::target::Target;
|
||||
use rustc_data_structures::flock;
|
||||
use llvm;
|
||||
@ -42,6 +43,7 @@ use std::cell::{self, Cell, RefCell};
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::ffi::CString;
|
||||
use std::io::Write;
|
||||
use std::rc::Rc;
|
||||
use std::fmt;
|
||||
use std::time::Duration;
|
||||
@ -306,9 +308,13 @@ impl Session {
|
||||
pub fn lto(&self) -> bool {
|
||||
self.opts.cg.lto
|
||||
}
|
||||
/// Returns the panic strategy for this compile session. If the user explicitly selected one
|
||||
/// using '-C panic', use that, otherwise use the panic strategy defined by the target.
|
||||
pub fn panic_strategy(&self) -> PanicStrategy {
|
||||
self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy)
|
||||
}
|
||||
pub fn no_landing_pads(&self) -> bool {
|
||||
self.opts.debugging_opts.no_landing_pads ||
|
||||
self.opts.cg.panic == PanicStrategy::Abort
|
||||
self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort
|
||||
}
|
||||
pub fn unstable_options(&self) -> bool {
|
||||
self.opts.debugging_opts.unstable_options
|
||||
@ -449,7 +455,8 @@ pub fn build_session(sopts: config::Options,
|
||||
local_crate_source_file,
|
||||
registry,
|
||||
cstore,
|
||||
Rc::new(codemap::CodeMap::new()))
|
||||
Rc::new(codemap::CodeMap::new()),
|
||||
None)
|
||||
}
|
||||
|
||||
pub fn build_session_with_codemap(sopts: config::Options,
|
||||
@ -457,7 +464,8 @@ pub fn build_session_with_codemap(sopts: config::Options,
|
||||
local_crate_source_file: Option<PathBuf>,
|
||||
registry: errors::registry::Registry,
|
||||
cstore: Rc<for<'a> CrateStore<'a>>,
|
||||
codemap: Rc<codemap::CodeMap>)
|
||||
codemap: Rc<codemap::CodeMap>,
|
||||
emitter_dest: Option<Box<Write + Send>>)
|
||||
-> Session {
|
||||
// FIXME: This is not general enough to make the warning lint completely override
|
||||
// normal diagnostic warnings, since the warning lint can also be denied and changed
|
||||
@ -470,14 +478,21 @@ pub fn build_session_with_codemap(sopts: config::Options,
|
||||
.unwrap_or(true);
|
||||
let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
|
||||
|
||||
let emitter: Box<Emitter> = match sopts.error_format {
|
||||
config::ErrorOutputType::HumanReadable(color_config) => {
|
||||
let emitter: Box<Emitter> = match (sopts.error_format, emitter_dest) {
|
||||
(config::ErrorOutputType::HumanReadable(color_config), None) => {
|
||||
Box::new(EmitterWriter::stderr(color_config,
|
||||
Some(codemap.clone())))
|
||||
}
|
||||
config::ErrorOutputType::Json => {
|
||||
(config::ErrorOutputType::HumanReadable(_), Some(dst)) => {
|
||||
Box::new(EmitterWriter::new(dst,
|
||||
Some(codemap.clone())))
|
||||
}
|
||||
(config::ErrorOutputType::Json, None) => {
|
||||
Box::new(JsonEmitter::stderr(Some(registry), codemap.clone()))
|
||||
}
|
||||
(config::ErrorOutputType::Json, Some(dst)) => {
|
||||
Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone()))
|
||||
}
|
||||
};
|
||||
|
||||
let diagnostic_handler =
|
||||
|
@ -17,7 +17,7 @@ use hir::TraitMap;
|
||||
use hir::def::DefMap;
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
|
||||
use hir::map as ast_map;
|
||||
use hir::map::{DefKey, DefPath, DefPathData, DisambiguatedDefPathData};
|
||||
use hir::map::{DefKey, DefPathData, DisambiguatedDefPathData};
|
||||
use middle::free_region::FreeRegionMap;
|
||||
use middle::region::RegionMaps;
|
||||
use middle::resolve_lifetime;
|
||||
@ -546,8 +546,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn retrace_path(self, path: &DefPath) -> Option<DefId> {
|
||||
debug!("retrace_path(path={:?}, krate={:?})", path, self.crate_name(path.krate));
|
||||
pub fn retrace_path(self,
|
||||
krate: CrateNum,
|
||||
path_data: &[DisambiguatedDefPathData])
|
||||
-> Option<DefId> {
|
||||
debug!("retrace_path(path={:?}, krate={:?})", path_data, self.crate_name(krate));
|
||||
|
||||
let root_key = DefKey {
|
||||
parent: None,
|
||||
@ -557,22 +560,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
},
|
||||
};
|
||||
|
||||
let root_index = self.def_index_for_def_key(path.krate, root_key)
|
||||
let root_index = self.def_index_for_def_key(krate, root_key)
|
||||
.expect("no root key?");
|
||||
|
||||
debug!("retrace_path: root_index={:?}", root_index);
|
||||
|
||||
let mut index = root_index;
|
||||
for data in &path.data {
|
||||
for data in path_data {
|
||||
let key = DefKey { parent: Some(index), disambiguated_data: data.clone() };
|
||||
debug!("retrace_path: key={:?}", key);
|
||||
match self.def_index_for_def_key(path.krate, key) {
|
||||
match self.def_index_for_def_key(krate, key) {
|
||||
Some(i) => index = i,
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
|
||||
Some(DefId { krate: path.krate, index: index })
|
||||
Some(DefId { krate: krate, index: index })
|
||||
}
|
||||
|
||||
pub fn type_parameter_def(self,
|
||||
|
@ -45,8 +45,36 @@ extern crate libc;
|
||||
extern crate serialize;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
extern crate serialize as rustc_serialize; // used by deriving
|
||||
|
||||
pub mod tempdir;
|
||||
pub mod sha2;
|
||||
pub mod target;
|
||||
pub mod slice;
|
||||
pub mod dynamic_lib;
|
||||
|
||||
use serialize::json::{Json, ToJson};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub enum PanicStrategy {
|
||||
Unwind,
|
||||
Abort,
|
||||
}
|
||||
|
||||
impl PanicStrategy {
|
||||
pub fn desc(&self) -> &str {
|
||||
match *self {
|
||||
PanicStrategy::Unwind => "unwind",
|
||||
PanicStrategy::Abort => "abort",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for PanicStrategy {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
PanicStrategy::Abort => "abort".to_json(),
|
||||
PanicStrategy::Unwind => "unwind".to_json(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,8 @@ use std::default::Default;
|
||||
use std::io::prelude::*;
|
||||
use syntax::abi::Abi;
|
||||
|
||||
use PanicStrategy;
|
||||
|
||||
mod android_base;
|
||||
mod apple_base;
|
||||
mod apple_ios_base;
|
||||
@ -347,6 +349,9 @@ pub struct TargetOptions {
|
||||
/// Maximum integer size in bits that this target can perform atomic
|
||||
/// operations on.
|
||||
pub max_atomic_width: u64,
|
||||
|
||||
/// Panic strategy: "unwind" or "abort"
|
||||
pub panic_strategy: PanicStrategy,
|
||||
}
|
||||
|
||||
impl Default for TargetOptions {
|
||||
@ -396,6 +401,7 @@ impl Default for TargetOptions {
|
||||
has_elf_tls: false,
|
||||
obj_is_bitcode: false,
|
||||
max_atomic_width: 0,
|
||||
panic_strategy: PanicStrategy::Unwind,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -474,6 +480,19 @@ impl Target {
|
||||
.map(|o| o.as_u64()
|
||||
.map(|s| base.options.$key_name = s));
|
||||
} );
|
||||
($key_name:ident, PanicStrategy) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
|
||||
match s {
|
||||
"unwind" => base.options.$key_name = PanicStrategy::Unwind,
|
||||
"abort" => base.options.$key_name = PanicStrategy::Abort,
|
||||
_ => return Some(Err(format!("'{}' is not a valid value for \
|
||||
panic-strategy. Use 'unwind' or 'abort'.",
|
||||
s))),
|
||||
}
|
||||
Some(Ok(()))
|
||||
})).unwrap_or(Ok(()))
|
||||
} );
|
||||
($key_name:ident, list) => ( {
|
||||
let name = (stringify!($key_name)).replace("_", "-");
|
||||
obj.find(&name[..]).map(|o| o.as_array()
|
||||
@ -534,6 +553,7 @@ impl Target {
|
||||
key!(has_elf_tls, bool);
|
||||
key!(obj_is_bitcode, bool);
|
||||
key!(max_atomic_width, u64);
|
||||
try!(key!(panic_strategy, PanicStrategy));
|
||||
|
||||
Ok(base)
|
||||
}
|
||||
@ -676,6 +696,7 @@ impl ToJson for Target {
|
||||
target_option_val!(has_elf_tls);
|
||||
target_option_val!(obj_is_bitcode);
|
||||
target_option_val!(max_atomic_width);
|
||||
target_option_val!(panic_strategy);
|
||||
|
||||
Json::Object(d)
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ use rustc::dep_graph::DepGraph;
|
||||
use rustc::session::{self, config, Session, build_session, CompileResult};
|
||||
use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
|
||||
use rustc::session::config::nightly_options;
|
||||
use rustc::session::early_error;
|
||||
use rustc::lint::Lint;
|
||||
use rustc::lint;
|
||||
use rustc_metadata::loader;
|
||||
@ -93,8 +94,6 @@ use std::str;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
|
||||
use rustc::session::early_error;
|
||||
|
||||
use syntax::{ast, json};
|
||||
use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
|
||||
use syntax::feature_gate::{GatedCfg, UnstableFeatures};
|
||||
@ -131,17 +130,18 @@ pub fn abort_on_err<T>(result: Result<T, usize>, sess: &Session) -> T {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(args: Vec<String>) -> isize {
|
||||
pub fn run<F>(run_compiler: F) -> isize
|
||||
where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
|
||||
{
|
||||
monitor(move || {
|
||||
let (result, session) = run_compiler(&args, &mut RustcDefaultCalls);
|
||||
let (result, session) = run_compiler();
|
||||
if let Err(err_count) = result {
|
||||
if err_count > 0 {
|
||||
match session {
|
||||
Some(sess) => sess.fatal(&abort_msg(err_count)),
|
||||
None => {
|
||||
let emitter =
|
||||
errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
|
||||
None);
|
||||
errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None);
|
||||
let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
|
||||
handler.emit(&MultiSpan::new(),
|
||||
&abort_msg(err_count),
|
||||
@ -155,20 +155,15 @@ pub fn run(args: Vec<String>) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn run_compiler<'a>(args: &[String],
|
||||
callbacks: &mut CompilerCalls<'a>)
|
||||
-> (CompileResult, Option<Session>) {
|
||||
run_compiler_with_file_loader(args, callbacks, box RealFileLoader)
|
||||
}
|
||||
|
||||
// Parse args and run the compiler. This is the primary entry point for rustc.
|
||||
// See comments on CompilerCalls below for details about the callbacks argument.
|
||||
// The FileLoader provides a way to load files from sources other than the file system.
|
||||
pub fn run_compiler_with_file_loader<'a, L>(args: &[String],
|
||||
callbacks: &mut CompilerCalls<'a>,
|
||||
loader: Box<L>)
|
||||
-> (CompileResult, Option<Session>)
|
||||
where L: FileLoader + 'static {
|
||||
pub fn run_compiler<'a>(args: &[String],
|
||||
callbacks: &mut CompilerCalls<'a>,
|
||||
file_loader: Option<Box<FileLoader + 'static>>,
|
||||
emitter_dest: Option<Box<Write + Send>>)
|
||||
-> (CompileResult, Option<Session>)
|
||||
{
|
||||
macro_rules! do_or_return {($expr: expr, $sess: expr) => {
|
||||
match $expr {
|
||||
Compilation::Stop => return (Ok(()), $sess),
|
||||
@ -207,13 +202,16 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String],
|
||||
|
||||
let dep_graph = DepGraph::new(sopts.build_dep_graph());
|
||||
let cstore = Rc::new(CStore::new(&dep_graph));
|
||||
|
||||
let loader = file_loader.unwrap_or(box RealFileLoader);
|
||||
let codemap = Rc::new(CodeMap::with_file_loader(loader));
|
||||
let sess = session::build_session_with_codemap(sopts,
|
||||
&dep_graph,
|
||||
input_file_path,
|
||||
descriptions,
|
||||
cstore.clone(),
|
||||
codemap);
|
||||
codemap,
|
||||
emitter_dest);
|
||||
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
|
||||
let mut cfg = config::build_configuration(&sess, cfg);
|
||||
target_features::add_configuration(&mut cfg, &sess);
|
||||
@ -1144,6 +1142,9 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let result = run(env::args().collect());
|
||||
let result = run(|| run_compiler(&env::args().collect::<Vec<_>>(),
|
||||
&mut RustcDefaultCalls,
|
||||
None,
|
||||
None));
|
||||
process::exit(result as i32);
|
||||
}
|
||||
|
@ -99,8 +99,10 @@ impl EmitterWriter {
|
||||
pub fn new(dst: Box<Write + Send>,
|
||||
code_map: Option<Rc<CodeMapper>>)
|
||||
-> EmitterWriter {
|
||||
EmitterWriter { dst: Raw(dst),
|
||||
cm: code_map}
|
||||
EmitterWriter {
|
||||
dst: Raw(dst),
|
||||
cm: code_map,
|
||||
}
|
||||
}
|
||||
|
||||
fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec<FileWithAnnotatedLines> {
|
||||
|
@ -20,6 +20,7 @@ use rustc::ty::TyCtxt;
|
||||
use rustc::util::nodemap::DefIdMap;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::iter::once;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Index into the DefIdDirectory
|
||||
#[derive(Copy, Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq,
|
||||
@ -90,18 +91,29 @@ impl DefIdDirectory {
|
||||
}
|
||||
|
||||
pub fn retrace(&self, tcx: TyCtxt) -> RetracedDefIdDirectory {
|
||||
let max_current_crate = self.max_current_crate(tcx);
|
||||
|
||||
fn make_key(name: &str, disambiguator: &str) -> String {
|
||||
format!("{}/{}", name, disambiguator)
|
||||
}
|
||||
|
||||
let new_krates: HashMap<_, _> =
|
||||
once(LOCAL_CRATE)
|
||||
.chain(tcx.sess.cstore.crates())
|
||||
.map(|krate| (make_key(&tcx.crate_name(krate),
|
||||
&tcx.crate_disambiguator(krate)), krate))
|
||||
.collect();
|
||||
|
||||
let ids = self.paths.iter()
|
||||
.map(|path| {
|
||||
if self.krate_still_valid(tcx, max_current_crate, path.krate) {
|
||||
tcx.retrace_path(path)
|
||||
let old_krate_id = path.krate.as_usize();
|
||||
assert!(old_krate_id < self.krates.len());
|
||||
let old_crate_info = &self.krates[old_krate_id];
|
||||
let old_crate_key = make_key(&old_crate_info.name,
|
||||
&old_crate_info.disambiguator);
|
||||
if let Some(&new_crate_key) = new_krates.get(&old_crate_key) {
|
||||
tcx.retrace_path(new_crate_key, &path.data)
|
||||
} else {
|
||||
debug!("crate {} changed from {:?} to {:?}/{:?}",
|
||||
path.krate,
|
||||
self.krates[path.krate.as_usize()],
|
||||
tcx.crate_name(path.krate),
|
||||
tcx.crate_disambiguator(path.krate));
|
||||
debug!("crate {:?} no longer exists", old_crate_key);
|
||||
None
|
||||
}
|
||||
})
|
||||
|
@ -19,7 +19,7 @@ use rustc::hir::def_id::{CrateNum, DefIndex};
|
||||
use rustc::hir::svh::Svh;
|
||||
use rustc::middle::cstore::LoadedMacro;
|
||||
use rustc::session::{config, Session};
|
||||
use rustc::session::config::PanicStrategy;
|
||||
use rustc_back::PanicStrategy;
|
||||
use rustc::session::search_paths::PathKind;
|
||||
use rustc::middle;
|
||||
use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
|
||||
@ -710,7 +710,7 @@ impl<'a> CrateReader<'a> {
|
||||
// The logic for finding the panic runtime here is pretty much the same
|
||||
// as the allocator case with the only addition that the panic strategy
|
||||
// compilation mode also comes into play.
|
||||
let desired_strategy = self.sess.opts.cg.panic.clone();
|
||||
let desired_strategy = self.sess.panic_strategy();
|
||||
let mut runtime_found = false;
|
||||
let mut needs_panic_runtime = attr::contains_name(&krate.attrs,
|
||||
"needs_panic_runtime");
|
||||
|
@ -26,7 +26,7 @@ use rustc::hir::map::DefKey;
|
||||
use rustc::mir::repr::Mir;
|
||||
use rustc::mir::mir_map::MirMap;
|
||||
use rustc::util::nodemap::{NodeSet, DefIdMap};
|
||||
use rustc::session::config::PanicStrategy;
|
||||
use rustc_back::PanicStrategy;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use syntax::ast;
|
||||
|
@ -19,7 +19,7 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId};
|
||||
use rustc::hir::map::DefKey;
|
||||
use rustc::hir::svh::Svh;
|
||||
use rustc::middle::cstore::ExternCrate;
|
||||
use rustc::session::config::PanicStrategy;
|
||||
use rustc_back::PanicStrategy;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet};
|
||||
|
||||
|
@ -1293,7 +1293,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
triple: tcx.sess.opts.target_triple.clone(),
|
||||
hash: link_meta.crate_hash,
|
||||
disambiguator: tcx.sess.local_crate_disambiguator().to_string(),
|
||||
panic_strategy: tcx.sess.opts.cg.panic.clone(),
|
||||
panic_strategy: tcx.sess.panic_strategy(),
|
||||
plugin_registrar_fn: tcx.sess.plugin_registrar_fn.get().map(|id| {
|
||||
tcx.map.local_def_id(id).index
|
||||
}),
|
||||
|
@ -18,7 +18,7 @@ use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::session::config::PanicStrategy;
|
||||
use rustc_back::PanicStrategy;
|
||||
|
||||
use rustc_serialize as serialize;
|
||||
use syntax::{ast, attr};
|
||||
|
@ -683,9 +683,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
};
|
||||
|
||||
match (value_result, type_result) {
|
||||
// With `#![feature(item_like_imports)]`, all namespaces
|
||||
// must be re-exported with extra visibility for an error to occur.
|
||||
(Ok(value_binding), Ok(type_binding)) if self.new_import_semantics => {
|
||||
// All namespaces must be re-exported with extra visibility for an error to occur.
|
||||
(Ok(value_binding), Ok(type_binding)) => {
|
||||
let vis = directive.vis.get();
|
||||
if !value_binding.pseudo_vis().is_at_least(vis, self) &&
|
||||
!type_binding.pseudo_vis().is_at_least(vis, self) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use llvm::{self, ValueRef};
|
||||
use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector};
|
||||
use base;
|
||||
use build::AllocaFcx;
|
||||
use common::{type_is_fat_ptr, BlockAndBuilder, C_uint};
|
||||
@ -598,3 +598,73 @@ impl FnType {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn align_up_to(off: usize, a: usize) -> usize {
|
||||
return (off + a - 1) / a * a;
|
||||
}
|
||||
|
||||
fn align(off: usize, ty: Type, pointer: usize) -> usize {
|
||||
let a = ty_align(ty, pointer);
|
||||
return align_up_to(off, a);
|
||||
}
|
||||
|
||||
pub fn ty_align(ty: Type, pointer: usize) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => pointer,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
1
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t, pointer)))
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt, pointer)
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt, pointer) * len
|
||||
}
|
||||
_ => bug!("ty_align: unhandled type")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ty_size(ty: Type, pointer: usize) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => pointer,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(0, |s, t| s + ty_size(*t, pointer))
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
let size = str_tys.iter().fold(0, |s, t| {
|
||||
align(s, *t, pointer) + ty_size(*t, pointer)
|
||||
});
|
||||
align(size, ty, pointer)
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let len = ty.array_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt, pointer);
|
||||
len * eltsz
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt, pointer);
|
||||
len * eltsz
|
||||
},
|
||||
_ => bug!("ty_size: unhandled type")
|
||||
}
|
||||
}
|
||||
|
@ -11,78 +11,12 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
|
||||
use abi::{FnType, ArgType};
|
||||
use abi::{self, FnType, ArgType};
|
||||
use context::CrateContext;
|
||||
use type_::Type;
|
||||
|
||||
use std::cmp;
|
||||
|
||||
fn align_up_to(off: usize, a: usize) -> usize {
|
||||
return (off + a - 1) / a * a;
|
||||
}
|
||||
|
||||
fn align(off: usize, ty: Type) -> usize {
|
||||
let a = ty_align(ty);
|
||||
return align_up_to(off, a);
|
||||
}
|
||||
|
||||
fn ty_align(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 8,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
1
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt)
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt) * len
|
||||
}
|
||||
_ => bug!("ty_align: unhandled type")
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_size(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 8,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(0, |s, t| s + ty_size(*t))
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
|
||||
align(size, ty)
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let len = ty.array_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt);
|
||||
len * eltsz
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt);
|
||||
len * eltsz
|
||||
}
|
||||
_ => bug!("ty_size: unhandled type")
|
||||
}
|
||||
abi::ty_size(ty, 8)
|
||||
}
|
||||
|
||||
fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
|
||||
|
@ -11,7 +11,7 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
|
||||
use abi::{FnType, ArgType};
|
||||
use abi::{self, align_up_to, FnType, ArgType};
|
||||
use context::CrateContext;
|
||||
use type_::Type;
|
||||
|
||||
@ -24,40 +24,13 @@ pub enum Flavor {
|
||||
|
||||
type TyAlignFn = fn(ty: Type) -> usize;
|
||||
|
||||
fn align_up_to(off: usize, a: usize) -> usize {
|
||||
return (off + a - 1) / a * a;
|
||||
}
|
||||
|
||||
fn align(off: usize, ty: Type, align_fn: TyAlignFn) -> usize {
|
||||
let a = align_fn(ty);
|
||||
return align_up_to(off, a);
|
||||
}
|
||||
|
||||
fn general_ty_align(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 4,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
1
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(1, |a, t| cmp::max(a, general_ty_align(*t)))
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let elt = ty.element_type();
|
||||
general_ty_align(elt)
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
general_ty_align(elt) * len
|
||||
}
|
||||
_ => bug!("ty_align: unhandled type")
|
||||
}
|
||||
abi::ty_align(ty, 4)
|
||||
}
|
||||
|
||||
// For more information see:
|
||||
|
@ -13,77 +13,17 @@
|
||||
use libc::c_uint;
|
||||
use std::cmp;
|
||||
use llvm;
|
||||
use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
|
||||
use abi::{ArgType, FnType};
|
||||
use llvm::{Integer, Pointer, Float, Double, Vector};
|
||||
use abi::{self, align_up_to, ArgType, FnType};
|
||||
use context::CrateContext;
|
||||
use type_::Type;
|
||||
|
||||
fn align_up_to(off: usize, a: usize) -> usize {
|
||||
return (off + a - 1) / a * a;
|
||||
}
|
||||
|
||||
fn align(off: usize, ty: Type) -> usize {
|
||||
let a = ty_align(ty);
|
||||
return align_up_to(off, a);
|
||||
}
|
||||
|
||||
fn ty_align(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 4,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
1
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt)
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt) * len
|
||||
}
|
||||
_ => bug!("ty_align: unhandled type")
|
||||
}
|
||||
abi::ty_align(ty, 4)
|
||||
}
|
||||
|
||||
fn ty_size(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 4,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(0, |s, t| s + ty_size(*t))
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
|
||||
align(size, ty)
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let len = ty.array_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt);
|
||||
len * eltsz
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt);
|
||||
len * eltsz
|
||||
}
|
||||
_ => bug!("ty_size: unhandled type")
|
||||
}
|
||||
abi::ty_size(ty, 4)
|
||||
}
|
||||
|
||||
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
|
||||
|
@ -13,77 +13,17 @@
|
||||
use libc::c_uint;
|
||||
use std::cmp;
|
||||
use llvm;
|
||||
use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
|
||||
use abi::{ArgType, FnType};
|
||||
use llvm::{Integer, Pointer, Float, Double, Vector};
|
||||
use abi::{self, align_up_to, ArgType, FnType};
|
||||
use context::CrateContext;
|
||||
use type_::Type;
|
||||
|
||||
fn align_up_to(off: usize, a: usize) -> usize {
|
||||
return (off + a - 1) / a * a;
|
||||
}
|
||||
|
||||
fn align(off: usize, ty: Type) -> usize {
|
||||
let a = ty_align(ty);
|
||||
return align_up_to(off, a);
|
||||
}
|
||||
|
||||
fn ty_align(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 8,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
1
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt)
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt) * len
|
||||
}
|
||||
_ => bug!("ty_align: unhandled type")
|
||||
}
|
||||
abi::ty_align(ty, 8)
|
||||
}
|
||||
|
||||
fn ty_size(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 8,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(0, |s, t| s + ty_size(*t))
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
|
||||
align(size, ty)
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let len = ty.array_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt);
|
||||
len * eltsz
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt);
|
||||
len * eltsz
|
||||
}
|
||||
_ => bug!("ty_size: unhandled type")
|
||||
}
|
||||
abi::ty_size(ty, 8)
|
||||
}
|
||||
|
||||
fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
|
||||
|
@ -10,67 +10,26 @@
|
||||
|
||||
use libc::c_uint;
|
||||
use llvm;
|
||||
use llvm::{Integer, Pointer, Float, Double, Struct, Array};
|
||||
use abi::{FnType, ArgType};
|
||||
use llvm::{Integer, Pointer, Float, Double, Vector};
|
||||
use abi::{self, align_up_to, FnType, ArgType};
|
||||
use context::CrateContext;
|
||||
use type_::Type;
|
||||
|
||||
use std::cmp;
|
||||
|
||||
fn align_up_to(off: usize, a: usize) -> usize {
|
||||
return (off + a - 1) / a * a;
|
||||
}
|
||||
|
||||
fn align(off: usize, ty: Type) -> usize {
|
||||
let a = ty_align(ty);
|
||||
return align_up_to(off, a);
|
||||
}
|
||||
|
||||
fn ty_align(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 4,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
1
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt)
|
||||
}
|
||||
_ => bug!("ty_size: unhandled type")
|
||||
if ty.kind() == Vector {
|
||||
bug!("ty_size: unhandled type")
|
||||
} else {
|
||||
abi::ty_align(ty, 4)
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_size(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 4,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(0, |s, t| s + ty_size(*t))
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
|
||||
align(size, ty)
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let len = ty.array_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt);
|
||||
len * eltsz
|
||||
}
|
||||
_ => bug!("ty_size: unhandled type")
|
||||
if ty.kind() == Vector {
|
||||
bug!("ty_size: unhandled type")
|
||||
} else {
|
||||
abi::ty_size(ty, 4)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,67 +15,16 @@
|
||||
// Alignment of 128 bit types is not currently handled, this will
|
||||
// need to be fixed when PowerPC vector support is added.
|
||||
|
||||
use llvm::{Integer, Pointer, Float, Double, Struct, Array};
|
||||
use abi::{FnType, ArgType};
|
||||
use llvm::{Integer, Pointer, Float, Double, Struct, Vector, Array};
|
||||
use abi::{self, FnType, ArgType};
|
||||
use context::CrateContext;
|
||||
use type_::Type;
|
||||
|
||||
use std::cmp;
|
||||
|
||||
fn align_up_to(off: usize, a: usize) -> usize {
|
||||
return (off + a - 1) / a * a;
|
||||
}
|
||||
|
||||
fn align(off: usize, ty: Type) -> usize {
|
||||
let a = ty_align(ty);
|
||||
return align_up_to(off, a);
|
||||
}
|
||||
|
||||
fn ty_align(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 8,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
1
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt)
|
||||
}
|
||||
_ => bug!("ty_align: unhandled type")
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_size(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 8,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(0, |s, t| s + ty_size(*t))
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
|
||||
align(size, ty)
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let len = ty.array_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt);
|
||||
len * eltsz
|
||||
}
|
||||
_ => bug!("ty_size: unhandled type")
|
||||
if ty.kind() == Vector {
|
||||
bug!("ty_size: unhandled type")
|
||||
} else {
|
||||
abi::ty_size(ty, 8)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,16 +12,12 @@
|
||||
// for a pre-z13 machine or using -mno-vx.
|
||||
|
||||
use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
|
||||
use abi::{FnType, ArgType};
|
||||
use abi::{align_up_to, FnType, ArgType};
|
||||
use context::CrateContext;
|
||||
use type_::Type;
|
||||
|
||||
use std::cmp;
|
||||
|
||||
fn align_up_to(off: usize, a: usize) -> usize {
|
||||
return (off + a - 1) / a * a;
|
||||
}
|
||||
|
||||
fn align(off: usize, ty: Type) -> usize {
|
||||
let a = ty_align(ty);
|
||||
return align_up_to(off, a);
|
||||
|
@ -16,12 +16,10 @@ use self::RegClass::*;
|
||||
|
||||
use llvm::{Integer, Pointer, Float, Double};
|
||||
use llvm::{Struct, Array, Attribute, Vector};
|
||||
use abi::{ArgType, FnType};
|
||||
use abi::{self, ArgType, FnType};
|
||||
use context::CrateContext;
|
||||
use type_::Type;
|
||||
|
||||
use std::cmp;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum RegClass {
|
||||
NoClass,
|
||||
@ -90,62 +88,11 @@ fn classify_ty(ty: Type) -> Vec<RegClass> {
|
||||
}
|
||||
|
||||
fn ty_align(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => ((ty.int_width() as usize) + 7) / 8,
|
||||
Pointer => 8,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
if ty.is_packed() {
|
||||
1
|
||||
} else {
|
||||
let str_tys = ty.field_types();
|
||||
str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t)))
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt)
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
ty_align(elt) * len
|
||||
}
|
||||
_ => bug!("ty_align: unhandled type")
|
||||
}
|
||||
abi::ty_align(ty, 8)
|
||||
}
|
||||
|
||||
fn ty_size(ty: Type) -> usize {
|
||||
match ty.kind() {
|
||||
Integer => (ty.int_width() as usize + 7) / 8,
|
||||
Pointer => 8,
|
||||
Float => 4,
|
||||
Double => 8,
|
||||
Struct => {
|
||||
let str_tys = ty.field_types();
|
||||
if ty.is_packed() {
|
||||
str_tys.iter().fold(0, |s, t| s + ty_size(*t))
|
||||
} else {
|
||||
let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t));
|
||||
align(size, ty)
|
||||
}
|
||||
}
|
||||
Array => {
|
||||
let len = ty.array_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt);
|
||||
len * eltsz
|
||||
}
|
||||
Vector => {
|
||||
let len = ty.vector_length();
|
||||
let elt = ty.element_type();
|
||||
let eltsz = ty_size(elt);
|
||||
len * eltsz
|
||||
}
|
||||
|
||||
_ => bug!("ty_size: unhandled type")
|
||||
}
|
||||
abi::ty_size(ty, 8)
|
||||
}
|
||||
|
||||
fn all_mem(cls: &mut [RegClass]) {
|
||||
|
@ -20,7 +20,7 @@ use middle::lang_items::UnsizeTraitLangItem;
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::{self, TyCtxt, TypeFoldable};
|
||||
use rustc::traits::{self, Reveal};
|
||||
use rustc::ty::{ParameterEnvironment};
|
||||
use rustc::ty::ParameterEnvironment;
|
||||
use rustc::ty::{Ty, TyBool, TyChar, TyError};
|
||||
use rustc::ty::{TyParam, TyRawPtr};
|
||||
use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple};
|
||||
@ -44,13 +44,13 @@ mod orphan;
|
||||
mod overlap;
|
||||
mod unsafety;
|
||||
|
||||
struct CoherenceChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
struct CoherenceChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
crate_context: &'a CrateCtxt<'a, 'gcx>,
|
||||
inference_context: InferCtxt<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
struct CoherenceCheckVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>
|
||||
struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
|
||||
@ -62,36 +62,25 @@ impl<'a, 'gcx, 'tcx, 'v> intravisit::Visitor<'v> for CoherenceCheckVisitor<'a, '
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Returns the def ID of the base type, if there is one.
|
||||
fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
|
||||
match ty.sty {
|
||||
TyAdt(def, _) => {
|
||||
Some(def.did)
|
||||
}
|
||||
TyAdt(def, _) => Some(def.did),
|
||||
|
||||
TyTrait(ref t) => {
|
||||
Some(t.principal.def_id())
|
||||
}
|
||||
TyTrait(ref t) => Some(t.principal.def_id()),
|
||||
|
||||
TyBox(_) => {
|
||||
self.inference_context.tcx.lang_items.owned_box()
|
||||
}
|
||||
TyBox(_) => self.inference_context.tcx.lang_items.owned_box(),
|
||||
|
||||
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
|
||||
TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) |
|
||||
TyTuple(..) | TyParam(..) | TyError | TyNever |
|
||||
TyRawPtr(_) | TyRef(..) | TyProjection(..) => {
|
||||
None
|
||||
}
|
||||
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
|
||||
TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
|
||||
TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None,
|
||||
|
||||
TyInfer(..) | TyClosure(..) | TyAnon(..) => {
|
||||
// `ty` comes from a user declaration so we should only expect types
|
||||
// that the user can type
|
||||
span_bug!(
|
||||
span,
|
||||
"coherence encountered unexpected type searching for base type: {}",
|
||||
ty);
|
||||
span_bug!(span,
|
||||
"coherence encountered unexpected type searching for base type: {}",
|
||||
ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -100,9 +89,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
// Check implementations and traits. This populates the tables
|
||||
// containing the inherent methods and extension methods. It also
|
||||
// builds up the trait inheritance table.
|
||||
self.crate_context.tcx.visit_all_items_in_krate(
|
||||
DepNode::CoherenceCheckImpl,
|
||||
&mut CoherenceCheckVisitor { cc: self });
|
||||
self.crate_context.tcx.visit_all_items_in_krate(DepNode::CoherenceCheckImpl,
|
||||
&mut CoherenceCheckVisitor { cc: self });
|
||||
|
||||
// Populate the table of destructors. It might seem a bit strange to
|
||||
// do this here, but it's actually the most convenient place, since
|
||||
@ -167,7 +155,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
|
||||
fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) {
|
||||
debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
|
||||
impl_trait_ref, impl_def_id);
|
||||
impl_trait_ref,
|
||||
impl_def_id);
|
||||
let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
|
||||
trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
|
||||
}
|
||||
@ -176,9 +165,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
fn create_impl_from_item(&self, item: &Item) -> Vec<DefId> {
|
||||
match item.node {
|
||||
ItemImpl(.., ref impl_items) => {
|
||||
impl_items.iter().map(|impl_item| {
|
||||
self.crate_context.tcx.map.local_def_id(impl_item.id)
|
||||
}).collect()
|
||||
impl_items.iter()
|
||||
.map(|impl_item| self.crate_context.tcx.map.local_def_id(impl_item.id))
|
||||
.collect()
|
||||
}
|
||||
_ => {
|
||||
span_bug!(item.span, "can't convert a non-impl to an impl");
|
||||
@ -186,14 +175,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Destructors
|
||||
//
|
||||
|
||||
fn populate_destructors(&self) {
|
||||
let tcx = self.crate_context.tcx;
|
||||
let drop_trait = match tcx.lang_items.drop_trait() {
|
||||
Some(id) => id, None => { return }
|
||||
Some(id) => id,
|
||||
None => return,
|
||||
};
|
||||
tcx.populate_implementations_for_trait_if_necessary(drop_trait);
|
||||
let drop_trait = tcx.lookup_trait_def(drop_trait);
|
||||
@ -219,13 +208,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
match tcx.map.find(impl_node_id) {
|
||||
Some(hir_map::NodeItem(item)) => {
|
||||
let span = match item.node {
|
||||
ItemImpl(.., ref ty, _) => {
|
||||
ty.span
|
||||
},
|
||||
_ => item.span
|
||||
ItemImpl(.., ref ty, _) => ty.span,
|
||||
_ => item.span,
|
||||
};
|
||||
struct_span_err!(tcx.sess, span, E0120,
|
||||
"the Drop trait may only be implemented on structures")
|
||||
struct_span_err!(tcx.sess,
|
||||
span,
|
||||
E0120,
|
||||
"the Drop trait may only be implemented on \
|
||||
structures")
|
||||
.span_label(span,
|
||||
&format!("implementing Drop requires a struct"))
|
||||
.emit();
|
||||
@ -254,15 +244,14 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
let copy_trait = tcx.lookup_trait_def(copy_trait);
|
||||
|
||||
copy_trait.for_each_impl(tcx, |impl_did| {
|
||||
debug!("check_implementations_of_copy: impl_did={:?}",
|
||||
impl_did);
|
||||
debug!("check_implementations_of_copy: impl_did={:?}", impl_did);
|
||||
|
||||
let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
|
||||
n
|
||||
} else {
|
||||
debug!("check_implementations_of_copy(): impl not in this \
|
||||
crate");
|
||||
return
|
||||
return;
|
||||
};
|
||||
|
||||
let self_type = tcx.lookup_item_type(impl_did);
|
||||
@ -280,14 +269,12 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
match param_env.can_type_implement_copy(tcx, self_type, span) {
|
||||
Ok(()) => {}
|
||||
Err(CopyImplementationError::InfrigingField(name)) => {
|
||||
struct_span_err!(tcx.sess, span, E0204,
|
||||
"the trait `Copy` may not be implemented for \
|
||||
this type")
|
||||
.span_label(span, &format!(
|
||||
"field `{}` does not implement `Copy`", name)
|
||||
)
|
||||
.emit()
|
||||
|
||||
struct_span_err!(tcx.sess,
|
||||
span,
|
||||
E0204,
|
||||
"the trait `Copy` may not be implemented for this type")
|
||||
.span_label(span, &format!("field `{}` does not implement `Copy`", name))
|
||||
.emit()
|
||||
}
|
||||
Err(CopyImplementationError::InfrigingVariant(name)) => {
|
||||
let item = tcx.map.expect_item(impl_node_id);
|
||||
@ -297,10 +284,12 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
span
|
||||
};
|
||||
|
||||
struct_span_err!(tcx.sess, span, E0205,
|
||||
struct_span_err!(tcx.sess,
|
||||
span,
|
||||
E0205,
|
||||
"the trait `Copy` may not be implemented for this type")
|
||||
.span_label(span, &format!("variant `{}` does not implement `Copy`",
|
||||
name))
|
||||
.span_label(span,
|
||||
&format!("variant `{}` does not implement `Copy`", name))
|
||||
.emit()
|
||||
}
|
||||
Err(CopyImplementationError::NotAnAdt) => {
|
||||
@ -311,15 +300,19 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
span
|
||||
};
|
||||
|
||||
struct_span_err!(tcx.sess, span, E0206,
|
||||
struct_span_err!(tcx.sess,
|
||||
span,
|
||||
E0206,
|
||||
"the trait `Copy` may not be implemented for this type")
|
||||
.span_label(span, &format!("type is not a structure or enumeration"))
|
||||
.emit();
|
||||
}
|
||||
Err(CopyImplementationError::HasDestructor) => {
|
||||
struct_span_err!(tcx.sess, span, E0184,
|
||||
"the trait `Copy` may not be implemented for this type; \
|
||||
the type has a destructor")
|
||||
struct_span_err!(tcx.sess,
|
||||
span,
|
||||
E0184,
|
||||
"the trait `Copy` may not be implemented for this type; the \
|
||||
type has a destructor")
|
||||
.span_label(span, &format!("Copy not allowed on types with destructors"))
|
||||
.emit();
|
||||
}
|
||||
@ -359,7 +352,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
|
||||
let target = trait_ref.substs.type_at(1);
|
||||
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
|
||||
source, target);
|
||||
source,
|
||||
target);
|
||||
|
||||
let span = tcx.map.span(impl_node_id);
|
||||
let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
|
||||
@ -368,15 +362,19 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
assert!(!source.has_escaping_regions());
|
||||
|
||||
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
|
||||
source, target);
|
||||
source,
|
||||
target);
|
||||
|
||||
tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
|
||||
let origin = TypeOrigin::Misc(span);
|
||||
let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>, mt_b: ty::TypeAndMut<'gcx>,
|
||||
let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>,
|
||||
mt_b: ty::TypeAndMut<'gcx>,
|
||||
mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
|
||||
if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
|
||||
infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty),
|
||||
target, ty::error::TypeError::Mutability);
|
||||
infcx.report_mismatched_types(origin,
|
||||
mk_ptr(mt_b.ty),
|
||||
target,
|
||||
ty::error::TypeError::Mutability);
|
||||
}
|
||||
(mt_a.ty, mt_b.ty, unsize_trait, None)
|
||||
};
|
||||
@ -394,37 +392,45 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
(&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b))
|
||||
if def_a.is_struct() && def_b.is_struct() => {
|
||||
if def_a.is_struct() && def_b.is_struct() => {
|
||||
if def_a != def_b {
|
||||
let source_path = tcx.item_path_str(def_a.did);
|
||||
let target_path = tcx.item_path_str(def_b.did);
|
||||
span_err!(tcx.sess, span, E0377,
|
||||
span_err!(tcx.sess,
|
||||
span,
|
||||
E0377,
|
||||
"the trait `CoerceUnsized` may only be implemented \
|
||||
for a coercion between structures with the same \
|
||||
definition; expected {}, found {}",
|
||||
source_path, target_path);
|
||||
source_path,
|
||||
target_path);
|
||||
return;
|
||||
}
|
||||
|
||||
let fields = &def_a.struct_variant().fields;
|
||||
let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| {
|
||||
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
|
||||
let diff_fields = fields.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, f)| {
|
||||
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
|
||||
|
||||
if f.unsubst_ty().is_phantom_data() {
|
||||
// Ignore PhantomData fields
|
||||
None
|
||||
} else if infcx.sub_types(false, origin, b, a).is_ok() {
|
||||
// Ignore fields that aren't significantly changed
|
||||
None
|
||||
} else {
|
||||
// Collect up all fields that were significantly changed
|
||||
// i.e. those that contain T in coerce_unsized T -> U
|
||||
Some((i, a, b))
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
if f.unsubst_ty().is_phantom_data() {
|
||||
// Ignore PhantomData fields
|
||||
None
|
||||
} else if infcx.sub_types(false, origin, b, a).is_ok() {
|
||||
// Ignore fields that aren't significantly changed
|
||||
None
|
||||
} else {
|
||||
// Collect up all fields that were significantly changed
|
||||
// i.e. those that contain T in coerce_unsized T -> U
|
||||
Some((i, a, b))
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if diff_fields.is_empty() {
|
||||
span_err!(tcx.sess, span, E0374,
|
||||
span_err!(tcx.sess,
|
||||
span,
|
||||
E0374,
|
||||
"the trait `CoerceUnsized` may only be implemented \
|
||||
for a coercion between structures with one field \
|
||||
being coerced, none found");
|
||||
@ -437,16 +443,22 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
tcx.map.span(impl_node_id)
|
||||
};
|
||||
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0375,
|
||||
"implementing the trait `CoerceUnsized` \
|
||||
requires multiple coercions");
|
||||
let mut err = struct_span_err!(tcx.sess,
|
||||
span,
|
||||
E0375,
|
||||
"implementing the trait \
|
||||
`CoerceUnsized` requires multiple \
|
||||
coercions");
|
||||
err.note("`CoerceUnsized` may only be implemented for \
|
||||
a coercion between structures with one field being coerced");
|
||||
err.note(&format!("currently, {} fields need coercions: {}",
|
||||
diff_fields.len(),
|
||||
diff_fields.iter().map(|&(i, a, b)| {
|
||||
format!("{} ({} to {})", fields[i].name, a, b)
|
||||
}).collect::<Vec<_>>().join(", ") ));
|
||||
diff_fields.len(),
|
||||
diff_fields.iter()
|
||||
.map(|&(i, a, b)| {
|
||||
format!("{} ({} to {})", fields[i].name, a, b)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")));
|
||||
err.span_label(span, &format!("requires multiple coercions"));
|
||||
err.emit();
|
||||
return;
|
||||
@ -458,7 +470,9 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
_ => {
|
||||
span_err!(tcx.sess, span, E0376,
|
||||
span_err!(tcx.sess,
|
||||
span,
|
||||
E0376,
|
||||
"the trait `CoerceUnsized` may only be implemented \
|
||||
for a coercion between structures");
|
||||
return;
|
||||
@ -469,8 +483,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Register an obligation for `A: Trait<B>`.
|
||||
let cause = traits::ObligationCause::misc(span, impl_node_id);
|
||||
let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0,
|
||||
source, &[target]);
|
||||
let predicate =
|
||||
tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
|
||||
fulfill_cx.register_predicate_obligation(&infcx, predicate);
|
||||
|
||||
// Check that all transitive obligations are satisfied.
|
||||
@ -480,8 +494,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Finally, resolve all regions.
|
||||
let mut free_regions = FreeRegionMap::new();
|
||||
free_regions.relate_free_regions_from_predicates(
|
||||
&infcx.parameter_environment.caller_bounds);
|
||||
free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
|
||||
.caller_bounds);
|
||||
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
|
||||
|
||||
if let Some(kind) = kind {
|
||||
@ -495,7 +509,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
|
||||
fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) {
|
||||
if tcx.sess.features.borrow().unboxed_closures {
|
||||
// the feature gate allows all of them
|
||||
return
|
||||
return;
|
||||
}
|
||||
let did = Some(trait_def_id);
|
||||
let li = &tcx.lang_items;
|
||||
@ -507,14 +521,15 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
|
||||
} else if did == li.fn_once_trait() {
|
||||
"FnOnce"
|
||||
} else {
|
||||
return // everything OK
|
||||
return; // everything OK
|
||||
};
|
||||
let mut err = struct_span_err!(tcx.sess,
|
||||
sp,
|
||||
E0183,
|
||||
"manual implementations of `{}` are experimental",
|
||||
trait_name);
|
||||
help!(&mut err, "add `#![feature(unboxed_closures)]` to the crate attributes to enable");
|
||||
help!(&mut err,
|
||||
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
|
||||
err.emit();
|
||||
}
|
||||
|
||||
@ -522,9 +537,10 @@ pub fn check_coherence(ccx: &CrateCtxt) {
|
||||
let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
|
||||
ccx.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
|
||||
CoherenceChecker {
|
||||
crate_context: ccx,
|
||||
inference_context: infcx,
|
||||
}.check();
|
||||
crate_context: ccx,
|
||||
inference_context: infcx,
|
||||
}
|
||||
.check();
|
||||
});
|
||||
unsafety::check(ccx.tcx);
|
||||
orphan::check(ccx.tcx);
|
||||
|
@ -25,17 +25,20 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
tcx.visit_all_items_in_krate(DepNode::CoherenceOrphanCheck, &mut orphan);
|
||||
}
|
||||
|
||||
struct OrphanChecker<'cx, 'tcx:'cx> {
|
||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>
|
||||
struct OrphanChecker<'cx, 'tcx: 'cx> {
|
||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
|
||||
if def_id.krate != LOCAL_CRATE {
|
||||
struct_span_err!(self.tcx.sess, item.span, E0116,
|
||||
"cannot define inherent `impl` for a type outside of the \
|
||||
crate where the type is defined")
|
||||
.span_label(item.span, &format!("impl for type defined outside of crate."))
|
||||
struct_span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0116,
|
||||
"cannot define inherent `impl` for a type outside of the crate \
|
||||
where the type is defined")
|
||||
.span_label(item.span,
|
||||
&format!("impl for type defined outside of crate."))
|
||||
.note("define and implement a trait or new type instead")
|
||||
.emit();
|
||||
}
|
||||
@ -48,11 +51,17 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
ty: &str,
|
||||
span: Span) {
|
||||
match lang_def_id {
|
||||
Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ },
|
||||
Some(lang_def_id) if lang_def_id == impl_def_id => {
|
||||
// OK
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(self.tcx.sess, span, E0390,
|
||||
"only a single inherent implementation marked with `#[lang = \"{}\"]` \
|
||||
is allowed for the `{}` primitive", lang, ty)
|
||||
struct_span_err!(self.tcx.sess,
|
||||
span,
|
||||
E0390,
|
||||
"only a single inherent implementation marked with `#[lang = \
|
||||
\"{}\"]` is allowed for the `{}` primitive",
|
||||
lang,
|
||||
ty)
|
||||
.span_help(span, "consider using a trait to implement these methods")
|
||||
.emit();
|
||||
}
|
||||
@ -209,12 +218,14 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(self.tcx.sess, ty.span, E0118,
|
||||
struct_span_err!(self.tcx.sess,
|
||||
ty.span,
|
||||
E0118,
|
||||
"no base type found for inherent implementation")
|
||||
.span_label(ty.span, &format!("impl requires a base type"))
|
||||
.note(&format!("either implement a trait on it or create a newtype \
|
||||
to wrap it instead"))
|
||||
.emit();
|
||||
.span_label(ty.span, &format!("impl requires a base type"))
|
||||
.note(&format!("either implement a trait on it or create a newtype \
|
||||
to wrap it instead"))
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -226,20 +237,23 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
|
||||
let trait_def_id = trait_ref.def_id;
|
||||
match traits::orphan_check(self.tcx, def_id) {
|
||||
Ok(()) => { }
|
||||
Ok(()) => {}
|
||||
Err(traits::OrphanCheckErr::NoLocalInputType) => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess, item.span, E0117,
|
||||
"only traits defined in the current crate can be \
|
||||
implemented for arbitrary types")
|
||||
.span_label(item.span, &format!("impl doesn't use types inside crate"))
|
||||
.note(&format!("the impl does not reference any \
|
||||
types defined in this crate"))
|
||||
.emit();
|
||||
struct_span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0117,
|
||||
"only traits defined in the current crate can be \
|
||||
implemented for arbitrary types")
|
||||
.span_label(item.span, &format!("impl doesn't use types inside crate"))
|
||||
.note(&format!("the impl does not reference any types defined in \
|
||||
this crate"))
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
Err(traits::OrphanCheckErr::UncoveredTy(param_ty)) => {
|
||||
span_err!(self.tcx.sess, item.span, E0210,
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0210,
|
||||
"type parameter `{}` must be used as the type parameter for \
|
||||
some local type (e.g. `MyStruct<T>`); only traits defined in \
|
||||
the current crate can be implemented for a type parameter",
|
||||
@ -285,10 +299,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
trait_ref,
|
||||
trait_def_id,
|
||||
self.tcx.trait_has_default_impl(trait_def_id));
|
||||
if
|
||||
self.tcx.trait_has_default_impl(trait_def_id) &&
|
||||
trait_def_id.krate != LOCAL_CRATE
|
||||
{
|
||||
if self.tcx.trait_has_default_impl(trait_def_id) &&
|
||||
trait_def_id.krate != LOCAL_CRATE {
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let opt_self_def_id = match self_ty.sty {
|
||||
ty::TyAdt(self_def, _) => Some(self_def.did),
|
||||
@ -305,20 +317,17 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
if self_def_id.is_local() {
|
||||
None
|
||||
} else {
|
||||
Some(format!(
|
||||
"cross-crate traits with a default impl, like `{}`, \
|
||||
can only be implemented for a struct/enum type \
|
||||
defined in the current crate",
|
||||
self.tcx.item_path_str(trait_def_id)))
|
||||
Some(format!("cross-crate traits with a default impl, like `{}`, \
|
||||
can only be implemented for a struct/enum type \
|
||||
defined in the current crate",
|
||||
self.tcx.item_path_str(trait_def_id)))
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
Some(format!(
|
||||
"cross-crate traits with a default impl, like `{}`, \
|
||||
can only be implemented for a struct/enum type, \
|
||||
not `{}`",
|
||||
self.tcx.item_path_str(trait_def_id),
|
||||
self_ty))
|
||||
Some(format!("cross-crate traits with a default impl, like `{}`, can \
|
||||
only be implemented for a struct/enum type, not `{}`",
|
||||
self.tcx.item_path_str(trait_def_id),
|
||||
self_ty))
|
||||
}
|
||||
};
|
||||
|
||||
@ -330,14 +339,18 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
|
||||
// Disallow *all* explicit impls of `Sized` and `Unsize` for now.
|
||||
if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
|
||||
struct_span_err!(self.tcx.sess, item.span, E0322,
|
||||
"explicit impls for the `Sized` trait are not permitted")
|
||||
struct_span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0322,
|
||||
"explicit impls for the `Sized` trait are not permitted")
|
||||
.span_label(item.span, &format!("impl of 'Sized' not allowed"))
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
|
||||
span_err!(self.tcx.sess, item.span, E0328,
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0328,
|
||||
"explicit impls for the `Unsize` trait are not permitted");
|
||||
return;
|
||||
}
|
||||
@ -348,9 +361,11 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
self.tcx.map.node_to_string(item.id));
|
||||
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
|
||||
if trait_ref.def_id.krate != LOCAL_CRATE {
|
||||
struct_span_err!(self.tcx.sess, item_trait_ref.path.span, E0318,
|
||||
"cannot create default implementations for traits outside the \
|
||||
crate they're defined in; define a new trait instead")
|
||||
struct_span_err!(self.tcx.sess,
|
||||
item_trait_ref.path.span,
|
||||
E0318,
|
||||
"cannot create default implementations for traits outside \
|
||||
the crate they're defined in; define a new trait instead")
|
||||
.span_label(item_trait_ref.path.span,
|
||||
&format!("`{}` trait not defined in this crate",
|
||||
item_trait_ref.path))
|
||||
@ -365,7 +380,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
|
||||
impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item) {
|
||||
self.check_item(item);
|
||||
}
|
||||
|
@ -23,15 +23,17 @@ use util::nodemap::DefIdMap;
|
||||
use lint;
|
||||
|
||||
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
let mut overlap = OverlapChecker { tcx: tcx,
|
||||
default_impls: DefIdMap() };
|
||||
let mut overlap = OverlapChecker {
|
||||
tcx: tcx,
|
||||
default_impls: DefIdMap(),
|
||||
};
|
||||
|
||||
// this secondary walk specifically checks for some other cases,
|
||||
// like defaulted traits, for which additional overlap rules exist
|
||||
tcx.visit_all_items_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
|
||||
}
|
||||
|
||||
struct OverlapChecker<'cx, 'tcx:'cx> {
|
||||
struct OverlapChecker<'cx, 'tcx: 'cx> {
|
||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||
|
||||
// maps from a trait def-id to an impl id
|
||||
@ -41,18 +43,21 @@ struct OverlapChecker<'cx, 'tcx:'cx> {
|
||||
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||
fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
enum Namespace { Type, Value }
|
||||
enum Namespace {
|
||||
Type,
|
||||
Value,
|
||||
}
|
||||
|
||||
fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> (ast::Name, Namespace)
|
||||
{
|
||||
-> (ast::Name, Namespace) {
|
||||
let item = tcx.impl_or_trait_item(def_id);
|
||||
(item.name(), match item {
|
||||
ty::TypeTraitItem(..) => Namespace::Type,
|
||||
ty::ConstTraitItem(..) => Namespace::Value,
|
||||
ty::MethodTraitItem(..) => Namespace::Value,
|
||||
})
|
||||
(item.name(),
|
||||
match item {
|
||||
ty::TypeTraitItem(..) => Namespace::Type,
|
||||
ty::ConstTraitItem(..) => Namespace::Value,
|
||||
ty::MethodTraitItem(..) => Namespace::Value,
|
||||
})
|
||||
}
|
||||
|
||||
let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow();
|
||||
@ -79,11 +84,11 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||
let inherent_impls = self.tcx.inherent_impls.borrow();
|
||||
let impls = match inherent_impls.get(&ty_def_id) {
|
||||
Some(impls) => impls,
|
||||
None => return
|
||||
None => return,
|
||||
};
|
||||
|
||||
for (i, &impl1_def_id) in impls.iter().enumerate() {
|
||||
for &impl2_def_id in &impls[(i+1)..] {
|
||||
for &impl2_def_id in &impls[(i + 1)..] {
|
||||
self.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
|
||||
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
|
||||
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
|
||||
@ -94,10 +99,12 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||
impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||
fn visit_item(&mut self, item: &'v hir::Item) {
|
||||
match item.node {
|
||||
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
|
||||
hir::ItemEnum(..) |
|
||||
hir::ItemStruct(..) |
|
||||
hir::ItemUnion(..) => {
|
||||
let type_def_id = self.tcx.map.local_def_id(item.id);
|
||||
self.check_for_overlapping_inherent_impls(type_def_id);
|
||||
}
|
||||
@ -111,12 +118,14 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||
|
||||
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
|
||||
if let Some(prev_id) = prev_default_impl {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
self.tcx.span_of_impl(impl_def_id).unwrap(), E0521,
|
||||
"redundant default implementations of trait `{}`:",
|
||||
trait_ref);
|
||||
err.span_note(self.tcx.span_of_impl(self.tcx.map.local_def_id(prev_id))
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
self.tcx.span_of_impl(impl_def_id).unwrap(),
|
||||
E0521,
|
||||
"redundant default implementations of trait \
|
||||
`{}`:",
|
||||
trait_ref);
|
||||
err.span_note(self.tcx
|
||||
.span_of_impl(self.tcx.map.local_def_id(prev_id))
|
||||
.unwrap(),
|
||||
"redundant implementation is here:");
|
||||
err.emit();
|
||||
@ -127,8 +136,8 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let trait_def_id = trait_ref.def_id;
|
||||
|
||||
let _task = self.tcx.dep_graph.in_task(
|
||||
DepNode::CoherenceOverlapCheck(trait_def_id));
|
||||
let _task =
|
||||
self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
|
||||
|
||||
let def = self.tcx.lookup_trait_def(trait_def_id);
|
||||
|
||||
@ -137,17 +146,19 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||
|
||||
// insertion failed due to overlap
|
||||
if let Err(overlap) = insert_result {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119,
|
||||
"conflicting implementations of trait `{}`{}:",
|
||||
overlap.trait_desc,
|
||||
overlap.self_desc.clone().map_or(String::new(),
|
||||
|ty| format!(" for type `{}`", ty)));
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
self.tcx.span_of_impl(impl_def_id).unwrap(),
|
||||
E0119,
|
||||
"conflicting implementations of trait `{}`{}:",
|
||||
overlap.trait_desc,
|
||||
overlap.self_desc.clone().map_or(String::new(),
|
||||
|ty| {
|
||||
format!(" for type `{}`", ty)
|
||||
}));
|
||||
|
||||
match self.tcx.span_of_impl(overlap.with_impl) {
|
||||
Ok(span) => {
|
||||
err.span_label(span,
|
||||
&format!("first implementation here"));
|
||||
err.span_label(span, &format!("first implementation here"));
|
||||
err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(),
|
||||
&format!("conflicting implementation{}",
|
||||
overlap.self_desc
|
||||
@ -155,8 +166,7 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||
|ty| format!(" for `{}`", ty))));
|
||||
}
|
||||
Err(cname) => {
|
||||
err.note(&format!("conflicting implementation in crate `{}`",
|
||||
cname));
|
||||
err.note(&format!("conflicting implementation in crate `{}`", cname));
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +187,9 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||
let mut supertrait_def_ids =
|
||||
traits::supertrait_def_ids(self.tcx, data.principal.def_id());
|
||||
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
||||
span_err!(self.tcx.sess, item.span, E0371,
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0371,
|
||||
"the object type `{}` automatically \
|
||||
implements the trait `{}`",
|
||||
trait_ref.self_ty(),
|
||||
|
@ -20,21 +20,26 @@ pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
tcx.map.krate().visit_all_items(&mut orphan);
|
||||
}
|
||||
|
||||
struct UnsafetyChecker<'cx, 'tcx:'cx> {
|
||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>
|
||||
struct UnsafetyChecker<'cx, 'tcx: 'cx> {
|
||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
|
||||
fn check_unsafety_coherence(&mut self, item: &'v hir::Item,
|
||||
fn check_unsafety_coherence(&mut self,
|
||||
item: &'v hir::Item,
|
||||
unsafety: hir::Unsafety,
|
||||
polarity: hir::ImplPolarity) {
|
||||
match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) {
|
||||
None => {
|
||||
// Inherent impl.
|
||||
match unsafety {
|
||||
hir::Unsafety::Normal => { /* OK */ }
|
||||
hir::Unsafety::Normal => {
|
||||
// OK
|
||||
}
|
||||
hir::Unsafety::Unsafe => {
|
||||
span_err!(self.tcx.sess, item.span, E0197,
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0197,
|
||||
"inherent impls cannot be declared as unsafe");
|
||||
}
|
||||
}
|
||||
@ -43,31 +48,33 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
|
||||
Some(trait_ref) => {
|
||||
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
|
||||
match (trait_def.unsafety, unsafety, polarity) {
|
||||
(hir::Unsafety::Unsafe,
|
||||
hir::Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
|
||||
span_err!(self.tcx.sess, item.span, E0198,
|
||||
(hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0198,
|
||||
"negative implementations are not unsafe");
|
||||
}
|
||||
|
||||
(hir::Unsafety::Normal, hir::Unsafety::Unsafe, _) => {
|
||||
span_err!(self.tcx.sess, item.span, E0199,
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0199,
|
||||
"implementing the trait `{}` is not unsafe",
|
||||
trait_ref);
|
||||
}
|
||||
|
||||
(hir::Unsafety::Unsafe,
|
||||
hir::Unsafety::Normal, hir::ImplPolarity::Positive) => {
|
||||
span_err!(self.tcx.sess, item.span, E0200,
|
||||
(hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Positive) => {
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0200,
|
||||
"the trait `{}` requires an `unsafe impl` declaration",
|
||||
trait_ref);
|
||||
}
|
||||
|
||||
(hir::Unsafety::Unsafe,
|
||||
hir::Unsafety::Normal, hir::ImplPolarity::Negative) |
|
||||
(hir::Unsafety::Unsafe,
|
||||
hir::Unsafety::Unsafe, hir::ImplPolarity::Positive) |
|
||||
(hir::Unsafety::Unsafe, hir::Unsafety::Normal, hir::ImplPolarity::Negative) |
|
||||
(hir::Unsafety::Unsafe, hir::Unsafety::Unsafe, hir::ImplPolarity::Positive) |
|
||||
(hir::Unsafety::Normal, hir::Unsafety::Normal, _) => {
|
||||
/* OK */
|
||||
// OK
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,7 +82,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
|
||||
impl<'cx, 'tcx, 'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
|
||||
fn visit_item(&mut self, item: &'v hir::Item) {
|
||||
match item.node {
|
||||
hir::ItemDefaultImpl(unsafety, _) => {
|
||||
@ -84,7 +91,7 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
|
||||
hir::ItemImpl(unsafety, polarity, ..) => {
|
||||
self.check_unsafety_coherence(item, unsafety, polarity);
|
||||
}
|
||||
_ => { }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ const EMPTY_BUCKET: u64 = 0;
|
||||
/// around just the "table" part of the hashtable. It enforces some
|
||||
/// invariants at the type level and employs some performance trickery,
|
||||
/// but in general is just a tricked out `Vec<Option<u64, K, V>>`.
|
||||
#[cfg_attr(stage0, unsafe_no_drop_flag)]
|
||||
pub struct RawTable<K, V> {
|
||||
capacity: usize,
|
||||
size: usize,
|
||||
|
@ -314,9 +314,11 @@ impl CString {
|
||||
}
|
||||
|
||||
// Turns this `CString` into an empty string to prevent
|
||||
// memory unsafe code from working by accident.
|
||||
// memory unsafe code from working by accident. Inline
|
||||
// to prevent LLVM from optimizing it away in debug builds.
|
||||
#[stable(feature = "cstring_drop", since = "1.13.0")]
|
||||
impl Drop for CString {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe { *self.inner.get_unchecked_mut(0) = 0; }
|
||||
}
|
||||
|
@ -278,7 +278,6 @@
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unicode)]
|
||||
#![feature(unique)]
|
||||
#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
|
||||
#![feature(unwind_attributes)]
|
||||
#![feature(vec_push_all)]
|
||||
#![feature(zero_one)]
|
||||
|
@ -557,7 +557,9 @@ pub struct ExpansionData {
|
||||
pub depth: usize,
|
||||
pub backtrace: ExpnId,
|
||||
pub module: Rc<ModuleData>,
|
||||
pub in_block: bool,
|
||||
|
||||
// True if non-inline modules without a `#[path]` are forbidden at the root of this expansion.
|
||||
pub no_noninline_mod: bool,
|
||||
}
|
||||
|
||||
/// One of these is made during expansion and incrementally updated as we go;
|
||||
@ -590,7 +592,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
depth: 0,
|
||||
backtrace: NO_EXPANSION,
|
||||
module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
|
||||
in_block: false,
|
||||
no_noninline_mod: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -667,9 +667,9 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||
}
|
||||
|
||||
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
|
||||
let orig_in_block = mem::replace(&mut self.cx.current_expansion.in_block, true);
|
||||
let no_noninline_mod = mem::replace(&mut self.cx.current_expansion.no_noninline_mod, true);
|
||||
let result = noop_fold_block(block, self);
|
||||
self.cx.current_expansion.in_block = orig_in_block;
|
||||
self.cx.current_expansion.no_noninline_mod = no_noninline_mod;
|
||||
result
|
||||
}
|
||||
|
||||
@ -708,6 +708,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||
return noop_fold_item(item, self);
|
||||
}
|
||||
|
||||
let orig_no_noninline_mod = self.cx.current_expansion.no_noninline_mod;
|
||||
let mut module = (*self.cx.current_expansion.module).clone();
|
||||
module.mod_path.push(item.ident);
|
||||
|
||||
@ -717,11 +718,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||
let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP;
|
||||
|
||||
if inline_module {
|
||||
module.directory.push(&*{
|
||||
::attr::first_attr_value_str_by_name(&item.attrs, "path")
|
||||
.unwrap_or(item.ident.name.as_str())
|
||||
});
|
||||
if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
|
||||
self.cx.current_expansion.no_noninline_mod = false;
|
||||
module.directory.push(&*path);
|
||||
} else {
|
||||
module.directory.push(&*item.ident.name.as_str());
|
||||
}
|
||||
} else {
|
||||
self.cx.current_expansion.no_noninline_mod = false;
|
||||
module.directory =
|
||||
PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
|
||||
module.directory.pop();
|
||||
@ -731,6 +735,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
|
||||
let result = noop_fold_item(item, self);
|
||||
self.cx.current_expansion.module = orig_module;
|
||||
self.cx.current_expansion.no_noninline_mod = orig_no_noninline_mod;
|
||||
return result;
|
||||
}
|
||||
// Ensure that test functions are accessible from the test harness.
|
||||
|
@ -122,7 +122,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||
rhs);
|
||||
let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
|
||||
p.directory = cx.current_expansion.module.directory.clone();
|
||||
p.restrictions = match cx.current_expansion.in_block {
|
||||
p.restrictions = match cx.current_expansion.no_noninline_mod {
|
||||
true => Restrictions::NO_NONINLINE_MOD,
|
||||
false => Restrictions::empty(),
|
||||
};
|
||||
|
@ -38,10 +38,6 @@ pub struct JsonEmitter {
|
||||
}
|
||||
|
||||
impl JsonEmitter {
|
||||
pub fn basic() -> JsonEmitter {
|
||||
JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
|
||||
}
|
||||
|
||||
pub fn stderr(registry: Option<Registry>,
|
||||
code_map: Rc<CodeMap>) -> JsonEmitter {
|
||||
JsonEmitter {
|
||||
@ -50,6 +46,20 @@ impl JsonEmitter {
|
||||
cm: code_map,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn basic() -> JsonEmitter {
|
||||
JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
|
||||
}
|
||||
|
||||
pub fn new(dst: Box<Write + Send>,
|
||||
registry: Option<Registry>,
|
||||
code_map: Rc<CodeMap>) -> JsonEmitter {
|
||||
JsonEmitter {
|
||||
dst: dst,
|
||||
registry: registry,
|
||||
cm: code_map,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Emitter for JsonEmitter {
|
||||
|
@ -5274,23 +5274,27 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
} else {
|
||||
let directory = self.directory.clone();
|
||||
self.push_directory(id, &outer_attrs);
|
||||
let restrictions = self.push_directory(id, &outer_attrs);
|
||||
self.expect(&token::OpenDelim(token::Brace))?;
|
||||
let mod_inner_lo = self.span.lo;
|
||||
let attrs = self.parse_inner_attributes()?;
|
||||
let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
|
||||
let m = self.with_res(restrictions, |this| {
|
||||
this.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)
|
||||
})?;
|
||||
self.directory = directory;
|
||||
Ok((id, ItemKind::Mod(m), Some(attrs)))
|
||||
}
|
||||
}
|
||||
|
||||
fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
|
||||
let default_path = self.id_to_interned_str(id);
|
||||
let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") {
|
||||
Some(d) => d,
|
||||
None => default_path,
|
||||
};
|
||||
self.directory.push(&*file_path)
|
||||
fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) -> Restrictions {
|
||||
if let Some(path) = ::attr::first_attr_value_str_by_name(attrs, "path") {
|
||||
self.directory.push(&*path);
|
||||
self.restrictions - Restrictions::NO_NONINLINE_MOD
|
||||
} else {
|
||||
let default_path = self.id_to_interned_str(id);
|
||||
self.directory.push(&*default_path);
|
||||
self.restrictions
|
||||
}
|
||||
}
|
||||
|
||||
pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option<PathBuf> {
|
||||
|
@ -19,7 +19,7 @@ use std::iter;
|
||||
use std::slice;
|
||||
use std::mem;
|
||||
use std::vec;
|
||||
use attr;
|
||||
use attr::{self, HasAttrs};
|
||||
use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos};
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -226,12 +226,20 @@ fn mk_reexport_mod(cx: &mut TestCtxt, parent: ast::NodeId, tests: Vec<ast::Ident
|
||||
tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P<ast::Item>, ast::Ident) {
|
||||
let super_ = token::str_to_ident("super");
|
||||
|
||||
// Generate imports with `#[allow(private_in_public)]` to work around issue #36768.
|
||||
let allow_private_in_public = cx.ext_cx.attribute(DUMMY_SP, cx.ext_cx.meta_list(
|
||||
DUMMY_SP,
|
||||
InternedString::new("allow"),
|
||||
vec![cx.ext_cx.meta_list_item_word(DUMMY_SP, InternedString::new("private_in_public"))],
|
||||
));
|
||||
let items = tests.into_iter().map(|r| {
|
||||
cx.ext_cx.item_use_simple(DUMMY_SP, ast::Visibility::Public,
|
||||
cx.ext_cx.path(DUMMY_SP, vec![super_, r]))
|
||||
.map_attrs(|_| vec![allow_private_in_public.clone()])
|
||||
}).chain(tested_submods.into_iter().map(|(r, sym)| {
|
||||
let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]);
|
||||
cx.ext_cx.item_use_simple_(DUMMY_SP, ast::Visibility::Public, r, path)
|
||||
.map_attrs(|_| vec![allow_private_in_public.clone()])
|
||||
})).collect();
|
||||
|
||||
let reexport_mod = ast::Mod {
|
||||
|
@ -12,6 +12,6 @@
|
||||
# tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was
|
||||
# released on `$date`
|
||||
|
||||
rustc: beta-2016-08-17
|
||||
rustc_key: 195e6261
|
||||
cargo: nightly-2016-08-21
|
||||
rustc: beta-2016-09-28
|
||||
rustc_key: 62b3e239
|
||||
cargo: nightly-2016-09-26
|
||||
|
14
src/test/incremental/change_crate_order/auxiliary/a.rs
Normal file
14
src/test/incremental/change_crate_order/auxiliary/a.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#![crate_type="rlib"]
|
||||
|
||||
pub static A : u32 = 32;
|
||||
|
14
src/test/incremental/change_crate_order/auxiliary/b.rs
Normal file
14
src/test/incremental/change_crate_order/auxiliary/b.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#![crate_type="rlib"]
|
||||
|
||||
pub static B: u32 = 32;
|
||||
|
34
src/test/incremental/change_crate_order/main.rs
Normal file
34
src/test/incremental/change_crate_order/main.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
// aux-build:a.rs
|
||||
// aux-build:b.rs
|
||||
// revisions:rpass1 rpass2
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
|
||||
#[cfg(rpass1)]
|
||||
extern crate a;
|
||||
#[cfg(rpass1)]
|
||||
extern crate b;
|
||||
|
||||
#[cfg(rpass2)]
|
||||
extern crate b;
|
||||
#[cfg(rpass2)]
|
||||
extern crate a;
|
||||
|
||||
use a::A;
|
||||
use b::B;
|
||||
|
||||
//? #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
|
||||
pub fn main() {
|
||||
A + B;
|
||||
}
|
@ -79,8 +79,8 @@ fn main() {
|
||||
format!("_ _ --sysroot {} --crate-type dylib", path.to_str().unwrap())
|
||||
.split(' ').map(|s| s.to_string()).collect();
|
||||
|
||||
let (result, _) = rustc_driver::run_compiler_with_file_loader(
|
||||
&args, &mut JitCalls, box JitLoader);
|
||||
let (result, _) = rustc_driver::run_compiler(
|
||||
&args, &mut JitCalls, Some(box JitLoader), None);
|
||||
if let Err(n) = result {
|
||||
panic!("Error {}", n);
|
||||
}
|
||||
|
@ -86,6 +86,6 @@ fn main() {
|
||||
let mut tc = TestCalls { count: 1 };
|
||||
// we should never get use this filename, but lets make sure they are valid args.
|
||||
let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
|
||||
rustc_driver::run_compiler(&args, &mut tc);
|
||||
rustc_driver::run_compiler(&args, &mut tc, None, None);
|
||||
assert_eq!(tc.count, 30);
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
// Copyright 2016 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-emscripten
|
||||
|
||||
// Test that `CString::new("hello").unwrap().as_ptr()` pattern
|
||||
// leads to failure.
|
||||
|
||||
use std::env;
|
||||
use std::ffi::{CString, CStr};
|
||||
use std::os::raw::c_char;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 && args[1] == "child" {
|
||||
// Repeat several times to be more confident that
|
||||
// it is `Drop` for `CString` that does the cleanup,
|
||||
// and not just some lucky UB.
|
||||
let xs = vec![CString::new("Hello").unwrap(); 10];
|
||||
let ys = xs.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
|
||||
drop(xs);
|
||||
assert!(ys.into_iter().any(is_hello));
|
||||
return;
|
||||
}
|
||||
|
||||
let output = Command::new(&args[0]).arg("child").output().unwrap();
|
||||
assert!(!output.status.success());
|
||||
}
|
||||
|
||||
fn is_hello(s: *const c_char) -> bool {
|
||||
// `s` is a dangling pointer and reading it is technically
|
||||
// undefined behavior. But we want to prevent the most diabolical
|
||||
// kind of UB (apart from nasal demons): reading a value that was
|
||||
// previously written.
|
||||
//
|
||||
// Segfaulting or reading an empty string is Ok,
|
||||
// reading "Hello" is bad.
|
||||
let s = unsafe { CStr::from_ptr(s) };
|
||||
let hello = CString::new("Hello").unwrap();
|
||||
s == hello.as_ref()
|
||||
}
|
18
src/test/run-pass/issue-36768.rs
Normal file
18
src/test/run-pass/issue-36768.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2016 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:--test
|
||||
#![deny(private_in_public)]
|
||||
|
||||
#[test] fn foo() {}
|
||||
mod foo {}
|
||||
|
||||
#[test] fn core() {}
|
||||
extern crate core;
|
@ -17,4 +17,15 @@ mod mod_dir_simple {
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(mod_dir_simple::syrup::foo(), 10);
|
||||
|
||||
#[path = "auxiliary"]
|
||||
mod foo {
|
||||
mod two_macros;
|
||||
}
|
||||
|
||||
#[path = "auxiliary"]
|
||||
mod bar {
|
||||
macro_rules! m { () => { mod two_macros; } }
|
||||
m!();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user