From 069072019ac5ea034014ab9507e6834126c8d796 Mon Sep 17 00:00:00 2001 From: ggomez Date: Thu, 21 Apr 2016 14:54:05 +0200 Subject: [PATCH 1/8] Doc improvement on std::fmt module --- src/libcollections/fmt.rs | 12 ++++++++++++ src/libcore/fmt/mod.rs | 26 ++++++++++++++++++++++++++ src/liblibc | 2 +- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index e30e0b213afa1..bf13ea067b4c8 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -505,12 +505,24 @@ use string; /// /// # Examples /// +/// Basic usage: +/// /// ``` /// use std::fmt; /// /// let s = fmt::format(format_args!("Hello, {}!", "world")); /// assert_eq!(s, "Hello, world!".to_string()); /// ``` +/// +/// Please note that using `[format!]` might be preferrable. +/// Example: +/// +/// ``` +/// let s = format!("Hello, {}!", "world"); +/// assert_eq!(s, "Hello, world!".to_string()); +/// ``` +/// +/// [format!]: ../std/macro.format!.html #[stable(feature = "rust1", since = "1.0.0")] pub fn format(args: Arguments) -> string::String { let mut output = string::String::new(); diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0c824b5a8e69a..3819657ebbb0d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -776,6 +776,32 @@ pub trait UpperExp { /// /// * output - the buffer to write output to /// * args - the precompiled arguments generated by `format_args!` +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::fmt; +/// +/// let mut output = String::new(); +/// fmt::write(&mut output, format_args!("Hello {}!", "world")) +/// .expect("Error occurred while trying to write in String"); +/// assert_eq!(output, "Hello world!"); +/// ``` +/// +/// Please note that using [write!][write_macro] might be preferrable. Example: +/// +/// ``` +/// use std::fmt::Write; +/// +/// let mut output = String::new(); +/// write!(&mut output, "Hello {}!", "world") +/// .expect("Error occurred while trying to write in String"); +/// assert_eq!(output, "Hello world!"); +/// ``` +/// +/// [write_macro]: ../std/macro.write!.html #[stable(feature = "rust1", since = "1.0.0")] pub fn write(output: &mut Write, args: Arguments) -> Result { let mut formatter = Formatter { diff --git a/src/liblibc b/src/liblibc index 7265c17d18453..2278a549559c3 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 7265c17d1845354f979a39b4ceb3a6934025b2ab +Subproject commit 2278a549559c38872b4338cb002ecc2a80d860dc From 84bd1ce9841dbefc30c2ade67964ac652856e8a3 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Thu, 28 Apr 2016 20:18:39 +0200 Subject: [PATCH 2/8] Fix std::fmt format spec: named args are allowed with "$" syntax --- src/libcollections/fmt.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 710a30ff2364e..d58c26a72136b 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -333,7 +333,7 @@ //! precision := count | '*' //! type := identifier | '' //! count := parameter | integer -//! parameter := integer '$' +//! parameter := argument '$' //! ``` //! //! # Formatting Parameters @@ -403,11 +403,12 @@ //! println!("Hello {:5}!", "x"); //! println!("Hello {:1$}!", "x", 5); //! println!("Hello {1:0$}!", 5, "x"); +//! println!("Hello {:width$}!", "x", width = 5); //! ``` //! //! Referring to an argument with the dollar syntax does not affect the "next -//! argument" counter, so it's usually a good idea to refer to all arguments by -//! their position explicitly. +//! argument" counter, so it's usually a good idea to refer to arguments by +//! position, or use named arguments. //! //! ## Precision //! @@ -426,7 +427,7 @@ //! //! the integer `N` itself is the precision. //! -//! 2. An integer followed by dollar sign `.N$`: +//! 2. An integer or name followed by dollar sign `.N$`: //! //! use format *argument* `N` (which must be a `usize`) as the precision. //! @@ -456,6 +457,10 @@ //! // Hello {next arg (x)} is {arg 2 (0.01) with precision //! // specified in its predecessor (5)} //! println!("Hello {} is {2:.*}", "x", 5, 0.01); +//! +//! // Hello {next arg (x)} is {arg "number" (0.01) with precision specified +//! // in arg "prec" (5)} +//! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); //! ``` //! //! All print the same thing: From 538098c7a4bdab205a7057b1925c1dad68382bce Mon Sep 17 00:00:00 2001 From: Stephen Mather Date: Sun, 1 May 2016 19:15:33 +0100 Subject: [PATCH 3/8] doc/book/getting-started.md: Corrected spelling of 'Internet'. --- src/doc/book/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/getting-started.md b/src/doc/book/getting-started.md index fc2a762088331..b8435438be796 100644 --- a/src/doc/book/getting-started.md +++ b/src/doc/book/getting-started.md @@ -8,7 +8,7 @@ we’ll talk about Cargo, Rust’s build system and package manager. The first step to using Rust is to install it. Generally speaking, you’ll need an Internet connection to run the commands in this section, as we’ll be -downloading Rust from the internet. +downloading Rust from the Internet. We’ll be showing off a number of commands using a terminal, and those lines all start with `$`. We don't need to type in the `$`s, they are there to indicate From 3f49920495c1db358e5964acf8182b96405ce435 Mon Sep 17 00:00:00 2001 From: Timothy McRoy Date: Sun, 1 May 2016 13:41:11 -0500 Subject: [PATCH 4/8] Add error explanation for E0501 --- src/librustc_borrowck/diagnostics.rs | 77 +++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 7f6fd9de3d294..6eccc7082aad4 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -314,6 +314,82 @@ let c = &i; // still ok! ``` "##, +E0501: r##" +This error indicates that a mutable variable is being used while it is still +captured by a closure. Because the closure has borrowed the variable, it is not +available for use until the closure goes out of scope. + +Note that a capture will either move or borrow a variable, but in this +situation, the closure is borrowing the variable. Take a look at +http://rustbyexample.com/fn/closures/capture.html for more information about +capturing. + +Example of erroneous code: + +```compile_fail +fn inside_closure(x: &mut i32) { + // Actions which require unique access +} + +fn outside_closure(x: &mut i32) { + // Actions which require unique access +} + +fn foo(a: &mut i32) { + let bar = || { + inside_closure(a) + }; + outside_closure(a); // error: cannot borrow `*a` as mutable because previous + // closure requires unique access. +} +``` + +To fix this error, you can place the closure in its own scope: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + { + let bar = || { + inside_closure(a) + }; + } // borrow on `a` ends. + outside_closure(a); // ok! +} +``` + +Or you can pass the variable as a parameter to the closure: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + let bar = |s: &mut i32| { + inside_closure(s) + }; + outside_closure(a); + bar(a); +} +``` + +It may be possible to define the closure later: + +``` +fn inside_closure(x: &mut i32) {} +fn outside_closure(x: &mut i32) {} + +fn foo(a: &mut i32) { + outside_closure(a); + let bar = || { + inside_closure(a) + }; +} +``` +"##, + E0507: r##" You tried to move out of a value which was borrowed. Erroneous code example: @@ -436,7 +512,6 @@ register_diagnostics! { E0388, // {} in a static location E0389, // {} in a `&` reference E0500, // closure requires unique access to `..` but .. is already borrowed - E0501, // cannot borrow `..`.. as .. because previous closure requires unique access E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ... E0503, // cannot use `..` because it was mutably borrowed E0504, // cannot move `..` into closure because it is borrowed From 018c595574ef78d6f00dcf529914a7a54bac6423 Mon Sep 17 00:00:00 2001 From: Stephen Mather Date: Sun, 1 May 2016 19:45:38 +0100 Subject: [PATCH 5/8] doc/book/getting-started.md: Removed references to creating a new executable from 'Converting to Cargo'. --- src/doc/book/getting-started.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/book/getting-started.md b/src/doc/book/getting-started.md index b8435438be796..e61a76a2c37a9 100644 --- a/src/doc/book/getting-started.md +++ b/src/doc/book/getting-started.md @@ -399,13 +399,13 @@ Let’s convert the Hello World program to Cargo. To Cargo-fy a project, you nee to do three things: 1. Put your source file in the right directory. -2. Get rid of the old executable (`main.exe` on Windows, `main` everywhere else) - and make a new one. +2. Get rid of the old executable (`main.exe` on Windows, `main` everywhere + else). 3. Make a Cargo configuration file. Let's get started! -### Creating a new Executable and Source Directory +### Creating a Source Directory and Removing the Old Executable First, go back to your terminal, move to your *hello_world* directory, and enter the following commands: From eba43fb5c3baaeb543edb6c0abbcf778a176c4a9 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sun, 1 May 2016 22:59:20 +0200 Subject: [PATCH 6/8] std::thread docs: spawn() returns not a Thread anymore Also move the "Thread type" section down a bit, since it is not so important anymore. Fixes: #33321 --- src/libstd/thread/mod.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index b3549dc12645a..2f0dec759b3d5 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -13,7 +13,8 @@ //! ## The threading model //! //! An executing Rust program consists of a collection of native OS threads, -//! each with their own stack and local state. +//! each with their own stack and local state. Threads can be named, and +//! provide some built-in support for low-level synchronization. //! //! Communication between threads can be done through //! [channels](../../std/sync/mpsc/index.html), Rust's message-passing @@ -37,20 +38,6 @@ //! convenient facilities for automatically waiting for the termination of a //! child thread (i.e., join). //! -//! ## The `Thread` type -//! -//! Threads are represented via the `Thread` type, which you can -//! get in one of two ways: -//! -//! * By spawning a new thread, e.g. using the `thread::spawn` function. -//! * By requesting the current thread, using the `thread::current` function. -//! -//! Threads can be named, and provide some built-in support for low-level -//! synchronization (described below). -//! -//! The `thread::current()` function is available even for threads not spawned -//! by the APIs of this module. -//! //! ## Spawning a thread //! //! A new thread can be spawned using the `thread::spawn` function: @@ -99,6 +86,18 @@ //! }); //! ``` //! +//! ## The `Thread` type +//! +//! Threads are represented via the `Thread` type, which you can get in one of +//! two ways: +//! +//! * By spawning a new thread, e.g. using the `thread::spawn` function, and +//! calling `thread()` on the `JoinHandle`. +//! * By requesting the current thread, using the `thread::current` function. +//! +//! The `thread::current()` function is available even for threads not spawned +//! by the APIs of this module. +//! //! ## Blocking support: park and unpark //! //! Every thread is equipped with some basic low-level blocking support, via the From 665be00d6f202cad32f13cc87065f71823033f54 Mon Sep 17 00:00:00 2001 From: mrmiywj Date: Sun, 1 May 2016 00:33:39 +0800 Subject: [PATCH 7/8] add help on pattern guard fix too long column fix typo of help on pattern guard one nit --- src/librustc_const_eval/diagnostics.rs | 61 +++++++++++++++++++++----- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index 4f5176f6b0be5..fa6f379e51208 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -215,22 +215,63 @@ match Some("hi".to_string()) { The variable `s` has type `String`, and its use in the guard is as a variable of type `String`. The guard code effectively executes in a separate scope to the body of the arm, so the value would be moved into this anonymous scope and -therefore become unavailable in the body of the arm. Although this example seems -innocuous, the problem is most clear when considering functions that take their -argument by value. +therefore becomes unavailable in the body of the arm. -```compile_fail +The problem above can be solved by using the `ref` keyword. + +``` match Some("hi".to_string()) { - Some(s) if { drop(s); false } => (), - Some(s) => {}, // use s. + Some(ref s) if s.len() == 0 => {}, _ => {}, } ``` -The value would be dropped in the guard then become unavailable not only in the -body of that arm but also in all subsequent arms! The solution is to bind by -reference when using guards or refactor the entire expression, perhaps by -putting the condition inside the body of the arm. +Though this example seems innocuous and easy to solve, the problem becomes clear +when it encounters functions which consume the value: + +```compile_fail +struct A{} + +impl A { + fn consume(self) -> usize { + 0 + } +} + +fn main() { + let a = Some(A{}); + match a { + Some(y) if y.consume() > 0 => {} + _ => {} + } +} +``` + +In this situation, even the `ref` keyword cannot solve it, since borrowed +content cannot be moved. This problem cannot be solved generally. If the value +can be cloned, here is a not-so-specific solution: + +``` +#[derive(Clone)] +struct A{} + +impl A { + fn consume(self) -> usize { + 0 + } +} + +fn main() { + let a = Some(A{}); + match a{ + Some(y) if y.clone().consume() > 0 => {} + _ => {} + } +} +``` + +If the value will be consumed in the pattern guard, using its clone will not +move its ownership, so the code works. "##, E0009: r##" From fcebf52f416c943c546d42381f5541d50e5aea08 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Mon, 2 May 2016 14:52:48 +0200 Subject: [PATCH 8/8] typeck: if a private field exists, also check for a public method For example, `Vec::len` is both a field and a method, and usually encountering `vec.len` just means that the parens were forgotten. Fixes: #26472 --- src/librustc_typeck/check/method/mod.rs | 5 +++-- src/librustc_typeck/check/mod.rs | 13 ++++++++++--- src/test/compile-fail/issue-26472.rs | 24 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/issue-26472.rs diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 31d95af4fbb9c..b9f36a252c612 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -84,7 +84,8 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, method_name: ast::Name, self_ty: ty::Ty<'tcx>, - call_expr_id: ast::NodeId) + call_expr_id: ast::NodeId, + allow_private: bool) -> bool { let mode = probe::Mode::MethodCall; @@ -93,7 +94,7 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Err(NoMatch(..)) => false, Err(Ambiguity(..)) => true, Err(ClosureAmbiguity(..)) => true, - Err(PrivateMatch(..)) => true, + Err(PrivateMatch(..)) => allow_private, } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2d0505d9347d5..759d0ee619dbd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2943,12 +2943,19 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, if let Some((did, field_ty)) = private_candidate { let struct_path = fcx.tcx().item_path_str(did); - let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path); - fcx.tcx().sess.span_err(expr.span, &msg); fcx.write_ty(expr.id, field_ty); + let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path); + let mut err = fcx.tcx().sess.struct_span_err(expr.span, &msg); + // Also check if an accessible method exists, which is often what is meant. + if method::exists(fcx, field.span, field.node, expr_t, expr.id, false) { + err.fileline_note(field.span, &format!("a method called `{}` also exists, \ + maybe a `()` to call it is missing?", + field.node)); + } + err.emit(); } else if field.node == keywords::Invalid.name() { fcx.write_error(expr.id); - } else if method::exists(fcx, field.span, field.node, expr_t, expr.id) { + } else if method::exists(fcx, field.span, field.node, expr_t, expr.id, true) { fcx.type_error_struct(field.span, |actual| { format!("attempted to take value of method `{}` on type \ diff --git a/src/test/compile-fail/issue-26472.rs b/src/test/compile-fail/issue-26472.rs new file mode 100644 index 0000000000000..2ee6f1cdead8c --- /dev/null +++ b/src/test/compile-fail/issue-26472.rs @@ -0,0 +1,24 @@ +// 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. + +mod sub { + pub struct S { len: usize } + impl S { + pub fn new() -> S { S { len: 0 } } + pub fn len(&self) -> usize { self.len } + } +} + +fn main() { + let s = sub::S::new(); + let v = s.len; + //~^ ERROR field `len` of struct `sub::S` is private + //~| NOTE a method called `len` also exists, maybe a `()` to call it is missing +}