From 194a91b0ce12d85a6a7ae1db20b3f4aa8408b80d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Sep 2016 21:46:35 -0700 Subject: [PATCH 1/9] rustbuild: Fix dependency tracking with new Cargo The recent Cargo update changed filenames, which broke a lot of incremental rustbuild builds. What it thought were the output files were indeed no longer the output files! (wreaking havoc). This commit updates this to stop guessing filenames of Cargo and just manage stamp files instead. --- src/bootstrap/compile.rs | 45 +++++++++++++++++++++++++++++++++------- src/bootstrap/lib.rs | 2 ++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e87669ba08ca9..11fe5fe6caad9 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -16,12 +16,14 @@ //! compiler. This module is also responsible for assembling the sysroot as it //! goes along from the output of the previous stage. +use std::cmp; use std::collections::HashMap; -use std::fs; +use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::process::Command; use build_helper::output; +use filetime::FileTime; use util::{exe, staticlib, libdir, mtime, is_dylib, copy}; use {Build, Compiler, Mode}; @@ -66,6 +68,7 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { } build.run(&mut cargo); + update_mtime(&libstd_stamp(build, compiler, target)); std_link(build, target, compiler, compiler.host); } @@ -141,11 +144,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { println!("Building stage{} test artifacts ({} -> {})", compiler.stage, compiler.host, target); let out_dir = build.cargo_out(compiler, Mode::Libtest, target); - build.clear_if_dirty(&out_dir, &libstd_shim(build, compiler, target)); + build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build"); cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/test_shim/Cargo.toml")); build.run(&mut cargo); + update_mtime(&libtest_stamp(build, compiler, target)); test_link(build, target, compiler, compiler.host); } @@ -173,7 +177,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { compiler.stage, compiler.host, target); let out_dir = build.cargo_out(compiler, Mode::Librustc, target); - build.clear_if_dirty(&out_dir, &libtest_shim(build, compiler, target)); + build.clear_if_dirty(&out_dir, &libtest_stamp(build, compiler, target)); let mut cargo = build.cargo(compiler, Mode::Librustc, target, "build"); cargo.arg("--features").arg(build.rustc_features()) @@ -238,14 +242,14 @@ pub fn rustc_link(build: &Build, /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. -fn libstd_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { - build.cargo_out(compiler, Mode::Libstd, target).join("libstd_shim.rlib") +fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { + build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp") } /// Cargo's output path for libtest in a given stage, compiled by a particular /// compiler for the specified target. -fn libtest_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { - build.cargo_out(compiler, Mode::Libtest, target).join("libtest_shim.rlib") +fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { + build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") } fn compiler_file(compiler: &Path, file: &str) -> PathBuf { @@ -358,10 +362,35 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) { // Maybe when libstd is compiled it should clear out the rustc of the // corresponding stage? // let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target); - // build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target)); + // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target)); let mut cargo = build.cargo(&compiler, Mode::Tool, host, "build"); cargo.arg("--manifest-path") .arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool))); build.run(&mut cargo); } + +/// Updates the mtime of a stamp file if necessary, only changing it if it's +/// older than some other file in the same directory. +/// +/// We don't know what file Cargo is going to output (because there's a hash in +/// the file name) but we know where it's going to put it. We use this helper to +/// detect changes to that output file by looking at the modification time for +/// all files in a directory and updating the stamp if any are newer. +fn update_mtime(path: &Path) { + let mut max = None; + if let Ok(entries) = path.parent().unwrap().read_dir() { + for entry in entries.map(|e| t!(e)) { + if t!(entry.file_type()).is_file() { + let meta = t!(entry.metadata()); + let time = FileTime::from_last_modification_time(&meta); + max = cmp::max(max, Some(time)); + } + } + } + + if !max.is_none() && max <= Some(mtime(path)) { + return + } + t!(File::create(path)); +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 94c14f7ea2546..c2dbfe1bbc58f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -585,6 +585,8 @@ impl Build { if mtime(&stamp) < mtime(input) { self.verbose(&format!("Dirty - {}", dir.display())); let _ = fs::remove_dir_all(dir); + } else if stamp.exists() { + return } t!(fs::create_dir_all(dir)); t!(File::create(stamp)); From 6b2cf78c52285801b59d5928e8e45a5d19476496 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 13 Sep 2016 12:30:17 -0700 Subject: [PATCH 2/9] rustbuild: Use current_dir instead of -C Apparently some versions of git don't support the `-C` flag, so let's use the guaranteed-to-work `current_dir` function. --- src/bootstrap/lib.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 94c14f7ea2546..741067fee6b78 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -559,9 +559,11 @@ impl Build { match submodule.state { State::MaybeDirty => { // drop staged changes - self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"])); + self.run(git().current_dir(submodule.path) + .args(&["reset", "--hard"])); // drops unstaged changes - self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"])); + self.run(git().current_dir(submodule.path) + .args(&["clean", "-fdx"])); }, State::NotInitialized => { self.run(git_submodule().arg("init").arg(submodule.path)); @@ -570,8 +572,10 @@ impl Build { State::OutOfSync => { // drops submodule commits that weren't reported to the (outer) git repository self.run(git_submodule().arg("update").arg(submodule.path)); - self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"])); - self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"])); + self.run(git().current_dir(submodule.path) + .args(&["reset", "--hard"])); + self.run(git().current_dir(submodule.path) + .args(&["clean", "-fdx"])); }, } } From 1b3a588f55c84d4fc36f4889f4c7ef7357ad471a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 22:09:22 -0400 Subject: [PATCH 3/9] trans: Let the collector find drop-glue for all vtables, not just VTableImpl. --- src/librustc_trans/collector.rs | 13 ++++++----- .../instantiation-through-vtable.rs | 2 -- .../codegen-units/item-collection/unsizing.rs | 2 -- .../partitioning/vtable-through-const.rs | 2 -- src/test/run-pass/issue36260.rs | 22 +++++++++++++++++++ 5 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 src/test/run-pass/issue36260.rs diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 5a8ab62a2aa2d..a58de71ca41ed 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output); } } - mir::Rvalue::Box(_) => { + mir::Rvalue::Box(..) => { let exchange_malloc_fn_def_id = self.scx .tcx() @@ -1072,15 +1072,16 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, }); output.extend(items); - - // Also add the destructor - let dg_type = glue::get_drop_glue_type(scx.tcx(), - trait_ref.self_ty()); - output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); } _ => { /* */ } } } + + // Also add the destructor + let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty); + if glue::type_needs_drop(scx.tcx(), dg_type) { + output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); + } } } diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index 06e547f0dd037..b772525122001 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -40,5 +40,3 @@ fn main() { //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index 5c67ab7a82646..45ba441bc8ba6 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -78,5 +78,3 @@ fn main() //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0] let _wrapper_sized = wrapper_sized as Wrapper; } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index b40bb7f60973a..ee5e97cd9c212 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -89,5 +89,3 @@ fn main() { //~ TRANS_ITEM fn vtable_through_const::mod1[0]::id[0] @@ vtable_through_const[Internal] mod1::ID_CHAR('x'); } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/run-pass/issue36260.rs b/src/test/run-pass/issue36260.rs new file mode 100644 index 0000000000000..08dbbb5c9fe13 --- /dev/null +++ b/src/test/run-pass/issue36260.rs @@ -0,0 +1,22 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Make sure this compiles without getting a linker error because of missing +// drop-glue because the collector missed adding drop-glue for the closure: + +fn create_fn() -> Box { + let text = String::new(); + + Box::new(move || { let _ = &text; }) +} + +fn main() { + let _ = create_fn(); +} From 35584629f4f8ad1eb32c4363fb9b5437e1052e5e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 10 Sep 2016 17:52:26 +0200 Subject: [PATCH 4/9] Update E0049 to new error format --- src/librustc_typeck/check/compare_method.rs | 35 +++++++++++++++++++-- src/librustc_typeck/check/mod.rs | 4 ++- src/test/compile-fail/E0049.rs | 3 +- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 1604f34d57552..faad3f9b000cc 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -38,7 +38,8 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_span: Span, impl_m_body_id: ast::NodeId, trait_m: &ty::Method<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>) { + impl_trait_ref: &ty::TraitRef<'tcx>, + trait_item_span: Option) { debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); @@ -97,14 +98,42 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let num_impl_m_type_params = impl_m.generics.types.len(); let num_trait_m_type_params = trait_m.generics.types.len(); if num_impl_m_type_params != num_trait_m_type_params { - span_err!(tcx.sess, impl_m_span, E0049, + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let span = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => { + if impl_m_sig.generics.is_parameterized() { + impl_m_sig.generics.span + } else { + impl_m_span + } + } + _ => bug!("{:?} is not a method", impl_m) + }; + + struct_span_err!(tcx.sess, span, E0049, "method `{}` has {} type parameter{} \ but its trait declaration has {} type parameter{}", trait_m.name, num_impl_m_type_params, if num_impl_m_type_params == 1 {""} else {"s"}, num_trait_m_type_params, - if num_trait_m_type_params == 1 {""} else {"s"}); + if num_trait_m_type_params == 1 {""} else {"s"}) + .span_label(trait_item_span.unwrap(), + &format!("expected {}", + &if num_trait_m_type_params != 1 { + format!("{} type parameters", + num_trait_m_type_params) + } else { + format!("{} type parameter", + num_trait_m_type_params) + })) + .span_label(span, &format!("found {}", + &if num_impl_m_type_params != 1 { + format!("{} type parameters", num_impl_m_type_params) + } else { + format!("1 type parameter") + })) + .emit(); return; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 005cd2e46b89f..455bde9421d7f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1015,13 +1015,15 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, _ => span_bug!(impl_item.span, "non-method impl-item for method") }; + let trait_span = tcx.map.span_if_local(ty_trait_item.def_id()); if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item { compare_impl_method(ccx, &impl_method, impl_item.span, body.id, &trait_method, - &impl_trait_ref); + &impl_trait_ref, + trait_span); } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0324, "item `{}` is an associated method, \ diff --git a/src/test/compile-fail/E0049.rs b/src/test/compile-fail/E0049.rs index 5867e11e9acc6..33ebd3f7aca5e 100644 --- a/src/test/compile-fail/E0049.rs +++ b/src/test/compile-fail/E0049.rs @@ -9,13 +9,14 @@ // except according to those terms. trait Foo { - fn foo(x: T) -> Self; + fn foo(x: T) -> Self; //~ NOTE expected 1 type parameter } struct Bar; impl Foo for Bar { fn foo(x: bool) -> Self { Bar } //~ ERROR E0049 + //~| NOTE found 0 type parameters } fn main() { From a6da082e102966284857dc6849a0043e31b367e2 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 14 Sep 2016 22:41:17 +0200 Subject: [PATCH 5/9] doc: make that sound better --- src/libstd/env.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 63bf051c9bcd0..76eb92bd55989 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -83,7 +83,7 @@ pub struct VarsOs { inner: os_imp::Env } /// environment variables of the current process. /// /// The returned iterator contains a snapshot of the process's environment -/// variables at the time of this invocation, modifications to environment +/// variables at the time of this invocation. Modifications to environment /// variables afterwards will not be reflected in the returned iterator. /// /// # Panics @@ -112,7 +112,7 @@ pub fn vars() -> Vars { /// environment variables of the current process. /// /// The returned iterator contains a snapshot of the process's environment -/// variables at the time of this invocation, modifications to environment +/// variables at the time of this invocation. Modifications to environment /// variables afterwards will not be reflected in the returned iterator. /// /// # Examples From 5cab9525ae12a18ec0583ee1ddba3a9eb31a5cfd Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 14 Sep 2016 22:49:36 -0400 Subject: [PATCH 6/9] Don't ignore a doc code-block we can compile. --- src/doc/book/traits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index d07fb6b7c45bf..b0d954adf6771 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -291,7 +291,7 @@ let result = f.write(buf); We need to `use` the `Write` trait first: -```rust,ignore +```rust,no_run use std::io::Write; let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); From 6950242b1cfff94eda669f65bf082c54fde5e90f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 15 Sep 2016 19:02:10 +0200 Subject: [PATCH 7/9] Workaround #34427 by using memset of 0 on ARM to set the discriminant. --- src/librustc_trans/adt.rs | 25 +++++++++++++++++++++---- src/test/run-pass/issue-34427.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/issue-34427.rs diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index e8498363e45a3..050b5127e6acf 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -54,6 +54,7 @@ use syntax::ast; use syntax::attr; use syntax::attr::IntType; use abi::FAT_PTR_ADDR; +use base; use build::*; use common::*; use debuginfo::DebugLoc; @@ -963,16 +964,32 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, Store(bcx, C_null(llptrty), val); } } - StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { + StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => { if discr != nndiscr { - let llptrptr = GEPi(bcx, val, &discrfield[..]); - let llptrty = val_ty(llptrptr).element_type(); - Store(bcx, C_null(llptrty), llptrptr); + if target_sets_discr_via_memset(bcx) { + // Issue #34427: As workaround for LLVM bug on + // ARM, use memset of 0 on whole struct rather + // than storing null to single target field. + let b = B(bcx); + let llptr = b.pointercast(val, Type::i8(b.ccx).ptr_to()); + let fill_byte = C_u8(b.ccx, 0); + let size = C_u64(b.ccx, nonnull.size); + let align = C_u32(b.ccx, nonnull.align); + base::call_memset(&b, llptr, fill_byte, size, align, false); + } else { + let llptrptr = GEPi(bcx, val, &discrfield[..]); + let llptrty = val_ty(llptrptr).element_type(); + Store(bcx, C_null(llptrty), llptrptr); + } } } } } +fn target_sets_discr_via_memset<'blk, 'tcx>(bcx: Block<'blk, 'tcx>) -> bool { + bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64" +} + fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) { match ity { attr::UnsignedInt(_) => { diff --git a/src/test/run-pass/issue-34427.rs b/src/test/run-pass/issue-34427.rs new file mode 100644 index 0000000000000..6bf8a2ac6a72d --- /dev/null +++ b/src/test/run-pass/issue-34427.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue #34427: On ARM, the code in `foo` at one time was generating +// a machine code instruction of the form: `str r0, [r0, rN]!` (for +// some N), which is not legal because the source register and base +// register cannot be identical in the preindexed form signalled by +// the `!`. +// +// See LLVM bug: https://llvm.org/bugs/show_bug.cgi?id=28809 + +#[inline(never)] +fn foo(n: usize) -> Vec> { + (0..n).map(|_| None).collect() +} + +fn main() { + let _ = (foo(10), foo(32)); +} From b735c1bc7891a5a0176e544aa50c47b4d67f52b4 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Sun, 11 Sep 2016 15:09:05 -0700 Subject: [PATCH 8/9] Tweak std::marker docs Fixes #29361. --- src/libcore/marker.rs | 423 ++++++++++++++++++++++++++---------------- 1 file changed, 268 insertions(+), 155 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index c22c9f0d1c717..5a1a034a36358 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Primitive traits and marker types representing basic 'kinds' of types. +//! Primitive traits and types representing basic properties of types. //! //! Rust types can be classified in various useful ways according to -//! intrinsic properties of the type. These classifications, often called -//! 'kinds', are represented as traits. +//! their intrinsic properties. These classifications are represented +//! as traits. #![stable(feature = "rust1", since = "1.0.0")] @@ -22,7 +22,21 @@ use hash::Hasher; /// Types that can be transferred across thread boundaries. /// -/// This trait is automatically derived when the compiler determines it's appropriate. +/// This trait is automatically implemented when the compiler determines it's +/// appropriate. +/// +/// An example of a non-`Send` type is the reference-counting pointer +/// [`rc::Rc`][rc]. If two threads attempt to clone `Rc`s that point to the same +/// reference-counted value, they might try to update the reference count at the +/// same time, which is [undefined behavior][ub] because `Rc` doesn't use atomic +/// operations. Its cousin [`sync::Arc`][arc] does use atomic operations (incurring +/// some overhead) and thus is `Send`. +/// +/// See [the Nomicon](../../nomicon/send-and-sync.html) for more details. +/// +/// [rc]: ../../std/rc/struct.Rc.html +/// [arc]: ../../std/sync/struct.Arc.html +/// [ub]: ../../reference.html#behavior-considered-undefined #[stable(feature = "rust1", since = "1.0.0")] #[lang = "send"] #[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] @@ -38,10 +52,10 @@ impl !Send for *const T { } #[stable(feature = "rust1", since = "1.0.0")] impl !Send for *mut T { } -/// Types with a constant size known at compile-time. +/// Types with a constant size known at compile time. /// -/// All type parameters which can be bounded have an implicit bound of `Sized`. The special syntax -/// `?Sized` can be used to remove this bound if it is not appropriate. +/// All type parameters have an implicit bound of `Sized`. The special syntax +/// `?Sized` can be used to remove this bound if it's not appropriate. /// /// ``` /// # #![allow(dead_code)] @@ -51,6 +65,26 @@ impl !Send for *mut T { } /// // struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32] /// struct BarUse(Bar<[i32]>); // OK /// ``` +/// +/// The one exception is the implicit `Self` type of a trait, which does not +/// get an implicit `Sized` bound. This is because a `Sized` bound prevents +/// the trait from being used to form a [trait object]: +/// +/// ``` +/// # #![allow(unused_variables)] +/// trait Foo { } +/// trait Bar: Sized { } +/// +/// struct Impl; +/// impl Foo for Impl { } +/// impl Bar for Impl { } +/// +/// let x: &Foo = &Impl; // OK +/// // let y: &Bar = &Impl; // error: the trait `Bar` cannot +/// // be made into an object +/// ``` +/// +/// [trait object]: ../../book/trait-objects.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] @@ -59,14 +93,27 @@ pub trait Sized { // Empty. } -/// Types that can be "unsized" to a dynamically sized type. +/// Types that can be "unsized" to a dynamically-sized type. +/// +/// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and +/// `Unsize`. +/// +/// All implementations of `Unsize` are provided automatically by the compiler. +/// +/// `Unsize` is used along with [`ops::CoerceUnsized`][coerceunsized] to allow +/// "user-defined" containers such as [`rc::Rc`][rc] to contain dynamically-sized +/// types. See the [DST coercion RFC][RFC982] for more details. +/// +/// [coerceunsized]: ../ops/trait.CoerceUnsized.html +/// [rc]: ../../std/rc/struct.Rc.html +/// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md #[unstable(feature = "unsize", issue = "27732")] #[lang="unsize"] pub trait Unsize { // Empty. } -/// Types that can be copied by simply copying bits (i.e. `memcpy`). +/// Types whose values can be duplicated simply by copying bits. /// /// By default, variable bindings have 'move semantics.' In other /// words: @@ -87,7 +134,8 @@ pub trait Unsize { /// However, if a type implements `Copy`, it instead has 'copy semantics': /// /// ``` -/// // we can just derive a `Copy` implementation +/// // We can derive a `Copy` implementation. `Clone` is also required, as it's +/// // a supertrait of `Copy`. /// #[derive(Debug, Copy, Clone)] /// struct Foo; /// @@ -100,13 +148,59 @@ pub trait Unsize { /// println!("{:?}", x); // A-OK! /// ``` /// -/// It's important to note that in these two examples, the only difference is if you are allowed to -/// access `x` after the assignment: a move is also a bitwise copy under the hood. +/// It's important to note that in these two examples, the only difference is whether you +/// are allowed to access `x` after the assignment. Under the hood, both a copy and a move +/// can result in bits being copied in memory, although this is sometimes optimized away. +/// +/// ## How can I implement `Copy`? +/// +/// There are two ways to implement `Copy` on your type. The simplest is to use `derive`: +/// +/// ``` +/// #[derive(Copy, Clone)] +/// struct MyStruct; +/// ``` +/// +/// You can also implement `Copy` and `Clone` manually: +/// +/// ``` +/// struct MyStruct; +/// +/// impl Copy for MyStruct { } +/// +/// impl Clone for MyStruct { +/// fn clone(&self) -> MyStruct { +/// *self +/// } +/// } +/// ``` +/// +/// There is a small difference between the two: the `derive` strategy will also place a `Copy` +/// bound on type parameters, which isn't always desired. +/// +/// ## What's the difference between `Copy` and `Clone`? +/// +/// Copies happen implicitly, for example as part of an assignment `y = x`. The behavior of +/// `Copy` is not overloadable; it is always a simple bit-wise copy. +/// +/// Cloning is an explicit action, `x.clone()`. The implementation of [`Clone`][clone] can +/// provide any type-specific behavior necessary to duplicate values safely. For example, +/// the implementation of `Clone` for [`String`][string] needs to copy the pointed-to string +/// buffer in the heap. A simple bitwise copy of `String` values would merely copy the +/// pointer, leading to a double free down the line. For this reason, `String` is `Clone` +/// but not `Copy`. +/// +/// `Clone` is a supertrait of `Copy`, so everything which is `Copy` must also implement +/// `Clone`. If a type is `Copy` then its `Clone` implementation need only return `*self` +/// (see the example above). +/// +/// [clone]: ../clone/trait.Clone.html +/// [string]: ../../std/string/struct.String.html /// /// ## When can my type be `Copy`? /// /// A type can implement `Copy` if all of its components implement `Copy`. For example, this -/// `struct` can be `Copy`: +/// struct can be `Copy`: /// /// ``` /// # #[allow(dead_code)] @@ -116,7 +210,8 @@ pub trait Unsize { /// } /// ``` /// -/// A `struct` can be `Copy`, and `i32` is `Copy`, so therefore, `Point` is eligible to be `Copy`. +/// A struct can be `Copy`, and `i32` is `Copy`, therefore `Point` is eligible to be `Copy`. +/// By contrast, consider /// /// ``` /// # #![allow(dead_code)] @@ -126,57 +221,35 @@ pub trait Unsize { /// } /// ``` /// -/// The `PointList` `struct` cannot implement `Copy`, because [`Vec`] is not `Copy`. If we +/// The struct `PointList` cannot implement `Copy`, because [`Vec`] is not `Copy`. If we /// attempt to derive a `Copy` implementation, we'll get an error: /// /// ```text /// the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy` /// ``` /// -/// ## When can my type _not_ be `Copy`? +/// ## When *can't* my type be `Copy`? /// /// Some types can't be copied safely. For example, copying `&mut T` would create an aliased -/// mutable reference, and copying [`String`] would result in two attempts to free the same buffer. +/// mutable reference. Copying [`String`] would duplicate responsibility for managing the `String`'s +/// buffer, leading to a double free. /// /// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's /// managing some resource besides its own [`size_of::()`] bytes. /// -/// ## What if I derive `Copy` on a type that can't? -/// -/// If you try to derive `Copy` on a struct or enum, you will get a compile-time error. -/// Specifically, with structs you'll get [E0204](https://doc.rust-lang.org/error-index.html#E0204) -/// and with enums you'll get [E0205](https://doc.rust-lang.org/error-index.html#E0205). -/// -/// ## When should my type be `Copy`? -/// -/// Generally speaking, if your type _can_ implement `Copy`, it should. There's one important thing -/// to consider though: if you think your type may _not_ be able to implement `Copy` in the future, -/// then it might be prudent to not implement `Copy`. This is because removing `Copy` is a breaking -/// change: that second example would fail to compile if we made `Foo` non-`Copy`. +/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get a +/// compile-time error. Specifically, with structs you'll get [E0204] and with enums you'll get +/// [E0205]. /// -/// ## Derivable +/// [E0204]: https://doc.rust-lang.org/error-index.html#E0204 +/// [E0205]: https://doc.rust-lang.org/error-index.html#E0205 /// -/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type. +/// ## When *should* my type be `Copy`? /// -/// ## How can I implement `Copy`? -/// -/// There are two ways to implement `Copy` on your type: -/// -/// ``` -/// #[derive(Copy, Clone)] -/// struct MyStruct; -/// ``` -/// -/// and -/// -/// ``` -/// struct MyStruct; -/// impl Copy for MyStruct {} -/// impl Clone for MyStruct { fn clone(&self) -> MyStruct { *self } } -/// ``` -/// -/// There is a small difference between the two: the `derive` strategy will also place a `Copy` -/// bound on type parameters, which isn't always desired. +/// Generally speaking, if your type _can_ implement `Copy`, it should. Keep in mind, though, +/// that implementing `Copy` is part of the public API of your type. If the type might become +/// non-`Copy` in the future, it could be prudent to omit the `Copy` implementation now, to +/// avoid a breaking API change. /// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`String`]: ../../std/string/struct.String.html @@ -188,64 +261,74 @@ pub trait Copy : Clone { // Empty. } -/// Types that can be safely shared between threads when aliased. +/// Types for which it is safe to share references between threads. +/// +/// This trait is automatically implemented when the compiler determines +/// it's appropriate. /// /// The precise definition is: a type `T` is `Sync` if `&T` is -/// thread-safe. In other words, there is no possibility of data races -/// when passing `&T` references between threads. -/// -/// As one would expect, primitive types like [`u8`] and [`f64`] are all -/// `Sync`, and so are simple aggregate types containing them (like -/// tuples, structs and enums). More instances of basic `Sync` types -/// include "immutable" types like `&T` and those with simple -/// inherited mutability, such as [`Box`], [`Vec`] and most other -/// collection types. (Generic parameters need to be `Sync` for their -/// container to be `Sync`.) -/// -/// A somewhat surprising consequence of the definition is `&mut T` is -/// `Sync` (if `T` is `Sync`) even though it seems that it might -/// provide unsynchronized mutation. The trick is a mutable reference -/// stored in an aliasable reference (that is, `& &mut T`) becomes -/// read-only, as if it were a `& &T`, hence there is no risk of a data -/// race. +/// [`Send`][send]. In other words, if there is no possibility of +/// [undefined behavior][ub] (including data races) when passing +/// `&T` references between threads. +/// +/// As one would expect, primitive types like [`u8`][u8] and [`f64`][f64] +/// are all `Sync`, and so are simple aggregate types containing them, +/// like tuples, structs and enums. More examples of basic `Sync` +/// types include "immutable" types like `&T`, and those with simple +/// inherited mutability, such as [`Box`][box], [`Vec`][vec] and +/// most other collection types. (Generic parameters need to be `Sync` +/// for their container to be `Sync`.) +/// +/// A somewhat surprising consequence of the definition is that `&mut T` +/// is `Sync` (if `T` is `Sync`) even though it seems like that might +/// provide unsynchronized mutation. The trick is that a mutable +/// reference behind a shared reference (that is, `& &mut T`) +/// becomes read-only, as if it were a `& &T`. Hence there is no risk +/// of a data race. /// /// Types that are not `Sync` are those that have "interior -/// mutability" in a non-thread-safe way, such as [`Cell`] and [`RefCell`] -/// in [`std::cell`]. These types allow for mutation of their contents -/// even when in an immutable, aliasable slot, e.g. the contents of -/// [`&Cell`][`Cell`] can be [`.set`], and do not ensure data races are -/// impossible, hence they cannot be `Sync`. A higher level example -/// of a non-`Sync` type is the reference counted pointer -/// [`std::rc::Rc`][`Rc`], because any reference [`&Rc`][`Rc`] can clone a new -/// reference, which modifies the reference counts in a non-atomic -/// way. -/// -/// For cases when one does need thread-safe interior mutability, -/// types like the atomics in [`std::sync`][`sync`] and [`Mutex`] / [`RwLock`] in -/// the [`sync`] crate do ensure that any mutation cannot cause data -/// races. Hence these types are `Sync`. -/// -/// Any types with interior mutability must also use the [`std::cell::UnsafeCell`] -/// wrapper around the value(s) which can be mutated when behind a `&` -/// reference; not doing this is undefined behavior (for example, -/// [`transmute`]-ing from `&T` to `&mut T` is invalid). +/// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell] +/// and [`cell::RefCell`][refcell]. These types allow for mutation of +/// their contents even through an immutable, shared reference. For +/// example the `set` method on `Cell` takes `&self`, so it requires +/// only a shared reference `&Cell`. The method performs no +/// synchronization, thus `Cell` cannot be `Sync`. /// -/// This trait is automatically derived when the compiler determines it's appropriate. +/// Another example of a non-`Sync` type is the reference-counting +/// pointer [`rc::Rc`][rc]. Given any reference `&Rc`, you can clone +/// a new `Rc`, modifying the reference counts in a non-atomic way. /// -/// [`u8`]: ../../std/primitive.u8.html -/// [`f64`]: ../../std/primitive.f64.html -/// [`Vec`]: ../../std/vec/struct.Vec.html -/// [`Box`]: ../../std/boxed/struct.Box.html -/// [`Cell`]: ../../std/cell/struct.Cell.html -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`std::cell`]: ../../std/cell/index.html -/// [`.set`]: ../../std/cell/struct.Cell.html#method.set -/// [`Rc`]: ../../std/rc/struct.Rc.html -/// [`sync`]: ../../std/sync/index.html -/// [`Mutex`]: ../../std/sync/struct.Mutex.html -/// [`RwLock`]: ../../std/sync/struct.RwLock.html -/// [`std::cell::UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html -/// [`transmute`]: ../../std/mem/fn.transmute.html +/// For cases when one does need thread-safe interior mutability, +/// Rust provides [atomic data types], as well as explicit locking via +/// [`sync::Mutex`][mutex] and [`sync::RWLock`][rwlock]. These types +/// ensure that any mutation cannot cause data races, hence the types +/// are `Sync`. Likewise, [`sync::Arc`][arc] provides a thread-safe +/// analogue of `Rc`. +/// +/// Any types with interior mutability must also use the +/// [`cell::UnsafeCell`][unsafecell] wrapper around the value(s) which +/// can be mutated through a shared reference. Failing to doing this is +/// [undefined behavior][ub]. For example, [`transmute`][transmute]-ing +/// from `&T` to `&mut T` is invalid. +/// +/// See [the Nomicon](../../nomicon/send-and-sync.html) for more +/// details about `Sync`. +/// +/// [send]: trait.Send.html +/// [u8]: ../../std/primitive.u8.html +/// [f64]: ../../std/primitive.f64.html +/// [box]: ../../std/boxed/struct.Box.html +/// [vec]: ../../std/vec/struct.Vec.html +/// [cell]: ../cell/struct.Cell.html +/// [refcell]: ../cell/struct.RefCell.html +/// [rc]: ../../std/rc/struct.Rc.html +/// [arc]: ../../std/sync/struct.Arc.html +/// [atomic data types]: ../sync/atomic/index.html +/// [mutex]: ../../std/sync/struct.Mutex.html +/// [rwlock]: ../../std/sync/struct.RwLock.html +/// [unsafecell]: ../cell/struct.UnsafeCell.html +/// [ub]: ../../reference.html#behavior-considered-undefined +/// [transmute]: ../../std/mem/fn.transmute.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] @@ -314,29 +397,30 @@ macro_rules! impls{ ) } -/// `PhantomData` allows you to describe that a type acts as if it stores a value of type `T`, -/// even though it does not. This allows you to inform the compiler about certain safety properties -/// of your code. +/// Zero-sized type used to mark things that "act like" they own a `T`. /// -/// For a more in-depth explanation of how to use `PhantomData`, please see [the Nomicon]. +/// Adding a `PhantomData` field to your type tells the compiler that your +/// type acts as though it stores a value of type `T`, even though it doesn't +/// really. This information is used when computing certain safety properties. /// -/// [the Nomicon]: ../../nomicon/phantom-data.html +/// For a more in-depth explanation of how to use `PhantomData`, please see +/// [the Nomicon](../../nomicon/phantom-data.html). /// /// # A ghastly note 👻👻👻 /// -/// Though they both have scary names, `PhantomData` and 'phantom types' are related, but not -/// identical. Phantom types are a more general concept that don't require `PhantomData` to -/// implement, but `PhantomData` is the most common way to implement them in a correct manner. +/// Though they both have scary names, `PhantomData` and 'phantom types' are +/// related, but not identical. A phantom type parameter is simply a type +/// parameter which is never used. In Rust, this often causes the compiler to +/// complain, and the solution is to add a "dummy" use by way of `PhantomData`. /// /// # Examples /// -/// ## Unused lifetime parameter +/// ## Unused lifetime parameters /// -/// Perhaps the most common time that `PhantomData` is required is -/// with a struct that has an unused lifetime parameter, typically as -/// part of some unsafe code. For example, here is a struct `Slice` -/// that has two pointers of type `*const T`, presumably pointing into -/// an array somewhere: +/// Perhaps the most common use case for `PhantomData` is a struct that has an +/// unused lifetime parameter, typically as part of some unsafe code. For +/// example, here is a struct `Slice` that has two pointers of type `*const T`, +/// presumably pointing into an array somewhere: /// /// ```ignore /// struct Slice<'a, T> { @@ -350,7 +434,7 @@ macro_rules! impls{ /// intent is not expressed in the code, since there are no uses of /// the lifetime `'a` and hence it is not clear what data it applies /// to. We can correct this by telling the compiler to act *as if* the -/// `Slice` struct contained a borrowed reference `&'a T`: +/// `Slice` struct contained a reference `&'a T`: /// /// ``` /// use std::marker::PhantomData; @@ -359,29 +443,53 @@ macro_rules! impls{ /// struct Slice<'a, T: 'a> { /// start: *const T, /// end: *const T, -/// phantom: PhantomData<&'a T> +/// phantom: PhantomData<&'a T>, /// } /// ``` /// -/// This also in turn requires that we annotate `T:'a`, indicating -/// that `T` is a type that can be borrowed for the lifetime `'a`. +/// This also in turn requires the annotation `T: 'a`, indicating +/// that any references in `T` are valid over the lifetime `'a`. +/// +/// When initializing a `Slice` you simply provide the value +/// `PhantomData` for the field `phantom`: +/// +/// ``` +/// # #![allow(dead_code)] +/// # use std::marker::PhantomData; +/// # struct Slice<'a, T: 'a> { +/// # start: *const T, +/// # end: *const T, +/// # phantom: PhantomData<&'a T>, +/// # } +/// fn borrow_vec<'a, T>(vec: &'a Vec) -> Slice<'a, T> { +/// let ptr = vec.as_ptr(); +/// Slice { +/// start: ptr, +/// end: unsafe { ptr.offset(vec.len() as isize) }, +/// phantom: PhantomData, +/// } +/// } +/// ``` /// /// ## Unused type parameters /// -/// It sometimes happens that there are unused type parameters that +/// It sometimes happens that you have unused type parameters which /// indicate what type of data a struct is "tied" to, even though that /// data is not actually found in the struct itself. Here is an -/// example where this arises when handling external resources over a -/// foreign function interface. `PhantomData` can prevent -/// mismatches by enforcing types in the method implementations: +/// example where this arises with [FFI]. The foreign interface uses +/// handles of type `*mut ()` to refer to Rust values of different +/// types. We track the Rust type using a phantom type parameter on +/// the struct `ExternalResource` which wraps a handle. +/// +/// [FFI]: ../../book/ffi.html /// /// ``` /// # #![allow(dead_code)] -/// # trait ResType { fn foo(&self); } +/// # trait ResType { } /// # struct ParamType; /// # mod foreign_lib { -/// # pub fn new(_: usize) -> *mut () { 42 as *mut () } -/// # pub fn do_stuff(_: *mut (), _: usize) {} +/// # pub fn new(_: usize) -> *mut () { 42 as *mut () } +/// # pub fn do_stuff(_: *mut (), _: usize) {} /// # } /// # fn convert_params(_: ParamType) -> usize { 42 } /// use std::marker::PhantomData; @@ -408,21 +516,20 @@ macro_rules! impls{ /// } /// ``` /// -/// ## Indicating ownership +/// ## Ownership and the drop check /// -/// Adding a field of type `PhantomData` also indicates that your -/// struct owns data of type `T`. This in turn implies that when your -/// struct is dropped, it may in turn drop one or more instances of -/// the type `T`, though that may not be apparent from the other -/// structure of the type itself. This is commonly necessary if the -/// structure is using a raw pointer like `*mut T` whose referent -/// may be dropped when the type is dropped, as a `*mut T` is -/// otherwise not treated as owned. +/// Adding a field of type `PhantomData` indicates that your +/// type owns data of type `T`. This in turn implies that when your +/// type is dropped, it may drop one or more instances of the type +/// `T`. This has bearing on the Rust compiler's [drop check] +/// analysis. /// /// If your struct does not in fact *own* the data of type `T`, it is /// better to use a reference type, like `PhantomData<&'a T>` /// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so /// as not to indicate ownership. +/// +/// [drop check]: ../../nomicon/dropck.html #[lang = "phantom_data"] #[stable(feature = "rust1", since = "1.0.0")] pub struct PhantomData; @@ -438,10 +545,13 @@ mod impls { /// Types that can be reflected over. /// -/// This trait is implemented for all types. Its purpose is to ensure -/// that when you write a generic function that will employ -/// reflection, that must be reflected (no pun intended) in the -/// generic bounds of that function. Here is an example: +/// By "reflection" we mean use of the [`Any`][any] trait, or related +/// machinery such as [`TypeId`][typeid]. +/// +/// `Reflect` is implemented for all types. Its purpose is to ensure +/// that when you write a generic function that will employ reflection, +/// that must be reflected (no pun intended) in the generic bounds of +/// that function. /// /// ``` /// #![feature(reflect_marker)] @@ -455,21 +565,24 @@ mod impls { /// } /// ``` /// -/// Without the declaration `T: Reflect`, `foo` would not type check -/// (note: as a matter of style, it would be preferable to write -/// `T: Any`, because `T: Any` implies `T: Reflect` and `T: 'static`, but -/// we use `Reflect` here to show how it works). The `Reflect` bound -/// thus serves to alert `foo`'s caller to the fact that `foo` may -/// behave differently depending on whether `T = u32` or not. In -/// particular, thanks to the `Reflect` bound, callers know that a -/// function declared like `fn bar(...)` will always act in -/// precisely the same way no matter what type `T` is supplied, -/// because there are no bounds declared on `T`. (The ability for a -/// caller to reason about what a function may do based solely on what -/// generic bounds are declared is often called the ["parametricity -/// property"][1].) -/// -/// [1]: http://en.wikipedia.org/wiki/Parametricity +/// Without the bound `T: Reflect`, `foo` would not typecheck. (As +/// a matter of style, it would be preferable to write `T: Any`, +/// because `T: Any` implies `T: Reflect` and `T: 'static`, but we +/// use `Reflect` here for illustrative purposes.) +/// +/// The `Reflect` bound serves to alert `foo`'s caller to the +/// fact that `foo` may behave differently depending on whether +/// `T` is `u32` or not. The ability for a caller to reason about what +/// a function may do based solely on what generic bounds are declared +/// is often called the "[parametricity property][param]". Despite the +/// use of `Reflect`, Rust lacks true parametricity because a generic +/// function can, at the very least, call [`mem::size_of`][size_of] +/// without employing any trait bounds whatsoever. +/// +/// [any]: ../any/trait.Any.html +/// [typeid]: ../any/struct.TypeId.html +/// [param]: http://en.wikipedia.org/wiki/Parametricity +/// [size_of]: ../mem/fn.size_of.html #[rustc_reflect_like] #[unstable(feature = "reflect_marker", reason = "requires RFC and more experience", From ffaebadc990579c8813b3c21b5cd05c6bfdc595a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 15 Sep 2016 23:40:48 +0300 Subject: [PATCH 9/9] Default RUST_MIN_STACK to 16MiB for now --- src/librustc_driver/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index fbd48fc42c92d..a18a754b184b0 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1054,7 +1054,8 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec(f: F) { - const STACK_SIZE: usize = 8 * 1024 * 1024; // 8MB + // Temporarily have stack size set to 16MB to deal with nom-using crates failing + const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB struct Sink(Arc>>); impl Write for Sink {