Auto merge of #55974 - pietroalbini:rollup, r=pietroalbini

Rollup of 17 pull requests

Successful merges:

 - #55182 (Redox: Update to new changes)
 - #55211 (Add BufWriter::buffer method)
 - #55507 (Add link to std::mem::size_of to size_of intrinsic documentation)
 - #55530 (Speed up String::from_utf16)
 - #55556 (Use `Mmap` to open the rmeta file.)
 - #55622 (NetBSD: link libstd with librt in addition to libpthread)
 - #55750 (Make `NodeId` and `HirLocalId` `newtype_index`)
 - #55778 (Wrap some query results in `Lrc`.)
 - #55781 (More precise spans for temps and their drops)
 - #55785 (Add mem::forget_unsized() for forgetting unsized values)
 - #55852 (Rewrite `...` as `..=` as a `MachineApplicable` 2018 idiom lint)
 - #55865 (Unix RwLock: avoid racy access to write_locked)
 - #55901 (fix various typos in doc comments)
 - #55926 (Change sidebar selector to fix compatibility with docs.rs)
 - #55930 (A handful of hir tweaks)
 - #55932 (core/char: Speed up `to_digit()` for `radix <= 10`)
 - #55956 (add tests for some fixed ICEs)

Failed merges:

r? @ghost
This commit is contained in:
bors 2018-11-15 12:43:01 +00:00
commit 9649c1f70f
120 changed files with 937 additions and 393 deletions

View File

@ -2278,12 +2278,14 @@ version = "0.0.0"
dependencies = [
"flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"proc_macro 0.0.0",
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"rustc_target 0.0.0",
"serialize 0.0.0",
"stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntax 0.0.0",
"syntax_ext 0.0.0",
"syntax_pos 0.0.0",

View File

@ -69,7 +69,7 @@ struct LeafNode<K, V> {
/// This node's index into the parent node's `edges` array.
/// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`.
/// This is only guaranteed to be initialized when `parent` is nonnull.
/// This is only guaranteed to be initialized when `parent` is non-null.
parent_idx: MaybeUninit<u16>,
/// The number of keys and values this node stores.

View File

@ -44,7 +44,7 @@ use boxed::Box;
/// This enables you to use capacity growing logic catch the overflows in your length
/// that might occur with zero-sized types.
///
/// However this means that you need to be careful when roundtripping this type
/// However this means that you need to be careful when round-tripping this type
/// with a `Box<[T]>`: `cap()` won't yield the len. However `with_capacity`,
/// `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

View File

@ -618,7 +618,15 @@ impl String {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error> {
decode_utf16(v.iter().cloned()).collect::<Result<_, _>>().map_err(|_| FromUtf16Error(()))
let mut ret = String::with_capacity(v.len());
for c in decode_utf16(v.iter().cloned()) {
if let Ok(c) = c {
ret.push(c);
} else {
return Err(FromUtf16Error(()));
}
}
Ok(ret)
}
/// Decode a UTF-16 encoded slice `v` into a `String`, replacing

View File

@ -0,0 +1,42 @@
// Copyright 2017 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.
use test::Bencher;
const CHARS: [char; 9] = ['0', 'x', '2', '5', 'A', 'f', '7', '8', '9'];
const RADIX: [u32; 5] = [2, 8, 10, 16, 32];
#[bench]
fn bench_to_digit_radix_2(b: &mut Bencher) {
b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(2)).min())
}
#[bench]
fn bench_to_digit_radix_10(b: &mut Bencher) {
b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(10)).min())
}
#[bench]
fn bench_to_digit_radix_16(b: &mut Bencher) {
b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(16)).min())
}
#[bench]
fn bench_to_digit_radix_36(b: &mut Bencher) {
b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(36)).min())
}
#[bench]
fn bench_to_digit_radix_var(b: &mut Bencher) {
b.iter(|| CHARS.iter().cycle()
.zip(RADIX.iter().cycle())
.take(10_000)
.map(|(c, radix)| c.to_digit(*radix)).min())
}

View File

@ -0,0 +1,11 @@
// Copyright 2017 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.
mod methods;

View File

@ -15,6 +15,7 @@ extern crate core;
extern crate test;
mod any;
mod char;
mod hash;
mod iter;
mod num;

View File

