diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 7ca7ef4bd720c..3f8286f9e9e55 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -59,6 +59,16 @@ def delete_if_present(path, verbose): def download(path, url, probably_big, verbose): + for x in range(0, 4): + try: + _download(path, url, probably_big, verbose, True) + return + except RuntimeError: + print("\nspurious failure, trying again") + _download(path, url, probably_big, verbose, False) + + +def _download(path, url, probably_big, verbose, exception): if probably_big or verbose: print("downloading {}".format(url)) # see http://serverfault.com/questions/301128/how-to-download @@ -66,13 +76,16 @@ def download(path, url, probably_big, verbose): run(["PowerShell.exe", "/nologo", "-Command", "(New-Object System.Net.WebClient)" ".DownloadFile('{}', '{}')".format(url, path)], - verbose=verbose) + verbose=verbose, + exception=exception) else: if probably_big or verbose: option = "-#" else: option = "-s" - run(["curl", option, "--retry", "3", "-Sf", "-o", path, url], verbose=verbose) + run(["curl", option, "--retry", "3", "-Sf", "-o", path, url], + verbose=verbose, + exception=exception) def verify(path, sha_path, verbose): @@ -112,7 +125,7 @@ def unpack(tarball, dst, verbose=False, match=None): shutil.move(tp, fp) shutil.rmtree(os.path.join(dst, fname)) -def run(args, verbose=False): +def run(args, verbose=False, exception=False): if verbose: print("running: " + ' '.join(args)) sys.stdout.flush() @@ -122,7 +135,7 @@ def run(args, verbose=False): code = ret.wait() if code != 0: err = "failed to run: " + ' '.join(args) - if verbose: + if verbose or exception: raise RuntimeError(err) sys.exit(err) @@ -472,6 +485,8 @@ def build_triple(self): ostype += 'abi64' elif cputype in {'powerpc', 'ppc', 'ppc64'}: cputype = 'powerpc' + elif cputype == 'sparcv9': + pass elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}: cputype = 'x86_64' else: diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md index 079324d56d1e6..4f5a6a7c0332d 100644 --- a/src/doc/book/src/procedural-macros.md +++ b/src/doc/book/src/procedural-macros.md @@ -170,7 +170,7 @@ a representation of our type (which can be either a `struct` or an `enum`). Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html), there is some useful information there. We are able to get the name of the type using `ast.ident`. The `quote!` macro lets us write up the Rust code -that we wish to return and convert it into `Tokens`. `quote!` let's us use some +that we wish to return and convert it into `Tokens`. `quote!` lets us use some really cool templating mechanics; we simply write `#name` and `quote!` will replace it with the variable named `name`. You can even do some repetition similar to regular macros work. You should check out the @@ -211,3 +211,76 @@ Hello, World! My name is Waffles ``` We've done it! + +## Custom Attributes + +In some cases it might make sense to allow users some kind of configuration. +For example, the user might want to overwrite the name that is printed in the `hello_world()` method. + +This can be achieved with custom attributes: + +```rust,ignore +#[derive(HelloWorld)] +#[HelloWorldName = "the best Pancakes"] +struct Pancakes; + +fn main() { + Pancakes::hello_world(); +} +``` + +If we try to compile this though, the compiler will respond with an error: + +```bash +error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +``` + +The compiler needs to know that we're handling this attribute and to not respond with an error. +This is done in the `hello-world-derive` crate by adding `attributes` to the `proc_macro_derive` attribute: + +```rust,ignore +#[proc_macro_derive(HelloWorld, attributes(HelloWorldName))] +pub fn hello_world(input: TokenStream) -> TokenStream +``` + +Multiple attributes can be specified that way. + +## Raising Errors + +Let's assume that we do not want to accept enums as input to our custom derive method. + +This condition can be easily checked with the help of `syn`. +But how do we tell the user, that we do not accept enums? +The idiomatic way to report errors in procedural macros is to panic: + +```rust,ignore +fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens { + let name = &ast.ident; + // Check if derive(HelloWorld) was specified for a struct + if let syn::Body::Struct(_) = ast.body { + // Yes, this is a struct + quote! { + impl HelloWorld for #name { + fn hello_world() { + println!("Hello, World! My name is {}", stringify!(#name)); + } + } + } + } else { + //Nope. This is an Enum. We cannot handle these! + panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!"); + } +} +``` + +If a user now tries to derive `HelloWorld` from an enum they will be greeted with following, hopefully helpful, error: + +```bash +error: custom derive attribute panicked + --> src/main.rs + | + | #[derive(HelloWorld)] + | ^^^^^^^^^^ + | + = help: message: #[derive(HelloWorld)] is only defined for structs, not for enums! +``` diff --git a/src/doc/book/src/the-stack-and-the-heap.md b/src/doc/book/src/the-stack-and-the-heap.md index b9b3b801eae58..6866505df1310 100644 --- a/src/doc/book/src/the-stack-and-the-heap.md +++ b/src/doc/book/src/the-stack-and-the-heap.md @@ -86,7 +86,7 @@ to a large number, representing how much RAM your computer has. For example, if you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,823`. That number comes from 230, the number of bytes in a gigabyte. [^gigabyte] -[^gigabyte]: ‘Gigabyte’ can mean two things: 10^9, or 2^30. The SI standard resolved this by stating that ‘gigabyte’ is 10^9, and ‘gibibyte’ is 2^30. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here. +[^gigabyte]: ‘Gigabyte’ can mean two things: 109, or 230. The IEC standard resolved this by stating that ‘gigabyte’ is 109, and ‘gibibyte’ is 230. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here. This memory is kind of like a giant array: addresses start at zero and go up to the final number. So here’s a diagram of our first stack frame: diff --git a/src/doc/nomicon/src/exception-safety.md b/src/doc/nomicon/src/exception-safety.md index 80e72cd5e36c9..a3cbc6abd69cc 100644 --- a/src/doc/nomicon/src/exception-safety.md +++ b/src/doc/nomicon/src/exception-safety.md @@ -93,7 +93,7 @@ uselessly. We would rather have the following: ```text bubble_up(heap, index): let elem = heap[index] - while index != 0 && element < heap[parent(index)]: + while index != 0 && elem < heap[parent(index)]: heap[index] = heap[parent(index)] index = parent(index) heap[index] = elem @@ -137,7 +137,7 @@ If Rust had `try` and `finally` like in Java, we could do the following: bubble_up(heap, index): let elem = heap[index] try: - while index != 0 && element < heap[parent(index)]: +        while index != 0 && elem < heap[parent(index)]: heap[index] = heap[parent(index)] index = parent(index) finally: diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index bd74848a01d83..079541235a25e 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -62,7 +62,7 @@ //! //! A format string is required to use all of its arguments, otherwise it is a //! compile-time error. You may refer to the same argument more than once in the -//! format string, although it must always be referred to with the same type. +//! format string. //! //! ## Named parameters //! @@ -89,19 +89,8 @@ //! //! ## Argument types //! -//! Each argument's type is dictated by the format string. It is a requirement -//! that every argument is only ever referred to by one type. For example, this -//! is an invalid format string: -//! -//! ```text -//! {0:x} {0:o} -//! ``` -//! -//! This is invalid because the first argument is both referred to as a -//! hexadecimal as well as an -//! octal. -//! -//! There are various parameters which do require a particular type, however. +//! Each argument's type is dictated by the format string. +//! There are various parameters which require a particular type, however. //! An example is the `{:.*}` syntax, which sets the number of decimal places //! in floating-point types: //! @@ -113,13 +102,7 @@ //! //! If this syntax is used, then the number of characters to print precedes the //! actual object being formatted, and the number of characters must have the -//! type `usize`. Although a `usize` can be printed with `{}`, it is invalid to -//! reference an argument as such. For example this is another invalid format -//! string: -//! -//! ```text -//! {:.*} {0} -//! ``` +//! type `usize`. //! //! ## Formatting traits //! diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index e92eb4ff7bdd4..10bc5ab88c93f 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1629,6 +1629,43 @@ impl hash::Hash for String { } } +/// Implements the `+` operator for concatenating two strings. +/// +/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if +/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on +/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by +/// repeated concatenation. +/// +/// The string on the right-hand side is only borrowed; its contents are copied into the returned +/// `String`. +/// +/// # Examples +/// +/// Concatenating two `String`s takes the first by value and borrows the second: +/// +/// ``` +/// let a = String::from("hello"); +/// let b = String::from(" world"); +/// let c = a + &b; +/// // `a` is moved and can no longer be used here. +/// ``` +/// +/// If you want to keep using the first `String`, you can clone it and append to the clone instead: +/// +/// ``` +/// let a = String::from("hello"); +/// let b = String::from(" world"); +/// let c = a.clone() + &b; +/// // `a` is still valid here. +/// ``` +/// +/// Concatenating `&str` slices can be done by converting the first to a `String`: +/// +/// ``` +/// let a = "hello"; +/// let b = " world"; +/// let c = a.to_string() + b; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Add<&'a str> for String { type Output = String; @@ -1640,6 +1677,11 @@ impl<'a> Add<&'a str> for String { } } +/// Implements the `+=` operator for appending to a `String`. +/// +/// This has the same behavior as the [`push_str()`] method. +/// +/// [`push_str()`]: struct.String.html#method.push_str #[stable(feature = "stringaddassign", since = "1.12.0")] impl<'a> AddAssign<&'a str> for String { #[inline] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 9e3f117f9b20e..bc7f562452d3b 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1776,6 +1776,7 @@ array_impls! { 30 31 32 } +/// Implements comparison of vectors, lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Vec { #[inline] @@ -1787,6 +1788,7 @@ impl PartialOrd for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for Vec {} +/// Implements ordering of vectors, lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Vec { #[inline] diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs index 5360bbdeacd6a..16ecf88256670 100644 --- a/src/libcompiler_builtins/build.rs +++ b/src/libcompiler_builtins/build.rs @@ -92,7 +92,15 @@ fn main() { // compiler-rt's build system already cfg.flag("-fno-builtin"); cfg.flag("-fvisibility=hidden"); - cfg.flag("-fomit-frame-pointer"); + // Accepted practice on Solaris is to never omit frame pointer so that + // system observability tools work as expected. In addition, at least + // on Solaris, -fomit-frame-pointer on sparcv9 appears to generate + // references to data outside of the current stack frame. A search of + // the gcc bug database provides a variety of issues surrounding + // -fomit-frame-pointer on non-x86 platforms. + if !target.contains("solaris") && !target.contains("sparc") { + cfg.flag("-fomit-frame-pointer"); + } cfg.flag("-ffreestanding"); cfg.define("VISIBILITY_HIDDEN", None); } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 3e0b842557353..0331c5d4ba401 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -2202,6 +2202,7 @@ impl PartialEq<[B]> for [A] where A: PartialEq { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for [T] {} +/// Implements comparison of vectors lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for [T] { fn cmp(&self, other: &[T]) -> Ordering { @@ -2209,6 +2210,7 @@ impl Ord for [T] { } } +/// Implements comparison of vectors lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for [T] { fn partial_cmp(&self, other: &[T]) -> Option { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 49a6b1b5fceb7..925cd84154a2e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1366,6 +1366,13 @@ mod traits { use ops; use str::eq_slice; + /// Implements ordering of strings. + /// + /// Strings are ordered lexicographically by their byte values. This orders Unicode code + /// points based on their positions in the code charts. This is not necessarily the same as + /// "alphabetical" order, which varies by language and locale. Sorting strings according to + /// culturally-accepted standards requires locale-specific data that is outside the scope of + /// the `str` type. #[stable(feature = "rust1", since = "1.0.0")] impl Ord for str { #[inline] @@ -1387,6 +1394,13 @@ mod traits { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for str {} + /// Implements comparison operations on strings. + /// + /// Strings are compared lexicographically by their byte values. This compares Unicode code + /// points based on their positions in the code charts. This is not necessarily the same as + /// "alphabetical" order, which varies by language and locale. Comparing strings according to + /// culturally-accepted standards requires locale-specific data that is outside the scope of + /// the `str` type. #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for str { #[inline] diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 595059332895d..5e6566b5fcf54 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -32,7 +32,7 @@ struct LoopScope { } pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: &hir::Expr) -> CFG { + body: &hir::Body) -> CFG { let mut graph = graph::Graph::new(); let entry = graph.add_node(CFGNodeData::Entry); @@ -43,26 +43,18 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let fn_exit = graph.add_node(CFGNodeData::Exit); let body_exit; - // Find the function this expression is from. - let mut node_id = body.id; - loop { - let node = tcx.hir.get(node_id); - if hir::map::blocks::FnLikeNode::from_node(node).is_some() { - break; - } - let parent = tcx.hir.get_parent_node(node_id); - assert!(node_id != parent); - node_id = parent; - } + // Find the tables for this body. + let owner_def_id = tcx.hir.local_def_id(tcx.hir.body_owner(body.id())); + let tables = tcx.item_tables(owner_def_id); let mut cfg_builder = CFGBuilder { tcx: tcx, - tables: tcx.item_tables(tcx.hir.local_def_id(node_id)), + tables: tables, graph: graph, fn_exit: fn_exit, loop_scopes: Vec::new() }; - body_exit = cfg_builder.expr(body, entry); + body_exit = cfg_builder.expr(&body.value, entry); cfg_builder.add_contained_edge(body_exit, fn_exit); let CFGBuilder {graph, ..} = cfg_builder; CFG {graph: graph, diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index 43434b884c8d4..1473dbb1676f3 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -59,7 +59,7 @@ pub type CFGEdge = graph::Edge; impl CFG { pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: &hir::Expr) -> CFG { + body: &hir::Body) -> CFG { construct::construct(tcx, body) } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 96d1a925425e8..c5f97d1410864 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -90,6 +90,7 @@ pub enum DepNode { // things read/modify that MIR. Mir(D), + BorrowCheckKrate, BorrowCheck(D), RvalueCheck(D), Reachability, @@ -206,6 +207,7 @@ impl DepNode { match *self { Krate => Some(Krate), + BorrowCheckKrate => Some(BorrowCheckKrate), CollectLanguageItems => Some(CollectLanguageItems), CheckStaticRecursion => Some(CheckStaticRecursion), ResolveLifetimes => Some(ResolveLifetimes), diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index e365cea6d0e5e..7331756f35b8e 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -25,5 +25,6 @@ pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; +pub use self::visit::visit_all_bodies_in_krate; pub use self::visit::visit_all_item_likes_in_krate; pub use self::raii::DepTask; diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index f0a81fd1cfd33..a34a3591c151d 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -74,3 +74,13 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> }; krate.visit_all_item_likes(&mut tracking_visitor) } + +pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C) + where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), +{ + let krate = tcx.hir.krate(); + for &body_id in &krate.body_ids { + let body_owner_def_id = tcx.hir.body_owner_def_id(body_id); + callback(body_owner_def_id, body_id); + } +} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c87ce6505fcd5..ed6d2356fd91c 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -46,7 +46,7 @@ use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId}; use hir::def::{Def, PathResolution}; use session::Session; -use util::nodemap::{DefIdMap, NodeMap, FxHashMap}; +use util::nodemap::{DefIdMap, NodeMap}; use std::collections::BTreeMap; use std::iter; @@ -77,7 +77,7 @@ pub struct LoweringContext<'a> { trait_items: BTreeMap, impl_items: BTreeMap, - bodies: FxHashMap, + bodies: BTreeMap, type_def_lifetime_params: DefIdMap, } @@ -111,7 +111,7 @@ pub fn lower_crate(sess: &Session, items: BTreeMap::new(), trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), - bodies: FxHashMap(), + bodies: BTreeMap::new(), type_def_lifetime_params: DefIdMap(), }.lower_crate(krate) } @@ -185,6 +185,7 @@ impl<'a> LoweringContext<'a> { let module = self.lower_mod(&c.module); let attrs = self.lower_attrs(&c.attrs); let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); + let body_ids = body_ids(&self.bodies); hir::Crate { module: module, @@ -195,6 +196,7 @@ impl<'a> LoweringContext<'a> { trait_items: self.trait_items, impl_items: self.impl_items, bodies: self.bodies, + body_ids: body_ids, } } @@ -2408,3 +2410,11 @@ impl<'a> LoweringContext<'a> { } } } + +fn body_ids(bodies: &BTreeMap) -> Vec { + // Sorting by span ensures that we get things in order within a + // file, and also puts the files in a sensible order. + let mut body_ids: Vec<_> = bodies.keys().cloned().collect(); + body_ids.sort_by_key(|b| bodies[b].value.span); + body_ids +} diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 9f31b5b456b9f..093c931ae54c9 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -168,43 +168,48 @@ impl<'hir> MapEntry<'hir> { }) } - fn is_body_owner(self, node_id: NodeId) -> bool { + fn associated_body(self) -> Option { match self { EntryItem(_, item) => { match item.node { ItemConst(_, body) | ItemStatic(.., body) | - ItemFn(_, _, _, _, _, body) => body.node_id == node_id, - _ => false + ItemFn(_, _, _, _, _, body) => Some(body), + _ => None, } } EntryTraitItem(_, item) => { match item.node { TraitItemKind::Const(_, Some(body)) | - TraitItemKind::Method(_, TraitMethod::Provided(body)) => { - body.node_id == node_id - } - _ => false + TraitItemKind::Method(_, TraitMethod::Provided(body)) => Some(body), + _ => None } } EntryImplItem(_, item) => { match item.node { ImplItemKind::Const(_, body) | - ImplItemKind::Method(_, body) => body.node_id == node_id, - _ => false + ImplItemKind::Method(_, body) => Some(body), + _ => None, } } EntryExpr(_, expr) => { match expr.node { - ExprClosure(.., body, _) => body.node_id == node_id, - _ => false + ExprClosure(.., body, _) => Some(body), + _ => None, } } - _ => false + _ => None + } + } + + fn is_body_owner(self, node_id: NodeId) -> bool { + match self.associated_body() { + Some(b) => b.node_id == node_id, + None => false, } } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4ebe416e1bfe6..8715c89c6540d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -31,7 +31,7 @@ pub use self::PathParameters::*; use hir::def::Def; use hir::def_id::DefId; -use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; +use util::nodemap::{NodeMap, FxHashSet}; use syntax_pos::{Span, ExpnId, DUMMY_SP}; use syntax::codemap::{self, Spanned}; @@ -409,7 +409,13 @@ pub struct Crate { pub trait_items: BTreeMap, pub impl_items: BTreeMap, - pub bodies: FxHashMap, + pub bodies: BTreeMap, + + /// A list of the body ids written out in the order in which they + /// appear in the crate. If you're going to process all the bodies + /// in the crate, you should iterate over this list rather than the keys + /// of bodies. + pub body_ids: Vec, } impl Crate { diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 9295fb2ee327b..f48ff87689fb0 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -379,40 +379,41 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { values: Option>, terr: &TypeError<'tcx>) { - let expected_found = match values { - None => None, - Some(values) => match self.values_str(&values) { - Some((expected, found)) => Some((expected, found)), - None => { - // Derived error. Cancel the emitter. - self.tcx.sess.diagnostic().cancel(diag); - return - } + let (expected_found, is_simple_error) = match values { + None => (None, false), + Some(values) => { + let is_simple_error = match values { + ValuePairs::Types(exp_found) => { + exp_found.expected.is_primitive() && exp_found.found.is_primitive() + } + _ => false, + }; + let vals = match self.values_str(&values) { + Some((expected, found)) => Some((expected, found)), + None => { + // Derived error. Cancel the emitter. + self.tcx.sess.diagnostic().cancel(diag); + return + } + }; + (vals, is_simple_error) } }; let span = cause.span; if let Some((expected, found)) = expected_found { - let is_simple_error = if let &TypeError::Sorts(ref values) = terr { - values.expected.is_primitive() && values.found.is_primitive() - } else { - false - }; - - if !is_simple_error { - if expected == found { - if let &TypeError::Sorts(ref values) = terr { - diag.note_expected_found_extra( - &"type", &expected, &found, - &format!(" ({})", values.expected.sort_string(self.tcx)), - &format!(" ({})", values.found.sort_string(self.tcx))); - } else { - diag.note_expected_found(&"type", &expected, &found); - } - } else { + match (terr, is_simple_error, expected == found) { + (&TypeError::Sorts(ref values), false, true) => { + diag.note_expected_found_extra( + &"type", &expected, &found, + &format!(" ({})", values.expected.sort_string(self.tcx)), + &format!(" ({})", values.found.sort_string(self.tcx))); + } + (_, false, _) => { diag.note_expected_found(&"type", &expected, &found); } + _ => (), } } diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index bd35bfc9829a5..cdb081ab40098 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -19,7 +19,7 @@ use ty::{self, TyCtxt, FreeRegion, Region}; use ty::wf::ImpliedBound; use rustc_data_structures::transitive_relation::TransitiveRelation; -#[derive(Clone)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub struct FreeRegionMap { // Stores the relation `a < b`, where `a` and `b` are regions. relation: TransitiveRelation @@ -30,6 +30,10 @@ impl FreeRegionMap { FreeRegionMap { relation: TransitiveRelation::new() } } + pub fn is_empty(&self) -> bool { + self.relation.is_empty() + } + pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self, implied_bounds: &[ImpliedBound<'tcx>]) { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 19bb8a63aa277..33fb997a14e70 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -242,6 +242,11 @@ pub struct TypeckTables<'tcx> { /// Lints for the body of this fn generated by typeck. pub lints: lint::LintTable, + + /// Stores the free-region relationships that were deduced from + /// its where clauses and parameter types. These are then + /// read-again by borrowck. + pub free_region_map: FreeRegionMap, } impl<'tcx> TypeckTables<'tcx> { @@ -259,6 +264,7 @@ impl<'tcx> TypeckTables<'tcx> { fru_field_types: NodeMap(), cast_kinds: NodeMap(), lints: lint::LintTable::new(), + free_region_map: FreeRegionMap::new(), } } @@ -406,14 +412,6 @@ pub struct GlobalCtxt<'tcx> { pub region_maps: RegionMaps, - // For each fn declared in the local crate, type check stores the - // free-region relationships that were deduced from its where - // clauses and parameter types. These are then read-again by - // borrowck. (They are not used during trans, and hence are not - // serialized or needed for cross-crate fns.) - free_region_maps: RefCell>, - // FIXME: jroesch make this a refcell - pub tables: RefCell>>, /// Maps from a trait item to the trait item "descriptor" @@ -706,16 +704,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { interned } - pub fn store_free_region_map(self, id: NodeId, map: FreeRegionMap) { - if self.free_region_maps.borrow_mut().insert(id, map).is_some() { - bug!("Tried to overwrite interned FreeRegionMap for NodeId {:?}", id) - } - } - - pub fn free_region_map(self, id: NodeId) -> FreeRegionMap { - self.free_region_maps.borrow()[&id].clone() - } - pub fn lift>(self, value: &T) -> Option { value.lift_to_tcx(self) } @@ -762,7 +750,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { types: common_types, named_region_map: named_region_map, region_maps: region_maps, - free_region_maps: RefCell::new(FxHashMap()), item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())), variance_computed: Cell::new(false), sess: s, diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 24ca476e5ff79..77c863a012318 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -187,7 +187,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { // which contains a Foo<((T, T), (T, T))> // which contains a Foo<(((T, T), (T, T)), ((T, T), (T, T)))> // etc. - let error = format!("reached recursion limit while checking + let error = format!("reached recursion limit while checking \ inhabitedness of `{}`", self); tcx.sess.fatal(&error); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7937d2ccfe46d..3af38683cd229 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2668,6 +2668,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor); } + /// Invokes `callback` for each body in the krate. This will + /// create a read edge from `DepNode::Krate` to the current task; + /// it is meant to be run in the context of some global task like + /// `BorrowckCrate`. The callback would then create a task like + /// `BorrowckBody(DefId)` to process each individual item. + pub fn visit_all_bodies_in_krate(self, callback: C) + where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), + { + dep_graph::visit_all_bodies_in_krate(self.global_tcx(), callback) + } + /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` /// with the name of the crate containing the impl. pub fn span_of_impl(self, impl_did: DefId) -> Result { diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 1d5d1e3ab2fc7..0c179469448fe 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -200,6 +200,7 @@ supported_targets! { ("armv7s-apple-ios", armv7s_apple_ios), ("x86_64-sun-solaris", x86_64_sun_solaris), + ("sparcv9-sun-solaris", sparcv9_sun_solaris), ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu), ("i686-pc-windows-gnu", i686_pc_windows_gnu), diff --git a/src/librustc_back/target/sparcv9_sun_solaris.rs b/src/librustc_back/target/sparcv9_sun_solaris.rs new file mode 100644 index 0000000000000..c88e5a402f2f5 --- /dev/null +++ b/src/librustc_back/target/sparcv9_sun_solaris.rs @@ -0,0 +1,35 @@ +// 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. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::solaris_base::opts(); + base.pre_link_args.push("-m64".to_string()); + // llvm calls this "v9" + base.cpu = "v9".to_string(); + base.max_atomic_width = Some(64); + + Ok(Target { + llvm_target: "sparcv9-sun-solaris".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), + // Use "sparc64" instead of "sparcv9" here, since the former is already + // used widely in the source base. If we ever needed ABI + // differentiation from the sparc64, we could, but that would probably + // just be confusing. + arch: "sparc64".to_string(), + target_os: "solaris".to_string(), + target_env: "".to_string(), + target_vendor: "sun".to_string(), + options: base, + }) +} diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index dbab3bca52b4e..c0f681680a967 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -27,7 +27,7 @@ use rustc::middle::mem_categorization as mc; use std::mem; use std::rc::Rc; use syntax::ast; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::DUMMY_SP; #[derive(PartialEq, Eq, PartialOrd, Ord)] enum Fragment { @@ -200,7 +200,6 @@ impl FragmentSets { pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, - sp: Span, id: ast::NodeId) { let span_err = tcx.hir.attrs(id).iter() .any(|a| a.check_name("rustc_move_fragments")); @@ -208,6 +207,8 @@ pub fn instrument_move_fragments<'a, 'tcx>(this: &MoveData<'tcx>, if !span_err && !print { return; } + let sp = tcx.hir.span(id); + let instrument_all_paths = |kind, vec_rc: &Vec| { for (i, mpi) in vec_rc.iter().enumerate() { let lp = || this.path_loan_path(*mpi); diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 1783ca74a2592..28b6c7a13f171 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -28,9 +28,6 @@ use rustc::ty::{self, TyCtxt}; use syntax::ast; use syntax_pos::Span; use rustc::hir; -use rustc::hir::Expr; -use rustc::hir::intravisit; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; use self::restrictions::RestrictionResult; @@ -514,47 +511,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } } -/// Context used while gathering loans on static initializers -/// -/// This visitor walks static initializer's expressions and makes -/// sure the loans being taken are sound. -struct StaticInitializerCtxt<'a, 'tcx: 'a> { - bccx: &'a BorrowckCtxt<'a, 'tcx>, - body_id: hir::BodyId, -} - -impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None - } - - fn visit_expr(&mut self, ex: &'tcx Expr) { - if let hir::ExprAddrOf(mutbl, ref base) = ex.node { - let infcx = self.bccx.tcx.borrowck_fake_infer_ctxt(self.body_id); - let mc = mc::MemCategorizationContext::new(&infcx); - let base_cmt = mc.cat_expr(&base).unwrap(); - let borrow_kind = ty::BorrowKind::from_mutbl(mutbl); - // Check that we don't allow borrows of unsafe static items. - let err = check_aliasability(self.bccx, ex.span, - BorrowViolation(euv::AddrOf), - base_cmt, borrow_kind).is_err(); - if err { - return; // reported an error, no sense in reporting more. - } - } - - intravisit::walk_expr(self, ex); - } -} - -pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, body: hir::BodyId) { - debug!("gather_loans_in_static_initializer(expr={:?})", body); - - let mut sicx = StaticInitializerCtxt { - bccx: bccx, - body_id: body - }; - - let body = sicx.bccx.tcx.hir.body(body); - sicx.visit_body(body); -} diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 46179b31d5cb4..47b614a81ae25 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -32,14 +32,12 @@ use rustc::middle::dataflow::DataFlowOperator; use rustc::middle::dataflow::KillFrom; use rustc::hir::def_id::DefId; use rustc::middle::expr_use_visitor as euv; -use rustc::middle::free_region::FreeRegionMap; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::region; use rustc::ty::{self, TyCtxt}; use std::fmt; -use std::mem; use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; @@ -47,7 +45,7 @@ use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use rustc::hir; -use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; +use rustc::hir::intravisit::{self, Visitor}; pub mod check_loans; @@ -62,93 +60,14 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; -impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir) - } - - fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl, - b: hir::BodyId, s: Span, id: ast::NodeId) { - match fk { - FnKind::ItemFn(..) | - FnKind::Method(..) => { - self.with_temp_region_map(id, |this| { - borrowck_fn(this, fk, fd, b, s, id, fk.attrs()) - }); - } - - FnKind::Closure(..) => { - borrowck_fn(self, fk, fd, b, s, id, fk.attrs()); - } - } - } - - fn visit_item(&mut self, item: &'tcx hir::Item) { - borrowck_item(self, item); - } - - fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { - if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node { - gather_loans::gather_loans_in_static_initializer(self, expr); - } - intravisit::walk_trait_item(self, ti); - } - - fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { - if let hir::ImplItemKind::Const(_, expr) = ii.node { - gather_loans::gather_loans_in_static_initializer(self, expr); - } - intravisit::walk_impl_item(self, ii); - } -} - pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut bccx = BorrowckCtxt { - tcx: tcx, - free_region_map: FreeRegionMap::new(), - stats: BorrowStats { - loaned_paths_same: 0, - loaned_paths_imm: 0, - stable_paths: 0, - guaranteed_paths: 0 - } - }; - - tcx.visit_all_item_likes_in_krate(DepNode::BorrowCheck, &mut bccx.as_deep_visitor()); - - if tcx.sess.borrowck_stats() { - println!("--- borrowck stats ---"); - println!("paths requiring guarantees: {}", - bccx.stats.guaranteed_paths); - println!("paths requiring loans : {}", - make_stat(&bccx, bccx.stats.loaned_paths_same)); - println!("paths requiring imm loans : {}", - make_stat(&bccx, bccx.stats.loaned_paths_imm)); - println!("stable paths : {}", - make_stat(&bccx, bccx.stats.stable_paths)); - } - - fn make_stat(bccx: &BorrowckCtxt, stat: usize) -> String { - let total = bccx.stats.guaranteed_paths as f64; - let perc = if total == 0.0 { 0.0 } else { stat as f64 * 100.0 / total }; - format!("{} ({:.0}%)", stat, perc) - } -} - -fn borrowck_item<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, item: &'tcx hir::Item) { - // Gather loans for items. Note that we don't need - // to check loans for single expressions. The check - // loan step is intended for things that have a data - // flow dependent conditions. - match item.node { - hir::ItemStatic(.., ex) | - hir::ItemConst(_, ex) => { - gather_loans::gather_loans_in_static_initializer(this, ex); - } - _ => { } - } - - intravisit::walk_item(this, item); + tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, || { + tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| { + tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), || { + borrowck_fn(tcx, body_id); + }); + }); + }); } /// Collection of conclusions determined via borrow checker analyses. @@ -158,40 +77,39 @@ pub struct AnalysisData<'a, 'tcx: 'a> { pub move_data: move_data::FlowedMoveData<'a, 'tcx>, } -fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, - fk: FnKind<'tcx>, - decl: &'tcx hir::FnDecl, - body_id: hir::BodyId, - sp: Span, - id: ast::NodeId, - attributes: &[ast::Attribute]) { - debug!("borrowck_fn(id={})", id); +fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { + debug!("borrowck_fn(body_id={:?})", body_id); - let body = this.tcx.hir.body(body_id); + let owner_id = tcx.hir.body_owner(body_id); + let owner_def_id = tcx.hir.local_def_id(owner_id); + let attributes = tcx.get_attrs(owner_def_id); + let tables = tcx.item_tables(owner_def_id); - if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) { - this.with_temp_region_map(id, |this| { - mir::borrowck_mir(this, id, attributes) - }); + let mut bccx = &mut BorrowckCtxt { + tcx: tcx, + tables: tables, + }; + + let body = bccx.tcx.hir.body(body_id); + + if bccx.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") { + mir::borrowck_mir(bccx, owner_id, &attributes); } - let cfg = cfg::CFG::new(this.tcx, &body.value); + let cfg = cfg::CFG::new(bccx.tcx, &body); let AnalysisData { all_loans, loans: loan_dfcx, move_data: flowed_moves } = - build_borrowck_dataflow_data(this, &cfg, body_id); + build_borrowck_dataflow_data(bccx, &cfg, body_id); move_data::fragments::instrument_move_fragments(&flowed_moves.move_data, - this.tcx, - sp, - id); - move_data::fragments::build_unfragmented_map(this, + bccx.tcx, + owner_id); + move_data::fragments::build_unfragmented_map(bccx, &flowed_moves.move_data, - id); - - check_loans::check_loans(this, &loan_dfcx, &flowed_moves, &all_loans[..], body); + owner_id); - intravisit::walk_fn(this, fk, decl, body_id, sp, id); + check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans[..], body); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, @@ -241,23 +159,20 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, /// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer. pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - body: hir::BodyId, + body_id: hir::BodyId, cfg: &cfg::CFG) -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>) { + let owner_id = tcx.hir.body_owner(body_id); + let owner_def_id = tcx.hir.local_def_id(owner_id); + let tables = tcx.item_tables(owner_def_id); let mut bccx = BorrowckCtxt { tcx: tcx, - free_region_map: FreeRegionMap::new(), - stats: BorrowStats { - loaned_paths_same: 0, - loaned_paths_imm: 0, - stable_paths: 0, - guaranteed_paths: 0 - } + tables: tables, }; - let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body); + let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id); (bccx, dataflow_data) } @@ -267,28 +182,9 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( pub struct BorrowckCtxt<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - // Hacky. As we visit various fns, we have to load up the - // free-region map for each one. This map is computed by during - // typeck for each fn item and stored -- closures just use the map - // from the fn item that encloses them. Since we walk the fns in - // order, we basically just overwrite this field as we enter a fn - // item and restore it afterwards in a stack-like fashion. Then - // the borrow checking code can assume that `free_region_map` is - // always the correct map for the current fn. Feels like it'd be - // better to just recompute this, rather than store it, but it's a - // bit of a pain to factor that code out at the moment. - free_region_map: FreeRegionMap, - - // Statistics: - stats: BorrowStats -} - -#[derive(Clone)] -struct BorrowStats { - loaned_paths_same: usize, - loaned_paths_imm: usize, - stable_paths: usize, - guaranteed_paths: usize + // tables for the current thing we are checking; set to + // Some in `borrowck_fn` and cleared later + tables: &'a ty::TypeckTables<'tcx>, } /////////////////////////////////////////////////////////////////////////// @@ -574,19 +470,12 @@ pub enum MovedValueUseKind { // Misc impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { - fn with_temp_region_map(&mut self, id: ast::NodeId, f: F) - where F: for <'b> FnOnce(&'b mut BorrowckCtxt<'a, 'tcx>) - { - let new_free_region_map = self.tcx.free_region_map(id); - let old_free_region_map = mem::replace(&mut self.free_region_map, new_free_region_map); - f(self); - self.free_region_map = old_free_region_map; - } - - pub fn is_subregion_of(&self, r_sub: &'tcx ty::Region, r_sup: &'tcx ty::Region) + pub fn is_subregion_of(&self, + r_sub: &'tcx ty::Region, + r_sup: &'tcx ty::Region) -> bool { - self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup) + self.tables.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup) } pub fn report(&self, err: BckError<'tcx>) { @@ -912,11 +801,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } mc::AliasableStatic | mc::AliasableStaticMut => { - let mut err = struct_span_err!( - self.tcx.sess, span, E0388, - "{} in a static location", prefix); - err.span_label(span, &format!("cannot write data in a static definition")); - err + // This path cannot occur. It happens when we have an + // `&mut` or assignment to a static. But in the case + // of `static X`, we get a mutability violation first, + // and never get here. In the case of `static mut X`, + // that is unsafe and hence the aliasability error is + // ignored. + span_bug!(span, "aliasability violation for static `{}`", prefix) } mc::AliasableBorrowed => { let mut e = struct_span_err!( diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 88f739d1c74bb..db4a1701e976b 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -287,27 +287,7 @@ https://doc.rust-lang.org/std/cell/ "##, E0388: r##" -A mutable borrow was attempted in a static location. - -Erroneous code example: - -```compile_fail,E0388 -static X: i32 = 1; - -static STATIC_REF: &'static mut i32 = &mut X; -// error: cannot borrow data mutably in a static location - -const CONST_REF: &'static mut i32 = &mut X; -// error: cannot borrow data mutably in a static location -``` - -To fix this error, you have to use constant borrow: - -``` -static X: i32 = 1; - -static STATIC_REF: &'static i32 = &X; -``` +E0388 was removed and is no longer issued. "##, E0389: r##" diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index cf6bf1cf1d483..3dce4398f3b91 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -28,6 +28,7 @@ #![feature(shared)] #![feature(collections_range)] #![feature(collections_bound)] +#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(nonzero)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index e09e260afc8d9..2bce7faf08cec 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -9,6 +9,7 @@ // except according to those terms. use bitvec::BitMatrix; +use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use std::cell::RefCell; use std::fmt::Debug; use std::mem; @@ -36,10 +37,10 @@ pub struct TransitiveRelation { closure: RefCell>, } -#[derive(Clone, PartialEq, PartialOrd)] +#[derive(Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)] struct Index(usize); -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] struct Edge { source: Index, target: Index, @@ -54,6 +55,10 @@ impl TransitiveRelation { } } + pub fn is_empty(&self) -> bool { + self.edges.is_empty() + } + fn index(&self, a: &T) -> Option { self.elements.iter().position(|e| *e == *a).map(Index) } @@ -305,6 +310,30 @@ fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { } } +impl Encodable for TransitiveRelation + where T: Encodable + Debug + PartialEq +{ + fn encode(&self, s: &mut E) -> Result<(), E::Error> { + s.emit_struct("TransitiveRelation", 2, |s| { + s.emit_struct_field("elements", 0, |s| self.elements.encode(s))?; + s.emit_struct_field("edges", 1, |s| self.edges.encode(s))?; + Ok(()) + }) + } +} + +impl Decodable for TransitiveRelation + where T: Decodable + Debug + PartialEq +{ + fn decode(d: &mut D) -> Result { + d.read_struct("TransitiveRelation", 2, |d| { + let elements = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?; + let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?; + Ok(TransitiveRelation { elements, edges, closure: RefCell::new(None) }) + }) + } +} + #[test] fn test_one_step() { let mut relation = TransitiveRelation::new(); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 7fd4fa44ca45d..9810f121ef2c1 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -24,6 +24,7 @@ #![deny(warnings)] #![feature(box_syntax)] +#![feature(loop_break_value)] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 21fe13997b787..54b4ae61ebe43 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -718,13 +718,24 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, mode: PpFlowGraphMode, mut out: W) -> io::Result<()> { - let cfg = match code { - blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr), - blocks::Code::FnLike(fn_like) => { - let body = tcx.hir.body(fn_like.body()); - cfg::CFG::new(tcx, &body.value) - }, + let body_id = match code { + blocks::Code::Expr(expr) => { + // Find the function this expression is from. + let mut node_id = expr.id; + loop { + let node = tcx.hir.get(node_id); + if let Some(n) = hir::map::blocks::FnLikeNode::from_node(node) { + break n.body(); + } + let parent = tcx.hir.get_parent_node(node_id); + assert!(node_id != parent); + node_id = parent; + } + } + blocks::Code::FnLike(fn_like) => fn_like.body(), }; + let body = tcx.hir.body(body_id); + let cfg = cfg::CFG::new(tcx, &body); let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; let lcfg = LabelledCFG { hir_map: &tcx.hir, diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index c7512f2971b33..40e534e25e998 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -1166,6 +1166,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { trait_items: _, impl_items: _, bodies: _, + body_ids: _, } = *krate; visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1592d17817641..c363810c50d2f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -712,7 +712,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // to have behaviour like the above, rather than // e.g. accidentally recurring after an assert. - let cfg = cfg::CFG::new(cx.tcx, &body.value); + let cfg = cfg::CFG::new(cx.tcx, &body); let mut work_queue = vec![cfg.entry]; let mut reached_exit_without_self_call = false; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index d84e9d3fd3731..7f7e27f45ff96 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -122,6 +122,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcx.visit_region_obligations(id); } rcx.resolve_regions_and_report_errors(); + + assert!(self.tables.borrow().free_region_map.is_empty()); + self.tables.borrow_mut().free_region_map = rcx.free_region_map; } /// Region checking during the WF phase for items. `wf_tys` are the @@ -156,10 +159,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcx.resolve_regions_and_report_errors(); - // For the top-level fn, store the free-region-map. We don't store - // any map for closures; they just share the same map as the - // function that created them. - self.tcx.store_free_region_map(fn_id, rcx.free_region_map); + // In this mode, we also copy the free-region-map into the + // tables of the enclosing fcx. In the other regionck modes + // (e.g., `regionck_item`), we don't have an enclosing tables. + assert!(self.tables.borrow().free_region_map.is_empty()); + self.tables.borrow_mut().free_region_map = rcx.free_region_map; } } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index a292227058379..9504dd254c884 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -54,6 +54,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_type_nodes(); wbcx.visit_cast_types(); wbcx.visit_lints(); + wbcx.visit_free_region_map(); let tables = self.tcx.alloc_tables(wbcx.tables); self.tcx.tables.borrow_mut().insert(item_def_id, tables); @@ -316,6 +317,14 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints); } + fn visit_free_region_map(&mut self) { + if self.fcx.writeback_errors.get() { + return + } + + self.tables.free_region_map = self.fcx.tables.borrow().free_region_map.clone(); + } + fn visit_anon_types(&self) { if self.fcx.writeback_errors.get() { return diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 0fca374f6e6d1..038dea77f3ead 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -59,6 +59,10 @@ fn main() { println!("cargo:rustc-link-lib=userenv"); println!("cargo:rustc-link-lib=shell32"); } else if target.contains("fuchsia") { + // use system-provided libbacktrace + if cfg!(feature = "backtrace") { + println!("cargo:rustc-link-lib=backtrace"); + } println!("cargo:rustc-link-lib=magenta"); println!("cargo:rustc-link-lib=mxio"); println!("cargo:rustc-link-lib=launchpad"); // for std::process diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index fc4fd4ce92b1b..f15e7ff891684 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -14,6 +14,8 @@ use sync::{Mutex, Condvar}; /// A barrier enables multiple threads to synchronize the beginning /// of some computation. /// +/// # Examples +/// /// ``` /// use std::sync::{Arc, Barrier}; /// use std::thread; @@ -50,8 +52,19 @@ struct BarrierState { /// A result returned from wait. /// -/// Currently this opaque structure only has one method, `.is_leader()`. Only +/// Currently this opaque structure only has one method, [`.is_leader()`]. Only /// one thread will receive a result that will return `true` from this function. +/// +/// [`.is_leader()`]: #method.is_leader +/// +/// # Examples +/// +/// ``` +/// use std::sync::Barrier; +/// +/// let barrier = Barrier::new(1); +/// let barrier_wait_result = barrier.wait(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct BarrierWaitResult(bool); @@ -65,8 +78,18 @@ impl fmt::Debug for Barrier { impl Barrier { /// Creates a new barrier that can block a given number of threads. /// - /// A barrier will block `n`-1 threads which call `wait` and then wake up - /// all threads at once when the `n`th thread calls `wait`. + /// A barrier will block `n`-1 threads which call [`wait`] and then wake up + /// all threads at once when the `n`th thread calls [`wait`]. + /// + /// [`wait`]: #method.wait + /// + /// # Examples + /// + /// ``` + /// use std::sync::Barrier; + /// + /// let barrier = Barrier::new(10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(n: usize) -> Barrier { Barrier { @@ -84,10 +107,37 @@ impl Barrier { /// Barriers are re-usable after all threads have rendezvoused once, and can /// be used continuously. /// - /// A single (arbitrary) thread will receive a `BarrierWaitResult` that - /// returns `true` from `is_leader` when returning from this function, and + /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that + /// returns `true` from [`is_leader`] when returning from this function, and /// all other threads will receive a result that will return `false` from - /// `is_leader` + /// [`is_leader`]. + /// + /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html + /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Barrier}; + /// use std::thread; + /// + /// let mut handles = Vec::with_capacity(10); + /// let barrier = Arc::new(Barrier::new(10)); + /// for _ in 0..10 { + /// let c = barrier.clone(); + /// // The same messages will be printed together. + /// // You will NOT see any interleaving. + /// handles.push(thread::spawn(move|| { + /// println!("before wait"); + /// c.wait(); + /// println!("after wait"); + /// })); + /// } + /// // Wait for other threads to finish. + /// for handle in handles { + /// handle.join().unwrap(); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn wait(&self) -> BarrierWaitResult { let mut lock = self.lock.lock().unwrap(); @@ -120,10 +170,22 @@ impl fmt::Debug for BarrierWaitResult { } impl BarrierWaitResult { - /// Returns whether this thread from `wait` is the "leader thread". + /// Returns whether this thread from [`wait`] is the "leader thread". /// /// Only one thread will have `true` returned from their result, all other /// threads will have `false` returned. + /// + /// [`wait`]: struct.Barrier.html#method.wait + /// + /// # Examples + /// + /// ``` + /// use std::sync::Barrier; + /// + /// let barrier = Barrier::new(1); + /// let barrier_wait_result = barrier.wait(); + /// println!("{:?}", barrier_wait_result.is_leader()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_leader(&self) -> bool { self.0 } } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 0d6ad5e38e98b..97b84d59218ac 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -133,11 +133,13 @@ unsafe impl Sync for Mutex { } /// dropped (falls out of scope), the lock will be unlocked. /// /// The data protected by the mutex can be access through this guard via its -/// `Deref` and `DerefMut` implementations. +/// [`Deref`] and [`DerefMut`] implementations. /// /// This structure is created by the [`lock()`] and [`try_lock()`] methods on /// [`Mutex`]. /// +/// [`Deref`]: ../../std/ops/trait.Deref.html +/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html /// [`lock()`]: struct.Mutex.html#method.lock /// [`try_lock()`]: struct.Mutex.html#method.try_lock /// [`Mutex`]: struct.Mutex.html diff --git a/src/libstd/sys/unix/process/magenta.rs b/src/libstd/sys/unix/process/magenta.rs index a81bedcad22ff..08a827ce08142 100644 --- a/src/libstd/sys/unix/process/magenta.rs +++ b/src/libstd/sys/unix/process/magenta.rs @@ -111,7 +111,7 @@ extern { pub fn mx_handle_duplicate(handle: mx_handle_t, rights: mx_rights_t, out: *const mx_handle_t) -> mx_handle_t; - pub fn mx_handle_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t, + pub fn mx_object_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t, pending: *mut mx_signals_t) -> mx_status_t; pub fn mx_object_get_info(handle: mx_handle_t, topic: u32, buffer: *mut c_void, diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 0bb2e0c1a83d4..608e44ca9e86e 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -151,7 +151,7 @@ impl Process { let mut avail: mx_size_t = 0; unsafe { - mx_cvt(mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED, + mx_cvt(mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED, MX_TIME_INFINITE, ptr::null_mut()))?; mx_cvt(mx_object_get_info(self.handle.raw(), MX_INFO_PROCESS, &mut proc_info as *mut _ as *mut libc::c_void, @@ -174,7 +174,7 @@ impl Process { let mut avail: mx_size_t = 0; unsafe { - let status = mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED, + let status = mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED, 0, ptr::null_mut()); match status { 0 => { }, // Success diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 93e320c45223c..2bc066d3fea55 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -235,7 +235,7 @@ pub use self::local::{LocalKey, LocalKeyState}; pub struct Builder { // A name for the thread-to-be, for identification in panic messages name: Option, - // The size of the stack for the spawned thread + // The size of the stack for the spawned thread in bytes stack_size: Option, } @@ -289,14 +289,17 @@ impl Builder { self } - /// Sets the size of the stack for the new thread. + /// Sets the size of the stack (in bytes) for the new thread. + /// + /// The actual stack size may be greater than this value if + /// the platform specifies minimal stack size. /// /// # Examples /// /// ``` /// use std::thread; /// - /// let builder = thread::Builder::new().stack_size(10); + /// let builder = thread::Builder::new().stack_size(32 * 1024); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stack_size(mut self, size: usize) -> Builder { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 112bf61cf9722..5fdb0aa0641a0 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -106,7 +106,7 @@ impl fmt::Display for TestName { } #[derive(Clone, Copy, PartialEq, Eq)] -enum NamePadding { +pub enum NamePadding { PadNone, PadOnRight, } @@ -950,7 +950,7 @@ fn stdout_isatty() -> bool { } #[derive(Clone)] -enum TestEvent { +pub enum TestEvent { TeFiltered(Vec), TeWait(TestDesc, NamePadding), TeResult(TestDesc, TestResult, Vec), @@ -960,7 +960,7 @@ enum TestEvent { pub type MonitorMsg = (TestDesc, TestResult, Vec); -fn run_tests(opts: &TestOpts, tests: Vec, mut callback: F) -> io::Result<()> +pub fn run_tests(opts: &TestOpts, tests: Vec, mut callback: F) -> io::Result<()> where F: FnMut(TestEvent) -> io::Result<()> { use std::collections::HashMap; diff --git a/src/test/compile-fail/E0017.rs b/src/test/compile-fail/E0017.rs index 44d2f158d20bb..c6bec6090f242 100644 --- a/src/test/compile-fail/E0017.rs +++ b/src/test/compile-fail/E0017.rs @@ -19,8 +19,7 @@ static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 //~| NOTE statics require immutable values //~| ERROR E0017 //~| NOTE statics require immutable values - //~| ERROR E0388 - //~| NOTE cannot write data in a static definition + //~| ERROR cannot borrow static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 //~| NOTE statics require immutable values //~| ERROR E0017 diff --git a/src/test/compile-fail/E0388.rs b/src/test/compile-fail/E0388.rs index 13f2c23d8c4a9..2c88039d373e5 100644 --- a/src/test/compile-fail/E0388.rs +++ b/src/test/compile-fail/E0388.rs @@ -15,7 +15,7 @@ const CR: &'static mut i32 = &mut C; //~ ERROR E0017 //~| ERROR E0017 static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 //~| ERROR E0017 - //~| ERROR E0388 + //~| ERROR cannot borrow static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 //~| ERROR E0017 diff --git a/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs new file mode 100644 index 0000000000000..3c1980e5b366c --- /dev/null +++ b/src/test/compile-fail/borrowck/move-in-static-initializer-issue-38520.rs @@ -0,0 +1,28 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #38520. Check that moves of `Foo` are not +// permitted as `Foo` is not copy (even in a static/const +// initializer). + +#![feature(const_fn)] + +struct Foo(usize); + +const fn get(x: Foo) -> usize { + x.0 +} + +const X: Foo = Foo(22); +static Y: usize = get(*&X); //~ ERROR E0507 +const Z: usize = get(*&X); //~ ERROR E0507 + +fn main() { +} diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs index 4702b504f157d..8cde239ca6edf 100644 --- a/src/test/compile-fail/default_ty_param_conflict.rs +++ b/src/test/compile-fail/default_ty_param_conflict.rs @@ -23,8 +23,6 @@ fn main() { // Here, F is instantiated with $0=uint let x = foo(); //~^ ERROR: mismatched types - //~| expected type `usize` - //~| found type `isize` //~| NOTE: conflicting type parameter defaults `usize` and `isize` //~| NOTE: conflicting type parameter defaults `usize` and `isize` //~| NOTE: ...that was applied to an unconstrained type variable here diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs index b608c6c99be89..e5b035e50aa93 100644 --- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs +++ b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs @@ -29,6 +29,4 @@ fn main() { //~| NOTE: conflicting type parameter defaults `bool` and `char` //~| a second default is defined on `default_param_test::bleh` //~| NOTE: ...that was applied to an unconstrained type variable here - //~| expected type `bool` - //~| found type `char` } diff --git a/src/test/compile-fail/issue-18118.rs b/src/test/compile-fail/issue-18118.rs index 3afb34f037bcc..35e57dffb6c45 100644 --- a/src/test/compile-fail/issue-18118.rs +++ b/src/test/compile-fail/issue-18118.rs @@ -13,6 +13,6 @@ pub fn main() { //~^ ERROR blocks in constants are limited to items and tail expressions let p = 3; //~^ ERROR blocks in constants are limited to items and tail expressions - &p + &p //~ ERROR `p` does not live long enough }; } diff --git a/src/test/compile-fail/issue-35869.rs b/src/test/compile-fail/issue-35869.rs index 8b7fc80bdb6b7..d1d6390cce35b 100644 --- a/src/test/compile-fail/issue-35869.rs +++ b/src/test/compile-fail/issue-35869.rs @@ -23,15 +23,19 @@ impl Foo for Bar { fn foo(_: fn(u16) -> ()) {} //~^ ERROR method `foo` has an incompatible type for trait //~| NOTE expected u8 + //~| NOTE expected type `fn(fn(u8))` fn bar(_: Option) {} //~^ ERROR method `bar` has an incompatible type for trait //~| NOTE expected u8 + //~| NOTE expected type `fn(std::option::Option)` fn baz(_: (u16, u16)) {} //~^ ERROR method `baz` has an incompatible type for trait //~| NOTE expected u8 + //~| NOTE expected type `fn((u8, u16))` fn qux() -> u16 { 5u16 } //~^ ERROR method `qux` has an incompatible type for trait //~| NOTE expected u8 + //~| NOTE expected type `fn() -> u8` } fn main() {} diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr index b6e3d663e36bd..d9871b8970c5c 100644 --- a/src/test/ui/mismatched_types/E0053.stderr +++ b/src/test/ui/mismatched_types/E0053.stderr @@ -6,6 +6,9 @@ error[E0053]: method `foo` has an incompatible type for trait ... 19 | fn foo(x: i16) { } | ^^^ expected u16, found i16 + | + = note: expected type `fn(u16)` + found type `fn(i16)` error[E0053]: method `bar` has an incompatible type for trait --> $DIR/E0053.rs:22:12 diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index 991197c2afba3..349432f64bbc2 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -6,6 +6,9 @@ error[E0053]: method `foo` has an incompatible type for trait ... 21 | fn foo(x: i16) { } | ^^^ expected u16, found i16 + | + = note: expected type `fn(u16)` + found type `fn(i16)` error[E0053]: method `bar` has an incompatible type for trait --> $DIR/trait-impl-fn-incompatibility.rs:22:28 diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr index e4ed062214715..01364c0714407 100644 --- a/src/test/ui/span/mut-arg-hint.stderr +++ b/src/test/ui/span/mut-arg-hint.stderr @@ -1,11 +1,3 @@ -error: cannot borrow immutable borrowed content `*a` as mutable - --> $DIR/mut-arg-hint.rs:18:5 - | -17 | pub fn foo<'a>(mut a: &'a String) { - | ---------- use `&'a mut String` here to make mutable -18 | a.push_str("foo"); - | ^ cannot borrow as mutable - error: cannot borrow immutable borrowed content `*a` as mutable --> $DIR/mut-arg-hint.rs:13:9 | @@ -14,6 +6,14 @@ error: cannot borrow immutable borrowed content `*a` as mutable 13 | a.push_str("bar"); | ^ cannot borrow as mutable +error: cannot borrow immutable borrowed content `*a` as mutable + --> $DIR/mut-arg-hint.rs:18:5 + | +17 | pub fn foo<'a>(mut a: &'a String) { + | ---------- use `&'a mut String` here to make mutable +18 | a.push_str("foo"); + | ^ cannot borrow as mutable + error: cannot borrow immutable borrowed content `*a` as mutable --> $DIR/mut-arg-hint.rs:25:9 |