Auto merge of #41905 - frewsxcv:rollup, r=frewsxcv

Rollup of 5 pull requests

- Successful merges: #41192, #41724, #41873, #41877, #41889
- Failed merges:
This commit is contained in:
bors 2017-05-11 07:06:58 +00:00
commit 24ea08e9b7
23 changed files with 295 additions and 127 deletions

View file

@ -178,7 +178,7 @@
- [peek](library-features/peek.md)
- [placement_in](library-features/placement-in.md)
- [placement_new_protocol](library-features/placement-new-protocol.md)
- [print](library-features/print.md)
- [print_internals](library-features/print-internals.md)
- [proc_macro_internals](library-features/proc-macro-internals.md)
- [process_try_wait](library-features/process-try-wait.md)
- [question_mark_carrier](library-features/question-mark-carrier.md)

View file

@ -1,4 +1,4 @@
# `print`
# `print_internals`
This feature is internal to the Rust compiler and is not intended for general use.

View file

@ -159,6 +159,14 @@ pub enum DepNode<D: Clone + Debug> {
DefSpan(D),
Stability(D),
Deprecation(D),
ItemBodyNestedBodies(D),
ConstIsRvaluePromotableToStatic(D),
ImplParent(D),
TraitOfItem(D),
IsExportedSymbol(D),
IsMirAvailable(D),
ItemAttrs(D),
FnArgNames(D),
FileMap(D, Arc<String>),
}
@ -273,6 +281,14 @@ impl<D: Clone + Debug> DepNode<D> {
DefSpan(ref d) => op(d).map(DefSpan),
Stability(ref d) => op(d).map(Stability),
Deprecation(ref d) => op(d).map(Deprecation),
ItemAttrs(ref d) => op(d).map(ItemAttrs),
FnArgNames(ref d) => op(d).map(FnArgNames),
ImplParent(ref d) => op(d).map(ImplParent),
TraitOfItem(ref d) => op(d).map(TraitOfItem),
IsExportedSymbol(ref d) => op(d).map(IsExportedSymbol),
ItemBodyNestedBodies(ref d) => op(d).map(ItemBodyNestedBodies),
ConstIsRvaluePromotableToStatic(ref d) => op(d).map(ConstIsRvaluePromotableToStatic),
IsMirAvailable(ref d) => op(d).map(IsMirAvailable),
GlobalMetaData(ref d, kind) => op(d).map(|d| GlobalMetaData(d, kind)),
FileMap(ref d, ref file_name) => op(d).map(|d| FileMap(d, file_name.clone())),
}

View file

@ -210,27 +210,21 @@ pub trait CrateStore {
fn visibility(&self, def: DefId) -> ty::Visibility;
fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap<DefId>>;
fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>;
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
// trait info
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
// impl info
fn impl_defaultness(&self, def: DefId) -> hir::Defaultness;
fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
// trait/impl-item info
fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem;
// flags
fn is_const_fn(&self, did: DefId) -> bool;
fn is_default_impl(&self, impl_did: DefId) -> bool;
fn is_foreign_item(&self, did: DefId) -> bool;
fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool;
fn is_exported_symbol(&self, def_id: DefId) -> bool;
// crate metadata
fn dylib_dependency_formats(&self, cnum: CrateNum)
@ -337,28 +331,22 @@ impl CrateStore for DummyCrateStore {
}
fn item_generics_cloned(&self, def: DefId) -> ty::Generics
{ bug!("item_generics_cloned") }
fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { bug!("item_attrs") }
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name> { bug!("fn_arg_names") }
// trait info
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
// impl info
fn impl_defaultness(&self, def: DefId) -> hir::Defaultness { bug!("impl_defaultness") }
fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
// trait/impl-item info
fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
{ bug!("associated_item_cloned") }
// flags
fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") }
fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false }
fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool { false }
fn is_exported_symbol(&self, def_id: DefId) -> bool { false }
// crate metadata
fn dylib_dependency_formats(&self, cnum: CrateNum)

View file

@ -205,7 +205,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
} else if match self.tcx.hir.get_if_local(def_id) {
Some(hir::map::NodeForeignItem(..)) => true,
Some(..) => false,
None => self.tcx.sess.cstore.is_foreign_item(def_id),
None => self.tcx.is_foreign_item(def_id),
} {
self.require_unsafe_ext(expr.id, expr.span, "use of extern static", true);
}