@ -121,15 +121,24 @@ impl char {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn to_digit(self, radix: u32) -> Option<u32> {
if radix > 36 {
panic!("to_digit: radix is too high (maximum 36)");
}
let val = match self {
'0' ..= '9' => self as u32 - '0' as u32,
'a' ..= 'z' => self as u32 - 'a' as u32 + 10,
'A' ..= 'Z' => self as u32 - 'A' as u32 + 10,
_ => return None,
assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
// the code is split up here to improve execution speed for cases where
// the `radix` is constant and 10 or smaller
let val = if radix <= 10 {
match self {
'0' ..= '9' => self as u32 - '0' as u32,
_ => return None,
}
} else {
match self {
'0'..='9' => self as u32 - '0' as u32,
'a'..='z' => self as u32 - 'a' as u32 + 10,
'A'..='Z' => self as u32 - 'A' as u32 + 10,
_ => return None,
}
};
if val < radix { Some(val) }
else { None }
}

View File

@ -672,6 +672,9 @@ extern "rust-intrinsic" {
///
/// More specifically, this is the offset in bytes between successive
/// items of the same type, including alignment padding.
///
/// The stabilized version of this intrinsic is
/// [`std::mem::size_of`](../../std/mem/fn.size_of.html).
pub fn size_of<T>() -> usize;
/// Moves a value to an uninitialized memory location.
@ -714,6 +717,10 @@ extern "rust-intrinsic" {
/// initialize memory previous set to the result of `uninit`.
pub fn uninit<T>() -> T;
/// Moves a value out of scope without running drop glue.
#[cfg(not(stage0))]
pub fn forget<T: ?Sized>(_: T);
/// Reinterprets the bits of a value of one type as another type.
///
/// Both types must have the same size. Neither the original, nor the result,

View File

@ -106,6 +106,7 @@
#![feature(staged_api)]
#![feature(stmt_expr_attributes)]
#![feature(unboxed_closures)]
#![feature(unsized_locals)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(doc_alias)]

View File

@ -143,6 +143,19 @@ pub fn forget<T>(t: T) {
ManuallyDrop::new(t);
}
/// Like [`forget`], but also accepts unsized values.
///
/// This function is just a shim intended to be removed when the `unsized_locals` feature gets
/// stabilized.
///
/// [`forget`]: fn.forget.html
#[inline]
#[cfg(not(stage0))]
#[unstable(feature = "forget_unsized", issue = "0")]
pub fn forget_unsized<T: ?Sized>(t: T) {
unsafe { intrinsics::forget(t) }
}
/// Returns the size of a type in bytes.
///
/// More specifically, this is the offset in bytes between successive elements

View File

@ -445,7 +445,7 @@ impl f32 {
/// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
///
/// Rather than trying to preserve signaling-ness cross-platform, this
/// implementation favours preserving the exact bits. This means that
/// implementation favors preserving the exact bits. This means that
/// any payloads encoded in NaNs will be preserved even if the result of
/// this method is sent over the network from an x86 machine to a MIPS one.
///

View File

@ -108,7 +108,7 @@ impl Drop for Waker {
/// is ready to be run.
///
/// This is similar to the `Waker` type, but cannot be sent across threads.
/// Task executors can use this type to implement more optimized singlethreaded wakeup
/// Task executors can use this type to implement more optimized single-threaded wakeup
/// behavior.
#[repr(transparent)]
#[derive(Clone)]

@ -1 +1 @@
Subproject commit 1844a772b60771d0124a157019f627d60fea4e73
Subproject commit c75ca6465a139704e00295be355b1f067af2f535

View File

@ -535,7 +535,7 @@ impl TokenTree {
}
}
/// Prints token treee in a form convenient for debugging.
/// Prints token tree in a form convenient for debugging.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl fmt::Debug for TokenTree {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -730,7 +730,7 @@ impl fmt::Debug for Group {
/// An `Punct` is an single punctuation character like `+`, `-` or `#`.
///
/// Multicharacter operators like `+=` are represented as two instances of `Punct` with different
/// Multi-character operators like `+=` are represented as two instances of `Punct` with different
/// forms of `Spacing` returned.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
#[derive(Clone)]
@ -788,7 +788,7 @@ impl Punct {
/// Returns the spacing of this punctuation character, indicating whether it's immediately
/// followed by another `Punct` in the token stream, so they can potentially be combined into
/// a multicharacter operator (`Joint`), or it's followed by some other token or whitespace
/// a multi-character operator (`Joint`), or it's followed by some other token or whitespace
/// (`Alone`) so the operator has certainly ended.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn spacing(&self) -> Spacing {
@ -947,7 +947,7 @@ macro_rules! suffixed_int_literals {
/// This function will create an integer like `1u32` where the integer
/// value specified is the first part of the token and the integral is
/// also suffixed at the end.
/// Literals created from negative numbers may not survive rountrips through
/// Literals created from negative numbers may not survive round-trips through
/// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
///
/// Literals created through this method have the `Span::call_site()`
@ -1047,7 +1047,7 @@ impl Literal {
/// Creates a new suffixed floating-point literal.
///
/// This consturctor will create a literal like `1.0f32` where the value
/// This constructor will create a literal like `1.0f32` where the value
/// specified is the preceding part of the token and `f32` is the suffix of
/// the token. This token will always be inferred to be an `f32` in the
/// compiler.
@ -1096,7 +1096,7 @@ impl Literal {
/// Creates a new suffixed floating-point literal.
///
/// This consturctor will create a literal like `1.0f64` where the value
/// This constructor will create a literal like `1.0f64` where the value
/// specified is the preceding part of the token and `f64` is the suffix of
/// the token. This token will always be inferred to be an `f64` in the
/// compiler.

View File

@ -9,7 +9,7 @@
// except according to those terms.
//! Some facilities for tracking how codegen-units are reused during incremental
//! compilition. This is used for incremental compiliation tests and debug
//! compilation. This is used for incremental compilation tests and debug
//! output.
use session::Session;

View File

@ -63,7 +63,7 @@
use mir::interpret::GlobalId;
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use hir::map::DefPathHash;
use hir::{HirId, ItemLocalId};
use hir::HirId;
use ich::{Fingerprint, StableHashingContext};
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
@ -790,11 +790,11 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for HirId {
fn to_fingerprint(&self, tcx: TyCtxt<'_, '_, '_>) -> Fingerprint {
let HirId {
owner,
local_id: ItemLocalId(local_id),
local_id,
} = *self;
let def_path_hash = tcx.def_path_hash(DefId::local(owner));
let local_id = Fingerprint::from_smaller_hash(local_id as u64);
let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into());
def_path_hash.0.combine(local_id)
}

View File

@ -36,7 +36,7 @@ pub enum NonMacroAttrKind {
Tool,
/// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
DeriveHelper,
/// Single-segment custom attriubte registered by a legacy plugin (`register_attribute`).
/// Single-segment custom attribute registered by a legacy plugin (`register_attribute`).
LegacyPluginHelper,
/// Single-segment custom attribute not registered in any way (`#[my_attr]`).
Custom,

View File

@ -49,7 +49,6 @@ use hir::map::{self, Map};
use super::itemlikevisit::DeepVisitor;
use std::cmp;
use std::u32;
#[derive(Copy, Clone)]
pub enum FnKind<'a> {
@ -1152,8 +1151,8 @@ pub struct IdRange {
impl IdRange {
pub fn max() -> IdRange {
IdRange {
min: NodeId::from_u32(u32::MAX),
max: NodeId::from_u32(u32::MIN),
min: NodeId::MAX,
max: NodeId::from_u32(0),
}
}

View File

@ -588,7 +588,7 @@ impl<'a> LoweringContext<'a> {
*local_id_counter += 1;
hir::HirId {
owner: def_index,
local_id: hir::ItemLocalId(local_id),
local_id: hir::ItemLocalId::from_u32(local_id),
}
})
}
@ -616,7 +616,7 @@ impl<'a> LoweringContext<'a> {
hir::HirId {
owner: def_index,
local_id: hir::ItemLocalId(local_id),
local_id: hir::ItemLocalId::from_u32(local_id),
}
})
}

View File

@ -101,7 +101,7 @@ impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {
if max != self.hir_ids_seen.len() - 1 {
// Collect the missing ItemLocalIds
let missing: Vec<_> = (0 .. max as u32 + 1)
.filter(|&i| !self.hir_ids_seen.contains_key(&ItemLocalId(i)))
.filter(|&i| !self.hir_ids_seen.contains_key(&ItemLocalId::from_u32(i)))
.collect();
// Try to map those to something more useful
@ -110,7 +110,7 @@ impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {
for local_id in missing {
let hir_id = HirId {
owner: owner_def_index,
local_id: ItemLocalId(local_id as u32),
local_id: ItemLocalId::from_u32(local_id),
};
trace!("missing hir id {:#?}", hir_id);
@ -124,7 +124,7 @@ impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> {
.enumerate()
.find(|&(_, &entry)| hir_id == entry)
.expect("no node_to_hir_id entry");
let node_id = NodeId::new(node_id);
let node_id = NodeId::from_usize(node_id);
missing_items.push(format!("[local_id: {}, node:{}]",
local_id,
self.hir_map.node_to_string(node_id)));

View File

@ -27,7 +27,7 @@ use syntax_pos::{Span, DUMMY_SP, symbol::InternedString};
use syntax::source_map::{self, Spanned};
use rustc_target::spec::abi::Abi;
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy};
use syntax::attr::InlineAttr;
use syntax::ext::hygiene::SyntaxContext;
use syntax::ptr::P;
@ -37,7 +37,6 @@ use syntax::util::parser::ExprPrecedence;
use ty::AdtKind;
use ty::query::Providers;
use rustc_data_structures::indexed_vec;
use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope};
use rustc_data_structures::thin_vec::ThinVec;
@ -58,7 +57,6 @@ macro_rules! hir_vec {
($($x:expr),*) => (
$crate::hir::HirVec::from(vec![$($x),*])
);
($($x:expr,)*) => (hir_vec![$($x),*])
}
pub mod check_attr;
@ -121,40 +119,28 @@ impl serialize::UseSpecializedDecodable for HirId {
}
}
/// An `ItemLocalId` uniquely identifies something within a given "item-like",
/// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
/// guarantee that the numerical value of a given `ItemLocalId` corresponds to
/// the node's position within the owning item in any way, but there is a
/// guarantee that the `LocalItemId`s within an owner occupy a dense range of
/// integers starting at zero, so a mapping that maps all or most nodes within
/// an "item-like" to something else can be implement by a `Vec` instead of a
/// tree or hash map.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug,
RustcEncodable, RustcDecodable)]
pub struct ItemLocalId(pub u32);
impl ItemLocalId {
pub fn as_usize(&self) -> usize {
self.0 as usize
// hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module
mod item_local_id_inner {
use rustc_data_structures::indexed_vec::Idx;
/// An `ItemLocalId` uniquely identifies something within a given "item-like",
/// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
/// guarantee that the numerical value of a given `ItemLocalId` corresponds to
/// the node's position within the owning item in any way, but there is a
/// guarantee that the `LocalItemId`s within an owner occupy a dense range of
/// integers starting at zero, so a mapping that maps all or most nodes within
/// an "item-like" to something else can be implement by a `Vec` instead of a
/// tree or hash map.
newtype_index! {
pub struct ItemLocalId { .. }
}
}
impl indexed_vec::Idx for ItemLocalId {
fn new(idx: usize) -> Self {
debug_assert!((idx as u32) as usize == idx);
ItemLocalId(idx as u32)
}
fn index(self) -> usize {
self.0 as usize
}
}
pub use self::item_local_id_inner::ItemLocalId;
/// The `HirId` corresponding to CRATE_NODE_ID and CRATE_DEF_INDEX
pub const CRATE_HIR_ID: HirId = HirId {
owner: CRATE_DEF_INDEX,
local_id: ItemLocalId(0)
local_id: ItemLocalId::from_u32_const(0)
};
pub const DUMMY_HIR_ID: HirId = HirId {
@ -162,7 +148,7 @@ pub const DUMMY_HIR_ID: HirId = HirId {
local_id: DUMMY_ITEM_LOCAL_ID,
};
pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId(!0);
pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX;
#[derive(Clone, RustcEncodable, RustcDecodable, Copy)]
pub struct Label {
@ -331,7 +317,7 @@ impl Path {
impl fmt::Debug for Path {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "path({})", print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
write!(f, "path({})", self)
}
}
@ -698,8 +684,6 @@ pub struct WhereEqPredicate {
pub rhs_ty: P<Ty>,
}
pub type CrateConfig = HirVec<P<MetaItem>>;
/// The top-level data structure that stores the entire contents of
/// the crate currently being compiled.
///
@ -1196,8 +1180,8 @@ impl StmtKind {
pub fn id(&self) -> NodeId {
match *self {
StmtKind::Decl(_, id) => id,
StmtKind::Expr(_, id) => id,
StmtKind::Decl(_, id) |
StmtKind::Expr(_, id) |
StmtKind::Semi(_, id) => id,
}
}

View File

@ -79,7 +79,14 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for CrateNum {
}
}
impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index });
impl<'a> HashStable<StableHashingContext<'a>> for hir::ItemLocalId {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
self.as_u32().hash_stable(hcx, hasher);
}
}
impl<'a> ToStableHashKey<StableHashingContext<'a>>
for hir::ItemLocalId {
@ -800,7 +807,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Mod {
.iter()
.map(|id| {
let (def_path_hash, local_id) = id.id.to_stable_hash_key(hcx);
debug_assert_eq!(local_id, hir::ItemLocalId(0));
debug_assert_eq!(local_id, hir::ItemLocalId::from_u32(0));
def_path_hash.0
}).fold(Fingerprint::ZERO, |a, b| {
a.combine_commutative(b)

View File

@ -10,7 +10,7 @@
//! This module contains the "canonicalizer" itself.
//!
//! For an overview of what canonicaliation is and how it fits into
//! For an overview of what canonicalization is and how it fits into
//! rustc, check out the [chapter in the rustc guide][c].
//!
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html

View File

@ -556,7 +556,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
}
/// Given two sets of values for the same set of canonical variables, unify them.
/// The second set is produced lazilly by supplying indices from the first set.
/// The second set is produced lazily by supplying indices from the first set.
fn unify_canonical_vars(
&self,
cause: &ObligationCause<'tcx>,

View File

@ -11,7 +11,7 @@
//! This module contains code to substitute new values into a
//! `Canonical<'tcx, T>`.
//!
//! For an overview of what canonicaliation is and how it fits into
//! For an overview of what canonicalization is and how it fits into
//! rustc, check out the [chapter in the rustc guide][c].
//!
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html

View File

@ -20,7 +20,7 @@ use util::common::ErrorReported;
use infer::lexical_region_resolve::RegionResolutionError::SubSupConflict;
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
/// Print the error message for lifetime errors when binding excapes a closure.
/// Print the error message for lifetime errors when binding escapes a closure.
///
/// Consider a case where we have
///

View File

@ -428,7 +428,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
///
/// This routine is only intended to be used when the leak-check has
/// passed; currently, it's used in the trait matching code to create
/// a set of nested obligations frmo an impl that matches against
/// a set of nested obligations from an impl that matches against
/// something higher-ranked. More details can be found in
/// `librustc/middle/traits/README.md`.
///

View File

@ -1160,10 +1160,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
/// Takes ownership of the list of variable regions. This implies
/// that all the region constriants have already been taken, and
/// that all the region constraints have already been taken, and
/// hence that `resolve_regions_and_report_errors` can never be
/// called. This is used only during NLL processing to "hand off" ownership
/// of the set of region vairables into the NLL region context.
/// of the set of region variables into the NLL region context.
pub fn take_region_var_origins(&self) -> VarInfos {
let (var_infos, data) = self.region_constraints
.borrow_mut()
@ -1478,7 +1478,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
/// Clears the selection, evaluation, and projection caches. This is useful when
/// repeatedly attemping to select an Obligation while changing only
/// repeatedly attempting to select an Obligation while changing only
/// its ParamEnv, since FulfillmentContext doesn't use 'probe'
pub fn clear_caches(&self) {
self.selection_cache.clear();

View File

@ -299,8 +299,8 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
let assoc_item = tcx.associated_item(assoc_item_def_id);
let trait_def_id = assoc_item.container.assert_trait();
let trait_predicates = tcx.predicates_of(trait_def_id).predicates
.into_iter()
.map(|(p, _)| p)
.iter()
.map(|(p, _)| *p)
.collect();
let identity_substs = Substs::identity_for_item(tcx, assoc_item_def_id);
let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs);

View File

@ -320,7 +320,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
/// but which have only been unified since `s` started, and
/// return the types with which they were unified. So if we had
/// a type variable `V0`, then we started the snapshot, then we
/// created a type variable `V1`, unifed `V0` with `T0`, and
/// created a type variable `V1`, unified `V0` with `T0`, and
/// unified `V1` with `T1`, this function would return `{T0}`.
pub fn types_escaping_snapshot(&mut self, s: &Snapshot<'tcx>) -> Vec<Ty<'tcx>> {
let mut new_elem_threshold = u32::MAX;

View File

@ -1020,9 +1020,12 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
}
fn visit_pat(&mut self, p: &'a ast::Pat) {
run_lints!(self, check_pat, p);
let mut visit_subpats = true;
run_lints!(self, check_pat, p, &mut visit_subpats);
self.check_id(p.id);
ast_visit::walk_pat(self, p);
if visit_subpats {
ast_visit::walk_pat(self, p);
}
}
fn visit_expr(&mut self, e: &'a ast::Expr) {

View File

@ -189,7 +189,7 @@ impl<'a> LintLevelsBuilder<'a> {
/// This function will perform a number of tasks:
///
/// * It'll validate all lint-related attributes in `attrs`
/// * It'll mark all lint-related attriutes as used
/// * It'll mark all lint-related attributes as used
/// * Lint levels will be updated based on the attributes provided
/// * Lint attributes are validated, e.g. a #[forbid] can't be switched to
/// #[allow]

View File

@ -341,7 +341,7 @@ pub trait EarlyLintPass: LintPass {
fn check_block_post(&mut self, _: &EarlyContext<'_>, _: &ast::Block) { }
fn check_stmt(&mut self, _: &EarlyContext<'_>, _: &ast::Stmt) { }
fn check_arm(&mut self, _: &EarlyContext<'_>, _: &ast::Arm) { }
fn check_pat(&mut self, _: &EarlyContext<'_>, _: &ast::Pat) { }
fn check_pat(&mut self, _: &EarlyContext<'_>, _: &ast::Pat, _: &mut bool) { }
fn check_expr(&mut self, _: &EarlyContext<'_>, _: &ast::Expr) { }
fn check_expr_post(&mut self, _: &EarlyContext<'_>, _: &ast::Expr) { }
fn check_ty(&mut self, _: &EarlyContext<'_>, _: &ast::Ty) { }

View File

@ -224,7 +224,7 @@ impl Default for ErrorOutputType {
// Use tree-based collections to cheaply get a deterministic Hash implementation.
// DO NOT switch BTreeMap out for an unsorted container type! That would break
// dependency tracking for commandline arguments.
// dependency tracking for command-line arguments.
#[derive(Clone, Hash)]
pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
@ -273,7 +273,7 @@ impl OutputTypes {
// Use tree-based collections to cheaply get a deterministic Hash implementation.
// DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
// would break dependency tracking for commandline arguments.
// would break dependency tracking for command-line arguments.
#[derive(Clone, Hash)]
pub struct Externs(BTreeMap<String, BTreeSet<Option<String>>>);
@ -339,7 +339,7 @@ macro_rules! top_level_options {
);
}
// The top-level commandline options struct
// The top-level command-line options struct
//
// For each option, one has to specify how it behaves with regard to the
// dependency tracking system of incremental compilation. This is done via the
@ -2377,11 +2377,11 @@ impl fmt::Display for CrateType {
}
}
/// Commandline arguments passed to the compiler have to be incorporated with
/// Command-line arguments passed to the compiler have to be incorporated with
/// the dependency tracking system for incremental compilation. This module
/// provides some utilities to make this more convenient.
///
/// The values of all commandline arguments that are relevant for dependency
/// The values of all command-line arguments that are relevant for dependency
/// tracking are hashed into a single value that determines whether the
/// incremental compilation cache can be re-used or not. This hashing is done
/// via the DepTrackingHash trait defined below, since the standard Hash
@ -2394,7 +2394,7 @@ impl fmt::Display for CrateType {
/// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the
/// Hash implementation for DepTrackingHash. It's important though that
/// we have an opt-in scheme here, so one is hopefully forced to think about
/// how the hash should be calculated when adding a new commandline argument.
/// how the hash should be calculated when adding a new command-line argument.
mod dep_tracking {
use lint;
use middle::cstore;

View File

@ -393,7 +393,7 @@ impl Session {
match id.as_usize().checked_add(count) {
Some(next) => {
self.next_node_id.set(ast::NodeId::new(next));
self.next_node_id.set(ast::NodeId::from_usize(next));
}
None => bug!("Input too large, ran out of node ids!"),
}
@ -1160,7 +1160,7 @@ pub fn build_session_(
recursion_limit: Once::new(),
type_length_limit: Once::new(),
const_eval_stack_frame_limit: 100,
next_node_id: OneThread::new(Cell::new(NodeId::new(1))),
next_node_id: OneThread::new(Cell::new(NodeId::from_u32(1))),
allocator_kind: Once::new(),
injected_panic_runtime: Once::new(),
imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())),

View File

@ -182,7 +182,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
};
predicates
.predicates
.into_iter()
.iter()
.map(|(predicate, _)| predicate.subst_supertrait(self, &trait_ref))
.any(|predicate| {
match predicate {
@ -302,9 +302,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
return Some(MethodViolationCode::Generic);
}
if self.predicates_of(method.def_id).predicates.into_iter()
if self.predicates_of(method.def_id).predicates.iter()
// A trait object can't claim to live more than the concrete type,
// so outlives predicates will always hold.
.cloned()
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
.collect::<Vec<_>>()
// Do a shallow visit so that `contains_illegal_self_type_reference`

View File

@ -200,7 +200,7 @@ impl_stable_hash_for!(struct DtorckConstraint<'tcx> {
/// trivial for dropck-outlives.
///
/// Note also that `needs_drop` requires a "global" type (i.e., one
/// with erased regions), but this funtcion does not.
/// with erased regions), but this function does not.
pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
match ty.sty {
// None of these types have a destructor and hence they do not

View File

@ -407,7 +407,7 @@ fn to_pretty_impl_header(tcx: TyCtxt<'_, '_, '_>, impl_def_id: DefId) -> Option<
// The predicates will contain default bounds like `T: Sized`. We need to
// remove these bounds, and add `T: ?Sized` to any untouched type parameters.
let predicates = tcx.predicates_of(impl_def_id).predicates;
let predicates = &tcx.predicates_of(impl_def_id).predicates;
let mut pretty_predicates = Vec::with_capacity(
predicates.len() + types_without_default_bounds.len());

View File

@ -781,7 +781,7 @@ pub fn shift_vars<'a, 'gcx, 'tcx, T>(
///
/// Note that what I'm calling an "escaping var" is often just called a "free var". However,
/// we already use the term "free var". It refers to the regions or types that we use to represent
/// bound regions or type params on a fn definition while we are typechecking its body.
/// bound regions or type params on a fn definition while we are type checking its body.
///
/// To clarify, conceptually there is no particular difference between
/// an "escaping" var and a "free" var. However, there is a big
@ -857,7 +857,7 @@ struct LateBoundRegionsCollector {
/// If true, we only want regions that are known to be
/// "constrained" when you equate this type with another type. In
/// partcular, if you have e.g. `&'a u32` and `&'b u32`, equating
/// particular, if you have e.g. `&'a u32` and `&'b u32`, equating
/// them constraints `'a == 'b`. But if you have `<&'a u32 as
/// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those
/// types may mean that `'a` and `'b` don't appear in the results,

View File

@ -1287,7 +1287,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
/// Type size "skeleton", i.e. the only information determining a type's size.
/// While this is conservative, (aside from constant sizes, only pointers,
/// newtypes thereof and null pointer optimized enums are allowed), it is
/// enough to statically check common usecases of transmute.
/// enough to statically check common use cases of transmute.
#[derive(Copy, Clone, Debug)]
pub enum SizeSkeleton<'tcx> {
/// Any statically computable Layout.

View File

@ -2130,7 +2130,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
}
#[inline]
pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> GenericPredicates<'gcx> {
pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Lrc<GenericPredicates<'gcx>> {
tcx.predicates_of(self.did)
}
@ -2373,8 +2373,8 @@ impl<'a, 'gcx, 'tcx> AdtDef {
def_id: sized_trait,
substs: tcx.mk_substs_trait(ty, &[])
}).to_predicate();
let predicates = tcx.predicates_of(self.did).predicates;
if predicates.into_iter().any(|(p, _)| p == sized_predicate) {
let predicates = &tcx.predicates_of(self.did).predicates;
if predicates.iter().any(|(p, _)| *p == sized_predicate) {
vec![]
} else {
vec![ty]
@ -2400,7 +2400,7 @@ impl<'a, 'gcx, 'tcx> FieldDef {
/// Represents the various closure traits in the Rust language. This
/// will determine the type of the environment (`self`, in the
/// desuaring) argument that the closure expects.
/// desugaring) argument that the closure expects.
///
/// You can get the environment type of a closure using
/// `tcx.closure_env_ty()`.

View File

@ -127,17 +127,18 @@ define_queries! { <'tcx>
/// predicate gets in the way of some checks, which are intended
/// to operate over only the actual where-clauses written by the
/// user.)
[] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
[] fn predicates_of: PredicatesOfItem(DefId) -> Lrc<ty::GenericPredicates<'tcx>>,
/// Maps from the def-id of an item (trait/struct/enum/fn) to the
/// predicates (where clauses) directly defined on it. This is
/// equal to the `explicit_predicates_of` predicates plus the
/// `inferred_outlives_of` predicates.
[] fn predicates_defined_on: PredicatesDefinedOnItem(DefId) -> ty::GenericPredicates<'tcx>,
[] fn predicates_defined_on: PredicatesDefinedOnItem(DefId)
-> Lrc<ty::GenericPredicates<'tcx>>,
/// Returns the predicates written explicit by the user.
[] fn explicit_predicates_of: ExplicitPredicatesOfItem(DefId)
-> ty::GenericPredicates<'tcx>,
-> Lrc<ty::GenericPredicates<'tcx>>,
/// Returns the inferred outlives predicates (e.g., for `struct
/// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
@ -149,12 +150,12 @@ define_queries! { <'tcx>
/// evaluate them even during type conversion, often before the
/// full predicates are available (note that supertraits have
/// additional acyclicity requirements).
[] fn super_predicates_of: SuperPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
[] fn super_predicates_of: SuperPredicatesOfItem(DefId) -> Lrc<ty::GenericPredicates<'tcx>>,
/// To avoid cycles within the predicates of a single item we compute
/// per-type-parameter predicates for resolving `T::AssocTy`.
[] fn type_param_predicates: type_param_predicates((DefId, DefId))
-> ty::GenericPredicates<'tcx>,
-> Lrc<ty::GenericPredicates<'tcx>>,
[] fn trait_def: TraitDefOfItem(DefId) -> &'tcx ty::TraitDef,
[] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef,

View File

@ -942,7 +942,7 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
///
/// In the process of working on rust-lang/rust#55238 a mysterious segfault was
/// stumbled upon. The segfault was never reproduced locally, but it was
/// suspected to be releated to the fact that codegen worker threads were
/// suspected to be related to the fact that codegen worker threads were
/// sticking around by the time the main thread was exiting, causing issues.
///
/// This structure is an attempt to fix that issue where the `codegen_aborted`

View File

@ -194,7 +194,7 @@ pub fn codegen_intrinsic_call(
return;
}
// Effectively no-ops
"uninit" => {
"uninit" | "forget" => {
return;
}
"needs_drop" => {

View File

@ -79,7 +79,7 @@
//! - In order to be able to also use symbols from two versions of the same
//! crate (which naturally also have the same name), a stronger measure is
//! required: The compiler accepts an arbitrary "disambiguator" value via the
//! `-C metadata` commandline argument. This disambiguator is then fed into
//! `-C metadata` command-line argument. This disambiguator is then fed into
//! the symbol hash of every exported item. Consequently, the symbols in two
//! identical crates but with different disambiguators are not in conflict
//! with each other. This facility is mainly intended to be used by build

View File

@ -38,7 +38,7 @@ struct SccData<S: Idx> {
/// successors can be found.
ranges: IndexVec<S, Range<usize>>,
/// Contains the succcessors for all the Sccs, concatenated. The
/// Contains the successors for all the Sccs, concatenated. The
/// range of indices corresponding to a given SCC is found in its
/// SccData.
all_successors: Vec<S>,

View File

@ -452,7 +452,7 @@ impl<O, T: ?Sized> OwningRef<O, T> {
/// use owning_ref::{OwningRef, Erased};
///
/// fn main() {
/// // NB: Using the concrete types here for explicitnes.
/// // NB: Using the concrete types here for explicitness.
/// // For less verbose code type aliases like `BoxRef` are provided.
///
/// let owning_ref_a: OwningRef<Box<[i32; 4]>, [i32; 4]>
@ -722,7 +722,7 @@ impl<O, T: ?Sized> OwningRefMut<O, T> {
/// use owning_ref::{OwningRefMut, Erased};
///
/// fn main() {
/// // NB: Using the concrete types here for explicitnes.
/// // NB: Using the concrete types here for explicitness.
/// // For less verbose code type aliases like `BoxRef` are provided.
///
/// let owning_ref_mut_a: OwningRefMut<Box<[i32; 4]>, [i32; 4]>

View File

@ -15,7 +15,7 @@ use std::mem;
use std::ops::{RangeBounds, Bound, Index, IndexMut};
/// `SortedMap` is a data structure with similar characteristics as BTreeMap but
/// slightly different trade-offs: lookup, inseration, and removal are O(log(N))
/// slightly different trade-offs: lookup, insertion, and removal are O(log(N))
/// and elements can be iterated in order cheaply.
///
/// `SortedMap` can be faster than a `BTreeMap` for small sizes (<50) since it

View File

@ -643,8 +643,8 @@ impl Compilation {
}
}
/// A trait for customising the compilation process. Offers a number of hooks for
/// executing custom code or customising input.
/// A trait for customizing the compilation process. Offers a number of hooks for
/// executing custom code or customizing input.
pub trait CompilerCalls<'a> {
/// Hook for a callback early in the process of handling arguments. This will
/// be called straight after options have been parsed but before anything

View File

@ -425,7 +425,7 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
pprust_hir::AnnNode::Item(item) => {
s.s.space()?;
s.synth_comment(format!("node_id: {} hir local_id: {}",
item.id, item.hir_id.local_id.0))
item.id, item.hir_id.local_id.as_u32()))
}
pprust_hir::AnnNode::SubItem(id) => {
s.s.space()?;
@ -434,18 +434,18 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
pprust_hir::AnnNode::Block(blk) => {
s.s.space()?;
s.synth_comment(format!("block node_id: {} hir local_id: {}",
blk.id, blk.hir_id.local_id.0))
blk.id, blk.hir_id.local_id.as_u32()))
}
pprust_hir::AnnNode::Expr(expr) => {
s.s.space()?;
s.synth_comment(format!("node_id: {} hir local_id: {}",
expr.id, expr.hir_id.local_id.0))?;
expr.id, expr.hir_id.local_id.as_u32()))?;
s.pclose()
}
pprust_hir::AnnNode::Pat(pat) => {
s.s.space()?;
s.synth_comment(format!("pat node_id: {} hir local_id: {}",
pat.id, pat.hir_id.local_id.0))
pat.id, pat.hir_id.local_id.as_u32()))
}
}
}
@ -566,7 +566,7 @@ impl FromStr for UserIdentifiedItem {
type Err = ();
fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
Ok(s.parse()
.map(ast::NodeId::new)
.map(ast::NodeId::from_u32)
.map(ItemViaNode)
.unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect())))
}

View File

@ -232,20 +232,20 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
// children of 1, etc
let dscope = region::Scope {
id: hir::ItemLocalId(1),
id: hir::ItemLocalId::from_u32(1),
data: region::ScopeData::Destruction,
};
self.region_scope_tree.record_scope_parent(dscope, None);
self.create_region_hierarchy(
&RH {
id: hir::ItemLocalId(1),
id: hir::ItemLocalId::from_u32(1),
sub: &[
RH {
id: hir::ItemLocalId(10),
id: hir::ItemLocalId::from_u32(10),
sub: &[],
},
RH {
id: hir::ItemLocalId(11),
id: hir::ItemLocalId::from_u32(11),
sub: &[],
},
],
@ -400,7 +400,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
let r = ty::ReScope(region::Scope {
id: hir::ItemLocalId(id),
id: hir::ItemLocalId::from_u32(id),
data: region::ScopeData::Node,
});
self.infcx

View File

@ -160,7 +160,7 @@ const LABELS_FN_IN_TRAIT: &[&[&str]] = &[
EXTRA_TRAIT,
];
/// For generic cases like inline-assemply/mod/etc
/// For generic cases like inline-assembly/mod/etc
const LABELS_HIR_ONLY: &[&[&str]] = &[
BASE_HIR,
];

View File

@ -40,6 +40,8 @@ use rustc::util::nodemap::FxHashSet;
use syntax::tokenstream::{TokenTree, TokenStream};
use syntax::ast;
use syntax::ptr::P;
use syntax::ast::Expr;
use syntax::attr;
use syntax::source_map::Spanned;
use syntax::edition::Edition;
@ -47,6 +49,7 @@ use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_a
use syntax_pos::{BytePos, Span, SyntaxContext};
use syntax::symbol::keywords;
use syntax::errors::{Applicability, DiagnosticBuilder};
use syntax::print::pprust::expr_to_string;
use rustc::hir::{self, GenericParamKind, PatKind};
use rustc::hir::intravisit::FnKind;
@ -1407,21 +1410,48 @@ impl LintPass for EllipsisInclusiveRangePatterns {
}
impl EarlyLintPass for EllipsisInclusiveRangePatterns {
fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) {
use self::ast::{PatKind, RangeEnd, RangeSyntax};
fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat, visit_subpats: &mut bool) {
use self::ast::{PatKind, RangeEnd, RangeSyntax::DotDotDot};
if let PatKind::Range(
_, _, Spanned { span, node: RangeEnd::Included(RangeSyntax::DotDotDot) }
) = pat.node {
/// If `pat` is a `...` pattern, return the start and end of the range, as well as the span
/// corresponding to the ellipsis.
fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(&P<Expr>, &P<Expr>, Span)> {
match &pat.node {
PatKind::Range(a, b, Spanned { span, node: RangeEnd::Included(DotDotDot), .. }) => {
Some((a, b, *span))
}
_ => None,
}
}
let (parenthesise, endpoints) = match &pat.node {
PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)),
_ => (false, matches_ellipsis_pat(pat)),
};
if let Some((start, end, join)) = endpoints {
let msg = "`...` range patterns are deprecated";
let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, span, msg);
err.span_suggestion_short_with_applicability(
span, "use `..=` for an inclusive range", "..=".to_owned(),
// FIXME: outstanding problem with precedence in ref patterns:
// https://github.com/rust-lang/rust/issues/51043#issuecomment-392252285
Applicability::MaybeIncorrect
);
err.emit()
let suggestion = "use `..=` for an inclusive range";
if parenthesise {
*visit_subpats = false;
let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg);
err.span_suggestion_with_applicability(
pat.span,
suggestion,
format!("&({}..={})", expr_to_string(&start), expr_to_string(&end)),
Applicability::MachineApplicable,
);
err.emit();
} else {
let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg);
err.span_suggestion_short_with_applicability(
join,
suggestion,
"..=".to_owned(),
Applicability::MachineApplicable,
);
err.emit();
};
}
}
}
@ -1486,7 +1516,7 @@ declare_lint! {
"detects edition keywords being used as an identifier"
}
/// Checks for uses of edtion keywords used as an identifier
/// Checks for uses of edition keywords used as an identifier
#[derive(Clone)]
pub struct KeywordIdents;

View File

@ -396,12 +396,12 @@ impl EarlyLintPass for UnusedParens {
self.check_unused_parens_expr(cx, &value, msg, followed_by_block);
}
fn check_pat(&mut self, cx: &EarlyContext, p: &ast::Pat) {
fn check_pat(&mut self, cx: &EarlyContext, p: &ast::Pat, _: &mut bool) {
use ast::PatKind::{Paren, Range};
// The lint visitor will visit each subpattern of `p`. We do not want to lint any range
// pattern no matter where it occurs in the pattern. For something like `&(a..=b)`, there
// is a recursive `check_pat` on `a` and `b`, but we will assume that if there are
// unnecessry parens they serve a purpose of readability.
// unnecessary parens they serve a purpose of readability.
if let Paren(ref pat) = p.node {
match pat.node {
Range(..) => {}

View File

@ -11,12 +11,14 @@ crate-type = ["dylib"]
[dependencies]
flate2 = "1.0"
log = "0.4"
memmap = "0.6"
proc_macro = { path = "../libproc_macro" }
rustc = { path = "../librustc" }
rustc_target = { path = "../librustc_target" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
rustc_target = { path = "../librustc_target" }
serialize = { path = "../libserialize" }
stable_deref_trait = "1.0.0"
syntax = { path = "../libsyntax" }
syntax_ext = { path = "../libsyntax_ext" }
syntax_pos = { path = "../libsyntax_pos" }

View File

@ -103,9 +103,9 @@ provide! { <'tcx> tcx, def_id, other, cdata,
generics_of => {
tcx.alloc_generics(cdata.get_generics(def_id.index, tcx.sess))
}
predicates_of => { cdata.get_predicates(def_id.index, tcx) }
predicates_defined_on => { cdata.get_predicates_defined_on(def_id.index, tcx) }
super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) }
predicates_of => { Lrc::new(cdata.get_predicates(def_id.index, tcx)) }
predicates_defined_on => { Lrc::new(cdata.get_predicates_defined_on(def_id.index, tcx)) }
super_predicates_of => { Lrc::new(cdata.get_super_predicates(def_id.index, tcx)) }
trait_def => {
tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx.sess))
}

View File

@ -30,6 +30,8 @@
extern crate libc;
#[macro_use]
extern crate log;
extern crate memmap;
extern crate stable_deref_trait;
#[macro_use]
extern crate syntax;
extern crate syntax_pos;

View File

@ -243,12 +243,14 @@ use std::cmp;
use std::fmt;
use std::fs;
use std::io::{self, Read};
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::time::Instant;
use flate2::read::DeflateDecoder;
use rustc_data_structures::owning_ref::OwningRef;
pub struct CrateMismatch {
path: PathBuf,
got: String,
@ -856,6 +858,19 @@ fn get_metadata_section(target: &Target,
return ret;
}
/// A trivial wrapper for `Mmap` that implements `StableDeref`.
struct StableDerefMmap(memmap::Mmap);
impl Deref for StableDerefMmap {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.0.deref()
}
}
unsafe impl stable_deref_trait::StableDeref for StableDerefMmap {}
fn get_metadata_section_imp(target: &Target,
flavor: CrateFlavor,
filename: &Path,
@ -892,9 +907,14 @@ fn get_metadata_section_imp(target: &Target,
}
}
CrateFlavor::Rmeta => {
let buf = fs::read(filename).map_err(|_|
format!("failed to read rmeta metadata: '{}'", filename.display()))?;
rustc_erase_owner!(OwningRef::new(buf).map_owner_box())
// mmap the file, because only a small fraction of it is read.
let file = std::fs::File::open(filename).map_err(|_|
format!("failed to open rmeta metadata: '{}'", filename.display()))?;
let mmap = unsafe { memmap::Mmap::map(&file) };
let mmap = mmap.map_err(|_|
format!("failed to mmap rmeta metadata: '{}'", filename.display()))?;
rustc_erase_owner!(OwningRef::new(StableDerefMmap(mmap)).map_owner_box())
}
};
let blob = MetadataBlob(raw_bytes);

View File

@ -112,7 +112,7 @@ mod relate_tys;
/// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
/// constraints for the regions in the types of variables
/// - `flow_inits` -- results of a maybe-init dataflow analysis
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysiss
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
pub(crate) fn type_check<'gcx, 'tcx>(
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'gcx>,

View File

@ -262,7 +262,7 @@ struct PlaceComponents<'p, 'tcx: 'p> {
impl<'p, 'tcx> PlaceComponents<'p, 'tcx> {
/// Converts a list of `Place` components into an iterator; this
/// iterator yields up a never-ending stream of `Option<&Place>`.
/// These begin with the "innermst" place and then with each
/// These begin with the "innermost" place and then with each
/// projection therefrom. So given a place like `a.b.c` it would
/// yield up:
///

View File

@ -90,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let source_info = this.source_info(span);
for stmt in stmts {
let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt);
let Stmt { kind, opt_destruction_scope, span: stmt_span } = this.hir.mirror(stmt);
match kind {
StmtKind::Expr { scope, expr } => {
this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let si = (scope, source_info);
this.in_scope(si, LintLevel::Inherited, block, |this| {
let expr = this.hir.mirror(expr);
this.stmt_expr(block, expr)
this.stmt_expr(block, expr, Some(stmt_span))
})
}));
}
@ -177,17 +177,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let destination_ty = destination.ty(&this.local_decls, tcx).to_ty(tcx);
if let Some(expr) = expr {
let tail_result_is_ignored = destination_ty.is_unit() ||
match this.block_context.last() {
// no context: conservatively assume result is read
None => false,
// sub-expression: block result feeds into some computation
Some(BlockFrame::SubExpr) => false,
// otherwise: use accumualated is_ignored state.
Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) |
Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored,
};
this.block_context.currently_ignores_tail_results();
this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored });
unpack!(block = this.into(destination, block, expr));

View File

@ -351,7 +351,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
block.and(Rvalue::Aggregate(adt, fields))
}
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
block = unpack!(this.stmt_expr(block, expr));
block = unpack!(this.stmt_expr(block, expr, None));
block.and(this.unit_rvalue())
}
ExprKind::Yield { value } => {

View File

@ -10,7 +10,7 @@
//! See docs in build/expr/mod.rs
use build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use build::{BlockAnd, BlockAndExtension, Builder};
use hair::*;
use rustc::middle::region;
use rustc::mir::*;
@ -68,19 +68,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context);
// Find out whether this temp is being created within the
// tail expression of a block whose result is ignored.
for bf in this.block_context.iter().rev() {
match bf {
BlockFrame::SubExpr => continue,
BlockFrame::Statement { .. } => break,
&BlockFrame::TailExpr { tail_result_is_ignored } => {
local_decl = local_decl.block_tail(BlockTailInfo {
tail_result_is_ignored
});
break;
}
}
if let Some(tail_info) = this.block_context.currently_in_block_tail() {
local_decl = local_decl.block_tail(tail_info);
}
this.local_decls.push(local_decl)
};
if !expr_ty.is_never() {

View File

@ -351,7 +351,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
| ExprKind::Break { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::Return { .. } => {
unpack!(block = this.stmt_expr(block, expr));
unpack!(block = this.stmt_expr(block, expr, None));
this.cfg.push_assign_unit(block, source_info, destination);
block.unit()
}

View File

@ -14,7 +14,18 @@ use hair::*;
use rustc::mir::*;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<()> {
/// Builds a block of MIR statements to evaluate the HAIR `expr`.
/// If the original expression was an AST statement,
/// (e.g. `some().code(&here());`) then `opt_stmt_span` is the
/// span of that statement (including its semicolon, if any).
/// Diagnostics use this span (which may be larger than that of
/// `expr`) to identify when statement temporaries are dropped.
pub fn stmt_expr(&mut self,
mut block: BasicBlock,
expr: Expr<'tcx>,
opt_stmt_span: Option<StatementSpan>)
-> BlockAnd<()>
{
let this = self;
let expr_span = expr.span;
let source_info = this.source_info(expr.span);
@ -29,7 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} => {
let value = this.hir.mirror(value);
this.in_scope((region_scope, source_info), lint_level, block, |this| {
this.stmt_expr(block, value)
this.stmt_expr(block, value, opt_stmt_span)
})
}
ExprKind::Assign { lhs, rhs } => {
@ -190,9 +201,56 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
_ => {
let expr_ty = expr.ty;
let temp = this.temp(expr.ty.clone(), expr_span);
// Issue #54382: When creating temp for the value of
// expression like:
//
// `{ side_effects(); { let l = stuff(); the_value } }`
//
// it is usually better to focus on `the_value` rather
// than the entirety of block(s) surrounding it.
let mut temp_span = expr_span;
let mut temp_in_tail_of_block = false;
if let ExprKind::Block { body } = expr.kind {
if let Some(tail_expr) = &body.expr {
let mut expr = tail_expr;
while let rustc::hir::ExprKind::Block(subblock, _label) = &expr.node {
if let Some(subtail_expr) = &subblock.expr {
expr = subtail_expr
} else {
break;
}
}
temp_span = expr.span;
temp_in_tail_of_block = true;
}
}
let temp = {
let mut local_decl = LocalDecl::new_temp(expr.ty.clone(), temp_span);
if temp_in_tail_of_block {
if this.block_context.currently_ignores_tail_results() {
local_decl = local_decl.block_tail(BlockTailInfo {
tail_result_is_ignored: true
});
}
}
let temp = this.local_decls.push(local_decl);
let place = Place::Local(temp);
debug!("created temp {:?} for expr {:?} in block_context: {:?}",
temp, expr, this.block_context);
place
};
unpack!(block = this.into(&temp, block, expr));
unpack!(block = this.build_drop(block, expr_span, temp, expr_ty));
// Attribute drops of the statement's temps to the
// semicolon at the statement's end.
let drop_point = this.hir.tcx().sess.source_map().end_point(match opt_stmt_span {
None => expr_span,
Some(StatementSpan(span)) => span,
});
unpack!(block = this.build_drop(block, drop_point, temp, expr_ty));
block.unit()
}
}

View File

@ -31,7 +31,7 @@ use std::cmp::Ordering;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
/// Identifies what test is needed to decide if `match_pair` is applicable.
///
/// It is a bug to call this with a simplifyable pattern.
/// It is a bug to call this with a simplifiable pattern.
pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
match *match_pair.pattern.kind {
PatternKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => {

View File

@ -336,6 +336,9 @@ impl BlockFrame {
}
}
#[derive(Debug)]
struct BlockContext(Vec<BlockFrame>);
struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
hir: Cx<'a, 'gcx, 'tcx>,
cfg: CFG<'tcx>,
@ -359,7 +362,7 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
/// start just throwing new entries onto that vector in order to
/// distinguish the context of EXPR1 from the context of EXPR2 in
/// `{ STMTS; EXPR1 } + EXPR2`
block_context: Vec<BlockFrame>,
block_context: BlockContext,
/// The current unsafe block in scope, even if it is hidden by
/// a PushUnsafeBlock
@ -409,6 +412,55 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
}
impl BlockContext {
fn new() -> Self { BlockContext(vec![]) }
fn push(&mut self, bf: BlockFrame) { self.0.push(bf); }
fn pop(&mut self) -> Option<BlockFrame> { self.0.pop() }
/// Traverses the frames on the BlockContext, searching for either
/// the first block-tail expression frame with no intervening
/// statement frame.
///
/// Notably, this skips over `SubExpr` frames; this method is
/// meant to be used in the context of understanding the
/// relationship of a temp (created within some complicated
/// expression) with its containing expression, and whether the
/// value of that *containing expression* (not the temp!) is
/// ignored.
fn currently_in_block_tail(&self) -> Option<BlockTailInfo> {
for bf in self.0.iter().rev() {
match bf {
BlockFrame::SubExpr => continue,
BlockFrame::Statement { .. } => break,
&BlockFrame::TailExpr { tail_result_is_ignored } =>
return Some(BlockTailInfo { tail_result_is_ignored })
}
}
return None;
}
/// Looks at the topmost frame on the BlockContext and reports
/// whether its one that would discard a block tail result.
///
/// Unlike `currently_within_ignored_tail_expression`, this does
/// *not* skip over `SubExpr` frames: here, we want to know
/// whether the block result itself is discarded.
fn currently_ignores_tail_results(&self) -> bool {
match self.0.last() {
// no context: conservatively assume result is read
None => false,
// sub-expression: block result feeds into some computation
Some(BlockFrame::SubExpr) => false,
// otherwise: use accumulated is_ignored state.
Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) |
Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored,
}
}
}
#[derive(Debug)]
enum LocalsForNode {
/// In the usual case, a node-id for an identifier maps to at most
@ -764,7 +816,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn_span: span,
arg_count,
scopes: vec![],
block_context: vec![],
block_context: BlockContext::new(),
source_scopes: IndexVec::new(),
source_scope: OUTERMOST_SOURCE_SCOPE,
source_scope_local_data: IndexVec::new(),

View File

@ -57,6 +57,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
for (index, stmt) in stmts.iter().enumerate() {
let hir_id = cx.tcx.hir.node_to_hir_id(stmt.node.id());
let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id);
let stmt_span = StatementSpan(cx.tcx.hir.span(stmt.node.id()));
match stmt.node {
hir::StmtKind::Expr(ref expr, _) |
hir::StmtKind::Semi(ref expr, _) => {
@ -69,6 +70,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: expr.to_ref(),
},
opt_destruction_scope: opt_dxn_ext,
span: stmt_span,
})))
}
hir::StmtKind::Decl(ref decl, _) => {
@ -111,6 +113,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
lint_level: cx.lint_level_of(local.id),
},
opt_destruction_scope: opt_dxn_ext,
span: stmt_span,
})));
}
}

View File

@ -72,10 +72,14 @@ pub enum StmtRef<'tcx> {
Mirror(Box<Stmt<'tcx>>),
}
#[derive(Clone, Debug)]
pub struct StatementSpan(pub Span);
#[derive(Clone, Debug)]
pub struct Stmt<'tcx> {
pub kind: StmtKind<'tcx>,
pub opt_destruction_scope: Option<region::Scope>,
pub span: StatementSpan,
}
#[derive(Clone, Debug)]
@ -116,7 +120,7 @@ pub enum StmtKind<'tcx> {
/// reference to an expression in this enum is an `ExprRef<'tcx>`, which
/// may in turn be another instance of this enum (boxed), or else an
/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
/// shortlived. They are created by `Hair::to_expr`, analyzed and
/// short-lived. They are created by `Hair::to_expr`, analyzed and
/// converted into MIR, and then discarded.
///
/// If you compare `Expr` to the full compiler AST, you will see it is

View File

@ -55,11 +55,11 @@
/// all the values it covers are already covered by row 2.
///
/// To compute `U`, we must have two other concepts.
/// 1. `S(c, P)` is a "specialised matrix", where `c` is a constructor (like `Some` or
/// 1. `S(c, P)` is a "specialized matrix", where `c` is a constructor (like `Some` or
/// `None`). You can think of it as filtering `P` to just the rows whose *first* pattern
/// can cover `c` (and expanding OR-patterns into distinct patterns), and then expanding
/// the constructor into all of its components.
/// The specialisation of a row vector is computed by `specialize`.
/// The specialization of a row vector is computed by `specialize`.
///
/// It is computed as follows. For each row `p_i` of P, we have four cases:
/// 1.1. `p_(i,1) = c(r_1, .., r_a)`. Then `S(c, P)` has a corresponding row:
@ -1453,7 +1453,7 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'_, 'tcx, 'tcx>, ctor: &Construct
/// mean creating a separate constructor for every single value in the range, which is clearly
/// impractical. However, observe that for some ranges of integers, the specialisation will be
/// identical across all values in that range (i.e. there are equivalence classes of ranges of
/// constructors based on their `is_useful_specialised` outcome). These classes are grouped by
/// constructors based on their `is_useful_specialized` outcome). These classes are grouped by
/// the patterns that apply to them (in the matrix `P`). We can split the range whenever the
/// patterns that apply to that range (specifically: the patterns that *intersect* with that range)
/// change.

View File

@ -67,7 +67,7 @@ macro_rules! try_validation {
}}
}
/// We want to show a nice path to the invalid field for diagnotsics,
/// We want to show a nice path to the invalid field for diagnostics,
/// but avoid string operations in the happy case where no error happens.
/// So we track a `Vec<PathElem>` where `PathElem` contains all the data we
/// need to later print something for the user.

View File

@ -172,7 +172,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
/// While the `ExprUseVisitor` walks, we will identify which
/// expressions are borrowed, and insert their ids into this
/// table. Actually, we insert the "borrow-id", which is normally
/// the id of the expession being borrowed: but in the case of
/// the id of the expression being borrowed: but in the case of
/// `ref mut` borrows, the `id` of the pattern is
/// inserted. Therefore later we remove that entry from the table
/// and transfer it over to the value being matched. This will

View File

@ -663,7 +663,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
let mut errors = false;
let mut seen_spans = FxHashSet::default();
let mut error_vec = Vec::new();
let mut prev_root_id: NodeId = NodeId::new(0);
let mut prev_root_id: NodeId = NodeId::from_u32(0);
for i in 0 .. self.determined_imports.len() {
let import = self.determined_imports[i];
let error = self.finalize_import(import);

View File

@ -217,8 +217,9 @@ fn program_clauses_for_trait<'a, 'tcx>(
let implemented_from_env = Clause::ForAll(ty::Binder::bind(implemented_from_env));
let where_clauses = &tcx.predicates_defined_on(def_id).predicates
.into_iter()
let predicates = &tcx.predicates_defined_on(def_id).predicates;
let where_clauses = &predicates
.iter()
.map(|(wc, _)| wc.lower())
.map(|wc| wc.subst(tcx, bound_vars))
.collect::<Vec<_>>();
@ -314,8 +315,9 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId
let trait_pred = ty::TraitPredicate { trait_ref }.lower();
// `WC`
let where_clauses = tcx.predicates_of(def_id).predicates
.into_iter()
let predicates = &tcx.predicates_of(def_id).predicates;
let where_clauses = predicates
.iter()
.map(|(wc, _)| wc.lower())
.map(|wc| wc.subst(tcx, bound_vars));
@ -352,7 +354,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>(
// `WC`
let where_clauses = tcx.predicates_of(def_id).predicates
.into_iter()
.iter()
.map(|(wc, _)| wc.lower())
.map(|wc| wc.subst(tcx, bound_vars))
.collect::<Vec<_>>();

View File

@ -24,6 +24,7 @@ use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
use rustc::ty::{GenericParamDef, GenericParamDefKind};
use rustc::ty::wf::object_region_bounds;
use rustc_data_structures::sync::Lrc;
use rustc_target::spec::abi;
use std::collections::BTreeSet;
use std::slice;
@ -45,7 +46,7 @@ pub trait AstConv<'gcx, 'tcx> {
/// Returns the set of bounds in scope for the type parameter with
/// the given id.
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-> ty::GenericPredicates<'tcx>;
-> Lrc<ty::GenericPredicates<'tcx>>;
/// What lifetime should we use when a lifetime is omitted (and not elided)?
fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>)
@ -1119,8 +1120,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
{
let tcx = self.tcx();
let bounds = self.get_type_parameter_bounds(span, ty_param_def_id)
.predicates.into_iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref());
let predicates = &self.get_type_parameter_bounds(span, ty_param_def_id).predicates;
let bounds = predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref());
// Check that there is exactly one way to find an associated type with the
// correct name.

View File

@ -134,6 +134,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
"rustc_peek" => (1, vec![param(0)], param(0)),
"init" => (1, Vec::new(), param(0)),
"uninit" => (1, Vec::new(), param(0)),
"forget" => (1, vec![param(0)], tcx.mk_unit()),
"transmute" => (2, vec![ param(0) ], param(1)),
"move_val_init" => {
(1,

View File

@ -1440,7 +1440,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
///
/// 1. Because the numbers of the region variables would otherwise be fairly unique to this
/// particular method call, it winds up creating fewer types overall, which helps for memory
/// usage. (Admittedly, this is a rather small effect, though measureable.)
/// usage. (Admittedly, this is a rather small effect, though measurable.)
///
/// 2. It makes it easier to deal with higher-ranked trait bounds, because we can replace any
/// late-bound regions with 'static. Otherwise, if we were going to replace late-bound

View File

@ -1869,7 +1869,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx }
fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
-> ty::GenericPredicates<'tcx>
-> Lrc<ty::GenericPredicates<'tcx>>
{
let tcx = self.tcx;
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
@ -1877,7 +1877,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
let item_def_id = tcx.hir.local_def_id(item_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
ty::GenericPredicates {
Lrc::new(ty::GenericPredicates {
parent: None,
predicates: self.param_env.caller_bounds.iter().filter_map(|&predicate| {
match predicate {
@ -1890,7 +1890,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
_ => None
}
}).collect()
}
})
}
fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>)

View File

@ -910,8 +910,8 @@ fn check_false_global_bounds<'a, 'gcx, 'tcx>(
let def_id = fcx.tcx.hir.local_def_id(id);
let predicates = fcx.tcx.predicates_of(def_id).predicates
.into_iter()
.map(|(p, _)| p)
.iter()
.map(|(p, _)| *p)
.collect();
// Check elaborated bounds
let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates);

View File

@ -39,6 +39,7 @@ use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
use rustc::ty::{ReprOptions, ToPredicate};
use rustc::util::captures::Captures;
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_target::spec::abi;
use syntax::ast;
@ -178,7 +179,8 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
self.tcx
}
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
-> Lrc<ty::GenericPredicates<'tcx>> {
self.tcx
.at(span)
.type_param_predicates((self.item_def_id, def_id))
@ -243,7 +245,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
fn type_param_predicates<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
(item_def_id, def_id): (DefId, DefId),
) -> ty::GenericPredicates<'tcx> {
) -> Lrc<ty::GenericPredicates<'tcx>> {
use rustc::hir::*;
// In the AST, bounds can derive from two places. Either
@ -264,11 +266,11 @@ fn type_param_predicates<'a, 'tcx>(
tcx.generics_of(item_def_id).parent
};
let mut result = parent.map_or(
ty::GenericPredicates {
let mut result = parent.map_or_else(
|| Lrc::new(ty::GenericPredicates {
parent: None,
predicates: vec![],
},
}),
|parent| {
let icx = ItemCtxt::new(tcx, parent);
icx.get_type_parameter_bounds(DUMMY_SP, def_id)
@ -298,7 +300,7 @@ fn type_param_predicates<'a, 'tcx>(
// Implied `Self: Trait` and supertrait bounds.
if param_id == item_node_id {
let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
result
Lrc::make_mut(&mut result)
.predicates
.push((identity_trait_ref.to_predicate(), item.span));
}
@ -317,7 +319,7 @@ fn type_param_predicates<'a, 'tcx>(
};
let icx = ItemCtxt::new(tcx, item_def_id);
result
Lrc::make_mut(&mut result)
.predicates
.extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty,
OnlySelfBounds(true)));
@ -685,7 +687,7 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad
fn super_predicates_of<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_def_id: DefId,
) -> ty::GenericPredicates<'tcx> {
) -> Lrc<ty::GenericPredicates<'tcx>> {
debug!("super_predicates(trait_def_id={:?})", trait_def_id);
let trait_node_id = tcx.hir.as_local_node_id(trait_def_id).unwrap();
@ -729,10 +731,10 @@ fn super_predicates_of<'a, 'tcx>(
}
}
ty::GenericPredicates {
Lrc::new(ty::GenericPredicates {
parent: None,
predicates: superbounds,
}
})
}
fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::TraitDef {
@ -1605,27 +1607,23 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>(
fn predicates_defined_on<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> ty::GenericPredicates<'tcx> {
let explicit = tcx.explicit_predicates_of(def_id);
let span = tcx.def_span(def_id);
let predicates = explicit.predicates.into_iter().chain(
tcx.inferred_outlives_of(def_id).iter().map(|&p| (p, span))
).collect();
ty::GenericPredicates {
parent: explicit.parent,
predicates: predicates,
) -> Lrc<ty::GenericPredicates<'tcx>> {
let mut result = tcx.explicit_predicates_of(def_id);
let inferred_outlives = tcx.inferred_outlives_of(def_id);
if !inferred_outlives.is_empty() {
let span = tcx.def_span(def_id);
Lrc::make_mut(&mut result)
.predicates
.extend(inferred_outlives.iter().map(|&p| (p, span)));
}
result
}
fn predicates_of<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> ty::GenericPredicates<'tcx> {
let ty::GenericPredicates {
parent,
mut predicates,
} = tcx.predicates_defined_on(def_id);
) -> Lrc<ty::GenericPredicates<'tcx>> {
let mut result = tcx.predicates_defined_on(def_id);
if tcx.is_trait(def_id) {
// For traits, add `Self: Trait` predicate. This is
@ -1641,16 +1639,17 @@ fn predicates_of<'a, 'tcx>(
// used, and adding the predicate into this list ensures
// that this is done.
let span = tcx.def_span(def_id);
predicates.push((ty::TraitRef::identity(tcx, def_id).to_predicate(), span));
Lrc::make_mut(&mut result)
.predicates
.push((ty::TraitRef::identity(tcx, def_id).to_predicate(), span));
}
ty::GenericPredicates { parent, predicates }
result
}
fn explicit_predicates_of<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> ty::GenericPredicates<'tcx> {
) -> Lrc<ty::GenericPredicates<'tcx>> {
use rustc::hir::*;
use rustc_data_structures::fx::FxHashSet;
@ -1761,10 +1760,10 @@ fn explicit_predicates_of<'a, 'tcx>(
if impl_trait_fn.is_some() {
// impl Trait
return ty::GenericPredicates {
return Lrc::new(ty::GenericPredicates {
parent: None,
predicates: bounds.predicates(tcx, opaque_ty),
};
});
} else {
// named existential types
predicates.extend(bounds.predicates(tcx, opaque_ty));
@ -1794,7 +1793,7 @@ fn explicit_predicates_of<'a, 'tcx>(
// on a trait we need to add in the supertrait bounds and bounds found on
// associated types.
if let Some((_trait_ref, _)) = is_trait {
predicates.extend(tcx.super_predicates_of(def_id).predicates);
predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
}
// In default impls, we can assume that the self type implements
@ -1971,10 +1970,10 @@ fn explicit_predicates_of<'a, 'tcx>(
);
}
ty::GenericPredicates {
Lrc::new(ty::GenericPredicates {
parent: generics.parent,
predicates,
}
})
}
pub enum SizedByDefault {

View File

@ -33,14 +33,14 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
) -> &RequiredPredicates<'tcx> {
self.map.entry(def_id).or_insert_with(|| {
let predicates = if def_id.is_local() {
tcx.explicit_predicates_of(def_id).predicates
tcx.explicit_predicates_of(def_id)
} else {
tcx.predicates_of(def_id).predicates
tcx.predicates_of(def_id)
};
let mut required_predicates = RequiredPredicates::default();
// process predicates and convert to `RequiredPredicates` entry, see below
for (pred, _) in predicates.into_iter() {
for (pred, _) in predicates.predicates.iter() {
match pred {
ty::Predicate::TypeOutlives(predicate) => {
let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder();

View File

@ -1563,7 +1563,7 @@ impl Clean<Generics> for hir::Generics {
}
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
&'a ty::GenericPredicates<'tcx>) {
&'a Lrc<ty::GenericPredicates<'tcx>>) {
fn clean(&self, cx: &DocContext) -> Generics {
use self::WherePredicate as WP;

View File

@ -156,8 +156,8 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId,
if child == trait_ {
return true
}
let predicates = cx.tcx.super_predicates_of(child).predicates;
predicates.iter().filter_map(|(pred, _)| {
let predicates = cx.tcx.super_predicates_of(child);
predicates.predicates.iter().filter_map(|(pred, _)| {
if let ty::Predicate::Trait(ref pred) = *pred {
if pred.skip_binder().trait_ref.self_ty().is_self() {
Some(pred.def_id())

View File

@ -187,7 +187,7 @@ pub struct RenderOptions {
/// Whether to generate a table of contents on the output file when reading a standalone
/// Markdown file.
pub markdown_no_toc: bool,
/// Additional CSS files to link in pages generated from standlone Markdown files.
/// Additional CSS files to link in pages generated from standalone Markdown files.
pub markdown_css: Vec<String>,
/// If present, playground URL to use in the "Run" button added to code samples generated from
/// standalone Markdown files. If not present, `playground_url` is used.

View File

@ -961,7 +961,7 @@ span.since {
padding-top: 0px;
}
body > .sidebar {
.rustdoc > .sidebar {
height: 45px;
min-height: 40px;
margin: 0;

View File

@ -243,7 +243,7 @@ fn look_for_tests<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx>(
if tests.found_tests == 0 {
let mut diag = cx.tcx.struct_span_lint_node(
lint::builtin::MISSING_DOC_CODE_EXAMPLES,
NodeId::new(0),
NodeId::from_u32(0),
span_of_attrs(&item.attrs),
"Missing code example in this documentation");
diag.emit();
@ -281,14 +281,14 @@ impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for LinkCollector<'a, 'tcx, 'rcx, 'cstor
let current_item = match item.inner {
ModuleItem(..) => {
if item.attrs.inner_docs {
if item_node_id.unwrap() != NodeId::new(0) {
if item_node_id.unwrap() != NodeId::from_u32(0) {
item.name.clone()
} else {
None
}
} else {
match parent_node.or(self.mod_ids.last().cloned()) {
Some(parent) if parent != NodeId::new(0) => {
Some(parent) if parent != NodeId::from_u32(0) => {
//FIXME: can we pull the parent module's name from elsewhere?
Some(self.cx.tcx.hir.name(parent).to_string())
}
@ -538,13 +538,13 @@ fn resolution_failure(
);
diag = cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
NodeId::new(0),
NodeId::from_u32(0),
sp,
&msg);
diag.span_label(sp, "cannot be resolved, ignoring");
} else {
diag = cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
NodeId::new(0),
NodeId::from_u32(0),
sp,
&msg);
@ -564,7 +564,7 @@ fn resolution_failure(
diag
} else {
cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
NodeId::new(0),
NodeId::from_u32(0),
sp,
&msg)
};

View File

@ -85,7 +85,7 @@ pub use alloc_crate::alloc::*;
/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
/// plus related functions.
///
/// This type implements the `GlobalAlloc` trait and Rust programs by deafult
/// This type implements the `GlobalAlloc` trait and Rust programs by default
/// work as if they had this definition:
///
/// ```rust

View File

@ -41,8 +41,11 @@ fn main() {
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=execinfo");
println!("cargo:rustc-link-lib=pthread");
} else if target.contains("netbsd") {
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=rt");
} else if target.contains("dragonfly") || target.contains("bitrig") ||
target.contains("netbsd") || target.contains("openbsd") {
target.contains("openbsd") {
println!("cargo:rustc-link-lib=pthread");
} else if target.contains("solaris") {
println!("cargo:rustc-link-lib=socket");

View File

@ -1569,7 +1569,7 @@ impl<K, V, S> HashMap<K, V, S>
/// where the key should go, meaning the keys may become "lost" if their
/// location does not reflect their state. For instance, if you change a key
/// so that the map now contains keys which compare equal, search may start
/// acting eratically, with two keys randomly masking eachother. Implementations
/// acting erratically, with two keys randomly masking each other. Implementations
/// are free to assume this doesn't happen (within the limits of memory-safety).
#[unstable(feature = "hash_raw_entry", issue = "54043")]
pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<K, V, S> {

View File

@ -525,6 +525,25 @@ impl<W: Write> BufWriter<W> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() }
/// Returns a reference to the internally buffered data.
///
/// # Examples
///
/// ```no_run
/// # #![feature(bufreader_buffer)]
/// use std::io::BufWriter;
/// use std::net::TcpStream;
///
/// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
/// // See how many bytes are currently buffered
/// let bytes_buffered = buf_writer.buffer().len();
/// ```
#[unstable(feature = "bufreader_buffer", issue = "45323")]
pub fn buffer(&self) -> &[u8] {
&self.buf
}
/// Unwraps this `BufWriter`, returning the underlying writer.
///
/// The buffer is written out before returning the writer.
@ -965,31 +984,31 @@ mod tests {
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(buf, b);
assert_eq!(buf, [5, 6, 7]);
assert_eq!(reader.buffer(), []);
let mut buf = [0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 2);
let b: &[_] = &[0, 1];
assert_eq!(buf, b);
assert_eq!(buf, [0, 1]);
assert_eq!(reader.buffer(), []);
let mut buf = [0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
let b: &[_] = &[2];
assert_eq!(buf, b);
assert_eq!(buf, [2]);
assert_eq!(reader.buffer(), [3]);
let mut buf = [0, 0, 0];
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
let b: &[_] = &[3, 0, 0];
assert_eq!(buf, b);
assert_eq!(buf, [3, 0, 0]);
assert_eq!(reader.buffer(), []);
let nread = reader.read(&mut buf);
assert_eq!(nread.unwrap(), 1);
let b: &[_] = &[4, 0, 0];
assert_eq!(buf, b);
assert_eq!(buf, [4, 0, 0]);
assert_eq!(reader.buffer(), []);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
@ -1078,31 +1097,40 @@ mod tests {
let mut writer = BufWriter::with_capacity(2, inner);
writer.write(&[0, 1]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[2]).unwrap();
assert_eq!(writer.buffer(), [2]);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.write(&[3]).unwrap();
assert_eq!(writer.buffer(), [2, 3]);
assert_eq!(*writer.get_ref(), [0, 1]);
writer.flush().unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[4]).unwrap();
writer.write(&[5]).unwrap();
assert_eq!(writer.buffer(), [4, 5]);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
writer.write(&[6]).unwrap();
assert_eq!(writer.buffer(), [6]);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]);
writer.write(&[7, 8]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]);
writer.write(&[9, 10, 11]).unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
writer.flush().unwrap();
assert_eq!(writer.buffer(), []);
assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
}

View File

@ -615,7 +615,7 @@ mod loop_keyword { }
//
/// The keyword used to define structs.
///
/// Structs in Rust come in three flavours: Structs with named fields, tuple structs, and unit
/// Structs in Rust come in three flavors: Structs with named fields, tuple structs, and unit
/// structs.
///
/// ```rust

View File

@ -852,7 +852,7 @@ impl From<[u8; 4]> for IpAddr {
impl Ipv6Addr {
/// Creates a new IPv6 address from eight 16-bit segments.
///
/// The result will represent the IP address a:b:c:d:e:f:g:h.
/// The result will represent the IP address `a:b:c:d:e:f:g:h`.
///
/// # Examples
///

View File

@ -1122,7 +1122,7 @@ impl From<fs::File> for Stdio {
/// let file = File::open("foo.txt").unwrap();
///
/// let reverse = Command::new("rev")
/// .stdin(file) // Implicit File convertion into a Stdio
/// .stdin(file) // Implicit File conversion into a Stdio
/// .output()
/// .expect("failed reverse command");
///
@ -1340,7 +1340,7 @@ impl Child {
/// Attempts to collect the exit status of the child if it has already
/// exited.
///
/// This function will not block the calling thread and will only advisorily
/// This function will not block the calling thread and will only
/// check to see if the child process has exited or not. If the child has
/// exited then on Unix the process id is reaped. This function is
/// guaranteed to repeatedly return a successful exit status so long as the

View File

@ -26,7 +26,7 @@ impl FileDesc {
pub fn raw(&self) -> usize { self.fd }
/// Extracts the actual filedescriptor without closing it.
/// Extracts the actual file descriptor without closing it.
pub fn into_raw(self) -> usize {
let fd = self.fd;
mem::forget(self);

View File

@ -77,6 +77,29 @@ pub fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}
macro_rules! impl_is_minus_one {
($($t:ident)*) => ($(impl IsMinusOne for $t {
fn is_minus_one(&self) -> bool {
*self == -1
}
})*)
}
impl_is_minus_one! { i8 i16 i32 i64 isize }
pub fn cvt_libc<T: IsMinusOne>(t: T) -> io::Result<T> {
if t.is_minus_one() {
Err(io::Error::last_os_error())
} else {
Ok(t)
}
}
/// On Redox, use an illegal instruction to abort
pub unsafe fn abort_internal() -> ! {
::core::intrinsics::abort();

View File

@ -12,10 +12,12 @@
#![allow(unused_imports)] // lots of cfg code here
use libc::{self, c_char};
use os::unix::prelude::*;
use error::Error as StdError;
use ffi::{OsString, OsStr};
use ffi::{CStr, CString, OsStr, OsString};
use fmt;
use io::{self, Read, Write};
use iter;
@ -27,7 +29,7 @@ use ptr;
use slice;
use str;
use sys_common::mutex::Mutex;
use sys::{cvt, fd, syscall};
use sys::{cvt, cvt_libc, fd, syscall};
use vec;
extern {
@ -129,6 +131,8 @@ pub fn current_exe() -> io::Result<PathBuf> {
Ok(PathBuf::from(path))
}
pub static ENV_LOCK: Mutex = Mutex::new();
pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
_dont_send_or_sync_me: PhantomData<*mut ()>,
@ -140,52 +144,83 @@ impl Iterator for Env {
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}
pub unsafe fn environ() -> *mut *const *const c_char {
extern { static mut environ: *const *const c_char; }
&mut environ
}
/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
let mut variables: Vec<(OsString, OsString)> = Vec::new();
if let Ok(mut file) = ::fs::File::open("env:") {
let mut string = String::new();
if file.read_to_string(&mut string).is_ok() {
for line in string.lines() {
let mut parts = line.splitn(2, '=');
if let Some(name) = parts.next() {
let value = parts.next().unwrap_or("");
variables.push((OsString::from(name.to_string()),
OsString::from(value.to_string())));
}
unsafe {
let _guard = ENV_LOCK.lock();
let mut environ = *environ();
if environ == ptr::null() {
panic!("os::env() failure getting env string from OS: {}",
io::Error::last_os_error());
}
let mut result = Vec::new();
while *environ != ptr::null() {
if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
result.push(key_value);
}
environ = environ.offset(1);
}
return Env {
iter: result.into_iter(),
_dont_send_or_sync_me: PhantomData,
}
}
Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData }
fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
// Strategy (copied from glibc): Variable name and value are separated
// by an ASCII equals sign '='. Since a variable name must not be
// empty, allow variable names starting with an equals sign. Skip all
// malformed lines.
if input.is_empty() {
return None;
}
let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
pos.map(|p| (
OsStringExt::from_vec(input[..p].to_vec()),
OsStringExt::from_vec(input[p+1..].to_vec()),
))
}
}
pub fn getenv(key: &OsStr) -> io::Result<Option<OsString>> {
if ! key.is_empty() {
if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) {
let mut string = String::new();
file.read_to_string(&mut string)?;
Ok(Some(OsString::from(string)))
pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
// environment variables with a nul byte can't be set, so their value is
// always None as well
let k = CString::new(k.as_bytes())?;
unsafe {
let _guard = ENV_LOCK.lock();
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
let ret = if s.is_null() {
None
} else {
Ok(None)
}
} else {
Ok(None)
Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
};
Ok(ret)
}
}
pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> {
if ! key.is_empty() {
let mut file = ::fs::File::create(&("env:".to_owned() + key.to_str().unwrap()))?;
file.write_all(value.as_bytes())?;
file.set_len(value.len() as u64)?;
pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
let k = CString::new(k.as_bytes())?;
let v = CString::new(v.as_bytes())?;
unsafe {
let _guard = ENV_LOCK.lock();
cvt_libc(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
}
Ok(())
}
pub fn unsetenv(key: &OsStr) -> io::Result<()> {
::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?;
Ok(())
pub fn unsetenv(n: &OsStr) -> io::Result<()> {
let nbuf = CString::new(n.as_bytes())?;
unsafe {
let _guard = ENV_LOCK.lock();
cvt_libc(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
}
}
pub fn page_size() -> usize {

View File

@ -9,15 +9,19 @@
// except according to those terms.
use env::{split_paths};
use ffi::OsStr;
use os::unix::ffi::OsStrExt;
use ffi::{CStr, OsStr};
use fmt;
use io::{self, Error, ErrorKind};
use iter;
use fs::File;
use io::{self, prelude::*, BufReader, Error, ErrorKind, SeekFrom};
use libc::{EXIT_SUCCESS, EXIT_FAILURE};
use os::unix::ffi::OsStrExt;
use path::{Path, PathBuf};
use ptr;
use sys::ext::fs::MetadataExt;
use sys::ext::io::AsRawFd;
use sys::fd::FileDesc;
use sys::fs::{File, OpenOptions};
use sys::fs::{File as SysFile, OpenOptions};
use sys::os::{ENV_LOCK, environ};
use sys::pipe::{self, AnonPipe};
use sys::{cvt, syscall};
use sys_common::process::{CommandEnv, DefaultEnvKey};
@ -297,12 +301,6 @@ impl Command {
t!(callback());
}
let args: Vec<[usize; 2]> = iter::once(
[self.program.as_ptr() as usize, self.program.len()]
).chain(
self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()])
).collect();
self.env.apply();
let program = if self.program.contains(':') || self.program.contains('/') {
@ -321,14 +319,93 @@ impl Command {
None
};
if let Some(program) = program {
if let Err(err) = syscall::execve(program.as_os_str().as_bytes(), &args) {
io::Error::from_raw_os_error(err.errno as i32)
} else {
panic!("return from exec without err");
}
let mut file = if let Some(program) = program {
t!(File::open(program.as_os_str()))
} else {
io::Error::from_raw_os_error(syscall::ENOENT)
return io::Error::from_raw_os_error(syscall::ENOENT);
};
// Push all the arguments
let mut args: Vec<[usize; 2]> = Vec::with_capacity(1 + self.args.len());
let interpreter = {
let mut reader = BufReader::new(&file);
let mut shebang = [0; 2];
let mut read = 0;
loop {
match t!(reader.read(&mut shebang[read..])) {
0 => break,
n => read += n,
}
}
if &shebang == b"#!" {
// This is an interpreted script.
// First of all, since we'll be passing another file to
// fexec(), we need to manually check that we have permission
// to execute this file:
let uid = t!(cvt(syscall::getuid()));
let gid = t!(cvt(syscall::getgid()));
let meta = t!(file.metadata());
let mode = if uid == meta.uid() as usize {
meta.mode() >> 3*2 & 0o7
} else if gid == meta.gid() as usize {
meta.mode() >> 3*1 & 0o7
} else {
meta.mode() & 0o7
};
if mode & 1 == 0 {
return io::Error::from_raw_os_error(syscall::EPERM);
}
// Second of all, we need to actually read which interpreter it wants
let mut interpreter = Vec::new();
t!(reader.read_until(b'\n', &mut interpreter));
// Pop one trailing newline, if any
if interpreter.ends_with(&[b'\n']) {
interpreter.pop().unwrap();
}
// FIXME: Here we could just reassign `file` directly, if it
// wasn't for lexical lifetimes. Remove the whole `let
// interpreter = { ... };` hack once NLL lands.
// NOTE: Although DO REMEMBER to make sure the interpreter path
// still lives long enough to reach fexec.
Some(interpreter)
} else {
None
}
};
if let Some(ref interpreter) = interpreter {
let path: &OsStr = OsStr::from_bytes(&interpreter);
file = t!(File::open(path));
args.push([interpreter.as_ptr() as usize, interpreter.len()]);
} else {
t!(file.seek(SeekFrom::Start(0)));
}
args.push([self.program.as_ptr() as usize, self.program.len()]);
args.extend(self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()]));
// Push all the variables
let mut vars: Vec<[usize; 2]> = Vec::new();
{
let _guard = ENV_LOCK.lock();
let mut environ = *environ();
while *environ != ptr::null() {
let var = CStr::from_ptr(*environ).to_bytes();
vars.push([var.as_ptr() as usize, var.len()]);
environ = environ.offset(1);
}
}
if let Err(err) = syscall::fexec(file.as_raw_fd(), &args, &vars) {
io::Error::from_raw_os_error(err.errno as i32)
} else {
panic!("return from exec without err");
}
}
@ -392,7 +469,7 @@ impl Stdio {
let mut opts = OpenOptions::new();
opts.read(readable);
opts.write(!readable);
let fd = File::open(Path::new("null:"), &opts)?;
let fd = SysFile::open(Path::new("null:"), &opts)?;
Ok((ChildStdio::Owned(fd.into_fd()), None))
}
}
@ -405,8 +482,8 @@ impl From<AnonPipe> for Stdio {
}
}
impl From<File> for Stdio {
fn from(file: File) -> Stdio {
impl From<SysFile> for Stdio {
fn from(file: SysFile) -> Stdio {
Stdio::Fd(file.into_fd())
}
}

View File

@ -45,7 +45,7 @@ pub unsafe fn brk(addr: usize) -> Result<usize> {
/// # Errors
///
/// * `EACCES` - permission is denied for one of the components of `path`, or `path`
/// * `EFAULT` - `path` does not point to the process's addressible memory
/// * `EFAULT` - `path` does not point to the process's addressable memory
/// * `EIO` - an I/O error occurred
/// * `ENOENT` - `path` does not exit
/// * `ENOTDIR` - `path` is not a directory
@ -82,12 +82,6 @@ pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> {
unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) }
}
/// Replace the current process with a new executable
pub fn execve<T: AsRef<[u8]>>(path: T, args: &[[usize; 2]]) -> Result<usize> {
unsafe { syscall4(SYS_EXECVE, path.as_ref().as_ptr() as usize,
path.as_ref().len(), args.as_ptr() as usize, args.len()) }
}
/// Exit the current process
pub fn exit(status: usize) -> Result<usize> {
unsafe { syscall1(SYS_EXIT, status) }
@ -110,9 +104,10 @@ pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) }
}
/// Register a file for event-based I/O
pub fn fevent(fd: usize, flags: usize) -> Result<usize> {
unsafe { syscall2(SYS_FEVENT, fd, flags) }
/// Replace the current process with a new executable
pub fn fexec(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result<usize> {
unsafe { syscall5(SYS_FEXEC, fd, args.as_ptr() as usize, args.len(),
vars.as_ptr() as usize, vars.len()) }
}
/// Map a file into memory
@ -347,7 +342,7 @@ pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result<usize>
///
/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block
/// * `EBADF` - the file descriptor is not valid or is not open for writing
/// * `EFAULT` - `buf` does not point to the process's addressible memory
/// * `EFAULT` - `buf` does not point to the process's addressable memory
/// * `EIO` - an I/O error occurred
/// * `ENOSPC` - the device containing the file descriptor has no room for data
/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed

View File

@ -113,4 +113,46 @@ pub const SA_RESTART: usize = 0x10000000;
pub const SA_NODEFER: usize = 0x40000000;
pub const SA_RESETHAND: usize = 0x80000000;
pub const WNOHANG: usize = 1;
pub const WNOHANG: usize = 0x01;
pub const WUNTRACED: usize = 0x02;
pub const WCONTINUED: usize = 0x08;
/// True if status indicates the child is stopped.
pub fn wifstopped(status: usize) -> bool {
(status & 0xff) == 0x7f
}
/// If wifstopped(status), the signal that stopped the child.
pub fn wstopsig(status: usize) -> usize {
(status >> 8) & 0xff
}
/// True if status indicates the child continued after a stop.
pub fn wifcontinued(status: usize) -> bool {
status == 0xffff
}
/// True if STATUS indicates termination by a signal.
pub fn wifsignaled(status: usize) -> bool {
((status & 0x7f) + 1) as i8 >= 2
}
/// If wifsignaled(status), the terminating signal.
pub fn wtermsig(status: usize) -> usize {
status & 0x7f
}
/// True if status indicates normal termination.
pub fn wifexited(status: usize) -> bool {
wtermsig(status) == 0
}
/// If wifexited(status), the exit status.
pub fn wexitstatus(status: usize) -> usize {
(status >> 8) & 0xff
}
/// True if status indicates a core dump was created.
pub fn wcoredump(status: usize) -> bool {
(status & 0x80) != 0
}

Some files were not shown because too many files have changed in this diff Show More