This is a work in progress PR that potentially should fix #29084, #28308, #25385, #28288, #31011. I think this may also adresse parts of #2887.
The problem in this issues seems to be that when transcribing macro arguments, we just clone the argument Nonterminal, which still has to original spans. This leads to the unprintable spans. One solution would be to update the spans of the inserted argument to match the argument in the macro definition. So for [this testcase](https://github.com/rust-lang/rust/compare/master...fhahn:macro-ice?expand=1#diff-f7def7420c51621640707b6337726876R2) the error message would be displayed in the macro definition:
src/test/compile-fail/issue-31011.rs:4:12: 4:22 error: attempted access of field `trace` on type `&T`, but no field with that name was found
src/test/compile-fail/issue-31011.rs:4 if $ctx.trace {
Currently I've added a very simple `update_span` function, which updates the span of the outer-most expression of a `NtExpr`, but this `update_span` function should be updated to handle all Nonterminals. But I'm pretty new to the macro system and would like to check if this approach makes sense, before doing that.
export CFG_DEFAULT_LINKER
export CFG_DEFAULT_AR
-# The standard libraries should be held up to a higher standard than any old
-# code, make sure that these common warnings are denied by default. These can
-# be overridden during development temporarily. For stage0, we allow warnings
-# which may be bugs in stage0 (should be fixed in stage1+)
-RUST_LIB_FLAGS_ST0 += -W warnings
-RUST_LIB_FLAGS_ST1 += -D warnings
-RUST_LIB_FLAGS_ST2 += -D warnings
-
# Macro that generates the full list of dependencies for a crate at a particular
# stage/target/host tuple.
#
We're not going to spend a lot of time on setting up a project with
Cargo because it is already covered well in [the Cargo
-section](../book/hello-cargo.html) and [Cargo's documentation][14].
+section](getting-started.html#hello-cargo) and [Cargo's documentation][14].
To get started from scratch, run `cargo new --bin city-pop` and make sure your
`Cargo.toml` looks something like this:
repair, or remove installation" page and ensure "Add to PATH" is installed on
the local hard drive.
+Rust does not do its own linking, and so you’ll need to have a linker
+installed. Doing so will depend on your specific system, consult its
+documentation for more details.
+
If not, there are a number of places where we can get help. The easiest is
[the #rust IRC channel on irc.mozilla.org][irc], which we can access through
[Mibbit][mibbit]. Click that link, and we'll be chatting with other Rustaceans
this book, and the rest of your time with Rust. Now that you’ve got the tools
down, we'll cover more about the Rust language itself.
-You have two options: Dive into a project with ‘[Learn Rust][learnrust]’, or
+You have two options: Dive into a project with ‘[Tutorial: Guessing Game][guessinggame]’, or
start from the bottom and work your way up with ‘[Syntax and
Semantics][syntax]’. More experienced systems programmers will probably prefer
-‘Learn Rust’, while those from dynamic backgrounds may enjoy either. Different
+‘Tutorial: Guessing Game’, while those from dynamic backgrounds may enjoy either. Different
people learn differently! Choose whatever’s right for you.
-[learnrust]: learn-rust.html
+[guessinggame]: guessing-game.html
[syntax]: syntax-and-semantics.html
+++ /dev/null
-% Learn Rust
-
-Welcome! This chapter has a few tutorials that teach you Rust through building
-projects. You’ll get a high-level overview, but we’ll skim over the details.
-
-If you’d prefer a more ‘from the ground up’-style experience, check
-out [Syntax and Semantics][ss].
-
-[ss]: syntax-and-semantics.html
You may also encounter situations where you have nested loops and need to
specify which one your `break` or `continue` statement is for. Like most
other languages, by default a `break` or `continue` will apply to innermost
-loop. In a situation where you would like to a `break` or `continue` for one
+loop. In a situation where you would like to `break` or `continue` for one
of the outer loops, you can use labels to specify which loop the `break` or
`continue` statement applies to. This will only print when both `x` and `y` are
odd:
use core::result::Result::{Ok, Err};
use core::clone::Clone;
-use std::boxed;
use std::boxed::Box;
#[test]
test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
#![no_std]
#![needs_allocator]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(allocator)]
#![feature(box_syntax)]
#![feature(coerce_unsized)]
+#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(custom_attribute)]
+#![feature(drop_in_place)]
+#![feature(dropck_parametricity)]
#![feature(fundamental)]
#![feature(lang_items)]
+#![feature(needs_allocator)]
#![feature(optin_builtin_traits)]
#![feature(placement_in_syntax)]
-#![feature(placement_new_protocol)]
-#![feature(raw)]
#![feature(shared)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(unique)]
#![feature(unsafe_no_drop_flag, filling_drop)]
-#![feature(dropck_parametricity)]
#![feature(unsize)]
-#![feature(drop_in_place)]
-#![feature(fn_traits)]
-#![feature(const_fn)]
-
-#![feature(needs_allocator)]
// Issue# 30592: Systematically use alloc_system during stage0 since jemalloc
// might be unavailable or disabled
#![cfg_attr(stage0, feature(alloc_system))]
+#![cfg_attr(not(test), feature(raw, fn_traits, placement_new_protocol))]
#![cfg_attr(test, feature(test, rustc_private, box_heap))]
#[cfg(stage0)]
reason = "this library is unlikely to be stabilized in its current \
form or name",
issue = "27783")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(allocator)]
#![feature(libc)]
#![feature(staged_api)]
#![crate_type = "rlib"]
#![no_std]
#![allocator]
+#![cfg_attr(not(stage0), deny(warnings))]
#![unstable(feature = "alloc_system",
reason = "this library is unlikely to be stabilized in its current \
form or name",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/",
test(no_crate_inject, attr(deny(warnings))))]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(alloc)]
#![feature(core_intrinsics)]
#![allow(trivial_casts)]
#![cfg_attr(test, allow(deprecated))] // rand
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(alloc)]
#![feature(box_patterns)]
#![feature(unicode)]
#![feature(unique)]
#![feature(unsafe_no_drop_flag)]
-#![cfg_attr(test, feature(clone_from_slice, rand, test))]
+#![cfg_attr(test, feature(rand, test))]
#![no_std]
// Many of the usings in this module are only used in the test configuration.
// It's cleaner to just turn off the unused_imports warning than to fix them.
-#![allow(unused_imports)]
+#![cfg_attr(test, allow(unused_imports, dead_code))]
use alloc::boxed::Box;
-use core::clone::Clone;
use core::cmp::Ordering::{self, Greater, Less};
-use core::cmp::{self, Ord, PartialEq};
-use core::iter::Iterator;
-use core::marker::Sized;
+use core::cmp;
use core::mem::size_of;
use core::mem;
-use core::ops::FnMut;
-use core::option::Option::{self, Some, None};
use core::ptr;
-use core::result::Result;
use core::slice as core_slice;
use borrow::{Borrow, BorrowMut, ToOwned};
// `test_permutations` test
mod hack {
use alloc::boxed::Box;
- use core::clone::Clone;
- #[cfg(test)]
- use core::iter::Iterator;
use core::mem;
- #[cfg(test)]
- use core::option::Option::{Some, None};
#[cfg(test)]
use string::ToString;
// It's cleaner to just turn off the unused_imports warning than to fix them.
#![allow(unused_imports)]
-use core::clone::Clone;
-use core::iter::{Iterator, Extend};
-use core::option::Option::{self, Some, None};
-use core::result::Result;
use core::str as core_str;
use core::str::pattern::Pattern;
use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
// except according to those terms.
use std::cmp::Ordering::{Equal, Greater, Less};
-use std::default::Default;
use std::mem;
use std::__rand::{Rng, thread_rng};
use std::rc::Rc;
///
/// let c = RefCell::new(5);
///
- /// let borrowed_five = c.borrow_mut();
+ /// *c.borrow_mut() = 7;
+ ///
+ /// assert_eq!(*c.borrow(), 7);
/// ```
///
/// An example of panic:
use prelude::v1::*;
+use marker;
use mem;
#[stable(feature = "rust1", since = "1.0.0")]
}
}
+/// A `BuildHasher` is typically used as a factory for instances of `Hasher`
+/// which a `HashMap` can then use to hash keys independently.
+///
+/// Note that for each instance of `BuildHasher` the create hashers should be
+/// identical. That is if the same stream of bytes is fed into each hasher the
+/// same output will also be generated.
+#[stable(since = "1.7.0", feature = "build_hasher")]
+pub trait BuildHasher {
+ /// Type of the hasher that will be created.
+ #[stable(since = "1.7.0", feature = "build_hasher")]
+ type Hasher: Hasher;
+
+ /// Creates a new hasher.
+ #[stable(since = "1.7.0", feature = "build_hasher")]
+ fn build_hasher(&self) -> Self::Hasher;
+}
+
+/// A structure which implements `BuildHasher` for all `Hasher` types which also
+/// implement `Default`.
+///
+/// This struct is 0-sized and does not need construction.
+#[stable(since = "1.7.0", feature = "build_hasher")]
+pub struct BuildHasherDefault<H>(marker::PhantomData<H>);
+
+#[stable(since = "1.7.0", feature = "build_hasher")]
+impl<H: Default + Hasher> BuildHasher for BuildHasherDefault<H> {
+ type Hasher = H;
+
+ fn build_hasher(&self) -> H {
+ H::default()
+ }
+}
+
+#[stable(since = "1.7.0", feature = "build_hasher")]
+impl<H> Clone for BuildHasherDefault<H> {
+ fn clone(&self) -> BuildHasherDefault<H> {
+ BuildHasherDefault(marker::PhantomData)
+ }
+}
+
+#[stable(since = "1.7.0", feature = "build_hasher")]
+impl<H> Default for BuildHasherDefault<H> {
+ fn default() -> BuildHasherDefault<H> {
+ BuildHasherDefault(marker::PhantomData)
+ }
+}
+
+// The HashState trait is super deprecated, but it's here to have the blanket
+// impl that goes from HashState -> BuildHasher
+
+/// Deprecated, renamed to `BuildHasher`
+#[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear",
+ issue = "27713")]
+#[rustc_deprecated(since = "1.7.0", reason = "support moved to std::hash and \
+ renamed to BuildHasher")]
+pub trait HashState {
+ /// Type of the hasher that will be created.
+ type Hasher: Hasher;
+
+ /// Creates a new hasher based on the given state of this object.
+ fn hasher(&self) -> Self::Hasher;
+}
+
+#[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear",
+ issue = "27713")]
+#[allow(deprecated)]
+impl<T: HashState> BuildHasher for T {
+ type Hasher = T::Hasher;
+ fn build_hasher(&self) -> T::Hasher { self.hasher() }
+}
+
//////////////////////////////////////////////////////////////////////////////
mod impls {
/// It is important to note that both back and forth work on the same range,
/// and do not cross: iteration is over when they meet in the middle.
///
+/// In a similar fashion to the [`Iterator`] protocol, once a
+/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again
+/// may or may not ever return `Some` again. `next()` and `next_back()` are
+/// interchangable for this purpose.
+///
/// [`Iterator`]: trait.Iterator.html
+///
/// # Examples
///
/// Basic usage:
///
/// # Examples
///
- /// ```ignore
- /// for i in (0u8..).step_by(2) {
+ /// ```
+ /// # #![feature(step_by)]
+ ///
+ /// for i in (0u8..).step_by(2).take(10) {
/// println!("{}", i);
/// }
/// ```
///
- /// This prints all even `u8` values.
+ /// This prints the first ten even natural integers (0 to 18).
#[unstable(feature = "step_by", reason = "recent addition",
issue = "27741")]
pub fn step_by(self, by: A) -> StepBy<A, Self> {
#![no_core]
#![deny(missing_docs)]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(allow_internal_unstable)]
#![feature(associated_type_defaults)]
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/",
test(attr(deny(warnings))))]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(libc)]
#![feature(staged_api)]
html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
test(attr(deny(warnings))))]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(staged_api)]
#![feature(unicode)]
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/",
test(attr(allow(unused_variables), deny(warnings))))]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(str_escape)]
html_playground_url = "https://play.rust-lang.org/",
test(attr(deny(warnings))))]
#![deny(missing_docs)]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(box_syntax)]
#![feature(const_fn)]
html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
test(attr(deny(warnings))))]
+#![cfg_attr(not(stage0), deny(warnings))]
#![no_std]
#![unstable(feature = "rand",
reason = "use `rand` from crates.io",
#![feature(custom_attribute)]
#![allow(unused_attributes)]
-#![cfg_attr(test, feature(test, rand, rustc_private, iter_order_deprecated))]
+#![cfg_attr(test, feature(test, rand, rustc_private))]
#![allow(deprecated)]
html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
test(attr(deny(warnings))))]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(rustc_private)]
#![feature(staged_api)]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
- html_root_url = "https://doc.rust-lang.org/nightly/")]
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+ html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(enumset)]
-#![feature(hashmap_hasher)]
#![feature(iter_arith)]
#![feature(libc)]
#![feature(nonzero)]
pub mod free_region;
pub mod intrinsicck;
pub mod infer;
- pub mod implicator;
pub mod lang_items;
pub mod liveness;
pub mod mem_categorization;
}
fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
- debug!("early context: exit_attrs({:?})", attrs);
+ debug!("early context: enter_attrs({:?})", attrs);
run_lints!(self, enter_lint_attrs, early_passes, attrs);
}
}
fn visit_expr(&mut self, e: &ast::Expr) {
- run_lints!(self, check_expr, early_passes, e);
- ast_visit::walk_expr(self, e);
+ self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| {
+ run_lints!(cx, check_expr, early_passes, e);
+ ast_visit::walk_expr(cx, e);
+ })
}
fn visit_stmt(&mut self, s: &ast::Stmt) {
}
fn visit_local(&mut self, l: &ast::Local) {
- run_lints!(self, check_local, early_passes, l);
- ast_visit::walk_local(self, l);
+ self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| {
+ run_lints!(cx, check_local, early_passes, l);
+ ast_visit::walk_local(cx, l);
+ })
}
fn visit_block(&mut self, b: &ast::Block) {
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir::MatchSource) {
match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) {
UsefulWithWitness(pats) => {
- let witness = match &pats[..] {
- [ref witness] => &**witness,
- [] => DUMMY_WILD_PAT,
- _ => unreachable!()
+ let witnesses = if pats.is_empty() {
+ vec![DUMMY_WILD_PAT]
+ } else {
+ pats.iter().map(|w| &**w ).collect()
};
match source {
hir::MatchSource::ForLoopDesugar => {
- // `witness` has the form `Some(<head>)`, peel off the `Some`
- let witness = match witness.node {
+ // `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
+ let witness = match witnesses[0].node {
hir::PatEnum(_, Some(ref pats)) => match &pats[..] {
[ref pat] => &**pat,
_ => unreachable!(),
},
_ => unreachable!(),
};
-
span_err!(cx.tcx.sess, sp, E0297,
"refutable pattern in `for` loop binding: \
`{}` not covered",
pat_to_string(witness));
},
_ => {
+ let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
+ pat_to_string(w)
+ }).collect();
+ const LIMIT: usize = 3;
+ let joined_patterns = match pattern_strings.len() {
+ 0 => unreachable!(),
+ 1 => format!("`{}`", pattern_strings[0]),
+ 2...LIMIT => {
+ let (tail, head) = pattern_strings.split_last().unwrap();
+ format!("`{}`", head.join("`, `") + "` and `" + tail)
+ },
+ _ => {
+ let (head, tail) = pattern_strings.split_at(LIMIT);
+ format!("`{}` and {} more", head.join("`, `"), tail.len())
+ }
+ };
span_err!(cx.tcx.sess, sp, E0004,
- "non-exhaustive patterns: `{}` not covered",
- pat_to_string(witness)
+ "non-exhaustive patterns: {} not covered",
+ joined_patterns
);
},
}
}
}
-fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
- left_ty: Ty, max_slice_length: usize) -> Option<Constructor> {
+fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
+ left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
let used_constructors: Vec<Constructor> = rows.iter()
.flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length))
.collect();
all_constructors(cx, left_ty, max_slice_length)
.into_iter()
- .find(|c| !used_constructors.contains(c))
+ .filter(|c| !used_constructors.contains(c))
+ .collect()
}
/// This determines the set of all possible constructors of a pattern matching
let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
if constructors.is_empty() {
- match missing_constructor(cx, matrix, left_ty, max_slice_length) {
- None => {
- all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| {
- match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
- UsefulWithWitness(pats) => UsefulWithWitness({
- let arity = constructor_arity(cx, &c, left_ty);
- let mut result = {
- let pat_slice = &pats[..];
- let subpats: Vec<_> = (0..arity).map(|i| {
- pat_slice.get(i).map_or(DUMMY_WILD_PAT, |p| &**p)
- }).collect();
- vec![construct_witness(cx, &c, subpats, left_ty)]
- };
- result.extend(pats.into_iter().skip(arity));
- result
- }),
- result => result
- }
- }).find(|result| result != &NotUseful).unwrap_or(NotUseful)
- },
-
- Some(constructor) => {
- let matrix = rows.iter().filter_map(|r| {
- if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), raw_pat(r[0])) {
- Some(r[1..].to_vec())
- } else {
- None
- }
- }).collect();
- match is_useful(cx, &matrix, &v[1..], witness) {
- UsefulWithWitness(pats) => {
- let arity = constructor_arity(cx, &constructor, left_ty);
- let wild_pats = vec![DUMMY_WILD_PAT; arity];
- let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
- let mut new_pats = vec![enum_pat];
- new_pats.extend(pats);
- UsefulWithWitness(new_pats)
- },
+ let constructors = missing_constructors(cx, matrix, left_ty, max_slice_length);
+ if constructors.is_empty() {
+ all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| {
+ match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
+ UsefulWithWitness(pats) => UsefulWithWitness({
+ let arity = constructor_arity(cx, &c, left_ty);
+ let mut result = {
+ let pat_slice = &pats[..];
+ let subpats: Vec<_> = (0..arity).map(|i| {
+ pat_slice.get(i).map_or(DUMMY_WILD_PAT, |p| &**p)
+ }).collect();
+ vec![construct_witness(cx, &c, subpats, left_ty)]
+ };
+ result.extend(pats.into_iter().skip(arity));
+ result
+ }),
result => result
}
+ }).find(|result| result != &NotUseful).unwrap_or(NotUseful)
+ } else {
+ let matrix = rows.iter().filter_map(|r| {
+ if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), raw_pat(r[0])) {
+ Some(r[1..].to_vec())
+ } else {
+ None
+ }
+ }).collect();
+ match is_useful(cx, &matrix, &v[1..], witness) {
+ UsefulWithWitness(pats) => {
+ let mut new_pats: Vec<_> = constructors.into_iter().map(|constructor| {
+ let arity = constructor_arity(cx, &constructor, left_ty);
+ let wild_pats = vec![DUMMY_WILD_PAT; arity];
+ construct_witness(cx, &constructor, wild_pats, left_ty)
+ }).collect();
+ new_pats.extend(pats);
+ UsefulWithWitness(new_pats)
+ },
+ result => result
}
}
} else {
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// #![warn(deprecated_mode)]
-
-use middle::def_id::DefId;
-use middle::infer::{InferCtxt, GenericKind};
-use middle::subst::Substs;
-use middle::traits;
-use middle::ty::{self, ToPredicate, Ty};
-use middle::ty::fold::{TypeFoldable, TypeFolder};
-
-use syntax::ast;
-use syntax::codemap::Span;
-
-use util::common::ErrorReported;
-use util::nodemap::FnvHashSet;
-
-// Helper functions related to manipulating region types.
-
-#[derive(Debug)]
-pub enum Implication<'tcx> {
- RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
- RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
- Predicate(DefId, ty::Predicate<'tcx>),
-}
-
-struct Implicator<'a, 'tcx: 'a> {
- infcx: &'a InferCtxt<'a,'tcx>,
- body_id: ast::NodeId,
- stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
- span: Span,
- out: Vec<Implication<'tcx>>,
- visited: FnvHashSet<Ty<'tcx>>,
-}
-
-/// This routine computes the well-formedness constraints that must hold for the type `ty` to
-/// appear in a context with lifetime `outer_region`
-pub fn implications<'a,'tcx>(
- infcx: &'a InferCtxt<'a,'tcx>,
- body_id: ast::NodeId,
- ty: Ty<'tcx>,
- outer_region: ty::Region,
- span: Span)
- -> Vec<Implication<'tcx>>
-{
- debug!("implications(body_id={}, ty={:?}, outer_region={:?})",
- body_id,
- ty,
- outer_region);
-
- let mut stack = Vec::new();
- stack.push((outer_region, None));
- let mut wf = Implicator { infcx: infcx,
- body_id: body_id,
- span: span,
- stack: stack,
- out: Vec::new(),
- visited: FnvHashSet() };
- wf.accumulate_from_ty(ty);
- debug!("implications: out={:?}", wf.out);
- wf.out
-}
-
-impl<'a, 'tcx> Implicator<'a, 'tcx> {
- fn tcx(&self) -> &'a ty::ctxt<'tcx> {
- self.infcx.tcx
- }
-
- fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
- debug!("accumulate_from_ty(ty={:?})",
- ty);
-
- // When expanding out associated types, we can visit a cyclic
- // set of types. Issue #23003.
- if !self.visited.insert(ty) {
- return;
- }
-
- match ty.sty {
- ty::TyBool |
- ty::TyChar |
- ty::TyInt(..) |
- ty::TyUint(..) |
- ty::TyFloat(..) |
- ty::TyBareFn(..) |
- ty::TyError |
- ty::TyStr => {
- // No borrowed content reachable here.
- }
-
- ty::TyClosure(_, ref substs) => {
- // FIXME(#27086). We do not accumulate from substs, since they
- // don't represent reachable data. This means that, in
- // practice, some of the lifetime parameters might not
- // be in scope when the body runs, so long as there is
- // no reachable data with that lifetime. For better or
- // worse, this is consistent with fn types, however,
- // which can also encapsulate data in this fashion
- // (though it's somewhat harder, and typically
- // requires virtual dispatch).
- //
- // Note that changing this (in a naive way, at least)
- // causes regressions for what appears to be perfectly
- // reasonable code like this:
- //
- // ```
- // fn foo<'a>(p: &Data<'a>) {
- // bar(|q: &mut Parser| q.read_addr())
- // }
- // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
- // }
- // ```
- //
- // Note that `p` (and `'a`) are not used in the
- // closure at all, but to meet the requirement that
- // the closure type `C: 'static` (so it can be coerced
- // to the object type), we get the requirement that
- // `'a: 'static` since `'a` appears in the closure
- // type `C`.
- //
- // A smarter fix might "prune" unused `func_substs` --
- // this would avoid breaking simple examples like
- // this, but would still break others (which might
- // indeed be invalid, depending on your POV). Pruning
- // would be a subtle process, since we have to see
- // what func/type parameters are used and unused,
- // taking into consideration UFCS and so forth.
-
- for &upvar_ty in &substs.upvar_tys {
- self.accumulate_from_ty(upvar_ty);
- }
- }
-
- ty::TyTrait(ref t) => {
- let required_region_bounds =
- object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds);
- self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
- }
-
- ty::TyEnum(def, substs) |
- ty::TyStruct(def, substs) => {
- let item_scheme = def.type_scheme(self.tcx());
- self.accumulate_from_adt(ty, def.did, &item_scheme.generics, substs)
- }
-
- ty::TyArray(t, _) |
- ty::TySlice(t) |
- ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) |
- ty::TyBox(t) => {
- self.accumulate_from_ty(t)
- }
-
- ty::TyRef(r_b, mt) => {
- self.accumulate_from_rptr(ty, *r_b, mt.ty);
- }
-
- ty::TyParam(p) => {
- self.push_param_constraint_from_top(p);
- }
-
- ty::TyProjection(ref data) => {
- // `<T as TraitRef<..>>::Name`
-
- self.push_projection_constraint_from_top(data);
- }
-
- ty::TyTuple(ref tuptys) => {
- for &tupty in tuptys {
- self.accumulate_from_ty(tupty);
- }
- }
-
- ty::TyInfer(_) => {
- // This should not happen, BUT:
- //
- // Currently we uncover region relationships on
- // entering the fn check. We should do this after
- // the fn check, then we can call this case a bug().
- }
- }
- }
-
- fn accumulate_from_rptr(&mut self,
- ty: Ty<'tcx>,
- r_b: ty::Region,
- ty_b: Ty<'tcx>) {
- // We are walking down a type like this, and current
- // position is indicated by caret:
- //
- // &'a &'b ty_b
- // ^
- //
- // At this point, top of stack will be `'a`. We must
- // require that `'a <= 'b`.
-
- self.push_region_constraint_from_top(r_b);
-
- // Now we push `'b` onto the stack, because it must
- // constrain any borrowed content we find within `T`.
-
- self.stack.push((r_b, Some(ty)));
- self.accumulate_from_ty(ty_b);
- self.stack.pop().unwrap();
- }
-
- /// Pushes a constraint that `r_b` must outlive the top region on the stack.
- fn push_region_constraint_from_top(&mut self,
- r_b: ty::Region) {
-
- // Indicates that we have found borrowed content with a lifetime
- // of at least `r_b`. This adds a constraint that `r_b` must
- // outlive the region `r_a` on top of the stack.
- //
- // As an example, imagine walking a type like:
- //
- // &'a &'b T
- // ^
- //
- // when we hit the inner pointer (indicated by caret), `'a` will
- // be on top of stack and `'b` will be the lifetime of the content
- // we just found. So we add constraint that `'a <= 'b`.
-
- let &(r_a, opt_ty) = self.stack.last().unwrap();
- self.push_sub_region_constraint(opt_ty, r_a, r_b);
- }
-
- /// Pushes a constraint that `r_a <= r_b`, due to `opt_ty`
- fn push_sub_region_constraint(&mut self,
- opt_ty: Option<Ty<'tcx>>,
- r_a: ty::Region,
- r_b: ty::Region) {
- self.out.push(Implication::RegionSubRegion(opt_ty, r_a, r_b));
- }
-
- /// Pushes a constraint that `param_ty` must outlive the top region on the stack.
- fn push_param_constraint_from_top(&mut self,
- param_ty: ty::ParamTy) {
- let &(region, opt_ty) = self.stack.last().unwrap();
- self.push_param_constraint(region, opt_ty, param_ty);
- }
-
- /// Pushes a constraint that `projection_ty` must outlive the top region on the stack.
- fn push_projection_constraint_from_top(&mut self,
- projection_ty: &ty::ProjectionTy<'tcx>) {
- let &(region, opt_ty) = self.stack.last().unwrap();
- self.out.push(Implication::RegionSubGeneric(
- opt_ty, region, GenericKind::Projection(projection_ty.clone())));
- }
-
- /// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
- fn push_param_constraint(&mut self,
- region: ty::Region,
- opt_ty: Option<Ty<'tcx>>,
- param_ty: ty::ParamTy) {
- self.out.push(Implication::RegionSubGeneric(
- opt_ty, region, GenericKind::Param(param_ty)));
- }
-
- fn accumulate_from_adt(&mut self,
- ty: Ty<'tcx>,
- def_id: DefId,
- _generics: &ty::Generics<'tcx>,
- substs: &Substs<'tcx>)
- {
- let predicates =
- self.tcx().lookup_predicates(def_id).instantiate(self.tcx(), substs);
- let predicates = match self.fully_normalize(&predicates) {
- Ok(predicates) => predicates,
- Err(ErrorReported) => { return; }
- };
-
- for predicate in predicates.predicates.as_slice() {
- match *predicate {
- ty::Predicate::Trait(..) => { }
- ty::Predicate::Equate(..) => { }
- ty::Predicate::Projection(..) => { }
- ty::Predicate::RegionOutlives(ref data) => {
- match self.tcx().no_late_bound_regions(data) {
- None => { }
- Some(ty::OutlivesPredicate(r_a, r_b)) => {
- self.push_sub_region_constraint(Some(ty), r_b, r_a);
- }
- }
- }
- ty::Predicate::TypeOutlives(ref data) => {
- match self.tcx().no_late_bound_regions(data) {
- None => { }
- Some(ty::OutlivesPredicate(ty_a, r_b)) => {
- self.stack.push((r_b, Some(ty)));
- self.accumulate_from_ty(ty_a);
- self.stack.pop().unwrap();
- }
- }
- }
- ty::Predicate::ObjectSafe(_) |
- ty::Predicate::WellFormed(_) => {
- }
- }
- }
-
- let obligations = predicates.predicates
- .into_iter()
- .map(|pred| Implication::Predicate(def_id, pred));
- self.out.extend(obligations);
-
- let variances = self.tcx().item_variances(def_id);
- self.accumulate_from_substs(substs, Some(&variances));
- }
-
- fn accumulate_from_substs(&mut self,
- substs: &Substs<'tcx>,
- variances: Option<&ty::ItemVariances>)
- {
- let mut tmp_variances = None;
- let variances = variances.unwrap_or_else(|| {
- tmp_variances = Some(ty::ItemVariances {
- types: substs.types.map(|_| ty::Variance::Invariant),
- regions: substs.regions().map(|_| ty::Variance::Invariant),
- });
- tmp_variances.as_ref().unwrap()
- });
-
- for (®ion, &variance) in substs.regions().iter().zip(&variances.regions) {
- match variance {
- ty::Contravariant | ty::Invariant => {
- // If any data with this lifetime is reachable
- // within, it must be at least contravariant.
- self.push_region_constraint_from_top(region)
- }
- ty::Covariant | ty::Bivariant => { }
- }
- }
-
- for (&ty, &variance) in substs.types.iter().zip(&variances.types) {
- match variance {
- ty::Covariant | ty::Invariant => {
- // If any data of this type is reachable within,
- // it must be at least covariant.
- self.accumulate_from_ty(ty);
- }
- ty::Contravariant | ty::Bivariant => { }
- }
- }
- }
-
- fn accumulate_from_object_ty(&mut self,
- ty: Ty<'tcx>,
- region_bound: ty::Region,
- required_region_bounds: Vec<ty::Region>)
- {
- // Imagine a type like this:
- //
- // trait Foo { }
- // trait Bar<'c> : 'c { }
- //
- // &'b (Foo+'c+Bar<'d>)
- // ^
- //
- // In this case, the following relationships must hold:
- //
- // 'b <= 'c
- // 'd <= 'c
- //
- // The first conditions is due to the normal region pointer
- // rules, which say that a reference cannot outlive its
- // referent.
- //
- // The final condition may be a bit surprising. In particular,
- // you may expect that it would have been `'c <= 'd`, since
- // usually lifetimes of outer things are conservative
- // approximations for inner things. However, it works somewhat
- // differently with trait objects: here the idea is that if the
- // user specifies a region bound (`'c`, in this case) it is the
- // "master bound" that *implies* that bounds from other traits are
- // all met. (Remember that *all bounds* in a type like
- // `Foo+Bar+Zed` must be met, not just one, hence if we write
- // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
- // 'y.)
- //
- // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
- // am looking forward to the future here.
-
- // The content of this object type must outlive
- // `bounds.region_bound`:
- let r_c = region_bound;
- self.push_region_constraint_from_top(r_c);
-
- // And then, in turn, to be well-formed, the
- // `region_bound` that user specified must imply the
- // region bounds required from all of the trait types:
- for &r_d in &required_region_bounds {
- // Each of these is an instance of the `'c <= 'b`
- // constraint above
- self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c));
- }
- }
-
- fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
- where T : TypeFoldable<'tcx>
- {
- let value =
- traits::fully_normalize(self.infcx,
- traits::ObligationCause::misc(self.span, self.body_id),
- value);
- match value {
- Ok(value) => Ok(value),
- Err(errors) => {
- // I don't like reporting these errors here, but I
- // don't know where else to report them just now. And
- // I don't really expect errors to arise here
- // frequently. I guess the best option would be to
- // propagate them out.
- traits::report_fulfillment_errors(self.infcx, &errors);
- Err(ErrorReported)
- }
- }
- }
-}
-
-/// Given an object type like `SomeTrait+Send`, computes the lifetime
-/// bounds that must hold on the elided self type. These are derived
-/// from the declarations of `SomeTrait`, `Send`, and friends -- if
-/// they declare `trait SomeTrait : 'static`, for example, then
-/// `'static` would appear in the list. The hard work is done by
-/// `ty::required_region_bounds`, see that for more information.
-pub fn object_region_bounds<'tcx>(
- tcx: &ty::ctxt<'tcx>,
- principal: &ty::PolyTraitRef<'tcx>,
- others: ty::BuiltinBounds)
- -> Vec<ty::Region>
-{
- // Since we don't actually *know* the self type for an object,
- // this "open(err)" serves as a kind of dummy standin -- basically
- // a skolemized type.
- let open_ty = tcx.mk_infer(ty::FreshTy(0));
-
- // Note that we preserve the overall binding levels here.
- assert!(!open_ty.has_escaping_regions());
- let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
- let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs)));
-
- let mut predicates = others.to_predicates(tcx, open_ty);
- predicates.extend(trait_refs.iter().map(|t| t.to_predicate()));
-
- tcx.required_region_bounds(open_ty, predicates)
-}
pub fn abort_if_errors(&self) {
self.diagnostic().abort_if_errors();
}
- pub fn abort_if_new_errors<F, T>(&self, f: F) -> T
+ pub fn track_errors<F, T>(&self, f: F) -> Result<T, usize>
where F: FnOnce() -> T
{
- let count = self.err_count();
+ let mut count = self.err_count();
let result = f();
- if self.err_count() > count {
- self.abort_if_errors();
+ count -= self.err_count();
+ if count == 0 {
+ Ok(result)
+ } else {
+ Err(count)
+ }
+ }
+ pub fn abort_if_new_errors<F, T>(&self, f: F) -> T
+ where F: FnOnce() -> T
+ {
+ match self.track_errors(f) {
+ Ok(result) => result,
+ Err(_) => {
+ self.abort_if_errors();
+ unreachable!();
+ }
}
- result
}
pub fn span_warn(&self, sp: Span, msg: &str) {
self.diagnostic().span_warn(sp, msg)
use std::cell::{RefCell, Cell};
use std::collections::HashMap;
-use std::collections::hash_state::HashState;
use std::ffi::CString;
use std::fmt::Debug;
-use std::hash::Hash;
+use std::hash::{Hash, BuildHasher};
use std::iter::repeat;
use std::path::Path;
use std::time::Instant;
}
impl<K, V, S> MemoizationMap for RefCell<HashMap<K,V,S>>
- where K: Hash+Eq+Clone, V: Clone, S: HashState
+ where K: Hash+Eq+Clone, V: Clone, S: BuildHasher
{
type Key = K;
type Value = V;
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(box_syntax)]
#![feature(libc)]
// libraries which follow this flag. Thus, use it before
// specifying libraries to link to.
"-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
),
position_independent_executables: true,
archive_format: "gnu".to_string(),
dynamic_linking: true,
executables: true,
has_rpath: true,
+ pre_link_args: vec![
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
+ ],
archive_format: "gnu".to_string(),
exe_allocation_crate: super::maybe_jemalloc(),
// following libraries so we're sure to pass it as one of the first
// arguments.
"-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
],
position_independent_executables: true,
archive_format: "gnu".to_string(),
// libraries which follow this flag. Thus, use it before
// specifying libraries to link to.
"-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
),
position_independent_executables: true,
archive_format: "gnu".to_string(),
// libraries which follow this flag. Thus, use it before
// specifying libraries to link to.
"-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
),
position_independent_executables: true,
archive_format: "gnu".to_string(),
#![crate_type = "rlib"]
#![no_std]
#![unstable(feature = "rustc_private", issue = "27812")]
+#![cfg_attr(not(stage0), deny(warnings))]
//! A typesafe bitmask flag generator.
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![allow(non_camel_case_types)]
// except according to those terms.
use std::collections::{HashMap, HashSet};
-use std::collections::hash_state::DefaultState;
use std::default::Default;
-use std::hash::{Hasher, Hash};
+use std::hash::{Hasher, Hash, BuildHasherDefault};
-pub type FnvHashMap<K, V> = HashMap<K, V, DefaultState<FnvHasher>>;
-pub type FnvHashSet<V> = HashSet<V, DefaultState<FnvHasher>>;
+pub type FnvHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FnvHasher>>;
+pub type FnvHashSet<V> = HashSet<V, BuildHasherDefault<FnvHasher>>;
#[allow(non_snake_case)]
pub fn FnvHashMap<K: Hash + Eq, V>() -> FnvHashMap<K, V> {
- Default::default()
+ HashMap::default()
}
#[allow(non_snake_case)]
pub fn FnvHashSet<V: Hash + Eq>() -> FnvHashSet<V> {
- Default::default()
+ HashSet::default()
}
/// A speedy hash algorithm for node ids and def ids. The hashmap in
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
-#![feature(hashmap_hasher)]
#![feature(nonzero)]
#![feature(rustc_private)]
#![feature(staged_api)]
use rustc_front::hir;
use rustc_front::lowering::{lower_crate, LoweringContext};
use rustc_passes::{no_asm, loops, consts, const_fn, rvalues, static_recursion};
-use super::Compilation;
+use super::{Compilation, CompileResult, compile_result_from_err_count};
use serialize::json;
use syntax;
use syntax_ext;
-pub fn compile_input(sess: Session,
+macro_rules! throw_if_errors {
+ ($tsess: expr) => {{
+ let err_count = $tsess.err_count();
+ if err_count > 0 {
+ return Err(err_count);
+ }
+ }}
+}
+
+pub fn compile_input(sess: &Session,
cstore: &CStore,
cfg: ast::CrateConfig,
input: &Input,
outdir: &Option<PathBuf>,
output: &Option<PathBuf>,
addl_plugins: Option<Vec<String>>,
- control: CompileController) {
+ control: CompileController) -> CompileResult {
macro_rules! controller_entry_point{($point: ident, $tsess: expr, $make_state: expr) => ({
let state = $make_state;
(control.$point.callback)(state);
if control.$point.stop == Compilation::Stop {
- $tsess.abort_if_errors();
- return;
+ return compile_result_from_err_count($tsess.err_count());
}
})}
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
- let result = {
+ let (outputs, trans) = {
let (outputs, expanded_crate, id) = {
- let krate = phase_1_parse_input(&sess, cfg, input);
+ let krate = phase_1_parse_input(sess, cfg, input);
controller_entry_point!(after_parse,
sess,
- CompileState::state_after_parse(input, &sess, outdir, &krate));
-
- let outputs = build_output_filenames(input, outdir, output, &krate.attrs, &sess);
- let id = link::find_crate_name(Some(&sess), &krate.attrs, input);
- let expanded_crate = match phase_2_configure_and_expand(&sess,
- &cstore,
- krate,
- &id[..],
- addl_plugins) {
- None => return,
- Some(k) => k,
- };
+ CompileState::state_after_parse(input, sess, outdir, &krate));
+
+ let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
+ let id = link::find_crate_name(Some(sess), &krate.attrs, input);
+ let expanded_crate = try!(phase_2_configure_and_expand(sess,
+ &cstore,
+ krate,
+ &id[..],
+ addl_plugins));
(outputs, expanded_crate, id)
};
controller_entry_point!(after_expand,
sess,
CompileState::state_after_expand(input,
- &sess,
+ sess,
outdir,
&expanded_crate,
&id[..]));
- let expanded_crate = assign_node_ids(&sess, expanded_crate);
+ let expanded_crate = assign_node_ids(sess, expanded_crate);
// Lower ast -> hir.
- let lcx = LoweringContext::new(&sess, Some(&expanded_crate));
+ let lcx = LoweringContext::new(sess, Some(&expanded_crate));
let mut hir_forest = time(sess.time_passes(),
"lowering ast -> hir",
|| hir_map::Forest::new(lower_crate(&lcx, &expanded_crate)));
}
let arenas = ty::CtxtArenas::new();
- let hir_map = make_map(&sess, &mut hir_forest);
+ let hir_map = make_map(sess, &mut hir_forest);
- write_out_deps(&sess, &outputs, &id);
+ write_out_deps(sess, &outputs, &id);
controller_entry_point!(after_write_deps,
sess,
CompileState::state_after_write_deps(input,
- &sess,
+ sess,
outdir,
&hir_map,
&expanded_crate,
&lcx));
time(sess.time_passes(), "attribute checking", || {
- front::check_attr::check_crate(&sess, &expanded_crate);
+ front::check_attr::check_crate(sess, &expanded_crate);
});
time(sess.time_passes(),
"early lint checks",
- || lint::check_ast_crate(&sess, &expanded_crate));
+ || lint::check_ast_crate(sess, &expanded_crate));
let opt_crate = if sess.opts.debugging_opts.keep_ast ||
sess.opts.debugging_opts.save_analysis {
None
};
- phase_3_run_analysis_passes(&sess,
- &cstore,
- hir_map,
- &arenas,
- &id,
- control.make_glob_map,
- |tcx, mir_map, analysis| {
-
- {
- let state =
- CompileState::state_after_analysis(input,
- &tcx.sess,
- outdir,
- opt_crate,
- tcx.map.krate(),
- &analysis,
- &mir_map,
- tcx,
- &lcx,
- &id);
- (control.after_analysis.callback)(state);
-
- tcx.sess.abort_if_errors();
- if control.after_analysis.stop == Compilation::Stop {
- return Err(());
- }
- }
-
- if log_enabled!(::log::INFO) {
- println!("Pre-trans");
- tcx.print_debug_stats();
- }
- let trans = phase_4_translate_to_llvm(tcx,
- mir_map,
- analysis);
-
- if log_enabled!(::log::INFO) {
- println!("Post-trans");
- tcx.print_debug_stats();
- }
-
- // Discard interned strings as they are no longer required.
- token::get_ident_interner().clear();
-
- Ok((outputs, trans))
- })
- };
+ try!(try!(phase_3_run_analysis_passes(sess,
+ &cstore,
+ hir_map,
+ &arenas,
+ &id,
+ control.make_glob_map,
+ |tcx, mir_map, analysis| {
+ {
+ let state =
+ CompileState::state_after_analysis(input,
+ &tcx.sess,
+ outdir,
+ opt_crate,
+ tcx.map.krate(),
+ &analysis,
+ &mir_map,
+ tcx,
+ &lcx,
+ &id);
+ (control.after_analysis.callback)(state);
+
+ throw_if_errors!(tcx.sess);
+ if control.after_analysis.stop == Compilation::Stop {
+ return Err(0usize);
+ }
+ }
- let (outputs, trans) = if let Ok(out) = result {
- out
- } else {
- return;
+ if log_enabled!(::log::INFO) {
+ println!("Pre-trans");
+ tcx.print_debug_stats();
+ }
+ let trans = phase_4_translate_to_llvm(tcx,
+ mir_map,
+ analysis);
+
+ if log_enabled!(::log::INFO) {
+ println!("Post-trans");
+ tcx.print_debug_stats();
+ }
+
+ // Discard interned strings as they are no longer required.
+ token::get_ident_interner().clear();
+
+ Ok((outputs, trans))
+ })))
};
- phase_5_run_llvm_passes(&sess, &trans, &outputs);
+ try!(phase_5_run_llvm_passes(sess, &trans, &outputs));
controller_entry_point!(after_llvm,
sess,
- CompileState::state_after_llvm(input, &sess, outdir, &trans));
+ CompileState::state_after_llvm(input, sess, outdir, &trans));
+
+ phase_6_link_output(sess, &trans, &outputs);
- phase_6_link_output(&sess, &trans, &outputs);
+ Ok(())
}
/// The name used for source code that doesn't originate in a file
mut krate: ast::Crate,
crate_name: &str,
addl_plugins: Option<Vec<String>>)
- -> Option<ast::Crate> {
+ -> Result<ast::Crate, usize> {
let time_passes = sess.time_passes();
// strip before anything else because crate metadata may use #[cfg_attr]
// baz! should not use this definition unless foo is enabled.
let mut feature_gated_cfgs = vec![];
- krate = time(time_passes, "configuration 1", || {
- sess.abort_if_new_errors(|| {
+ krate = try!(time(time_passes, "configuration 1", || {
+ sess.track_errors(|| {
syntax::config::strip_unconfigured_items(sess.diagnostic(),
krate,
&mut feature_gated_cfgs)
})
- });
+ }));
*sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
*sess.crate_metadata.borrow_mut() = collect_crate_metadata(sess, &krate.attrs);
middle::recursion_limit::update_recursion_limit(sess, &krate);
});
- time(time_passes, "gated macro checking", || {
- sess.abort_if_new_errors(|| {
+ try!(time(time_passes, "gated macro checking", || {
+ sess.track_errors(|| {
let features =
syntax::feature_gate::check_crate_macros(sess.codemap(),
&sess.parse_sess.span_diagnostic,
// these need to be set "early" so that expansion sees `quote` if enabled.
*sess.features.borrow_mut() = features;
- });
- });
+ })
+ }));
krate = time(time_passes, "crate injection", || {
let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
llvm_passes, attributes, .. } = registry;
- sess.abort_if_new_errors(|| {
+ try!(sess.track_errors(|| {
let mut ls = sess.lint_store.borrow_mut();
for pass in early_lint_passes {
ls.register_early_pass(Some(sess), true, pass);
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
*sess.plugin_attributes.borrow_mut() = attributes.clone();
- });
+ }));
// Lint plugins are registered; now we can process command line flags.
if sess.opts.describe_lints {
super::describe_lints(&*sess.lint_store.borrow(), true);
- return None;
+ return Err(0);
}
- sess.abort_if_new_errors(|| sess.lint_store.borrow_mut().process_command_line(sess));
+ try!(sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess)));
krate = time(time_passes, "expansion", || {
// Windows dlls do not have rpaths, so they don't know how to find their
// of macro expansion. This runs before #[cfg] to try to catch as
// much as possible (e.g. help the programmer avoid platform
// specific differences)
- time(time_passes, "complete gated feature checking 1", || {
- sess.abort_if_new_errors(|| {
+ try!(time(time_passes, "complete gated feature checking 1", || {
+ sess.track_errors(|| {
let features = syntax::feature_gate::check_crate(sess.codemap(),
&sess.parse_sess.span_diagnostic,
&krate,
&attributes,
sess.opts.unstable_features);
*sess.features.borrow_mut() = features;
- });
- });
+ })
+ }));
// JBC: make CFG processing part of expansion to avoid this problem:
// strip again, in case expansion added anything with a #[cfg].
- krate = sess.abort_if_new_errors(|| {
+ krate = try!(sess.track_errors(|| {
let krate = time(time_passes, "configuration 2", || {
syntax::config::strip_unconfigured_items(sess.diagnostic(),
krate,
});
krate
- });
+ }));
krate = time(time_passes, "maybe building test harness", || {
syntax::test::modify_for_testing(&sess.parse_sess, &sess.opts.cfg, krate, sess.diagnostic())
// One final feature gating of the true AST that gets compiled
// later, to make sure we've got everything (e.g. configuration
// can insert new attributes via `cfg_attr`)
- time(time_passes, "complete gated feature checking 2", || {
- sess.abort_if_new_errors(|| {
+ try!(time(time_passes, "complete gated feature checking 2", || {
+ sess.track_errors(|| {
let features = syntax::feature_gate::check_crate(sess.codemap(),
&sess.parse_sess.span_diagnostic,
&krate,
&attributes,
sess.opts.unstable_features);
*sess.features.borrow_mut() = features;
- });
- });
+ })
+ }));
time(time_passes,
"const fn bodies and arguments",
println!("Post-expansion node count: {}", count_nodes(&krate));
}
- Some(krate)
+ Ok(krate)
}
pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
name: &str,
make_glob_map: resolve::MakeGlobMap,
f: F)
- -> R
+ -> Result<R, usize>
where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>, MirMap<'tcx>, ty::CrateAnalysis) -> R
{
let time_passes = sess.time_passes();
"external crate/lib resolution",
|| LocalCrateReader::new(sess, cstore, &hir_map).read_crates(krate));
- let lang_items = time(time_passes, "language item collection", || {
- sess.abort_if_new_errors(|| {
+ let lang_items = try!(time(time_passes, "language item collection", || {
+ sess.track_errors(|| {
middle::lang_items::collect_language_items(&sess, &hir_map)
})
- });
+ }));
let resolve::CrateMap {
def_map,
lang_items,
stability::Index::new(krate),
|tcx| {
- // passes are timed inside typeck
- typeck::check_crate(tcx, trait_map);
-
- time(time_passes,
- "const checking",
- || consts::check_crate(tcx));
-
- let access_levels =
- time(time_passes, "privacy checking", || {
- rustc_privacy::check_crate(tcx,
- &export_map,
- external_exports)
- });
-
- // Do not move this check past lint
- time(time_passes, "stability index", || {
- tcx.stability.borrow_mut().build(tcx, krate, &access_levels)
- });
-
- time(time_passes,
- "intrinsic checking",
- || middle::intrinsicck::check_crate(tcx));
-
- time(time_passes,
- "effect checking",
- || middle::effect::check_crate(tcx));
-
- time(time_passes,
- "match checking",
- || middle::check_match::check_crate(tcx));
-
- let mir_map =
- time(time_passes,
- "MIR dump",
- || mir::mir_map::build_mir_for_crate(tcx));
-
- time(time_passes,
- "liveness checking",
- || middle::liveness::check_crate(tcx));
-
- time(time_passes,
- "borrow checking",
- || borrowck::check_crate(tcx));
-
- time(time_passes,
- "rvalue checking",
- || rvalues::check_crate(tcx));
-
- // Avoid overwhelming user with errors if type checking failed.
- // I'm not sure how helpful this is, to be honest, but it avoids
- // a
- // lot of annoying errors in the compile-fail tests (basically,
- // lint warnings and so on -- kindck used to do this abort, but
- // kindck is gone now). -nmatsakis
- tcx.sess.abort_if_errors();
-
- let reachable_map =
- time(time_passes,
- "reachability checking",
- || reachable::find_reachable(tcx, &access_levels));
-
- time(time_passes, "death checking", || {
- middle::dead::check_crate(tcx, &access_levels);
- });
-
- let ref lib_features_used =
- time(time_passes,
- "stability checking",
- || stability::check_unstable_api_usage(tcx));
-
- time(time_passes, "unused lib feature checking", || {
- stability::check_unused_or_stable_features(&tcx.sess,
- lib_features_used)
- });
-
- time(time_passes,
- "lint checking",
- || lint::check_crate(tcx, &access_levels));
-
- // The above three passes generate errors w/o aborting
- tcx.sess.abort_if_errors();
-
- f(tcx,
- mir_map,
- ty::CrateAnalysis {
- export_map: export_map,
- access_levels: access_levels,
- reachable: reachable_map,
- name: name,
- glob_map: glob_map,
- })
- })
+ // passes are timed inside typeck
+ typeck::check_crate(tcx, trait_map);
+
+ time(time_passes,
+ "const checking",
+ || consts::check_crate(tcx));
+
+ let access_levels =
+ time(time_passes, "privacy checking", || {
+ rustc_privacy::check_crate(tcx,
+ &export_map,
+ external_exports)
+ });
+
+ // Do not move this check past lint
+ time(time_passes, "stability index", || {
+ tcx.stability.borrow_mut().build(tcx, krate, &access_levels)
+ });
+
+ time(time_passes,
+ "intrinsic checking",
+ || middle::intrinsicck::check_crate(tcx));
+
+ time(time_passes,
+ "effect checking",
+ || middle::effect::check_crate(tcx));
+
+ time(time_passes,
+ "match checking",
+ || middle::check_match::check_crate(tcx));
+
+ let mir_map =
+ time(time_passes,
+ "MIR dump",
+ || mir::mir_map::build_mir_for_crate(tcx));
+
+ time(time_passes,
+ "liveness checking",
+ || middle::liveness::check_crate(tcx));
+
+ time(time_passes,
+ "borrow checking",
+ || borrowck::check_crate(tcx));
+
+ time(time_passes,
+ "rvalue checking",
+ || rvalues::check_crate(tcx));
+
+ // Avoid overwhelming user with errors if type checking failed.
+ // I'm not sure how helpful this is, to be honest, but it avoids
+ // a
+ // lot of annoying errors in the compile-fail tests (basically,
+ // lint warnings and so on -- kindck used to do this abort, but
+ // kindck is gone now). -nmatsakis
+ throw_if_errors!(tcx.sess);
+
+ let reachable_map =
+ time(time_passes,
+ "reachability checking",
+ || reachable::find_reachable(tcx, &access_levels));
+
+ time(time_passes, "death checking", || {
+ middle::dead::check_crate(tcx, &access_levels);
+ });
+
+ let ref lib_features_used =
+ time(time_passes,
+ "stability checking",
+ || stability::check_unstable_api_usage(tcx));
+
+ time(time_passes, "unused lib feature checking", || {
+ stability::check_unused_or_stable_features(&tcx.sess,
+ lib_features_used)
+ });
+
+ time(time_passes,
+ "lint checking",
+ || lint::check_crate(tcx, &access_levels));
+
+ // The above three passes generate errors w/o aborting
+ throw_if_errors!(tcx.sess);
+
+ Ok(f(tcx,
+ mir_map,
+ ty::CrateAnalysis {
+ export_map: export_map,
+ access_levels: access_levels,
+ reachable: reachable_map,
+ name: name,
+ glob_map: glob_map,
+ }))
+ })
}
/// Run the translation phase to LLVM, after which the AST and analysis can
/// as a side effect.
pub fn phase_5_run_llvm_passes(sess: &Session,
trans: &trans::CrateTranslation,
- outputs: &OutputFilenames) {
+ outputs: &OutputFilenames) -> CompileResult {
if sess.opts.cg.no_integrated_as {
let mut map = HashMap::new();
map.insert(OutputType::Assembly, None);
|| write::run_passes(sess, trans, &sess.opts.output_types, outputs));
}
- sess.abort_if_errors();
+ throw_if_errors!(sess);
+ Ok(())
}
/// Run the linker on any artifacts that resulted from the LLVM run.
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(box_syntax)]
#![feature(libc)]
const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
md#bug-reports";
+// Err(0) means compilation was stopped, but no errors were found.
+// This would be better as a dedicated enum, but using try! is so convenient.
+pub type CompileResult = Result<(), usize>;
+
+pub fn compile_result_from_err_count(err_count: usize) -> CompileResult {
+ if err_count == 0 {
+ Ok(())
+ } else {
+ Err(err_count)
+ }
+}
+
+#[inline]
+fn abort_msg(err_count: usize) -> String {
+ match err_count {
+ 0 => "aborting with no errors (maybe a bug?)".to_owned(),
+ 1 => "aborting due to previous error".to_owned(),
+ e => format!("aborting due to {} previous errors", e),
+ }
+}
+
+pub fn abort_on_err<T>(result: Result<T, usize>, sess: &Session) -> T {
+ match result {
+ Err(err_count) => {
+ sess.fatal(&abort_msg(err_count));
+ }
+ Ok(x) => x,
+ }
+}
+
pub fn run(args: Vec<String>) -> isize {
- monitor(move || run_compiler(&args, &mut RustcDefaultCalls));
+ monitor(move || {
+ let (result, session) = run_compiler(&args, &mut RustcDefaultCalls);
+ if let Err(err_count) = result {
+ if err_count > 0 {
+ match session {
+ Some(sess) => sess.fatal(&abort_msg(err_count)),
+ None => {
+ let mut emitter =
+ errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto);
+ emitter.emit(None, &abort_msg(err_count), None, errors::Level::Fatal);
+ panic!(errors::FatalError);
+ }
+ }
+ }
+ }
+ });
0
}
// Parse args and run the compiler. This is the primary entry point for rustc.
// See comments on CompilerCalls below for details about the callbacks argument.
-pub fn run_compiler<'a>(args: &[String], callbacks: &mut CompilerCalls<'a>) {
- macro_rules! do_or_return {($expr: expr) => {
+pub fn run_compiler<'a>(args: &[String],
+ callbacks: &mut CompilerCalls<'a>)
+ -> (CompileResult, Option<Session>) {
+ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
match $expr {
- Compilation::Stop => return,
+ Compilation::Stop => return (Ok(()), $sess),
Compilation::Continue => {}
}
}}
let matches = match handle_options(args.to_vec()) {
Some(matches) => matches,
- None => return,
+ None => return (Ok(()), None),
};
let sopts = config::build_session_options(&matches);
let descriptions = diagnostics_registry();
- do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.error_format));
+ do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.error_format), None);
let (odir, ofile) = make_output(&matches);
let (input, input_file_path) = match make_input(&matches.free) {
Some((input, input_file_path)) => callbacks.some_input(input, input_file_path),
None => match callbacks.no_input(&matches, &sopts, &odir, &ofile, &descriptions) {
Some((input, input_file_path)) => (input, input_file_path),
- None => return,
+ None => return (Ok(()), None),
},
};
let cstore = Rc::new(CStore::new(token::get_ident_interner()));
- let sess = build_session(sopts, input_file_path, descriptions,
- cstore.clone());
+ let sess = build_session(sopts, input_file_path, descriptions, cstore.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess);
target_features::add_configuration(&mut cfg, &sess);
- do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile));
+ do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile), Some(sess));
// It is somewhat unfortunate that this is hardwired in - this is forced by
// the fact that pretty_print_input requires the session by value.
match pretty {
Some((ppm, opt_uii)) => {
pretty::pretty_print_input(sess, &cstore, cfg, &input, ppm, opt_uii, ofile);
- return;
+ return (Ok(()), None);
}
None => {
// continue
let plugins = sess.opts.debugging_opts.extra_plugins.clone();
let control = callbacks.build_controller(&sess);
- driver::compile_input(sess, &cstore, cfg, &input, &odir, &ofile,
- Some(plugins), control);
+ (driver::compile_input(&sess, &cstore, cfg, &input, &odir, &ofile,
+ Some(plugins), control),
+ Some(sess))
}
// Extract output directory and file from matches.
use rustc_trans::back::link;
-use driver;
+use {driver, abort_on_err};
use rustc::middle::ty;
use rustc::middle::cfg;
f(&annotation, payload, &ast_map.forest.krate)
}
PpmTyped => {
- driver::phase_3_run_analysis_passes(sess,
- cstore,
- ast_map.clone(),
- arenas,
- id,
- resolve::MakeGlobMap::No,
- |tcx, _, _| {
- let annotation = TypedAnnotation {
- tcx: tcx,
- };
- let _ignore = tcx.dep_graph.in_ignore();
- f(&annotation,
- payload,
- &ast_map.forest.krate)
- })
+ abort_on_err(driver::phase_3_run_analysis_passes(sess,
+ cstore,
+ ast_map.clone(),
+ arenas,
+ id,
+ resolve::MakeGlobMap::No,
+ |tcx, _, _| {
+ let annotation = TypedAnnotation {
+ tcx: tcx,
+ };
+ let _ignore = tcx.dep_graph.in_ignore();
+ f(&annotation,
+ payload,
+ &ast_map.forest.krate)
+ }), sess)
}
_ => panic!("Should use call_with_pp_support"),
}
let compute_ast_map = needs_ast_map(&ppm, &opt_uii);
let krate = if compute_ast_map {
match driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id[..], None) {
- None => return,
- Some(k) => driver::assign_node_ids(&sess, k),
+ Err(_) => return,
+ Ok(k) => driver::assign_node_ids(&sess, k),
}
} else {
krate
match code {
Some(code) => {
let variants = gather_flowgraph_variants(&sess);
- driver::phase_3_run_analysis_passes(&sess,
- &cstore,
- ast_map,
- &arenas,
- &id,
- resolve::MakeGlobMap::No,
- |tcx, _, _| {
- print_flowgraph(variants,
- tcx,
- code,
- mode,
- out)
- })
+ abort_on_err(driver::phase_3_run_analysis_passes(&sess,
+ &cstore,
+ ast_map,
+ &arenas,
+ &id,
+ resolve::MakeGlobMap::No,
+ |tcx, _, _| {
+ print_flowgraph(variants,
+ tcx,
+ code,
+ mode,
+ out)
+ }), &sess)
}
None => {
let message = format!("--pretty=flowgraph needs block, fn, or method; got \
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/nightly/")]
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+ html_root_url = "http://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(associated_consts)]
#![feature(box_patterns)]
}
pub fn arg_to_string(arg: &hir::Arg) -> String {
- to_string(|s| s.print_arg(arg))
+ to_string(|s| s.print_arg(arg, false))
}
pub fn visibility_qualified(vis: hir::Visibility, s: &str) -> String {
pub fn print_fn_args(&mut self,
decl: &hir::FnDecl,
- opt_explicit_self: Option<&hir::ExplicitSelf_>)
+ opt_explicit_self: Option<&hir::ExplicitSelf_>,
+ is_closure: bool)
-> io::Result<()> {
// It is unfortunate to duplicate the commasep logic, but we want the
// self type and the args all in the same box.
} else {
try!(self.word_space(","));
}
- try!(self.print_arg(arg));
+ try!(self.print_arg(arg, is_closure));
}
self.end()
opt_explicit_self: Option<&hir::ExplicitSelf_>)
-> io::Result<()> {
try!(self.popen());
- try!(self.print_fn_args(decl, opt_explicit_self));
+ try!(self.print_fn_args(decl, opt_explicit_self, false));
if decl.variadic {
try!(word(&mut self.s, ", ..."));
}
pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
try!(word(&mut self.s, "|"));
- try!(self.print_fn_args(decl, None));
+ try!(self.print_fn_args(decl, None, true));
try!(word(&mut self.s, "|"));
if let hir::DefaultReturn(..) = decl.output {
self.print_type(&*mt.ty)
}
- pub fn print_arg(&mut self, input: &hir::Arg) -> io::Result<()> {
+ pub fn print_arg(&mut self, input: &hir::Arg, is_closure: bool) -> io::Result<()> {
try!(self.ibox(indent_unit));
match input.ty.node {
- hir::TyInfer => try!(self.print_pat(&*input.pat)),
+ hir::TyInfer if is_closure => try!(self.print_pat(&*input.pat)),
_ => {
match input.pat.node {
hir::PatIdent(_, ref path1, _) if
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![cfg_attr(test, feature(test))]
#![feature(box_patterns)]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(associated_consts)]
#![feature(box_syntax)]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
- html_root_url = "https://doc.rust-lang.org/nightly/")]
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+ html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(box_patterns)]
#![feature(enumset)]
#![crate_name = "rustc_mir"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
+#![cfg_attr(not(stage0), deny(warnings))]
+#![unstable(feature = "rustc_private", issue = "27812")]
#![feature(rustc_private)]
+#![feature(staged_api)]
#[macro_use] extern crate log;
extern crate graphviz as dot;
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
- html_root_url = "https://doc.rust-lang.org/nightly/")]
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+ html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(rustc_diagnostic_macros)]
#![feature(staged_api)]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![feature(staged_api, rustc_private)]
+#![cfg_attr(not(stage0), deny(warnings))]
extern crate rustc_llvm as llvm;
extern crate rustc;
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
- html_root_url = "https://doc.rust-lang.org/nightly/")]
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+ html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(dynamic_lib)]
#![feature(staged_api)]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(associated_consts)]
#![feature(borrow_state)]
}
#[derive(Copy, Clone)]
-enum TypeParameters<'a> {
+enum TypeParameters<'tcx, 'a> {
NoTypeParameters,
HasTypeParameters(// Type parameters.
&'a Generics,
ParamSpace,
// The kind of the rib used for type parameters.
- RibKind),
+ RibKind<'tcx>),
}
// The rib kind controls the translation of local
// definitions (`Def::Local`) to upvars (`Def::Upvar`).
#[derive(Copy, Clone, Debug)]
-enum RibKind {
+enum RibKind<'a> {
// No translation needs to be applied.
NormalRibKind,
// We're in a constant item. Can't refer to dynamic stuff.
ConstantItemRibKind,
+
+ // We passed through an anonymous module.
+ AnonymousModuleRibKind(Module<'a>),
}
#[derive(Copy, Clone)]
/// One local scope.
#[derive(Debug)]
-struct Rib {
+struct Rib<'a> {
bindings: HashMap<Name, DefLike>,
- kind: RibKind,
+ kind: RibKind<'a>,
}
-impl Rib {
- fn new(kind: RibKind) -> Rib {
+impl<'a> Rib<'a> {
+ fn new(kind: RibKind<'a>) -> Rib<'a> {
Rib {
bindings: HashMap::new(),
kind: kind,
// The current set of local scopes, for values.
// FIXME #4948: Reuse ribs to avoid allocation.
- value_ribs: Vec<Rib>,
+ value_ribs: Vec<Rib<'a>>,
// The current set of local scopes, for types.
- type_ribs: Vec<Rib>,
+ type_ribs: Vec<Rib<'a>>,
// The current set of local scopes, for labels.
- label_ribs: Vec<Rib>,
+ label_ribs: Vec<Rib<'a>>,
// The trait that the current context can refer to.
current_trait_ref: Option<(DefId, TraitRef)>,
self.arenas.modules.alloc(ModuleS::new(parent_link, def, external, is_public))
}
+ fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec<Rib<'a>> {
+ match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs }
+ }
+
#[inline]
fn record_import_use(&mut self, import_id: NodeId, name: Name) {
if !self.make_glob_map {
}
}
- fn with_type_parameter_rib<F>(&mut self, type_parameters: TypeParameters, f: F)
+ fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<'a, 'b>, f: F)
where F: FnOnce(&mut Resolver)
{
match type_parameters {
}
}
- fn resolve_function(&mut self, rib_kind: RibKind, declaration: &FnDecl, block: &Block) {
+ fn resolve_function(&mut self, rib_kind: RibKind<'a>, declaration: &FnDecl, block: &Block) {
// Create a value rib for the function.
self.value_ribs.push(Rib::new(rib_kind));
fn resolve_block(&mut self, block: &Block) {
debug!("(resolving block) entering block");
- self.value_ribs.push(Rib::new(NormalRibKind));
-
// Move down in the graph, if there's an anonymous module rooted here.
let orig_module = self.current_module;
- match orig_module.anonymous_children.borrow().get(&block.id) {
- None => {
- // Nothing to do.
- }
- Some(anonymous_module) => {
- debug!("(resolving block) found anonymous module, moving down");
- self.current_module = anonymous_module;
- }
+ let anonymous_module =
+ orig_module.anonymous_children.borrow().get(&block.id).map(|module| *module);
+
+ if let Some(anonymous_module) = anonymous_module {
+ debug!("(resolving block) found anonymous module, moving down");
+ self.value_ribs.push(Rib::new(AnonymousModuleRibKind(anonymous_module)));
+ self.type_ribs.push(Rib::new(AnonymousModuleRibKind(anonymous_module)));
+ self.current_module = anonymous_module;
+ } else {
+ self.value_ribs.push(Rib::new(NormalRibKind));
}
// Check for imports appearing after non-item statements.
if !self.resolved {
self.current_module = orig_module;
self.value_ribs.pop();
+ if let Some(_) = anonymous_module {
+ self.type_ribs.pop();
+ }
}
debug!("(resolving block) leaving block");
}
Def::Local(_, node_id) => {
for rib in ribs {
match rib.kind {
- NormalRibKind => {
+ NormalRibKind | AnonymousModuleRibKind(..) => {
// Nothing to do. Continue.
}
ClosureRibKind(function_id) => {
Def::TyParam(..) | Def::SelfTy(..) => {
for rib in ribs {
match rib.kind {
- NormalRibKind | MethodRibKind | ClosureRibKind(..) => {
+ NormalRibKind | MethodRibKind | ClosureRibKind(..) |
+ AnonymousModuleRibKind(..) => {
// Nothing to do. Continue.
}
ItemRibKind => {
namespace: Namespace)
-> Option<LocalDef> {
// Check the local set of ribs.
- let (name, ribs) = match namespace {
- ValueNS => (ident.name, &self.value_ribs),
- TypeNS => (ident.unhygienic_name, &self.type_ribs),
- };
+ let name = match namespace { ValueNS => ident.name, TypeNS => ident.unhygienic_name };
- for (i, rib) in ribs.iter().enumerate().rev() {
- if let Some(def_like) = rib.bindings.get(&name).cloned() {
+ for i in (0 .. self.get_ribs(namespace).len()).rev() {
+ if let Some(def_like) = self.get_ribs(namespace)[i].bindings.get(&name).cloned() {
match def_like {
DlDef(def) => {
debug!("(resolving path in local ribs) resolved `{}` to {:?} at {}",
}
}
}
+
+ if let AnonymousModuleRibKind(module) = self.get_ribs(namespace)[i].kind {
+ if let Success((target, _)) = self.resolve_name_in_module(module,
+ ident.unhygienic_name,
+ namespace,
+ PathSearch,
+ true) {
+ if let Some(def) = target.binding.def() {
+ return Some(LocalDef::from_def(def));
+ }
+ }
+ }
}
None
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(box_patterns)]
#![feature(box_syntax)]
use check::dropck;
use check::FnCtxt;
use middle::free_region::FreeRegionMap;
-use middle::implicator::{self, Implication};
use middle::mem_categorization as mc;
use middle::mem_categorization::Categorization;
use middle::region::{self, CodeExtent};
r_o, r_o.cause);
let sup_type = self.resolve_type(r_o.sup_type);
let origin = self.code_to_origin(r_o.cause.span, sup_type, &r_o.cause.code);
-
- if r_o.sub_region != ty::ReEmpty {
- type_must_outlive(self, origin, sup_type, r_o.sub_region);
- } else {
- self.visit_old_school_wf(node_id, sup_type, origin);
- }
+ type_must_outlive(self, origin, sup_type, r_o.sub_region);
}
// Processing the region obligations should not cause the list to grow further:
self.fcx.inh.infcx.fulfillment_cx.borrow().region_obligations(node_id).len());
}
- fn visit_old_school_wf(&mut self,
- body_id: ast::NodeId,
- ty: Ty<'tcx>,
- origin: infer::SubregionOrigin<'tcx>) {
- // As a weird kind of hack, we use a region of empty as a signal
- // to mean "old-school WF rules". The only reason the old-school
- // WF rules are not encoded using WF is that this leads to errors,
- // and we want to phase those in gradually.
-
- // FIXME(#27579) remove this weird special case once we phase in new WF rules completely
- let implications = implicator::implications(self.infcx(),
- body_id,
- ty,
- ty::ReEmpty,
- origin.span());
- let origin_for_ty = |ty: Option<Ty<'tcx>>| match ty {
- None => origin.clone(),
- Some(ty) => infer::ReferenceOutlivesReferent(ty, origin.span()),
- };
- for implication in implications {
- match implication {
- Implication::RegionSubRegion(ty, r1, r2) => {
- self.fcx.mk_subr(origin_for_ty(ty), r1, r2);
- }
- Implication::RegionSubGeneric(ty, r1, GenericKind::Param(param_ty)) => {
- param_ty_must_outlive(self, origin_for_ty(ty), r1, param_ty);
- }
- Implication::RegionSubGeneric(ty, r1, GenericKind::Projection(proj_ty)) => {
- projection_must_outlive(self, origin_for_ty(ty), r1, proj_ty);
- }
- Implication::Predicate(def_id, predicate) => {
- let cause = traits::ObligationCause::new(origin.span(),
- body_id,
- traits::ItemObligation(def_id));
- let obligation = traits::Obligation::new(cause, predicate);
- self.fcx.register_predicate(obligation);
- }
- }
- }
- }
-
fn code_to_origin(&self,
span: Span,
sup_type: Ty<'tcx>,
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![allow(non_camel_case_types)]
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
+#![cfg_attr(not(stage0), deny(warnings))]
#![no_std]
#![feature(core_char_ext)]
pub use self::MaybeTyped::*;
use rustc_lint;
-use rustc_driver::{driver, target_features};
+use rustc_driver::{driver, target_features, abort_on_err};
use rustc::session::{self, config};
use rustc::middle::def_id::DefId;
use rustc::middle::privacy::AccessLevels;
let arenas = ty::CtxtArenas::new();
let hir_map = driver::make_map(&sess, &mut hir_forest);
- driver::phase_3_run_analysis_passes(&sess,
- &cstore,
- hir_map,
- &arenas,
- &name,
- resolve::MakeGlobMap::No,
- |tcx, _, analysis| {
+ abort_on_err(driver::phase_3_run_analysis_passes(&sess,
+ &cstore,
+ hir_map,
+ &arenas,
+ &name,
+ resolve::MakeGlobMap::No,
+ |tcx, _, analysis| {
let _ignore = tcx.dep_graph.in_ignore();
let ty::CrateAnalysis { access_levels, .. } = analysis;
*analysis.inlined.borrow_mut() = map;
analysis.deref_trait_did = ctxt.deref_trait_did.get();
(krate, analysis)
- })
+ }), &sess)
}
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(box_patterns)]
#![feature(box_syntax)]
if no_run {
control.after_analysis.stop = Compilation::Stop;
}
- driver::compile_input(sess, &cstore, cfg, &input, &out, &None, None, control);
+ let result = driver::compile_input(&sess, &cstore, cfg, &input,
+ &out, &None, None, control);
+ match result {
+ Err(count) if count > 0 => sess.fatal("aborting due to previous error(s)"),
+ _ => {}
+ }
if no_run { return }
//! Implementations of serialization for structures found in libcollections
-use std::hash::Hash;
-use std::collections::hash_state::HashState;
+use std::hash::{Hash, BuildHasher};
use std::mem;
use {Decodable, Encodable, Decoder, Encoder};
impl<K, V, S> Encodable for HashMap<K, V, S>
where K: Encodable + Hash + Eq,
V: Encodable,
- S: HashState,
+ S: BuildHasher,
{
fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
e.emit_map(self.len(), |e| {
impl<K, V, S> Decodable for HashMap<K, V, S>
where K: Decodable + Hash + Eq,
V: Decodable,
- S: HashState + Default,
+ S: BuildHasher + Default,
{
fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
d.read_map(|d, len| {
let state = Default::default();
- let mut map = HashMap::with_capacity_and_hash_state(len, state);
+ let mut map = HashMap::with_capacity_and_hasher(len, state);
for i in 0..len {
let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
impl<T, S> Encodable for HashSet<T, S>
where T: Encodable + Hash + Eq,
- S: HashState,
+ S: BuildHasher,
{
fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
s.emit_seq(self.len(), |s| {
impl<T, S> Decodable for HashSet<T, S>
where T: Decodable + Hash + Eq,
- S: HashState + Default,
+ S: BuildHasher + Default,
{
fn decode<D: Decoder>(d: &mut D) -> Result<HashSet<T, S>, D::Error> {
d.read_seq(|d, len| {
let state = Default::default();
- let mut set = HashSet::with_capacity_and_hash_state(len, state);
+ let mut set = HashSet::with_capacity_and_hasher(len, state);
for i in 0..len {
set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
}
mod tests {
extern crate test;
use self::Animal::*;
- use self::DecodeEnum::*;
use self::test::Bencher;
use {Encodable, Decodable};
use super::Json::*;
html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/",
test(attr(allow(unused_variables), deny(warnings))))]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(enumset)]
-#![feature(hashmap_hasher)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(str_char)]
use self::VacantEntryState::*;
use borrow::Borrow;
-use clone::Clone;
-use cmp::{max, Eq, PartialEq};
-use default::Default;
+use cmp::max;
use fmt::{self, Debug};
-use hash::{Hash, SipHasher};
-use iter::{self, Iterator, ExactSizeIterator, IntoIterator, FromIterator, Extend, Map};
-use marker::Sized;
+use hash::{Hash, SipHasher, BuildHasher};
+use iter::{self, Map, FromIterator};
use mem::{self, replace};
-use ops::{Deref, FnMut, FnOnce, Index};
-use option::Option::{self, Some, None};
+use ops::{Deref, Index};
use rand::{self, Rng};
use super::table::{
Empty,
Full,
};
-use super::state::HashState;
const INITIAL_LOG2_CAP: usize = 5;
const INITIAL_CAPACITY: usize = 1 << INITIAL_LOG2_CAP; // 2^5
#[stable(feature = "rust1", since = "1.0.0")]
pub struct HashMap<K, V, S = RandomState> {
// All hashes are keyed on these values, to prevent hash collision attacks.
- hash_state: S,
+ hash_builder: S,
table: RawTable<K, V>,
}
impl<K, V, S> HashMap<K, V, S>
- where K: Eq + Hash, S: HashState
+ where K: Eq + Hash, S: BuildHasher
{
fn make_hash<X: ?Sized>(&self, x: &X) -> SafeHash where X: Hash {
- table::make_hash(&self.hash_state, x)
+ table::make_hash(&self.hash_builder, x)
}
/// Search for a key, yielding the index if it's found in the hashtable.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize) -> HashMap<K, V, RandomState> {
- HashMap::with_capacity_and_hash_state(capacity, Default::default())
+ HashMap::with_capacity_and_hasher(capacity, Default::default())
}
}
impl<K, V, S> HashMap<K, V, S>
- where K: Eq + Hash, S: HashState
+ where K: Eq + Hash, S: BuildHasher
{
- /// Creates an empty hashmap which will use the given hasher to hash keys.
+ /// Creates an empty hashmap which will use the given hash builder to hash
+ /// keys.
///
/// The created map has the default initial capacity.
///
+ /// Warning: `hash_builder` is normally randomly generated, and
+ /// is designed to allow HashMaps to be resistant to attacks that
+ /// cause many collisions and very poor performance. Setting it
+ /// manually using this function can expose a DoS attack vector.
+ ///
/// # Examples
///
/// ```
- /// #![feature(hashmap_hasher)]
- ///
/// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState;
///
/// let s = RandomState::new();
- /// let mut map = HashMap::with_hash_state(s);
+ /// let mut map = HashMap::with_hasher(s);
/// map.insert(1, 2);
/// ```
#[inline]
- #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear",
- issue = "27713")]
- pub fn with_hash_state(hash_state: S) -> HashMap<K, V, S> {
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
HashMap {
- hash_state: hash_state,
+ hash_builder: hash_builder,
resize_policy: DefaultResizePolicy::new(),
- table: RawTable::new(0),
+ table: RawTable::new(0),
}
}
+ /// Deprecated, renamed to `with_hasher`
+ #[inline]
+ #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear",
+ issue = "27713")]
+ #[rustc_deprecated(since = "1.7.0", reason = "renamed to with_hasher")]
+ pub fn with_hash_state(hash_state: S) -> HashMap<K, V, S> {
+ HashMap::with_hasher(hash_state)
+ }
+
/// Creates an empty HashMap with space for at least `capacity`
/// elements, using `hasher` to hash the keys.
///
/// # Examples
///
/// ```
- /// #![feature(hashmap_hasher)]
- ///
/// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState;
///
/// let s = RandomState::new();
- /// let mut map = HashMap::with_capacity_and_hash_state(10, s);
+ /// let mut map = HashMap::with_capacity_and_hasher(10, s);
/// map.insert(1, 2);
/// ```
#[inline]
- #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear",
- issue = "27713")]
- pub fn with_capacity_and_hash_state(capacity: usize, hash_state: S)
- -> HashMap<K, V, S> {
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S)
+ -> HashMap<K, V, S> {
let resize_policy = DefaultResizePolicy::new();
let min_cap = max(INITIAL_CAPACITY, resize_policy.min_capacity(capacity));
let internal_cap = min_cap.checked_next_power_of_two().expect("capacity overflow");
assert!(internal_cap >= capacity, "capacity overflow");
HashMap {
- hash_state: hash_state,
+ hash_builder: hash_builder,
resize_policy: resize_policy,
- table: RawTable::new(internal_cap),
+ table: RawTable::new(internal_cap),
}
}
+ /// Deprecated, renamed to `with_capacity_and_hasher`
+ #[inline]
+ #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear",
+ issue = "27713")]
+ #[rustc_deprecated(since = "1.7.0",
+ reason = "renamed to with_capacity_and_hasher")]
+ pub fn with_capacity_and_hash_state(capacity: usize, hash_state: S)
+ -> HashMap<K, V, S> {
+ HashMap::with_capacity_and_hasher(capacity, hash_state)
+ }
+
/// Returns the number of elements the map can hold without reallocating.
///
/// This number is a lower bound; the `HashMap<K, V>` might be able to hold
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V, S> PartialEq for HashMap<K, V, S>
- where K: Eq + Hash, V: PartialEq, S: HashState
+ where K: Eq + Hash, V: PartialEq, S: BuildHasher
{
fn eq(&self, other: &HashMap<K, V, S>) -> bool {
if self.len() != other.len() { return false; }
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V, S> Eq for HashMap<K, V, S>
- where K: Eq + Hash, V: Eq, S: HashState
+ where K: Eq + Hash, V: Eq, S: BuildHasher
{}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V, S> Debug for HashMap<K, V, S>
- where K: Eq + Hash + Debug, V: Debug, S: HashState
+ where K: Eq + Hash + Debug, V: Debug, S: BuildHasher
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V, S> Default for HashMap<K, V, S>
where K: Eq + Hash,
- S: HashState + Default,
+ S: BuildHasher + Default,
{
fn default() -> HashMap<K, V, S> {
- HashMap::with_hash_state(Default::default())
+ HashMap::with_hasher(Default::default())
}
}
impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S>
where K: Eq + Hash + Borrow<Q>,
Q: Eq + Hash,
- S: HashState,
+ S: BuildHasher,
{
type Output = V;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S>
- where K: Eq + Hash, S: HashState
+ where K: Eq + Hash, S: BuildHasher
{
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V>;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S>
- where K: Eq + Hash, S: HashState
+ where K: Eq + Hash, S: BuildHasher
{
type Item = (&'a K, &'a mut V);
type IntoIter = IterMut<'a, K, V>;
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V, S> IntoIterator for HashMap<K, V, S>
- where K: Eq + Hash, S: HashState
+ where K: Eq + Hash, S: BuildHasher
{
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S>
- where K: Eq + Hash, S: HashState + Default
+ where K: Eq + Hash, S: BuildHasher + Default
{
fn from_iter<T: IntoIterator<Item=(K, V)>>(iterable: T) -> HashMap<K, V, S> {
let iter = iterable.into_iter();
let lower = iter.size_hint().0;
- let mut map = HashMap::with_capacity_and_hash_state(lower,
- Default::default());
+ let mut map = HashMap::with_capacity_and_hasher(lower, Default::default());
map.extend(iter);
map
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V, S> Extend<(K, V)> for HashMap<K, V, S>
- where K: Eq + Hash, S: HashState
+ where K: Eq + Hash, S: BuildHasher
{
fn extend<T: IntoIterator<Item=(K, V)>>(&mut self, iter: T) {
for (k, v) in iter {
#[stable(feature = "hash_extend_copy", since = "1.4.0")]
impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
- where K: Eq + Hash + Copy, V: Copy, S: HashState
+ where K: Eq + Hash + Copy, V: Copy, S: BuildHasher
{
fn extend<T: IntoIterator<Item=(&'a K, &'a V)>>(&mut self, iter: T) {
self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
/// `Hasher`, but the hashers created by two different `RandomState`
/// instances are unlikely to produce the same result for the same values.
#[derive(Clone)]
-#[unstable(feature = "hashmap_hasher",
- reason = "hashing an hash maps may be altered",
- issue = "27713")]
+#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub struct RandomState {
k0: u64,
k1: u64,
}
-#[unstable(feature = "hashmap_hasher",
- reason = "hashing an hash maps may be altered",
- issue = "27713")]
impl RandomState {
/// Constructs a new `RandomState` that is initialized with random keys.
#[inline]
#[allow(deprecated)] // rand
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub fn new() -> RandomState {
let mut r = rand::thread_rng();
RandomState { k0: r.gen(), k1: r.gen() }
}
}
-#[unstable(feature = "hashmap_hasher",
- reason = "hashing an hash maps may be altered",
- issue = "27713")]
-impl HashState for RandomState {
+#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+impl BuildHasher for RandomState {
type Hasher = SipHasher;
#[inline]
- fn hasher(&self) -> SipHasher {
+ fn build_hasher(&self) -> SipHasher {
SipHasher::new_with_keys(self.k0, self.k1)
}
}
}
impl<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S>
- where K: Eq + Hash + Borrow<Q>, S: HashState, Q: Eq + Hash
+ where K: Eq + Hash + Borrow<Q>, S: BuildHasher, Q: Eq + Hash
{
type Key = K;
// except according to those terms.
use borrow::Borrow;
-use clone::Clone;
-use cmp::{Eq, PartialEq};
-use core::marker::Sized;
-use default::Default;
use fmt;
-use hash::Hash;
-use iter::{Iterator, IntoIterator, ExactSizeIterator, FromIterator, Map, Chain, Extend};
+use hash::{Hash, BuildHasher};
+use iter::{Map, Chain, FromIterator};
use ops::{BitOr, BitAnd, BitXor, Sub};
-use option::Option::{Some, None, self};
use super::Recover;
use super::map::{self, HashMap, Keys, RandomState};
-use super::state::HashState;
const INITIAL_CAPACITY: usize = 32;
}
impl<T, S> HashSet<T, S>
- where T: Eq + Hash, S: HashState
+ where T: Eq + Hash, S: BuildHasher
{
/// Creates a new empty hash set which will use the given hasher to hash
/// keys.
///
/// The hash set is also created with the default initial capacity.
///
+ /// Warning: `hasher` is normally randomly generated, and
+ /// is designed to allow `HashSet`s to be resistant to attacks that
+ /// cause many collisions and very poor performance. Setting it
+ /// manually using this function can expose a DoS attack vector.
+ ///
/// # Examples
///
/// ```
- /// #![feature(hashmap_hasher)]
- ///
/// use std::collections::HashSet;
/// use std::collections::hash_map::RandomState;
///
/// let s = RandomState::new();
- /// let mut set = HashSet::with_hash_state(s);
+ /// let mut set = HashSet::with_hasher(s);
/// set.insert(2);
/// ```
#[inline]
- #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear",
- issue = "27713")]
- pub fn with_hash_state(hash_state: S) -> HashSet<T, S> {
- HashSet::with_capacity_and_hash_state(INITIAL_CAPACITY, hash_state)
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub fn with_hasher(hasher: S) -> HashSet<T, S> {
+ HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher)
}
/// Creates an empty HashSet with space for at least `capacity`
/// # Examples
///
/// ```
- /// #![feature(hashmap_hasher)]
- ///
/// use std::collections::HashSet;
/// use std::collections::hash_map::RandomState;
///
/// let s = RandomState::new();
- /// let mut set = HashSet::with_capacity_and_hash_state(10, s);
+ /// let mut set = HashSet::with_capacity_and_hasher(10, s);
/// set.insert(1);
/// ```
#[inline]
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub fn with_capacity_and_hasher(capacity: usize, hasher: S)
+ -> HashSet<T, S> {
+ HashSet {
+ map: HashMap::with_capacity_and_hasher(capacity, hasher),
+ }
+ }
+
+ /// Deprecated, renamed to `with_hasher`
+ #[inline]
#[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear",
issue = "27713")]
+ #[rustc_deprecated(since = "1.7.0", reason = "renamed to with_hasher")]
+ pub fn with_hash_state(hash_state: S) -> HashSet<T, S> {
+ HashSet::with_hasher(hash_state)
+ }
+
+ /// Deprecated, renamed to `with_capacity_and_hasher`
+ #[inline]
+ #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear",
+ issue = "27713")]
+ #[rustc_deprecated(since = "1.7.0",
+ reason = "renamed to with_capacity_and_hasher")]
pub fn with_capacity_and_hash_state(capacity: usize, hash_state: S)
-> HashSet<T, S> {
- HashSet {
- map: HashMap::with_capacity_and_hash_state(capacity, hash_state),
- }
+ HashSet::with_capacity_and_hasher(capacity, hash_state)
}
/// Returns the number of elements the set can hold without reallocating.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> PartialEq for HashSet<T, S>
- where T: Eq + Hash, S: HashState
+ where T: Eq + Hash, S: BuildHasher
{
fn eq(&self, other: &HashSet<T, S>) -> bool {
if self.len() != other.len() { return false; }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> Eq for HashSet<T, S>
- where T: Eq + Hash, S: HashState
+ where T: Eq + Hash, S: BuildHasher
{}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> fmt::Debug for HashSet<T, S>
where T: Eq + Hash + fmt::Debug,
- S: HashState
+ S: BuildHasher
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_set().entries(self.iter()).finish()
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> FromIterator<T> for HashSet<T, S>
where T: Eq + Hash,
- S: HashState + Default,
+ S: BuildHasher + Default,
{
fn from_iter<I: IntoIterator<Item=T>>(iterable: I) -> HashSet<T, S> {
let iter = iterable.into_iter();
let lower = iter.size_hint().0;
- let mut set = HashSet::with_capacity_and_hash_state(lower, Default::default());
+ let mut set = HashSet::with_capacity_and_hasher(lower, Default::default());
set.extend(iter);
set
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> Extend<T> for HashSet<T, S>
where T: Eq + Hash,
- S: HashState,
+ S: BuildHasher,
{
fn extend<I: IntoIterator<Item=T>>(&mut self, iter: I) {
for k in iter {
#[stable(feature = "hash_extend_copy", since = "1.4.0")]
impl<'a, T, S> Extend<&'a T> for HashSet<T, S>
where T: 'a + Eq + Hash + Copy,
- S: HashState,
+ S: BuildHasher,
{
fn extend<I: IntoIterator<Item=&'a T>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned());
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> Default for HashSet<T, S>
where T: Eq + Hash,
- S: HashState + Default,
+ S: BuildHasher + Default,
{
fn default() -> HashSet<T, S> {
- HashSet::with_hash_state(Default::default())
+ HashSet::with_hasher(Default::default())
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, T, S> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S>
where T: Eq + Hash + Clone,
- S: HashState + Default,
+ S: BuildHasher + Default,
{
type Output = HashSet<T, S>;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, T, S> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S>
where T: Eq + Hash + Clone,
- S: HashState + Default,
+ S: BuildHasher + Default,
{
type Output = HashSet<T, S>;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, T, S> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S>
where T: Eq + Hash + Clone,
- S: HashState + Default,
+ S: BuildHasher + Default,
{
type Output = HashSet<T, S>;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, T, S> Sub<&'b HashSet<T, S>> for &'a HashSet<T, S>
where T: Eq + Hash + Clone,
- S: HashState + Default,
+ S: BuildHasher + Default,
{
type Output = HashSet<T, S>;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, S> IntoIterator for &'a HashSet<T, S>
- where T: Eq + Hash, S: HashState
+ where T: Eq + Hash, S: BuildHasher
{
type Item = &'a T;
type IntoIter = Iter<'a, T>;
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> IntoIterator for HashSet<T, S>
where T: Eq + Hash,
- S: HashState
+ S: BuildHasher
{
type Item = T;
type IntoIter = IntoIter<T>;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, S> Iterator for Intersection<'a, T, S>
- where T: Eq + Hash, S: HashState
+ where T: Eq + Hash, S: BuildHasher
{
type Item = &'a T;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, S> Iterator for Difference<'a, T, S>
- where T: Eq + Hash, S: HashState
+ where T: Eq + Hash, S: BuildHasher
{
type Item = &'a T;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S>
- where T: Eq + Hash, S: HashState
+ where T: Eq + Hash, S: BuildHasher
{
type Item = &'a T;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, S> Iterator for Union<'a, T, S>
- where T: Eq + Hash, S: HashState
+ where T: Eq + Hash, S: BuildHasher
{
type Item = &'a T;
#![unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear",
issue = "27713")]
+#![rustc_deprecated(since = "1.7.0", reason = "support moved to std::hash")]
+#![allow(deprecated)]
use clone::Clone;
use default::Default;
use hash;
use marker;
-/// A trait representing stateful hashes which can be used to hash keys in a
-/// `HashMap`.
-///
-/// A HashState is used as a factory for instances of `Hasher` which a `HashMap`
-/// can then use to hash keys independently. A `HashMap` by default uses a state
-/// which will create instances of a `SipHasher`, but a custom state factory can
-/// be provided to the `with_hash_state` function.
-///
-/// If a hashing algorithm has no initial state, then the `Hasher` type for that
-/// algorithm can implement the `Default` trait and create hash maps with the
-/// `DefaultState` structure. This state is 0-sized and will simply delegate
-/// to `Default` when asked to create a hasher.
-pub trait HashState {
- /// Type of the hasher that will be created.
- type Hasher: hash::Hasher;
-
- /// Creates a new hasher based on the given state of this object.
- fn hasher(&self) -> Self::Hasher;
-}
+pub use hash::HashState;
/// A structure which is a factory for instances of `Hasher` which implement the
/// default trait.
use alloc::heap::{allocate, deallocate, EMPTY};
use cmp;
-use hash::{Hash, Hasher};
+use hash::{Hash, Hasher, BuildHasher};
use marker;
use mem::{align_of, size_of};
use mem;
use ops::{Deref, DerefMut};
use ptr::{self, Unique};
-use collections::hash_state::HashState;
use self::BucketState::*;
/// This function wraps up `hash_keyed` to be the only way outside this
/// module to generate a SafeHash.
pub fn make_hash<T: ?Sized, S>(hash_state: &S, t: &T) -> SafeHash
- where T: Hash, S: HashState
+ where T: Hash, S: BuildHasher
{
- let mut state = hash_state.hasher();
+ let mut state = hash_state.build_hasher();
t.hash(&mut state);
// We need to avoid 0 in order to prevent collisions with
// EMPTY_HASH. We can maintain our precious uniform distribution
/// HashSet.
#[unstable(feature = "hashmap_hasher", reason = "module was recently added",
issue = "27713")]
+#[rustc_deprecated(since = "1.7.0", reason = "support moved to std::hash")]
+#[allow(deprecated)]
pub mod hash_state {
pub use super::hash::state::*;
}
reason = "API has not been scrutinized and is highly likely to \
either disappear or change",
issue = "27810")]
-#![rustc_deprecated(since = "1.5.0", reason = "replaced with 'dylib' on crates.io")]
#![allow(missing_docs)]
#![allow(deprecated)]
use ffi::{CString, OsString};
use path::{Path, PathBuf};
+#[unstable(feature = "dynamic_lib",
+ reason = "API has not been scrutinized and is highly likely to \
+ either disappear or change",
+ issue = "27810")]
+#[rustc_deprecated(since = "1.5.0", reason = "replaced with 'dylib' on crates.io")]
pub struct DynamicLibrary {
handle: *mut u8
}
}
}
+#[unstable(feature = "dynamic_lib",
+ reason = "API has not been scrutinized and is highly likely to \
+ either disappear or change",
+ issue = "27810")]
+#[rustc_deprecated(since = "1.5.0", reason = "replaced with 'dylib' on crates.io")]
impl DynamicLibrary {
/// Lazily open a dynamic library. When passed None it gives a
/// handle to the calling process
use prelude::v1::*;
use libc;
use mem;
- use path::Path;
#[test]
#[cfg_attr(any(windows,
target_os = "openbsd"))]
#[allow(deprecated)]
fn test_errors_do_not_crash() {
+ use path::Path;
+
// Open /dev/null as a library to get an error, and make sure
// that only causes an error, and not a crash.
let path = Path::new("/dev/null");
thread::spawn(|| {
let mut writer = BufWriter::new(PanicWriter);
- writer.write(b"hello world");
- writer.flush();
+ let _ = writer.write(b"hello world");
+ let _ = writer.flush();
}).join().err().unwrap();
assert_eq!(WRITES.load(Ordering::SeqCst), 1);
impl<R: io::Read> io::Read for Maybe<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match *self {
- Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), buf.len()),
+ Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), 0),
Maybe::Fake => Ok(0)
}
}
#![feature(float_from_str_radix)]
#![feature(fnbox)]
#![feature(heap_api)]
+#![feature(hashmap_hasher)]
#![feature(int_error_internals)]
#![feature(into_cow)]
#![feature(lang_items)]
#![deny(missing_docs)]
#![allow(unused_features)] // std may use features in a platform-specific way
+#![cfg_attr(not(stage0), deny(warnings))]
#[cfg(test)] extern crate test;
#[cfg(test)] #[macro_use] extern crate log;
}
#[cfg(test)]
+#[allow(unused_imports)]
mod tests {
use any::TypeId;
use libc;
use cell::RefCell;
use intrinsics;
use sync::StaticRwLock;
+use sync::atomic::{AtomicBool, Ordering};
use sys::stdio::Stderr;
use sys_common::backtrace;
use sys_common::thread_info;
static HANDLER_LOCK: StaticRwLock = StaticRwLock::new();
static mut HANDLER: Handler = Handler::Default;
+static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
/// Registers a custom panic handler, replacing any that was previously
/// registered.
let write = |err: &mut ::io::Write| {
let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}",
name, msg, file, line);
+
if log_backtrace {
let _ = backtrace::write(err);
+ } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
+ let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace.");
}
};
"{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2,
$ends_with, ends_with);
- let relative_from = path1.relative_from(path2).map(|p| p.to_str().unwrap());
+ let relative_from = path1.strip_prefix(path2)
+ .map(|p| p.to_str().unwrap())
+ .ok();
let exp: Option<&str> = $relative_from;
assert!(relative_from == exp,
- "{:?}.relative_from({:?}), expected {:?}, got {:?}", $path1, $path2,
- exp, relative_from);
+ "{:?}.strip_prefix({:?}), expected {:?}, got {:?}",
+ $path1, $path2, exp, relative_from);
});
);
// FIXME(#10380) these tests should not all be ignored on android.
- #[cfg(not(target_os="android"))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
fn smoke() {
let p = Command::new("true").spawn();
assert!(p.is_ok());
assert!(p.wait().unwrap().success());
}
- #[cfg(not(target_os="android"))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
fn smoke_failure() {
match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() {
Ok(..) => panic!(),
}
}
- #[cfg(not(target_os="android"))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
fn exit_reported_right() {
let p = Command::new("false").spawn();
assert!(p.is_ok());
drop(p.wait());
}
- #[cfg(all(unix, not(target_os="android")))]
#[test]
+ #[cfg(unix)]
+ #[cfg_attr(target_os = "android", ignore)]
fn signal_reported_right() {
use os::unix::process::ExitStatusExt;
return ret;
}
- #[cfg(not(target_os="android"))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
fn stdout_works() {
let mut cmd = Command::new("echo");
cmd.arg("foobar").stdout(Stdio::piped());
assert_eq!(run_output(cmd), "foobar\n");
}
- #[cfg(all(unix, not(target_os="android")))]
#[test]
+ #[cfg_attr(any(windows, target_os = "android"), ignore)]
fn set_current_dir_works() {
let mut cmd = Command::new("/bin/sh");
cmd.arg("-c").arg("pwd")
assert_eq!(run_output(cmd), "/\n");
}
- #[cfg(all(unix, not(target_os="android")))]
#[test]
+ #[cfg_attr(any(windows, target_os = "android"), ignore)]
fn stdin_works() {
let mut p = Command::new("/bin/sh")
.arg("-c").arg("read line; echo $line")
}
- #[cfg(all(unix, not(target_os="android")))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ #[cfg(unix)]
fn uid_works() {
use os::unix::prelude::*;
use libc;
assert!(p.wait().unwrap().success());
}
- #[cfg(all(unix, not(target_os="android")))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
+ #[cfg(unix)]
fn uid_to_root_fails() {
use os::unix::prelude::*;
use libc;
assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err());
}
- #[cfg(not(target_os="android"))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
fn test_process_status() {
let mut status = Command::new("false").status().unwrap();
assert!(status.code() == Some(1));
}
}
- #[cfg(not(target_os="android"))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
fn test_process_output_output() {
let Output {status, stdout, stderr}
= Command::new("echo").arg("hello").output().unwrap();
assert_eq!(stderr, Vec::new());
}
- #[cfg(not(target_os="android"))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
fn test_process_output_error() {
let Output {status, stdout, stderr}
= Command::new("mkdir").arg(".").output().unwrap();
assert!(!stderr.is_empty());
}
- #[cfg(not(target_os="android"))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
fn test_finish_once() {
let mut prog = Command::new("false").spawn().unwrap();
assert!(prog.wait().unwrap().code() == Some(1));
}
- #[cfg(not(target_os="android"))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
fn test_finish_twice() {
let mut prog = Command::new("false").spawn().unwrap();
assert!(prog.wait().unwrap().code() == Some(1));
assert!(prog.wait().unwrap().code() == Some(1));
}
- #[cfg(not(target_os="android"))]
#[test]
+ #[cfg_attr(target_os = "android", ignore)]
fn test_wait_with_output_once() {
let prog = Command::new("echo").arg("hello").stdout(Stdio::piped())
.spawn().unwrap();
cmd
}
- #[cfg(not(target_os="android"))]
#[test]
fn test_inherit_env() {
use env;
let output = String::from_utf8(result.stdout).unwrap();
for (ref k, ref v) in env::vars() {
+ // don't check android RANDOM variables
+ if cfg!(target_os = "android") && *k == "RANDOM" {
+ continue
+ }
+
// Windows has hidden environment variables whose names start with
// equals signs (`=`). Those do not show up in the output of the
// `set` command.
assert!((cfg!(windows) && k.starts_with("=")) ||
k.starts_with("DYLD") ||
- output.contains(&format!("{}={}", *k, *v)),
+ output.contains(&format!("{}={}", *k, *v)) ||
+ output.contains(&format!("{}='{}'", *k, *v)),
"output doesn't contain `{}={}`\n{}",
k, v, output);
}
}
- #[cfg(target_os="android")]
- #[test]
- fn test_inherit_env() {
- use env;
-
- let mut result = env_cmd().output().unwrap();
- let output = String::from_utf8(result.stdout).unwrap();
-
- for (ref k, ref v) in env::vars() {
- // don't check android RANDOM variables
- if *k != "RANDOM".to_string() {
- assert!(output.contains(&format!("{}={}",
- *k,
- *v)) ||
- output.contains(&format!("{}=\'{}\'",
- *k,
- *v)));
- }
- }
- }
#[test]
fn test_override_env() {
fn fmt_debug_handle() {
let (_, rx) = channel::<i32>();
let sel = Select::new();
- let mut handle = sel.handle(&rx);
+ let handle = sel.handle(&rx);
assert_eq!(format!("{:?}", handle), "Handle { .. }");
}
}
reason = "the interaction between semaphores and the acquisition/release \
of resources is currently unclear",
issue = "27798")]
-#![rustc_deprecated(since = "1.7.0",
- reason = "easily confused with system semaphores and not \
- used enough to pull its weight")]
#![allow(deprecated)]
use ops::Drop;
/// // Release our initially acquired resource
/// sem.release();
/// ```
+#[rustc_deprecated(since = "1.7.0",
+ reason = "easily confused with system semaphores and not \
+ used enough to pull its weight")]
+#[unstable(feature = "semaphore",
+ reason = "the interaction between semaphores and the acquisition/release \
+ of resources is currently unclear",
+ issue = "27798")]
pub struct Semaphore {
lock: Mutex<isize>,
cvar: Condvar,
/// An RAII guard which will release a resource acquired from a semaphore when
/// dropped.
+#[rustc_deprecated(since = "1.7.0",
+ reason = "easily confused with system semaphores and not \
+ used enough to pull its weight")]
+#[unstable(feature = "semaphore",
+ reason = "the interaction between semaphores and the acquisition/release \
+ of resources is currently unclear",
+ issue = "27798")]
pub struct SemaphoreGuard<'a> {
sem: &'a Semaphore,
}
+#[rustc_deprecated(since = "1.7.0",
+ reason = "easily confused with system semaphores and not \
+ used enough to pull its weight")]
+#[unstable(feature = "semaphore",
+ reason = "the interaction between semaphores and the acquisition/release \
+ of resources is currently unclear",
+ issue = "27798")]
impl Semaphore {
/// Creates a new semaphore with the initial count specified.
///
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(missing_docs)]
-#![allow(non_camel_case_types)]
+#![allow(missing_docs, bad_style)]
use io::{self, ErrorKind};
use libc;
use num::One;
use ops::Neg;
-use alloc::oom;
#[cfg(target_os = "android")] pub use os::android as platform;
#[cfg(target_os = "bitrig")] pub use os::bitrig as platform;
pub mod time;
pub mod stdio;
-// A nicer handler for out-of-memory situations than the default one. This one
-// prints a message to stderr before aborting. It is critical that this code
-// does not allocate any memory since we are in an OOM situation. Any errors are
-// ignored while printing since there's nothing we can do about them and we are
-// about to exit anyways.
-fn oom_handler() -> ! {
- use intrinsics;
- let msg = "fatal runtime error: out of memory\n";
- unsafe {
- libc::write(libc::STDERR_FILENO,
- msg.as_ptr() as *const libc::c_void,
- msg.len() as libc::size_t);
- intrinsics::abort();
- }
-}
-
-#[cfg(not(any(target_os = "nacl", test)))]
+#[cfg(not(test))]
pub fn init() {
- use libc::signal;
+ use alloc::oom;
+
// By default, some platforms will send a *signal* when an EPIPE error
// would otherwise be delivered. This runtime doesn't install a SIGPIPE
// handler, causing it to kill the program, which isn't exactly what we
// Hence, we set SIGPIPE to ignore when the program starts up in order
// to prevent this problem.
unsafe {
- assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
+ reset_sigpipe();
}
oom::set_oom_handler(oom_handler);
-}
-#[cfg(all(target_os = "nacl", not(test)))]
-pub fn init() {
- oom::set_oom_handler(oom_handler);
+ // A nicer handler for out-of-memory situations than the default one. This
+ // one prints a message to stderr before aborting. It is critical that this
+ // code does not allocate any memory since we are in an OOM situation. Any
+ // errors are ignored while printing since there's nothing we can do about
+ // them and we are about to exit anyways.
+ fn oom_handler() -> ! {
+ use intrinsics;
+ let msg = "fatal runtime error: out of memory\n";
+ unsafe {
+ libc::write(libc::STDERR_FILENO,
+ msg.as_ptr() as *const libc::c_void,
+ msg.len() as libc::size_t);
+ intrinsics::abort();
+ }
+ }
+
+ #[cfg(not(target_os = "nacl"))]
+ unsafe fn reset_sigpipe() {
+ assert!(libc::signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
+ }
+ #[cfg(target_os = "nacl")]
+ unsafe fn reset_sigpipe() {}
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
// <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.
+
#![cfg_attr(test, allow(dead_code))]
use libc;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(dead_code)]
-
use prelude::v1::*;
use alloc::boxed::FnBox;
not(target_os = "bitrig"),
not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
not(target_os = "openbsd")))]
+#[cfg_attr(test, allow(dead_code))]
pub mod guard {
pub unsafe fn current() -> Option<usize> { None }
pub unsafe fn init() -> Option<usize> { None }
target_os = "bitrig",
all(target_os = "netbsd", not(target_vendor = "rumprun")),
target_os = "openbsd"))]
-#[allow(unused_imports)]
+#[cfg_attr(test, allow(dead_code))]
pub mod guard {
use prelude::v1::*;
- use libc::{self, pthread_t};
+ use libc;
use libc::mmap;
use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
- use mem;
- use ptr;
use sys::os;
#[cfg(any(target_os = "macos",
#[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
let mut ret = None;
- let mut attr: libc::pthread_attr_t = mem::zeroed();
+ let mut attr: libc::pthread_attr_t = ::mem::zeroed();
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
if libc::pthread_getattr_np(libc::pthread_self(), &mut attr) == 0 {
- let mut stackaddr = ptr::null_mut();
+ let mut stackaddr = ::ptr::null_mut();
let mut stacksize = 0;
assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
&mut stacksize), 0);
#[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
pub unsafe fn current() -> Option<usize> {
- let mut current_stack: libc::stack_t = mem::zeroed();
+ let mut current_stack: libc::stack_t = ::mem::zeroed();
assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
&mut current_stack), 0);
#[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
pub unsafe fn current() -> Option<usize> {
let mut ret = None;
- let mut attr: libc::pthread_attr_t = mem::zeroed();
+ let mut attr: libc::pthread_attr_t = ::mem::zeroed();
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
if libc::pthread_getattr_np(libc::pthread_self(), &mut attr) == 0 {
let mut guardsize = 0;
if guardsize == 0 {
panic!("there is no guard page");
}
- let mut stackaddr = ptr::null_mut();
+ let mut stackaddr = ::ptr::null_mut();
let mut size = 0;
assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
&mut size), 0);
fn directory_junctions_are_directories() {
use ffi::OsStr;
use env;
- use rand::{self, StdRng, Rng};
+ use rand::{self, Rng};
use vec::Vec;
macro_rules! t {
let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
let mut db = data.as_mut_ptr()
as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER;
- let mut buf = &mut (*db).ReparseTarget as *mut _;
+ let buf = &mut (*db).ReparseTarget as *mut _;
let mut i = 0;
let v = br"\??\";
let v = v.iter().map(|x| *x as u16);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(missing_docs)]
-#![allow(non_camel_case_types)]
-#![allow(non_snake_case)]
+#![allow(missing_docs, bad_style)]
use prelude::v1::*;
use os::windows::ffi::{OsStrExt, OsStringExt};
use path::PathBuf;
use time::Duration;
-use alloc::oom;
#[macro_use] pub mod compat;
pub mod time;
pub mod stdio;
-// See comment in sys/unix/mod.rs
-fn oom_handler() -> ! {
- use intrinsics;
- use ptr;
- let msg = "fatal runtime error: out of memory\n";
- unsafe {
- // WriteFile silently fails if it is passed an invalid handle, so there
- // is no need to check the result of GetStdHandle.
- c::WriteFile(c::GetStdHandle(c::STD_ERROR_HANDLE),
- msg.as_ptr() as c::LPVOID,
- msg.len() as c::DWORD,
- ptr::null_mut(),
- ptr::null_mut());
- intrinsics::abort();
- }
-}
-
+#[cfg(not(test))]
pub fn init() {
- oom::set_oom_handler(oom_handler);
+ ::alloc::oom::set_oom_handler(oom_handler);
+
+ // See comment in sys/unix/mod.rs
+ fn oom_handler() -> ! {
+ use intrinsics;
+ use ptr;
+ let msg = "fatal runtime error: out of memory\n";
+ unsafe {
+ // WriteFile silently fails if it is passed an invalid handle, so
+ // there is no need to check the result of GetStdHandle.
+ c::WriteFile(c::GetStdHandle(c::STD_ERROR_HANDLE),
+ msg.as_ptr() as c::LPVOID,
+ msg.len() as c::DWORD,
+ ptr::null_mut(),
+ ptr::null_mut());
+ intrinsics::abort();
+ }
+ }
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
impl Stdio {
fn to_handle(&self, stdio_id: c::DWORD) -> io::Result<Handle> {
match *self {
+ // If no stdio handle is available, then inherit means that it
+ // should still be unavailable so propagate the
+ // INVALID_HANDLE_VALUE.
Stdio::Inherit => {
- stdio::get(stdio_id).and_then(|io| {
- io.handle().duplicate(0, true, c::DUPLICATE_SAME_ACCESS)
- })
+ match stdio::get(stdio_id) {
+ Ok(io) => io.handle().duplicate(0, true,
+ c::DUPLICATE_SAME_ACCESS),
+ Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)),
+ }
}
Stdio::Raw(handle) => {
RawHandle::new(handle).duplicate(0, true, c::DUPLICATE_SAME_ACCESS)
#[cfg(test)]
mod tests {
use prelude::v1::*;
- use str;
use ffi::{OsStr, OsString};
use super::make_command_line;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![cfg_attr(test, allow(dead_code))]
+
use sys_common::util::report_overflow;
use sys::c;
pub fn into_handle(self) -> Handle { self.handle }
}
+#[cfg_attr(test, allow(dead_code))]
pub mod guard {
pub unsafe fn current() -> Option<usize> { None }
pub unsafe fn init() -> Option<usize> { None }
use self::Destination::*;
-use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span};
+use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, DUMMY_SP, Pos, Span};
use diagnostics;
use errors::{Level, RenderSpan, DiagnosticBuilder};
lvl: Level) {
let error = match sp {
Some(COMMAND_LINE_SP) => self.emit_(FileLine(COMMAND_LINE_SP), msg, code, lvl),
+ Some(DUMMY_SP) | None => print_diagnostic(&mut self.dst, "", lvl, msg, code),
Some(sp) => self.emit_(FullSpan(sp), msg, code, lvl),
- None => print_diagnostic(&mut self.dst, "", lvl, msg, code),
};
if let Err(e) = error {
},
"path" | "ty" => {
match *tok {
- OpenDelim(token::DelimToken::Brace) |
+ OpenDelim(token::DelimToken::Brace) | OpenDelim(token::DelimToken::Bracket) |
Comma | FatArrow | Colon | Eq | Gt | Semi | BinOp(token::Or) => Ok(true),
Ident(i, _) if (i.name.as_str() == "as" ||
i.name.as_str() == "where") => Ok(true),
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/",
test(attr(deny(warnings))))]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(associated_consts)]
#![feature(filling_drop)]
ex = ExprBreak(None);
}
hi = self.last_span.hi;
+ } else if self.token.is_keyword(keywords::Let) {
+ // Catch this syntax error here, instead of in `check_strict_keywords`, so
+ // that we can explicitly mention that let is not to be used as an expression
+ let mut db = self.fatal("expected expression, found statement (`let`)");
+ db.note("variable declaration using `let` is a statement");
+ return Err(db);
} else if self.check(&token::ModSep) ||
self.token.is_ident() &&
!self.check_keyword(keywords::True) &&
}
pub fn arg_to_string(arg: &ast::Arg) -> String {
- to_string(|s| s.print_arg(arg))
+ to_string(|s| s.print_arg(arg, false))
}
pub fn mac_to_string(arg: &ast::Mac) -> String {
}
pub fn print_fn_args(&mut self, decl: &ast::FnDecl,
- opt_explicit_self: Option<&ast::ExplicitSelf_>)
- -> io::Result<()> {
+ opt_explicit_self: Option<&ast::ExplicitSelf_>,
+ is_closure: bool) -> io::Result<()> {
// It is unfortunate to duplicate the commasep logic, but we want the
// self type and the args all in the same box.
try!(self.rbox(0, Inconsistent));
for arg in args {
if first { first = false; } else { try!(self.word_space(",")); }
- try!(self.print_arg(arg));
+ try!(self.print_arg(arg, is_closure));
}
self.end()
opt_explicit_self: Option<&ast::ExplicitSelf_>)
-> io::Result<()> {
try!(self.popen());
- try!(self.print_fn_args(decl, opt_explicit_self));
+ try!(self.print_fn_args(decl, opt_explicit_self, false));
if decl.variadic {
try!(word(&mut self.s, ", ..."));
}
decl: &ast::FnDecl)
-> io::Result<()> {
try!(word(&mut self.s, "|"));
- try!(self.print_fn_args(decl, None));
+ try!(self.print_fn_args(decl, None, true));
try!(word(&mut self.s, "|"));
if let ast::DefaultReturn(..) = decl.output {
self.print_type(&*mt.ty)
}
- pub fn print_arg(&mut self, input: &ast::Arg) -> io::Result<()> {
+ pub fn print_arg(&mut self, input: &ast::Arg, is_closure: bool) -> io::Result<()> {
try!(self.ibox(INDENT_UNIT));
match input.ty.node {
- ast::TyInfer => try!(self.print_pat(&*input.pat)),
+ ast::TyInfer if is_closure => try!(self.print_pat(&*input.pat)),
_ => {
match input.pat.node {
ast::PatIdent(_, ref path1, _) if
use super::*;
use ast;
- use ast_util;
use codemap;
use parse::token;
//! Syntax extensions in the Rust compiler.
#![crate_name = "syntax_ext"]
+#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
-
-#![unstable(feature = "rustc_private", issue = "27812")]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(rustc_private)]
#![feature(staged_api)]
html_playground_url = "https://play.rust-lang.org/",
test(attr(deny(warnings))))]
#![deny(missing_docs)]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(box_syntax)]
#![feature(staged_api)]
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/",
test(attr(deny(warnings))))]
+#![cfg_attr(not(stage0), deny(warnings))]
#![feature(asm)]
#![feature(box_syntax)]
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// Check the macro follow sets (see corresponding rpass test).
+
+// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)}
+macro_rules! follow_pat {
+ ($p:pat ()) => {}; //~WARN `$p:pat` is followed by `(`
+ ($p:pat []) => {}; //~WARN `$p:pat` is followed by `[`
+ ($p:pat {}) => {}; //~WARN `$p:pat` is followed by `{`
+ ($p:pat :) => {}; //~ERROR `$p:pat` is followed by `:`
+ ($p:pat >) => {}; //~ERROR `$p:pat` is followed by `>`
+ ($p:pat +) => {}; //~ERROR `$p:pat` is followed by `+`
+ ($p:pat ident) => {}; //~ERROR `$p:pat` is followed by `ident`
+ ($p:pat $p:pat) => {}; //~ERROR `$p:pat` is followed by `$p:pat`
+ ($p:pat $e:expr) => {}; //~ERROR `$p:pat` is followed by `$e:expr`
+ ($p:pat $t:ty) => {}; //~ERROR `$p:pat` is followed by `$t:ty`
+ ($p:pat $s:stmt) => {}; //~ERROR `$p:pat` is followed by `$s:stmt`
+ ($p:pat $p:path) => {}; //~ERROR `$p:pat` is followed by `$p:path`
+ ($p:pat $b:block) => {}; //~ERROR `$p:pat` is followed by `$b:block`
+ ($p:pat $i:ident) => {}; //~ERROR `$p:pat` is followed by `$i:ident`
+ ($p:pat $t:tt) => {}; //~ERROR `$p:pat` is followed by `$t:tt`
+ ($p:pat $i:item) => {}; //~ERROR `$p:pat` is followed by `$i:item`
+ ($p:pat $m:meta) => {}; //~ERROR `$p:pat` is followed by `$m:meta`
+}
+// FOLLOW(expr) = {FatArrow, Comma, Semicolon}
+macro_rules! follow_expr {
+ ($e:expr ()) => {}; //~WARN `$e:expr` is followed by `(`
+ ($e:expr []) => {}; //~WARN `$e:expr` is followed by `[`
+ ($e:expr {}) => {}; //~WARN `$e:expr` is followed by `{`
+ ($e:expr =) => {}; //~ERROR `$e:expr` is followed by `=`
+ ($e:expr |) => {}; //~ERROR `$e:expr` is followed by `|`
+ ($e:expr :) => {}; //~ERROR `$e:expr` is followed by `:`
+ ($e:expr >) => {}; //~ERROR `$e:expr` is followed by `>`
+ ($e:expr +) => {}; //~ERROR `$e:expr` is followed by `+`
+ ($e:expr ident) => {}; //~ERROR `$e:expr` is followed by `ident`
+ ($e:expr if) => {}; //~ERROR `$e:expr` is followed by `if`
+ ($e:expr in) => {}; //~ERROR `$e:expr` is followed by `in`
+ ($e:expr $p:pat) => {}; //~ERROR `$e:expr` is followed by `$p:pat`
+ ($e:expr $e:expr) => {}; //~ERROR `$e:expr` is followed by `$e:expr`
+ ($e:expr $t:ty) => {}; //~ERROR `$e:expr` is followed by `$t:ty`
+ ($e:expr $s:stmt) => {}; //~ERROR `$e:expr` is followed by `$s:stmt`
+ ($e:expr $p:path) => {}; //~ERROR `$e:expr` is followed by `$p:path`
+ ($e:expr $b:block) => {}; //~ERROR `$e:expr` is followed by `$b:block`
+ ($e:expr $i:ident) => {}; //~ERROR `$e:expr` is followed by `$i:ident`
+ ($e:expr $t:tt) => {}; //~ERROR `$e:expr` is followed by `$t:tt`
+ ($e:expr $i:item) => {}; //~ERROR `$e:expr` is followed by `$i:item`
+ ($e:expr $m:meta) => {}; //~ERROR `$e:expr` is followed by `$m:meta`
+}
+// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or,
+// Ident(as), Ident(where), OpenDelim(Bracket)}
+macro_rules! follow_ty {
+ ($t:ty ()) => {}; //~WARN `$t:ty` is followed by `(`
+ ($t:ty []) => {}; // ok (RFC 1462)
+ ($t:ty +) => {}; //~ERROR `$t:ty` is followed by `+`
+ ($t:ty ident) => {}; //~ERROR `$t:ty` is followed by `ident`
+ ($t:ty if) => {}; //~ERROR `$t:ty` is followed by `if`
+ ($t:ty $p:pat) => {}; //~ERROR `$t:ty` is followed by `$p:pat`
+ ($t:ty $e:expr) => {}; //~ERROR `$t:ty` is followed by `$e:expr`
+ ($t:ty $t:ty) => {}; //~ERROR `$t:ty` is followed by `$t:ty`
+ ($t:ty $s:stmt) => {}; //~ERROR `$t:ty` is followed by `$s:stmt`
+ ($t:ty $p:path) => {}; //~ERROR `$t:ty` is followed by `$p:path`
+ ($t:ty $b:block) => {}; //~ERROR `$t:ty` is followed by `$b:block`
+ ($t:ty $i:ident) => {}; //~ERROR `$t:ty` is followed by `$i:ident`
+ ($t:ty $t:tt) => {}; //~ERROR `$t:ty` is followed by `$t:tt`
+ ($t:ty $i:item) => {}; //~ERROR `$t:ty` is followed by `$i:item`
+ ($t:ty $m:meta) => {}; //~ERROR `$t:ty` is followed by `$m:meta`
+}
+// FOLLOW(stmt) = FOLLOW(expr)
+macro_rules! follow_stmt {
+ ($s:stmt ()) => {}; //~WARN `$s:stmt` is followed by `(`
+ ($s:stmt []) => {}; //~WARN `$s:stmt` is followed by `[`
+ ($s:stmt {}) => {}; //~WARN `$s:stmt` is followed by `{`
+ ($s:stmt =) => {}; //~ERROR `$s:stmt` is followed by `=`
+ ($s:stmt |) => {}; //~ERROR `$s:stmt` is followed by `|`
+ ($s:stmt :) => {}; //~ERROR `$s:stmt` is followed by `:`
+ ($s:stmt >) => {}; //~ERROR `$s:stmt` is followed by `>`
+ ($s:stmt +) => {}; //~ERROR `$s:stmt` is followed by `+`
+ ($s:stmt ident) => {}; //~ERROR `$s:stmt` is followed by `ident`
+ ($s:stmt if) => {}; //~ERROR `$s:stmt` is followed by `if`
+ ($s:stmt in) => {}; //~ERROR `$s:stmt` is followed by `in`
+ ($s:stmt $p:pat) => {}; //~ERROR `$s:stmt` is followed by `$p:pat`
+ ($s:stmt $e:expr) => {}; //~ERROR `$s:stmt` is followed by `$e:expr`
+ ($s:stmt $t:ty) => {}; //~ERROR `$s:stmt` is followed by `$t:ty`
+ ($s:stmt $s:stmt) => {}; //~ERROR `$s:stmt` is followed by `$s:stmt`
+ ($s:stmt $p:path) => {}; //~ERROR `$s:stmt` is followed by `$p:path`
+ ($s:stmt $b:block) => {}; //~ERROR `$s:stmt` is followed by `$b:block`
+ ($s:stmt $i:ident) => {}; //~ERROR `$s:stmt` is followed by `$i:ident`
+ ($s:stmt $t:tt) => {}; //~ERROR `$s:stmt` is followed by `$t:tt`
+ ($s:stmt $i:item) => {}; //~ERROR `$s:stmt` is followed by `$i:item`
+ ($s:stmt $m:meta) => {}; //~ERROR `$s:stmt` is followed by `$m:meta`
+}
+// FOLLOW(path) = FOLLOW(ty)
+macro_rules! follow_path {
+ ($p:path ()) => {}; //~WARN `$p:path` is followed by `(`
+ ($p:path []) => {}; // ok (RFC 1462)
+ ($p:path +) => {}; //~ERROR `$p:path` is followed by `+`
+ ($p:path ident) => {}; //~ERROR `$p:path` is followed by `ident`
+ ($p:path if) => {}; //~ERROR `$p:path` is followed by `if`
+ ($p:path $p:pat) => {}; //~ERROR `$p:path` is followed by `$p:pat`
+ ($p:path $e:expr) => {}; //~ERROR `$p:path` is followed by `$e:expr`
+ ($p:path $t:ty) => {}; //~ERROR `$p:path` is followed by `$t:ty`
+ ($p:path $s:stmt) => {}; //~ERROR `$p:path` is followed by `$s:stmt`
+ ($p:path $p:path) => {}; //~ERROR `$p:path` is followed by `$p:path`
+ ($p:path $b:block) => {}; //~ERROR `$p:path` is followed by `$b:block`
+ ($p:path $i:ident) => {}; //~ERROR `$p:path` is followed by `$i:ident`
+ ($p:path $t:tt) => {}; //~ERROR `$p:path` is followed by `$t:tt`
+ ($p:path $i:item) => {}; //~ERROR `$p:path` is followed by `$i:item`
+ ($p:path $m:meta) => {}; //~ERROR `$p:path` is followed by `$m:meta`
+}
+// FOLLOW(block) = any token
+// FOLLOW(ident) = any token
+
+fn main() {}
+
second: Option<[usize; 4]>
}
-enum Color {
- Red,
- Green,
- CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
-}
-
fn struct_with_a_nested_enum_and_vector() {
match (Foo { first: true, second: None }) {
//~^ ERROR non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
}
}
-fn enum_with_multiple_missing_variants() {
+enum Color {
+ Red,
+ Green,
+ CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
+}
+
+fn enum_with_single_missing_variant() {
match Color::Red {
//~^ ERROR non-exhaustive patterns: `Red` not covered
- Color::CustomRGBA { .. } => ()
+ Color::CustomRGBA { .. } => (),
+ Color::Green => ()
+ }
+}
+
+enum Direction {
+ North, East, South, West
+}
+
+fn enum_with_multiple_missing_variants() {
+ match Direction::North {
+ //~^ ERROR non-exhaustive patterns: `East`, `South` and `West` not covered
+ Direction::North => ()
+ }
+}
+
+enum ExcessiveEnum {
+ First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth
+}
+
+fn enum_with_excessive_missing_variants() {
+ match ExcessiveEnum::First {
+ //~^ ERROR `Second`, `Third`, `Fourth` and 8 more not covered
+
+ ExcessiveEnum::First => ()
}
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// pp-exact:issue-31073.pp
+
+fn main() {
+ fn f1(x: i32, y: i32) -> i32 { y }
+ let f: fn(_, i32) -> i32 = f1;
+ f(1, 2);
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// pp-exact:issue-31073.pp
+
+fn main() {
+ fn f1(x: i32, y: i32) -> i32 { y }
+ let f: fn(_, i32) -> i32 = f1;
+ f(1, 2);
+}
// ignore-cross-compile
-// error-pattern:expected identifier, found keyword `let`
+// error-pattern:expected expression, found statement (`let`)
#![feature(quote, rustc_private)]
use rustc::middle::ty;
use rustc::session::config::{self, basic_options, build_configuration, Input, Options};
use rustc::session::build_session;
-use rustc_driver::driver;
+use rustc_driver::{driver, abort_on_err};
use rustc_front::lowering::{lower_crate, LoweringContext};
use rustc_resolve::MakeGlobMap;
use rustc_metadata::cstore::CStore;
let arenas = ty::CtxtArenas::new();
let ast_map = driver::make_map(&sess, &mut hir_forest);
- driver::phase_3_run_analysis_passes(
+ abort_on_err(driver::phase_3_run_analysis_passes(
&sess, &cstore, ast_map, &arenas, &id,
MakeGlobMap::No, |tcx, mir_map, analysis| {
let modp = llmod as usize;
(modp, deps)
- })
+ }), &sess)
}).unwrap();
match handle.join() {
let cfg = build_configuration(&sess);
let control = CompileController::basic();
- compile_input(sess, &cstore,
+ compile_input(&sess, &cstore,
cfg,
&Input::Str(code),
&None,
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests that items in subscopes can shadow type parameters and local variables (see issue #23880).
+
+#![allow(unused)]
+struct Foo<X> { x: Box<X> }
+impl<Bar> Foo<Bar> {
+ fn foo(&self) {
+ type Bar = i32;
+ let _: Bar = 42;
+ }
+}
+
+fn main() {
+ let f = 1;
+ {
+ fn f() {}
+ f();
+ }
+}
--- /dev/null
+// Copyright 2015 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.
+
+#![feature(stmt_expr_attributes)]
+#![deny(unused_parens)]
+
+// Tests that lint attributes on statements/expressions are
+// correctly applied to non-builtin early (AST) lints
+
+fn main() {
+ #[allow(unused_parens)]
+ {
+ let _ = (9);
+ }
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check the macro follow sets (see corresponding cfail test).
+
+// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)}
+macro_rules! follow_pat {
+ ($p:pat =>) => {};
+ ($p:pat ,) => {};
+ ($p:pat =) => {};
+ ($p:pat |) => {};
+ ($p:pat if) => {};
+ ($p:pat in) => {};
+}
+// FOLLOW(expr) = {FatArrow, Comma, Semicolon}
+macro_rules! follow_expr {
+ ($e:expr =>) => {};
+ ($e:expr ,) => {};
+ ($e:expr ;) => {};
+}
+// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or,
+// Ident(as), Ident(where), OpenDelim(Bracket)}
+macro_rules! follow_ty {
+ ($t:ty {}) => {};
+ ($t:ty ,) => {};
+ ($t:ty =>) => {};
+ ($t:ty :) => {};
+ ($t:ty =) => {};
+ ($t:ty >) => {};
+ ($t:ty ;) => {};
+ ($t:ty |) => {};
+ ($t:ty as) => {};
+ ($t:ty where) => {};
+ ($t:ty []) => {};
+}
+// FOLLOW(stmt) = FOLLOW(expr)
+macro_rules! follow_stmt {
+ ($s:stmt =>) => {};
+ ($s:stmt ,) => {};
+ ($s:stmt ;) => {};
+}
+// FOLLOW(path) = FOLLOW(ty)
+macro_rules! follow_path {
+ ($p:path {}) => {};
+ ($p:path ,) => {};
+ ($p:path =>) => {};
+ ($p:path :) => {};
+ ($p:path =) => {};
+ ($p:path >) => {};
+ ($p:path ;) => {};
+ ($p:path |) => {};
+ ($p:path as) => {};
+ ($p:path where) => {};
+ ($p:path []) => {};
+}
+// FOLLOW(block) = any token
+macro_rules! follow_block {
+ ($b:block ()) => {};
+ ($b:block []) => {};
+ ($b:block {}) => {};
+ ($b:block ,) => {};
+ ($b:block =>) => {};
+ ($b:block :) => {};
+ ($b:block =) => {};
+ ($b:block >) => {};
+ ($b:block ;) => {};
+ ($b:block |) => {};
+ ($b:block +) => {};
+ ($b:block ident) => {};
+ ($b:block $p:pat) => {};
+ ($b:block $e:expr) => {};
+ ($b:block $t:ty) => {};
+ ($b:block $s:stmt) => {};
+ ($b:block $p:path) => {};
+ ($b:block $b:block) => {};
+ ($b:block $i:ident) => {};
+ ($b:block $t:tt) => {};
+ ($b:block $i:item) => {};
+ ($b:block $m:meta) => {};
+}
+// FOLLOW(ident) = any token
+macro_rules! follow_ident {
+ ($i:ident ()) => {};
+ ($i:ident []) => {};
+ ($i:ident {}) => {};
+ ($i:ident ,) => {};
+ ($i:ident =>) => {};
+ ($i:ident :) => {};
+ ($i:ident =) => {};
+ ($i:ident >) => {};
+ ($i:ident ;) => {};
+ ($i:ident |) => {};
+ ($i:ident +) => {};
+ ($i:ident ident) => {};
+ ($i:ident $p:pat) => {};
+ ($i:ident $e:expr) => {};
+ ($i:ident $t:ty) => {};
+ ($i:ident $s:stmt) => {};
+ ($i:ident $p:path) => {};
+ ($i:ident $b:block) => {};
+ ($i:ident $i:ident) => {};
+ ($i:ident $t:tt) => {};
+ ($i:ident $i:item) => {};
+ ($i:ident $m:meta) => {};
+}
+// FOLLOW(tt) = any token
+macro_rules! follow_tt {
+ ($t:tt ()) => {};
+ ($t:tt []) => {};
+ ($t:tt {}) => {};
+ ($t:tt ,) => {};
+ ($t:tt =>) => {};
+ ($t:tt :) => {};
+ ($t:tt =) => {};
+ ($t:tt >) => {};
+ ($t:tt ;) => {};
+ ($t:tt |) => {};
+ ($t:tt +) => {};
+ ($t:tt ident) => {};
+ ($t:tt $p:pat) => {};
+ ($t:tt $e:expr) => {};
+ ($t:tt $t:ty) => {};
+ ($t:tt $s:stmt) => {};
+ ($t:tt $p:path) => {};
+ ($t:tt $b:block) => {};
+ ($t:tt $i:ident) => {};
+ ($t:tt $t:tt) => {};
+ ($t:tt $i:item) => {};
+ ($t:tt $m:meta) => {};
+}
+// FOLLOW(item) = any token
+macro_rules! follow_item {
+ ($i:item ()) => {};
+ ($i:item []) => {};
+ ($i:item {}) => {};
+ ($i:item ,) => {};
+ ($i:item =>) => {};
+ ($i:item :) => {};
+ ($i:item =) => {};
+ ($i:item >) => {};
+ ($i:item ;) => {};
+ ($i:item |) => {};
+ ($i:item +) => {};
+ ($i:item ident) => {};
+ ($i:item $p:pat) => {};
+ ($i:item $e:expr) => {};
+ ($i:item $t:ty) => {};
+ ($i:item $s:stmt) => {};
+ ($i:item $p:path) => {};
+ ($i:item $b:block) => {};
+ ($i:item $i:ident) => {};
+ ($i:item $t:tt) => {};
+ ($i:item $i:item) => {};
+ ($i:item $m:meta) => {};
+}
+// FOLLOW(meta) = any token
+macro_rules! follow_meta {
+ ($m:meta ()) => {};
+ ($m:meta []) => {};
+ ($m:meta {}) => {};
+ ($m:meta ,) => {};
+ ($m:meta =>) => {};
+ ($m:meta :) => {};
+ ($m:meta =) => {};
+ ($m:meta >) => {};
+ ($m:meta ;) => {};
+ ($m:meta |) => {};
+ ($m:meta +) => {};
+ ($m:meta ident) => {};
+ ($m:meta $p:pat) => {};
+ ($m:meta $e:expr) => {};
+ ($m:meta $t:ty) => {};
+ ($m:meta $s:stmt) => {};
+ ($m:meta $p:path) => {};
+ ($m:meta $b:block) => {};
+ ($m:meta $i:ident) => {};
+ ($m:meta $t:tt) => {};
+ ($m:meta $i:item) => {};
+ ($m:meta $m:meta) => {};
+}
+
+fn main() {}
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let args: Vec<String> = std::env::args().collect();
+ if args.len() > 1 && args[1] == "run_test" {
+ let _ = std::thread::spawn(|| {
+ panic!();
+ }).join();
+
+ panic!();
+ } else {
+ let test = std::process::Command::new(&args[0]).arg("run_test").output().unwrap();
+ assert!(!test.status.success());
+ let err = String::from_utf8_lossy(&test.stderr);
+ let mut it = err.lines();
+
+ assert_eq!(it.next().map(|l| l.starts_with("thread '<unnamed>' panicked at")), Some(true));
+ assert_eq!(it.next(), Some("note: Run with `RUST_BACKTRACE=1` for a backtrace."));
+ assert_eq!(it.next().map(|l| l.starts_with("thread '<main>' panicked at")), Some(true));
+ assert_eq!(it.next(), None);
+ }
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(libc)]
+
+extern crate libc;
+
+use std::process::{Command, Stdio};
+use std::env;
+use std::io::{self, Read, Write};
+
+#[cfg(unix)]
+unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
+ let doit = |a| {
+ let r = libc::dup(a);
+ assert!(r >= 0);
+ return r
+ };
+ let a = doit(0);
+ let b = doit(1);
+ let c = doit(2);
+
+ assert!(libc::close(0) >= 0);
+ assert!(libc::close(1) >= 0);
+ assert!(libc::close(2) >= 0);
+
+ let r = f();
+
+ assert!(libc::dup2(a, 0) >= 0);
+ assert!(libc::dup2(b, 1) >= 0);
+ assert!(libc::dup2(c, 2) >= 0);
+
+ return r
+}
+
+#[cfg(windows)]
+unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
+ type DWORD = u32;
+ type HANDLE = *mut u8;
+ type BOOL = i32;
+
+ const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD;
+ const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
+ const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
+ const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
+
+ extern "system" {
+ fn GetStdHandle(which: DWORD) -> HANDLE;
+ fn SetStdHandle(which: DWORD, handle: HANDLE) -> BOOL;
+ }
+
+ let doit = |id| {
+ let handle = GetStdHandle(id);
+ assert!(handle != INVALID_HANDLE_VALUE);
+ assert!(SetStdHandle(id, INVALID_HANDLE_VALUE) != 0);
+ return handle
+ };
+
+ let a = doit(STD_INPUT_HANDLE);
+ let b = doit(STD_OUTPUT_HANDLE);
+ let c = doit(STD_ERROR_HANDLE);
+
+ let r = f();
+
+ let doit = |id, handle| {
+ assert!(SetStdHandle(id, handle) != 0);
+ };
+ doit(STD_INPUT_HANDLE, a);
+ doit(STD_OUTPUT_HANDLE, b);
+ doit(STD_ERROR_HANDLE, c);
+
+ return r
+}
+
+fn main() {
+ if env::args().len() > 1 {
+ println!("test");
+ assert!(io::stdout().write(b"test\n").is_ok());
+ assert!(io::stderr().write(b"test\n").is_ok());
+ assert_eq!(io::stdin().read(&mut [0; 10]).unwrap(), 0);
+ return
+ }
+
+ // First, make sure reads/writes without stdio work if stdio itself is
+ // missing.
+ let (a, b, c) = unsafe {
+ without_stdio(|| {
+ let a = io::stdout().write(b"test\n");
+ let b = io::stderr().write(b"test\n");
+ let c = io::stdin().read(&mut [0; 10]);
+
+ (a, b, c)
+ })
+ };
+
+ assert_eq!(a.unwrap(), 5);
+ assert_eq!(b.unwrap(), 5);
+ assert_eq!(c.unwrap(), 0);
+
+ // Second, spawn a child and do some work with "null" descriptors to make
+ // sure it's ok
+ let me = env::current_exe().unwrap();
+ let status = Command::new(&me)
+ .arg("next")
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status().unwrap();
+ assert!(status.success(), "{:?} isn't a success", status);
+
+ // Finally, close everything then spawn a child to make sure everything is
+ // *still* ok.
+ let status = unsafe {
+ without_stdio(|| Command::new(&me).arg("next").status())
+ }.unwrap();
+ assert!(status.success(), "{:?} isn't a success", status);
+}