Rollup merge of #34547 - sanxiyn:pretty-lifetime, r=pnkfelix

Fix pretty-printing of lifetime bound

Fix #34527.
This commit is contained in:
Jeffrey Seyfried 2016-06-30 07:39:32 +00:00
commit a8751e077f
20 changed files with 244 additions and 133 deletions

View File

@ -27,12 +27,18 @@ endif
define DEF_LLVM_RULES
ifeq ($(1),$$(CFG_BUILD))
LLVM_DEPS_TARGET_$(1) := $$(LLVM_DEPS)
else
LLVM_DEPS_TARGET_$(1) := $$(LLVM_DEPS) $$(LLVM_CONFIG_$$(CFG_BUILD))
endif
# If CFG_LLVM_ROOT is defined then we don't build LLVM ourselves
ifeq ($(CFG_LLVM_ROOT),)
LLVM_STAMP_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-auto-clean-stamp
$$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS) $$(LLVM_STAMP_$(1))
$$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS_TARGET_$(1)) $$(LLVM_STAMP_$(1))
@$$(call E, cmake: llvm)
ifeq ($$(findstring msvc,$(1)),msvc)
$$(Q)$$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \
@ -42,7 +48,13 @@ else
endif
$$(Q)touch $$(LLVM_CONFIG_$(1))
ifeq ($$(findstring msvc,$(1)),msvc)
clean-llvm$(1):
else
clean-llvm$(1):
@$$(call E, clean: llvm)
$$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) clean
endif
else
clean-llvm$(1):

View File