View file

@ -34,6 +34,7 @@ use std::ops::Deref;
use std::rc::Rc;
use syntax_pos::{Span, DUMMY_SP};
use syntax::attr;
use syntax::ast;
use syntax::symbol::Symbol;
pub trait Key: Clone + Hash + Eq + Debug {
@ -340,6 +341,36 @@ impl<'tcx> QueryDescription for queries::deprecation<'tcx> {
}
}
impl<'tcx> QueryDescription for queries::item_attrs<'tcx> {
fn describe(_: TyCtxt, _: DefId) -> String {
bug!("item_attrs")
}
}
impl<'tcx> QueryDescription for queries::is_exported_symbol<'tcx> {
fn describe(_: TyCtxt, _: DefId) -> String {
bug!("is_exported_symbol")
}
}
impl<'tcx> QueryDescription for queries::fn_arg_names<'tcx> {
fn describe(_: TyCtxt, _: DefId) -> String {
bug!("fn_arg_names")
}
}
impl<'tcx> QueryDescription for queries::impl_parent<'tcx> {
fn describe(_: TyCtxt, _: DefId) -> String {
bug!("impl_parent")
}
}
impl<'tcx> QueryDescription for queries::trait_of_item<'tcx> {
fn describe(_: TyCtxt, _: DefId) -> String {
bug!("trait_of_item")
}
}
impl<'tcx> QueryDescription for queries::item_body_nested_bodies<'tcx> {
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("nested item bodies of `{}`", tcx.item_path_str(def_id))
@ -781,9 +812,14 @@ define_maps! { <'tcx>
[] def_span: DefSpan(DefId) -> Span,
[] stability: Stability(DefId) -> Option<attr::Stability>,
[] deprecation: Deprecation(DefId) -> Option<attr::Deprecation>,
[] item_body_nested_bodies: metadata_dep_node(DefId) -> Rc<BTreeMap<hir::BodyId, hir::Body>>,
[] const_is_rvalue_promotable_to_static: metadata_dep_node(DefId) -> bool,
[] is_mir_available: metadata_dep_node(DefId) -> bool,
[] item_attrs: ItemAttrs(DefId) -> Rc<[ast::Attribute]>,
[] fn_arg_names: FnArgNames(DefId) -> Vec<ast::Name>,
[] impl_parent: ImplParent(DefId) -> Option<DefId>,
[] trait_of_item: TraitOfItem(DefId) -> Option<DefId>,
[] is_exported_symbol: IsExportedSymbol(DefId) -> bool,
[] item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> Rc<BTreeMap<hir::BodyId, hir::Body>>,
[] const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
[] is_mir_available: IsMirAvailable(DefId) -> bool,
}
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@ -798,10 +834,6 @@ fn reachability_dep_node(_: CrateNum) -> DepNode<DefId> {
DepNode::Reachability
}
fn metadata_dep_node(def_id: DefId) -> DepNode<DefId> {
DepNode::MetaData(def_id)
}
fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode<DefId> {
instance.dep_node()
}

View file

@ -2360,7 +2360,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
if let Some(id) = self.hir.as_local_node_id(did) {
Attributes::Borrowed(self.hir.attrs(id))
} else {
Attributes::Owned(self.sess.cstore.item_attrs(did))
Attributes::Owned(self.item_attrs(did))
}
}
@ -2396,7 +2396,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
// Record the trait->implementation mapping.
let parent = self.sess.cstore.impl_parent(impl_def_id).unwrap_or(trait_id);
let parent = self.impl_parent(impl_def_id).unwrap_or(trait_id);
def.record_remote_impl(self, impl_def_id, trait_ref, parent);
}
@ -2433,22 +2433,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
}
/// If the given def ID describes an item belonging to a trait,
/// return the ID of the trait that the trait item belongs to.
/// Otherwise, return `None`.
pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
if def_id.krate != LOCAL_CRATE {
return self.sess.cstore.trait_of_item(def_id);
}
self.opt_associated_item(def_id)
.and_then(|associated_item| {
match associated_item.container {
TraitContainer(def_id) => Some(def_id),
ImplContainer(_) => None
}
})
}
/// Construct a parameter environment suitable for static contexts or other contexts where there
/// are no free type/lifetime parameters in scope.
pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> {
@ -2688,6 +2672,20 @@ fn def_span<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Span {
tcx.hir.span_if_local(def_id).unwrap()
}
/// If the given def ID describes an item belonging to a trait,
/// return the ID of the trait that the trait item belongs to.
/// Otherwise, return `None`.
fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option<DefId> {
tcx.opt_associated_item(def_id)
.and_then(|associated_item| {
match associated_item.container {
TraitContainer(def_id) => Some(def_id),
ImplContainer(_) => None
}
})
}
pub fn provide(providers: &mut ty::maps::Providers) {
*providers = ty::maps::Providers {
associated_item,
@ -2695,6 +2693,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
adt_sized_constraint,
adt_dtorck_constraint,
def_span,
trait_of_item,
..*providers
};
}

View file

@ -74,7 +74,7 @@ pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// constants, we only try to find the expression for a
// trait-associated const if the caller gives us the
// substitutions for the reference to it.
if tcx.sess.cstore.trait_of_item(def_id).is_some() {
if tcx.trait_of_item(def_id).is_some() {
resolve_trait_associated_const(tcx, def_id, substs)
} else {
Some((def_id, substs))

View file

@ -79,7 +79,11 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
DepNode::FileMap(def_id, ref name) => {
if def_id.is_local() {
Some(self.incremental_hashes_map[dep_node])
// We will have been able to retrace the DefId (which is
// always the local CRATE_DEF_INDEX), but the file with the
// given name might have been removed, so we use get() in
// order to allow for that case.
self.incremental_hashes_map.get(dep_node).map(|x| *x)
} else {
Some(self.metadata_hash(DepNode::FileMap(def_id, name.clone()),
def_id.krate,

View file

@ -718,7 +718,6 @@ fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) {
cx.span_lint(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
l.span,
"floating-point literals cannot be used in patterns");
error!("span mc spanspam");
},
_ => (),
}

View file

@ -41,8 +41,6 @@ use rustc::hir::svh::Svh;
use rustc_back::target::Target;
use rustc::hir;
use std::collections::BTreeMap;
macro_rules! provide {
(<$lt:tt> $tcx:ident, $def_id:ident, $cdata:ident $($name:ident => $compute:block)*) => {
pub fn provide<$lt>(providers: &mut Providers<$lt>) {
@ -113,21 +111,23 @@ provide! { <'tcx> tcx, def_id, cdata
def_span => { cdata.get_span(def_id.index, &tcx.sess) }
stability => { cdata.get_stability(def_id.index) }
deprecation => { cdata.get_deprecation(def_id.index) }
item_body_nested_bodies => {
let map: BTreeMap<_, _> = cdata.entry(def_id.index).ast.into_iter().flat_map(|ast| {
ast.decode(cdata).nested_bodies.decode(cdata).map(|body| (body.id(), body))
}).collect();
Rc::new(map)
item_attrs => { cdata.get_item_attrs(def_id.index, &tcx.dep_graph) }
// FIXME(#38501) We've skipped a `read` on the `HirBody` of
// a `fn` when encoding, so the dep-tracking wouldn't work.
// This is only used by rustdoc anyway, which shouldn't have
// incremental recompilation ever enabled.
fn_arg_names => { cdata.get_fn_arg_names(def_id.index) }
impl_parent => { cdata.get_parent_impl(def_id.index) }
trait_of_item => { cdata.get_trait_of_item(def_id.index) }
is_exported_symbol => {
let dep_node = cdata.metadata_dep_node(GlobalMetaDataKind::ExportedSymbols);
cdata.exported_symbols.get(&tcx.dep_graph, dep_node).contains(&def_id.index)
}
item_body_nested_bodies => { Rc::new(cdata.item_body_nested_bodies(def_id.index)) }
const_is_rvalue_promotable_to_static => {
cdata.entry(def_id.index).ast.expect("const item missing `ast`")
.decode(cdata).rvalue_promotable_to_static
}
is_mir_available => {
!cdata.is_proc_macro(def_id.index) &&
cdata.maybe_entry(def_id.index).and_then(|item| item.decode(cdata).mir).is_some()
cdata.const_is_rvalue_promotable_to_static(def_id.index)
}
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
}
impl CrateStore for cstore::CStore {
@ -145,22 +145,6 @@ impl CrateStore for cstore::CStore {
self.get_crate_data(def.krate).get_generics(def.index)
}
fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>
{
self.get_crate_data(def_id.krate)
.get_item_attrs(def_id.index, &self.dep_graph)
}
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>
{
// FIXME(#38501) We've skipped a `read` on the `HirBody` of
// a `fn` when encoding, so the dep-tracking wouldn't work.
// This is only used by rustdoc anyway, which shouldn't have
// incremental recompilation ever enabled.
assert!(!self.dep_graph.is_fully_enabled());
self.get_crate_data(did.krate).get_fn_arg_names(did.index)
}
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>
{
if let Some(def_id) = filter {
@ -179,16 +163,6 @@ impl CrateStore for cstore::CStore {
self.get_crate_data(def.krate).get_impl_defaultness(def.index)
}
fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
self.dep_graph.read(DepNode::MetaData(impl_def));
self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index)
}
fn trait_of_item(&self, def_id: DefId) -> Option<DefId> {
self.dep_graph.read(DepNode::MetaData(def_id));
self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index)
}
fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
{
self.dep_graph.read(DepNode::MetaData(def));
@ -206,23 +180,11 @@ impl CrateStore for cstore::CStore {
self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index)
}
fn is_foreign_item(&self, did: DefId) -> bool {
self.get_crate_data(did.krate).is_foreign_item(did.index)
}
fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool
{
self.do_is_statically_included_foreign_item(def_id)
}
fn is_exported_symbol(&self, def_id: DefId) -> bool {
let data = self.get_crate_data(def_id.krate);
let dep_node = data.metadata_dep_node(GlobalMetaDataKind::ExportedSymbols);
data.exported_symbols
.get(&self.dep_graph, dep_node)
.contains(&def_id.index)
}
fn is_dllimport_foreign_item(&self, def_id: DefId) -> bool {
if def_id.krate == LOCAL_CRATE {
self.dllimport_foreign_items.borrow().contains(&def_id.index)

View file

@ -30,6 +30,7 @@ use rustc::mir::Mir;
use std::borrow::Cow;
use std::cell::Ref;
use std::collections::BTreeMap;
use std::io;
use std::mem;
use std::rc::Rc;
@ -453,16 +454,16 @@ impl<'tcx> EntryKind<'tcx> {
}
impl<'a, 'tcx> CrateMetadata {
pub fn is_proc_macro(&self, id: DefIndex) -> bool {
fn is_proc_macro(&self, id: DefIndex) -> bool {
self.proc_macros.is_some() && id != CRATE_DEF_INDEX
}
pub fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
assert!(!self.is_proc_macro(item_id));
self.root.index.lookup(self.blob.raw_bytes(), item_id)
}
pub fn entry(&self, item_id: DefIndex) -> Entry<'tcx> {
fn entry(&self, item_id: DefIndex) -> Entry<'tcx> {
match self.maybe_entry(item_id) {
None => {
bug!("entry: id not found: {:?} in crate {:?} with number {}",
@ -789,6 +790,22 @@ impl<'a, 'tcx> CrateMetadata {
tcx.alloc_tables(ast.tables.decode((self, tcx)))
}
pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap<hir::BodyId, hir::Body> {
self.entry(id).ast.into_iter().flat_map(|ast| {
ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body))
}).collect()
}
pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool {
self.entry(id).ast.expect("const item missing `ast`")
.decode(self).rvalue_promotable_to_static
}
pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
!self.is_proc_macro(id) &&
self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
}
pub fn maybe_get_optimized_mir(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
id: DefIndex)

View file

@ -223,7 +223,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
_ => false
}
} else {
tcx.sess.cstore.is_foreign_item(def_id)
tcx.is_foreign_item(def_id)
};
if let Some(name) = weak_lang_items::link_name(&attrs) {

View file

@ -652,8 +652,8 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan
}
Some(_) => true,
None => {
if tcx.sess.cstore.is_exported_symbol(def_id) ||
tcx.sess.cstore.is_foreign_item(def_id)
if tcx.is_exported_symbol(def_id) ||
tcx.is_foreign_item(def_id)
{
// We can link to the item in question, no instance needed
// in this crate

View file

@ -186,7 +186,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
llvm::set_thread_local(g, true);
}
}
if ccx.use_dll_storage_attrs() && !ccx.sess().cstore.is_foreign_item(def_id) {
if ccx.use_dll_storage_attrs() && !ccx.tcx().is_foreign_item(def_id) {
// This item is external but not foreign, i.e. it originates from an external Rust
// crate. Since we don't know whether this crate will be linked dynamically or
// statically in the final application, we always mark such symbols as 'dllimport'.

View file

@ -1180,7 +1180,7 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
let mut names = if cx.tcx.hir.as_local_node_id(did).is_some() {
vec![].into_iter()
} else {
cx.tcx.sess.cstore.fn_arg_names(did).into_iter()
cx.tcx.fn_arg_names(did).into_iter()
}.peekable();
FnDecl {
output: Return(sig.skip_binder().output().clean(cx)),

View file

@ -287,9 +287,11 @@ pub use self::error::{Result, Error, ErrorKind};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::stdio::{stdin, stdout, stderr, _print, Stdin, Stdout, Stderr};
pub use self::stdio::{stdin, stdout, stderr, Stdin, Stdout, Stderr};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::stdio::{StdoutLock, StderrLock, StdinLock};
#[unstable(feature = "print_internals", issue = "0")]
pub use self::stdio::{_print, _eprint};
#[unstable(feature = "libstd_io_internals", issue = "0")]
#[doc(no_inline, hidden)]
pub use self::stdio::{set_panic, set_print};

View file

@ -17,7 +17,7 @@ use io::{self, BufReader, LineWriter};
use sync::{Arc, Mutex, MutexGuard};
use sys::stdio;
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
use thread::LocalKeyState;
use thread::{LocalKey, LocalKeyState};
/// Stdout used by print! and println! macros
thread_local! {
@ -659,41 +659,56 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
})
}
#[unstable(feature = "print",
reason = "implementation detail which may disappear or be replaced at any time",
issue = "0")]
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
// As an implementation of the `println!` macro, we want to try our best to
// not panic wherever possible and get the output somewhere. There are
// currently two possible vectors for panics we take care of here:
//
// 1. If the TLS key for the local stdout has been destroyed, accessing it
// would cause a panic. Note that we just lump in the uninitialized case
// here for convenience, we're not trying to avoid a panic.
// 2. If the local stdout is currently in use (e.g. we're in the middle of
// already printing) then accessing again would cause a panic.
//
// If, however, the actual I/O causes an error, we do indeed panic.
let result = match LOCAL_STDOUT.state() {
/// Write `args` to output stream `local_s` if possible, `global_s`
/// otherwise. `label` identifies the stream in a panic message.
///
/// This function is used to print error messages, so it takes extra
/// care to avoid causing a panic when `local_stream` is unusable.
/// For instance, if the TLS key for the local stream is uninitialized
/// or already destroyed, or if the local stream is locked by another
/// thread, it will just fall back to the global stream.
///
/// However, if the actual I/O causes an error, this function does panic.
fn print_to<T>(args: fmt::Arguments,
local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>,
global_s: fn() -> T,
label: &str) where T: Write {
let result = match local_s.state() {
LocalKeyState::Uninitialized |
LocalKeyState::Destroyed => stdout().write_fmt(args),
LocalKeyState::Destroyed => global_s().write_fmt(args),
LocalKeyState::Valid => {
LOCAL_STDOUT.with(|s| {
local_s.with(|s| {
if let Ok(mut borrowed) = s.try_borrow_mut() {
if let Some(w) = borrowed.as_mut() {
return w.write_fmt(args);
}
}
stdout().write_fmt(args)
global_s().write_fmt(args)
})
}
};
if let Err(e) = result {
panic!("failed printing to stdout: {}", e);
panic!("failed printing to {}: {}", label, e);
}
}
#[unstable(feature = "print_internals",
reason = "implementation detail which may disappear or be replaced at any time",
issue = "0")]
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
print_to(args, &LOCAL_STDOUT, stdout, "stdout");
}
#[unstable(feature = "print_internals",
reason = "implementation detail which may disappear or be replaced at any time",
issue = "0")]
#[doc(hidden)]
pub fn _eprint(args: fmt::Arguments) {
use panicking::LOCAL_STDERR;
print_to(args, &LOCAL_STDERR, stderr, "stderr");
}
#[cfg(test)]
mod tests {
use thread;

View file

@ -68,6 +68,9 @@ macro_rules! panic {
/// necessary to use `io::stdout().flush()` to ensure the output is emitted
/// immediately.
///
/// Use `print!` only for the primary output of your program. Use
/// `eprint!` instead to print error and progress messages.
///
/// # Panics
///
/// Panics if writing to `io::stdout()` fails.
@ -105,9 +108,12 @@ macro_rules! print {
/// Use the `format!` syntax to write data to the standard output.
/// See `std::fmt` for more information.
///
/// Use `println!` only for the primary output of your program. Use
/// `eprintln!` instead to print error and progress messages.
///
/// # Panics
///
/// Panics if writing to `io::stdout()` fails.
/// Panics if writing to `io::stdout` fails.
///
/// # Examples
///
@ -124,6 +130,45 @@ macro_rules! println {
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
/// Macro for printing to the standard error.
///
/// Equivalent to the `print!` macro, except that output goes to
/// `io::stderr` instead of `io::stdout`. See `print!` for
/// example usage.
///
/// Use `eprint!` only for error and progress messages. Use `print!`
/// instead for the primary output of your program.
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
#[macro_export]
#[stable(feature = "eprint", since="1.18.0")]
#[allow_internal_unstable]
macro_rules! eprint {
($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*)));
}
/// Macro for printing to the standard error, with a newline.
///
/// Equivalent to the `println!` macro, except that output goes to
/// `io::stderr` instead of `io::stdout`. See `println!` for
/// example usage.
///
/// Use `eprintln!` only for error and progress messages. Use `println!`
/// instead for the primary output of your program.
///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
#[macro_export]
#[stable(feature = "eprint", since="1.18.0")]
macro_rules! eprintln {
() => (eprint!("\n"));
($fmt:expr) => (eprint!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
}
/// A macro to select an event from a number of receivers.
///
/// This macro is used to wait for the first event to occur on a number of

View file

@ -0,0 +1,13 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub fn print_hello() {
println!("hello");
}

View file

@ -0,0 +1,31 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This test case makes sure that the compiler doesn't crash due to a failing
// table lookup when a source file is removed.
// revisions:rpass1 rpass2
// Note that we specify -g so that the FileMaps actually get referenced by the
// incr. comp. cache:
// compile-flags: -Z query-dep-graph -g
#[cfg(rpass1)]
mod auxiliary;
#[cfg(rpass1)]
fn main() {
auxiliary::print_hello();
}
#[cfg(rpass2)]
fn main() {
println!("hello");
}

View file

@ -0,0 +1,40 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-emscripten spawning processes is not supported
use std::{env, process};
fn child() {
print!("[stdout 0]");
print!("[stdout {}]", 1);
println!("[stdout {}]", 2);
println!();
eprint!("[stderr 0]");
eprint!("[stderr {}]", 1);
eprintln!("[stderr {}]", 2);
eprintln!();
}
fn parent() {
let this = env::args().next().unwrap();
let output = process::Command::new(this).arg("-").output().unwrap();
assert!(output.status.success());
let stdout = String::from_utf8(output.stdout).unwrap();
let stderr = String::from_utf8(output.stderr).unwrap();
assert_eq!(stdout, "[stdout 0][stdout 1][stdout 2]\n\n");
assert_eq!(stderr, "[stderr 0][stderr 1][stderr 2]\n\n");
}
fn main() {
if env::args().count() == 2 { child() } else { parent() }
}

View file

@ -647,6 +647,11 @@ actual:\n\
exe_file.to_str().unwrap()
.replace(r"\", r"\\")));
// Force GDB to print values in the Rust format.
if self.config.gdb_native_rust {
script_str.push_str("set language rust\n");
}
// Add line breakpoints
for line in &breakpoint_lines {
script_str.push_str(&format!("break '{}':{}\n",