@ -135,39 +135,7 @@ pub fn compiler_rt(build: &Build, target: &str) {
let dst = build.compiler_rt_out(target);
let arch = target.split('-').next().unwrap();
let mode = if build.config.rust_optimize {"Release"} else {"Debug"};
let (dir, build_target, libname) = if target.contains("linux") ||
target.contains("freebsd") ||
target.contains("netbsd") {
let os = if target.contains("android") {"-android"} else {""};
let arch = if arch.starts_with("arm") && target.contains("eabihf") {
"armhf"
} else {
arch
};
let target = format!("clang_rt.builtins-{}{}", arch, os);
("linux".to_string(), target.clone(), target)
} else if target.contains("darwin") {
let target = format!("clang_rt.builtins_{}_osx", arch);
("builtins".to_string(), target.clone(), target)
} else if target.contains("windows-gnu") {
let target = format!("clang_rt.builtins-{}", arch);
("windows".to_string(), target.clone(), target)
} else if target.contains("windows-msvc") {
(format!("windows/{}", mode),
"lib/builtins/builtins".to_string(),
format!("clang_rt.builtins-{}", arch.replace("i686", "i386")))
} else {
panic!("can't get os from target: {}", target)
};
let output = dst.join("build/lib").join(dir)
.join(staticlib(&libname, target));
build.compiler_rt_built.borrow_mut().insert(target.to_string(),
output.clone());
if fs::metadata(&output).is_ok() {
return
}
let _ = fs::remove_dir_all(&dst);
t!(fs::create_dir_all(&dst));
let build_llvm_config = build.llvm_config(&build.config.build);
let mut cfg = cmake::Config::new(build.src.join("src/compiler-rt"));
cfg.target(target)
@ -181,8 +149,63 @@ pub fn compiler_rt(build: &Build, target: &str) {
// inform about c/c++ compilers, the c++ compiler isn't actually used but
// it's needed to get the initial configure to work on all platforms.
.define("CMAKE_C_COMPILER", build.cc(target))
.define("CMAKE_CXX_COMPILER", build.cc(target))
.build_target(&build_target);
.define("CMAKE_CXX_COMPILER", build.cc(target));
let (dir, build_target, libname) = if target.contains("linux") ||
target.contains("freebsd") ||
target.contains("netbsd") {
let os_extra = if target.contains("android") && target.contains("arm") {
"-android"
} else {
""
};
let builtins_arch = match arch {
"i586" => "i386",
"arm" | "armv7" if target.contains("android") => "armhf",
"arm" if target.contains("eabihf") => "armhf",
_ => arch,
};
let target = format!("clang_rt.builtins-{}{}", builtins_arch, os_extra);
("linux".to_string(), target.clone(), target)
} else if target.contains("apple-darwin") {
let builtins_arch = match arch {
"i686" => "i386",
_ => arch,
};
let target = format!("clang_rt.builtins_{}_osx", builtins_arch);
("builtins".to_string(), target.clone(), target)
} else if target.contains("apple-ios") {
cfg.define("COMPILER_RT_ENABLE_IOS", "ON");
let target = match arch {
"armv7s" => "hard_pic_armv7em_macho_embedded".to_string(),
"aarch64" => "builtins_arm64_ios".to_string(),
_ => format!("hard_pic_{}_macho_embedded", arch),
};
("builtins".to_string(), target.clone(), target)
} else if target.contains("windows-gnu") {
let target = format!("clang_rt.builtins-{}", arch);
("windows".to_string(), target.clone(), target)
} else if target.contains("windows-msvc") {
let builtins_arch = match arch {
"i586" | "i686" => "i386",
_ => arch,
};
(format!("windows/{}", mode),
"lib/builtins/builtins".to_string(),
format!("clang_rt.builtins-{}", builtins_arch))
} else {
panic!("can't get os from target: {}", target)
};
let output = dst.join("build/lib").join(dir)
.join(staticlib(&libname, target));
build.compiler_rt_built.borrow_mut().insert(target.to_string(),
output.clone());
if fs::metadata(&output).is_ok() {
return
}
let _ = fs::remove_dir_all(&dst);
t!(fs::create_dir_all(&dst));
cfg.build_target(&build_target);
cfg.build();
}

View File

@ -322,7 +322,7 @@ to our closure when we pass it to `call_with_one`, so we use `&||`.
A quick note about closures that use explicit lifetimes. Sometimes you might have a closure
that takes a reference like so:
```
```rust
fn call_with_ref<F>(some_closure:F) -> i32
where F: Fn(&i32) -> i32 {
@ -334,8 +334,8 @@ fn call_with_ref<F>(some_closure:F) -> i32
Normally you can specify the lifetime of the parameter to our closure. We
could annotate it on the function declaration:
```ignore
fn call_with_ref<'a, F>(some_closure:F) -> i32
```rust,ignore
fn call_with_ref<'a, F>(some_closure:F) -> i32
where F: Fn(&'a 32) -> i32 {
```
@ -353,11 +353,11 @@ fn call_with_ref<F>(some_closure:F) -> i32
where F: for<'a> Fn(&'a 32) -> i32 {
```
This lets the Rust compiler find the minimum lifetime to invoke our closure and
This lets the Rust compiler find the minimum lifetime to invoke our closure and
satisfy the borrow checker's rules. Our function then compiles and excutes as we
expect.
```
```rust
fn call_with_ref<F>(some_closure:F) -> i32
where F: for<'a> Fn(&'a i32) -> i32 {

View File

@ -22,12 +22,10 @@ As an example, lets make a *phrases* crate, which will give us various phrase
in different languages. To keep things simple, well stick to greetings and
farewells as two kinds of phrases, and use English and Japanese (日本語) as
two languages for those phrases to be in. Well use this module layout:
```text
+-----------+
+---| greetings |
| +-----------+
+---------+ |
+---------+ | +-----------+
+---| english |---+
| +---------+ | +-----------+
| +---| farewells |
@ -37,8 +35,7 @@ two languages for those phrases to be in. Well use this module layout:
| +---| greetings |
| +----------+ | +-----------+
+---| japanese |--+
+----------+ |
| +-----------+
+----------+ | +-----------+
+---| farewells |
+-----------+
```

View File

@ -67,7 +67,7 @@ Vectors have a [generic type][generics] `Vec<T>`, so in this example `v` will ha
[arrays]: primitive-types.html#arrays
[vectors]: vectors.html
[heap]: the-stack-and-the-heap.html
[heap]: the-stack-and-the-heap.html#the-heap
[stack]: the-stack-and-the-heap.html#the-stack
[bindings]: variable-bindings.html
[generics]: generics.html
@ -136,6 +136,8 @@ Rust allocates memory for an integer [i32] on the [stack][sh], copies the bit
pattern representing the value of 10 to the allocated memory and binds the
variable name x to this memory region for future reference.
[i32]: primitive-types.html#numeric-types
Now consider the following code fragment:
```rust

View File

@ -397,10 +397,10 @@ fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
}
// can be called with T == i64
fn inverse<T>() -> T
fn inverse<T>(x: i32) -> T
// this is using ConvertTo as if it were "ConvertTo<i64>"
where i32: ConvertTo<T> {
42.convert()
x.convert()
}
```

View File

@ -114,12 +114,20 @@ Non-doc comments are interpreted as a form of whitespace.
## Whitespace
Whitespace is any non-empty string containing only the following characters:
Whitespace is any non-empty string containing only characters that have the
`Pattern_White_Space` Unicode property, namely:
- `U+0009` (horizontal tab, `'\t'`)
- `U+000A` (line feed, `'\n'`)
- `U+000B` (vertical tab)
- `U+000C` (form feed)
- `U+000D` (carriage return, `'\r'`)
- `U+0020` (space, `' '`)
- `U+0009` (tab, `'\t'`)
- `U+000A` (LF, `'\n'`)
- `U+000D` (CR, `'\r'`)
- `U+0085` (next line)
- `U+200E` (left-to-right mark)
- `U+200F` (right-to-left mark)
- `U+2028` (line separator)
- `U+2029` (paragraph separator)
Rust is a "free-form" language, meaning that all forms of whitespace serve only
to separate _tokens_ in the grammar, and have no semantic significance.

View File

@ -28,6 +28,7 @@
//! format!("{:?}", (3, 4)); // => "(3, 4)"
//! format!("{value}", value=4); // => "4"
//! format!("{} {}", 1, 2); // => "1 2"
//! format!("{:04}", 42); // => "0042" with leading zeros
//! ```
//!
//! From these, you can see that the first argument is a format string. It is

View File

@ -673,45 +673,35 @@ extern "C" {
"##,
E0269: r##"
Functions must eventually return a value of their return type. For example, in
the following function:
A returned value was expected but not all control paths return one.
Erroneous code example:
```compile_fail,E0269
fn abracada_FAIL() -> String {
"this won't work".to_string();
// error: not all control paths return a value
}
```
If the condition is true, the value `x` is returned, but if the condition is
false, control exits the `if` block and reaches a place where nothing is being
returned. All possible control paths must eventually return a `u8`, which is not
happening here.
In the previous code, the function is supposed to return a `String`, however,
the code returns nothing (because of the ';'). Another erroneous code would be:
An easy fix for this in a complicated function is to specify a default return
value, if possible:
```ignore
fn foo(x: u8) -> u8 {
if x > 0 {
x // alternatively, `return x`
```compile_fail
fn abracada_FAIL(b: bool) -> u32 {
if b {
0
} else {
"a" // It fails because an `u32` was expected and something else is
// returned.
}
// lots of other if branches
0 // return 0 if all else fails
}
```
It is advisable to find out what the unhandled cases are and check for them,
returning an appropriate value or panicking if necessary. Check if you need
to remove a semicolon from the last expression, like in this case:
```ignore
fn foo(x: u8) -> u8 {
inner(2*x + 1);
}
```
The semicolon discards the return value of `inner`, instead of returning
it from `foo`.
to remove a semicolon from the last expression, like in the first erroneous
code example.
"##,
E0270: r##"

View File

@ -189,8 +189,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
}
hir::ViewPathList(p, paths) => {
let mine = paths.into_iter().filter(|path| {
!self.maybe_inline_local(path.node.id(), None, false, om,
please_inline)
!self.maybe_inline_local(path.node.id(), path.node.rename(),
false, om, please_inline)
}).collect::<hir::HirVec<hir::PathListItem>>();
if mine.is_empty() {

View File

@ -78,14 +78,11 @@ pub struct Empty { _priv: () }
/// A slightly sad example of not reading anything into a buffer:
///
/// ```
/// use std::io;
/// use std::io::Read;
/// use std::io::{self, Read};
///
/// # fn foo() -> io::Result<String> {
/// let mut buffer = String::new();
/// try!(io::empty().read_to_string(&mut buffer));
/// # Ok(buffer)
/// # }
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn empty() -> Empty { Empty { _priv: () } }
@ -113,6 +110,16 @@ pub struct Repeat { byte: u8 }
///
/// All reads from this reader will succeed by filling the specified buffer with
/// the given byte.
///
/// # Examples
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = [0; 3];
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }
@ -139,6 +146,16 @@ pub struct Sink { _priv: () }
///
/// All calls to `write` on the returned instance will return `Ok(buf.len())`
/// and the contents of the buffer will not be inspected.
///
/// # Examples
///
/// ```rust
/// use std::io::{self, Write};
///
/// let mut buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::sink().write(&mut buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn sink() -> Sink { Sink { _priv: () } }

View File

@ -217,7 +217,7 @@ impl f32 {
/// // Values between `0` and `min` are Subnormal.
/// assert!(!lower_than_min.is_normal());
/// ```
/// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number
/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_normal(self) -> bool { num::Float::is_normal(self) }
@ -923,12 +923,12 @@ impl f32 {
/// Computes the tangent of a number (in radians).
///
/// ```
/// use std::f64;
/// use std::f32;
///
/// let x = f64::consts::PI/4.0;
/// let x = f32::consts::PI / 4.0;
/// let abs_difference = (x.tan() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// assert!(abs_difference <= f32::EPSILON);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
@ -1052,12 +1052,14 @@ impl f32 {
/// number is close to zero.
///
/// ```
/// let x = 7.0f64;
/// use std::f32;
///
/// // e^(ln(7)) - 1
/// let abs_difference = (x.ln().exp_m1() - 6.0).abs();
/// let x = 6.0f32;
///
/// assert!(abs_difference < 1e-10);
/// // e^(ln(6)) - 1
/// let abs_difference = (x.ln().exp_m1() - 5.0).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]

View File

@ -147,23 +147,23 @@ impl f64 {
/// [subnormal][subnormal], or `NaN`.
///
/// ```
/// use std::f32;
/// use std::f64;
///
/// let min = f32::MIN_POSITIVE; // 1.17549435e-38f64
/// let max = f32::MAX;
/// let lower_than_min = 1.0e-40_f32;
/// let zero = 0.0f32;
/// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64
/// let max = f64::MAX;
/// let lower_than_min = 1.0e-308_f64;
/// let zero = 0.0f64;
///
/// assert!(min.is_normal());
/// assert!(max.is_normal());
///
/// assert!(!zero.is_normal());
/// assert!(!f32::NAN.is_normal());
/// assert!(!f32::INFINITY.is_normal());
/// assert!(!f64::NAN.is_normal());
/// assert!(!f64::INFINITY.is_normal());
/// // Values between `0` and `min` are Subnormal.
/// assert!(!lower_than_min.is_normal());
/// ```
/// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number
/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_normal(self) -> bool { num::Float::is_normal(self) }
@ -655,9 +655,9 @@ impl f64 {
/// ```
/// #![feature(float_extras)]
///
/// let x = 1.0f32;
/// let x = 1.0f64;
///
/// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs();
/// let abs_diff = (x.next_after(2.0) - 1.0000000000000002220446049250313_f64).abs();
///
/// assert!(abs_diff < 1e-10);
/// ```

View File

@ -525,6 +525,26 @@ impl<'a> Hash for PrefixComponent<'a> {
///
/// See the module documentation for an in-depth explanation of components and
/// their role in the API.
///
/// This `enum` is created from iterating over the [`path::Components`]
/// `struct`.
///
/// # Examples
///
/// ```rust
/// use std::path::{Component, Path};
///
/// let path = Path::new("/tmp/foo/bar.txt");
/// let components = path.components().collect::<Vec<_>>();
/// assert_eq!(&components, &[
/// Component::RootDir,
/// Component::Normal("tmp".as_ref()),
/// Component::Normal("foo".as_ref()),
/// Component::Normal("bar.txt".as_ref()),
/// ]);
/// ```
///
/// [`path::Components`]: struct.Components.html
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Component<'a> {

View File

@ -490,9 +490,6 @@ mod prim_tuple { }
///
/// *[See also the `std::f32` module](f32/index.html).*
///
/// However, please note that examples are shared between the `f64` and `f32`
/// primitive types. So it's normal if you see usage of `f64` in there.
///
mod prim_f32 { }
#[doc(primitive = "f64")]
@ -501,9 +498,6 @@ mod prim_f32 { }
///
/// *[See also the `std::f64` module](f64/index.html).*
///
/// However, please note that examples are shared between the `f64` and `f32`
/// primitive types. So it's normal if you see usage of `f32` in there.
///
mod prim_f64 { }
#[doc(primitive = "i8")]

View File

@ -394,6 +394,19 @@ pub fn sleep_ms(ms: u32) {
/// signal being received or a spurious wakeup. Platforms which do not support
/// nanosecond precision for sleeping will have `dur` rounded up to the nearest
/// granularity of time they can sleep for.
///
/// # Examples
///
/// ```rust,no_run
/// use std::{thread, time};
///
/// let ten_millis = time::Duration::from_millis(10);
/// let now = time::Instant::now();
///
/// thread::sleep(ten_millis);
///
/// assert!(now.elapsed() >= ten_millis);
/// ```
#[stable(feature = "thread_sleep", since = "1.4.0")]
pub fn sleep(dur: Duration) {
imp::Thread::sleep(dur)

View File

@ -1338,7 +1338,7 @@ impl<'a> State<'a> {
if comma {
try!(self.word_space(","))
}
try!(self.print_lifetime_def(lifetime_def));
try!(self.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds));
comma = true;
}
try!(word(&mut self.s, ">"));
@ -2749,16 +2749,20 @@ impl<'a> State<'a> {
self.print_name(lifetime.name)
}
pub fn print_lifetime_def(&mut self,
lifetime: &ast::LifetimeDef)
-> io::Result<()>
pub fn print_lifetime_bounds(&mut self,
lifetime: &ast::Lifetime,
bounds: &[ast::Lifetime])
-> io::Result<()>
{
try!(self.print_lifetime(&lifetime.lifetime));
let mut sep = ":";
for v in &lifetime.bounds {
try!(word(&mut self.s, sep));
try!(self.print_lifetime(v));
sep = "+";
try!(self.print_lifetime(lifetime));
if !bounds.is_empty() {
try!(word(&mut self.s, ": "));
for (i, bound) in bounds.iter().enumerate() {
if i != 0 {
try!(word(&mut self.s, " + "));
}
try!(self.print_lifetime(bound));
}
}
Ok(())
}
@ -2781,8 +2785,8 @@ impl<'a> State<'a> {
try!(self.commasep(Inconsistent, &ints[..], |s, &idx| {
if idx < generics.lifetimes.len() {
let lifetime = &generics.lifetimes[idx];
s.print_lifetime_def(lifetime)
let lifetime_def = &generics.lifetimes[idx];
s.print_lifetime_bounds(&lifetime_def.lifetime, &lifetime_def.bounds)
} else {
let idx = idx - generics.lifetimes.len();
let param = &generics.ty_params[idx];
@ -2833,16 +2837,7 @@ impl<'a> State<'a> {
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
ref bounds,
..}) => {
try!(self.print_lifetime(lifetime));
try!(word(&mut self.s, ":"));
for (i, bound) in bounds.iter().enumerate() {
try!(self.print_lifetime(bound));
if i != 0 {
try!(word(&mut self.s, ":"));
}
}
try!(self.print_lifetime_bounds(lifetime, bounds));
}
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
try!(self.print_path(path, false, 0));

View File

@ -0,0 +1,15 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// pp-exact
fn f1<'a, 'b, 'c>(_x: &'a u32, _y: &'b u32, _z: &'c u32) where 'c: 'a + 'b { }
fn main() { }

View File

@ -10,6 +10,6 @@
// pp-exact
fn f<'a, 'b, T>(t: T) -> isize where T: 'a, 'a:'b, T: Eq { 0 }
fn f<'a, 'b, T>(t: T) -> isize where T: 'a, 'a: 'b, T: Eq { 0 }
fn main() { }

View File

@ -0,0 +1,22 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_name = "foo"]
mod second {
pub struct SomeTypeWithLongName;
}
// @has foo/index.html
// @!has - SomeTypeWithLongName
// @has foo/struct.SomeType.html
// @!has - SomeTypeWithLongName
// @!has foo/struct.SomeTypeWithLongName.html
pub use second::{SomeTypeWithLongName as SomeType};