Auto merge of #29039 - Manishearth:rollup, r=Manishearth
- Successful merges: #28991, #29004, #29006, #29013, #29016, #29024, #29027, #29028, #29029, #29032, #29035 - Failed merges:
This commit is contained in:
commit
294ef5b158
13 changed files with 516 additions and 273 deletions
|
@ -1435,11 +1435,11 @@ struct Foo;
|
||||||
|
|
||||||
trait Shape { fn area(&self) -> f64; }
|
trait Shape { fn area(&self) -> f64; }
|
||||||
trait Circle : Shape { fn radius(&self) -> f64; }
|
trait Circle : Shape { fn radius(&self) -> f64; }
|
||||||
# impl Shape for Foo {
|
impl Shape for Foo {
|
||||||
# fn area(&self) -> f64 {
|
fn area(&self) -> f64 {
|
||||||
# 0.0
|
0.0
|
||||||
# }
|
}
|
||||||
# }
|
}
|
||||||
impl Circle for Foo {
|
impl Circle for Foo {
|
||||||
fn radius(&self) -> f64 {
|
fn radius(&self) -> f64 {
|
||||||
println!("calling area: {}", self.area());
|
println!("calling area: {}", self.area());
|
||||||
|
|
|
@ -74,7 +74,7 @@ associated with it, but the compiler lets you elide (i.e. omit, see
|
||||||
["Lifetime Elision"][lifetime-elision] below) them in common cases.
|
["Lifetime Elision"][lifetime-elision] below) them in common cases.
|
||||||
Before we get to that, though, let’s break the explicit example down:
|
Before we get to that, though, let’s break the explicit example down:
|
||||||
|
|
||||||
[lifetime-elision]: #user-content-lifetime-elision
|
[lifetime-elision]: #lifetime-elision
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
fn bar<'a>(...)
|
fn bar<'a>(...)
|
||||||
|
|
|
@ -3032,7 +3032,52 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
|
||||||
fn next_back(&mut self) -> Option<A> { Some(self.element.clone()) }
|
fn next_back(&mut self) -> Option<A> { Some(self.element.clone()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new iterator that endlessly repeats the element `elt`.
|
/// Creates a new iterator that endlessly repeats a single element.
|
||||||
|
///
|
||||||
|
/// The `repeat()` function repeats a single value over and over and over and
|
||||||
|
/// over and over and 🔁.
|
||||||
|
///
|
||||||
|
/// Infinite iterators like `repeat()` are often used with adapters like
|
||||||
|
/// [`take()`], in order to make them finite.
|
||||||
|
///
|
||||||
|
/// [`take()`]: trait.Iterator.html#method.take
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::iter;
|
||||||
|
///
|
||||||
|
/// // the number four 4ever:
|
||||||
|
/// let mut fours = iter::repeat(4);
|
||||||
|
///
|
||||||
|
/// assert_eq!(Some(4), fours.next());
|
||||||
|
/// assert_eq!(Some(4), fours.next());
|
||||||
|
/// assert_eq!(Some(4), fours.next());
|
||||||
|
/// assert_eq!(Some(4), fours.next());
|
||||||
|
/// assert_eq!(Some(4), fours.next());
|
||||||
|
///
|
||||||
|
/// // yup, still four
|
||||||
|
/// assert_eq!(Some(4), fours.next());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Going finite with [`take()`]:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::iter;
|
||||||
|
///
|
||||||
|
/// // that last example was too many fours. Let's only have four fours.
|
||||||
|
/// let mut four_fours = iter::repeat(4).take(4);
|
||||||
|
///
|
||||||
|
/// assert_eq!(Some(4), four_fours.next());
|
||||||
|
/// assert_eq!(Some(4), four_fours.next());
|
||||||
|
/// assert_eq!(Some(4), four_fours.next());
|
||||||
|
/// assert_eq!(Some(4), four_fours.next());
|
||||||
|
///
|
||||||
|
/// // ... and now we're done
|
||||||
|
/// assert_eq!(None, four_fours.next());
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
|
pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
|
||||||
|
@ -3089,6 +3134,19 @@ impl<T> Default for Empty<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an iterator that yields nothing.
|
/// Creates an iterator that yields nothing.
|
||||||
|
///
|
||||||
|
/// # Exampes
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::iter;
|
||||||
|
///
|
||||||
|
/// // this could have been an iterator over i32, but alas, it's just not.
|
||||||
|
/// let mut nope = iter::empty::<i32>();
|
||||||
|
///
|
||||||
|
/// assert_eq!(None, nope.next());
|
||||||
|
/// ```
|
||||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||||
pub fn empty<T>() -> Empty<T> {
|
pub fn empty<T>() -> Empty<T> {
|
||||||
Empty(marker::PhantomData)
|
Empty(marker::PhantomData)
|
||||||
|
@ -3129,6 +3187,56 @@ impl<T> ExactSizeIterator for Once<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an iterator that yields an element exactly once.
|
/// Creates an iterator that yields an element exactly once.
|
||||||
|
///
|
||||||
|
/// This is commonly used to adapt a single value into a [`chain()`] of other
|
||||||
|
/// kinds of iteration. Maybe you have an iterator that covers almost
|
||||||
|
/// everything, but you need an extra special case. Maybe you have a function
|
||||||
|
/// which works on iterators, but you only need to process one value.
|
||||||
|
///
|
||||||
|
/// [`chain()`]: trait.Iterator.html#method.chain
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Basic usage:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::iter;
|
||||||
|
///
|
||||||
|
/// // one is the loneliest number
|
||||||
|
/// let mut one = iter::once(1);
|
||||||
|
///
|
||||||
|
/// assert_eq!(Some(1), one.next());
|
||||||
|
///
|
||||||
|
/// // just one, that's all we get
|
||||||
|
/// assert_eq!(None, one.next());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Chaining together with another iterator. Let's say that we want to iterate
|
||||||
|
/// over each file of the `.foo` directory, but also a configuration file,
|
||||||
|
/// `.foorc`:
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::iter;
|
||||||
|
/// use std::fs;
|
||||||
|
/// use std::path::PathBuf;
|
||||||
|
///
|
||||||
|
/// let dirs = fs::read_dir(".foo").unwrap();
|
||||||
|
///
|
||||||
|
/// // we need to convert from an iterator of DirEntry-s to an iterator of
|
||||||
|
/// // PathBufs, so we use map
|
||||||
|
/// let dirs = dirs.map(|file| file.unwrap().path());
|
||||||
|
///
|
||||||
|
/// // now, our iterator just for our config file
|
||||||
|
/// let config = iter::once(PathBuf::from(".foorc"));
|
||||||
|
///
|
||||||
|
/// // chain the two iterators together into one big iterator
|
||||||
|
/// let files = dirs.chain(config);
|
||||||
|
///
|
||||||
|
/// // this will give us all of the files in .foo as well as .foorc
|
||||||
|
/// for f in files {
|
||||||
|
/// println!("{:?}", f);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[stable(feature = "iter_once", since = "1.2.0")]
|
#[stable(feature = "iter_once", since = "1.2.0")]
|
||||||
pub fn once<T>(value: T) -> Once<T> {
|
pub fn once<T>(value: T) -> Once<T> {
|
||||||
Once { inner: Some(value).into_iter() }
|
Once { inner: Some(value).into_iter() }
|
||||||
|
|
|
@ -75,7 +75,7 @@ pub struct FormatSpec<'a> {
|
||||||
/// The descriptor string representing the name of the format desired for
|
/// The descriptor string representing the name of the format desired for
|
||||||
/// this argument, this can be empty or any number of characters, although
|
/// this argument, this can be empty or any number of characters, although
|
||||||
/// it is required to be one word.
|
/// it is required to be one word.
|
||||||
pub ty: &'a str
|
pub ty: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enum describing where an argument for a format can be located.
|
/// Enum describing where an argument for a format can be located.
|
||||||
|
@ -202,7 +202,12 @@ impl<'a> Parser<'a> {
|
||||||
/// returned, otherwise the character is consumed and true is returned.
|
/// returned, otherwise the character is consumed and true is returned.
|
||||||
fn consume(&mut self, c: char) -> bool {
|
fn consume(&mut self, c: char) -> bool {
|
||||||
if let Some(&(_, maybe)) = self.cur.peek() {
|
if let Some(&(_, maybe)) = self.cur.peek() {
|
||||||
if c == maybe { self.cur.next(); true } else { false }
|
if c == maybe {
|
||||||
|
self.cur.next();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -227,7 +232,11 @@ impl<'a> Parser<'a> {
|
||||||
/// character
|
/// character
|
||||||
fn ws(&mut self) {
|
fn ws(&mut self) {
|
||||||
while let Some(&(_, c)) = self.cur.peek() {
|
while let Some(&(_, c)) = self.cur.peek() {
|
||||||
if c.is_whitespace() { self.cur.next(); } else { break }
|
if c.is_whitespace() {
|
||||||
|
self.cur.next();
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,8 +246,12 @@ impl<'a> Parser<'a> {
|
||||||
// we may not consume the character, peek the iterator
|
// we may not consume the character, peek the iterator
|
||||||
while let Some(&(pos, c)) = self.cur.peek() {
|
while let Some(&(pos, c)) = self.cur.peek() {
|
||||||
match c {
|
match c {
|
||||||
'{' | '}' => { return &self.input[start..pos]; }
|
'{' | '}' => {
|
||||||
_ => { self.cur.next(); }
|
return &self.input[start..pos];
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.cur.next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&self.input[start..self.input.len()]
|
&self.input[start..self.input.len()]
|
||||||
|
@ -263,7 +276,7 @@ impl<'a> Parser<'a> {
|
||||||
Some(&(_, c)) if c.is_alphabetic() => {
|
Some(&(_, c)) if c.is_alphabetic() => {
|
||||||
ArgumentNamed(self.word())
|
ArgumentNamed(self.word())
|
||||||
}
|
}
|
||||||
_ => ArgumentNext
|
_ => ArgumentNext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,7 +292,9 @@ impl<'a> Parser<'a> {
|
||||||
width: CountImplied,
|
width: CountImplied,
|
||||||
ty: &self.input[..0],
|
ty: &self.input[..0],
|
||||||
};
|
};
|
||||||
if !self.consume(':') { return spec }
|
if !self.consume(':') {
|
||||||
|
return spec
|
||||||
|
}
|
||||||
|
|
||||||
// fill character
|
// fill character
|
||||||
if let Some(&(_, c)) = self.cur.peek() {
|
if let Some(&(_, c)) = self.cur.peek() {
|
||||||
|
@ -347,7 +362,11 @@ impl<'a> Parser<'a> {
|
||||||
/// width.
|
/// width.
|
||||||
fn count(&mut self) -> Count<'a> {
|
fn count(&mut self) -> Count<'a> {
|
||||||
if let Some(i) = self.integer() {
|
if let Some(i) = self.integer() {
|
||||||
if self.consume('$') { CountIsParam(i) } else { CountIs(i) }
|
if self.consume('$') {
|
||||||
|
CountIsParam(i)
|
||||||
|
} else {
|
||||||
|
CountIs(i)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let tmp = self.cur.clone();
|
let tmp = self.cur.clone();
|
||||||
let word = self.word();
|
let word = self.word();
|
||||||
|
@ -370,8 +389,13 @@ impl<'a> Parser<'a> {
|
||||||
/// characters.
|
/// characters.
|
||||||
fn word(&mut self) -> &'a str {
|
fn word(&mut self) -> &'a str {
|
||||||
let start = match self.cur.peek() {
|
let start = match self.cur.peek() {
|
||||||
Some(&(pos, c)) if c.is_xid_start() => { self.cur.next(); pos }
|
Some(&(pos, c)) if c.is_xid_start() => {
|
||||||
_ => { return &self.input[..0]; }
|
self.cur.next();
|
||||||
|
pos
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return &self.input[..0];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
while let Some(&(pos, c)) = self.cur.peek() {
|
while let Some(&(pos, c)) = self.cur.peek() {
|
||||||
if c.is_xid_continue() {
|
if c.is_xid_continue() {
|
||||||
|
@ -397,7 +421,11 @@ impl<'a> Parser<'a> {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found { Some(cur) } else { None }
|
if found {
|
||||||
|
Some(cur)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,178 +465,210 @@ mod tests {
|
||||||
same("\\}}", &[String("\\"), String("}")]);
|
same("\\}}", &[String("\\"), String("}")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test] fn invalid01() { musterr("{") }
|
#[test]
|
||||||
#[test] fn invalid02() { musterr("}") }
|
fn invalid01() {
|
||||||
#[test] fn invalid04() { musterr("{3a}") }
|
musterr("{")
|
||||||
#[test] fn invalid05() { musterr("{:|}") }
|
}
|
||||||
#[test] fn invalid06() { musterr("{:>>>}") }
|
#[test]
|
||||||
|
fn invalid02() {
|
||||||
|
musterr("}")
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn invalid04() {
|
||||||
|
musterr("{3a}")
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn invalid05() {
|
||||||
|
musterr("{:|}")
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn invalid06() {
|
||||||
|
musterr("{:>>>}")
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn format_nothing() {
|
fn format_nothing() {
|
||||||
same("{}", &[NextArgument(Argument {
|
same("{}",
|
||||||
position: ArgumentNext,
|
&[NextArgument(Argument {
|
||||||
format: fmtdflt(),
|
position: ArgumentNext,
|
||||||
})]);
|
format: fmtdflt(),
|
||||||
|
})]);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_position() {
|
fn format_position() {
|
||||||
same("{3}", &[NextArgument(Argument {
|
same("{3}",
|
||||||
position: ArgumentIs(3),
|
&[NextArgument(Argument {
|
||||||
format: fmtdflt(),
|
position: ArgumentIs(3),
|
||||||
})]);
|
format: fmtdflt(),
|
||||||
|
})]);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_position_nothing_else() {
|
fn format_position_nothing_else() {
|
||||||
same("{3:}", &[NextArgument(Argument {
|
same("{3:}",
|
||||||
position: ArgumentIs(3),
|
&[NextArgument(Argument {
|
||||||
format: fmtdflt(),
|
position: ArgumentIs(3),
|
||||||
})]);
|
format: fmtdflt(),
|
||||||
|
})]);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_type() {
|
fn format_type() {
|
||||||
same("{3:a}", &[NextArgument(Argument {
|
same("{3:a}",
|
||||||
position: ArgumentIs(3),
|
&[NextArgument(Argument {
|
||||||
format: FormatSpec {
|
position: ArgumentIs(3),
|
||||||
fill: None,
|
format: FormatSpec {
|
||||||
align: AlignUnknown,
|
fill: None,
|
||||||
flags: 0,
|
align: AlignUnknown,
|
||||||
precision: CountImplied,
|
flags: 0,
|
||||||
width: CountImplied,
|
precision: CountImplied,
|
||||||
ty: "a",
|
width: CountImplied,
|
||||||
},
|
ty: "a",
|
||||||
})]);
|
},
|
||||||
|
})]);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_align_fill() {
|
fn format_align_fill() {
|
||||||
same("{3:>}", &[NextArgument(Argument {
|
same("{3:>}",
|
||||||
position: ArgumentIs(3),
|
&[NextArgument(Argument {
|
||||||
format: FormatSpec {
|
position: ArgumentIs(3),
|
||||||
fill: None,
|
format: FormatSpec {
|
||||||
align: AlignRight,
|
fill: None,
|
||||||
flags: 0,
|
align: AlignRight,
|
||||||
precision: CountImplied,
|
flags: 0,
|
||||||
width: CountImplied,
|
precision: CountImplied,
|
||||||
ty: "",
|
width: CountImplied,
|
||||||
},
|
ty: "",
|
||||||
})]);
|
},
|
||||||
same("{3:0<}", &[NextArgument(Argument {
|
})]);
|
||||||
position: ArgumentIs(3),
|
same("{3:0<}",
|
||||||
format: FormatSpec {
|
&[NextArgument(Argument {
|
||||||
fill: Some('0'),
|
position: ArgumentIs(3),
|
||||||
align: AlignLeft,
|
format: FormatSpec {
|
||||||
flags: 0,
|
fill: Some('0'),
|
||||||
precision: CountImplied,
|
align: AlignLeft,
|
||||||
width: CountImplied,
|
flags: 0,
|
||||||
ty: "",
|
precision: CountImplied,
|
||||||
},
|
width: CountImplied,
|
||||||
})]);
|
ty: "",
|
||||||
same("{3:*<abcd}", &[NextArgument(Argument {
|
},
|
||||||
position: ArgumentIs(3),
|
})]);
|
||||||
format: FormatSpec {
|
same("{3:*<abcd}",
|
||||||
fill: Some('*'),
|
&[NextArgument(Argument {
|
||||||
align: AlignLeft,
|
position: ArgumentIs(3),
|
||||||
flags: 0,
|
format: FormatSpec {
|
||||||
precision: CountImplied,
|
fill: Some('*'),
|
||||||
width: CountImplied,
|
align: AlignLeft,
|
||||||
ty: "abcd",
|
flags: 0,
|
||||||
},
|
precision: CountImplied,
|
||||||
})]);
|
width: CountImplied,
|
||||||
|
ty: "abcd",
|
||||||
|
},
|
||||||
|
})]);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_counts() {
|
fn format_counts() {
|
||||||
same("{:10s}", &[NextArgument(Argument {
|
same("{:10s}",
|
||||||
position: ArgumentNext,
|
&[NextArgument(Argument {
|
||||||
format: FormatSpec {
|
position: ArgumentNext,
|
||||||
fill: None,
|
format: FormatSpec {
|
||||||
align: AlignUnknown,
|
fill: None,
|
||||||
flags: 0,
|
align: AlignUnknown,
|
||||||
precision: CountImplied,
|
flags: 0,
|
||||||
width: CountIs(10),
|
precision: CountImplied,
|
||||||
ty: "s",
|
width: CountIs(10),
|
||||||
},
|
ty: "s",
|
||||||
})]);
|
},
|
||||||
same("{:10$.10s}", &[NextArgument(Argument {
|
})]);
|
||||||
position: ArgumentNext,
|
same("{:10$.10s}",
|
||||||
format: FormatSpec {
|
&[NextArgument(Argument {
|
||||||
fill: None,
|
position: ArgumentNext,
|
||||||
align: AlignUnknown,
|
format: FormatSpec {
|
||||||
flags: 0,
|
fill: None,
|
||||||
precision: CountIs(10),
|
align: AlignUnknown,
|
||||||
width: CountIsParam(10),
|
flags: 0,
|
||||||
ty: "s",
|
precision: CountIs(10),
|
||||||
},
|
width: CountIsParam(10),
|
||||||
})]);
|
ty: "s",
|
||||||
same("{:.*s}", &[NextArgument(Argument {
|
},
|
||||||
position: ArgumentNext,
|
})]);
|
||||||
format: FormatSpec {
|
same("{:.*s}",
|
||||||
fill: None,
|
&[NextArgument(Argument {
|
||||||
align: AlignUnknown,
|
position: ArgumentNext,
|
||||||
flags: 0,
|
format: FormatSpec {
|
||||||
precision: CountIsNextParam,
|
fill: None,
|
||||||
width: CountImplied,
|
align: AlignUnknown,
|
||||||
ty: "s",
|
flags: 0,
|
||||||
},
|
precision: CountIsNextParam,
|
||||||
})]);
|
width: CountImplied,
|
||||||
same("{:.10$s}", &[NextArgument(Argument {
|
ty: "s",
|
||||||
position: ArgumentNext,
|
},
|
||||||
format: FormatSpec {
|
})]);
|
||||||
fill: None,
|
same("{:.10$s}",
|
||||||
align: AlignUnknown,
|
&[NextArgument(Argument {
|
||||||
flags: 0,
|
position: ArgumentNext,
|
||||||
precision: CountIsParam(10),
|
format: FormatSpec {
|
||||||
width: CountImplied,
|
fill: None,
|
||||||
ty: "s",
|
align: AlignUnknown,
|
||||||
},
|
flags: 0,
|
||||||
})]);
|
precision: CountIsParam(10),
|
||||||
same("{:a$.b$s}", &[NextArgument(Argument {
|
width: CountImplied,
|
||||||
position: ArgumentNext,
|
ty: "s",
|
||||||
format: FormatSpec {
|
},
|
||||||
fill: None,
|
})]);
|
||||||
align: AlignUnknown,
|
same("{:a$.b$s}",
|
||||||
flags: 0,
|
&[NextArgument(Argument {
|
||||||
precision: CountIsName("b"),
|
position: ArgumentNext,
|
||||||
width: CountIsName("a"),
|
format: FormatSpec {
|
||||||
ty: "s",
|
fill: None,
|
||||||
},
|
align: AlignUnknown,
|
||||||
})]);
|
flags: 0,
|
||||||
|
precision: CountIsName("b"),
|
||||||
|
width: CountIsName("a"),
|
||||||
|
ty: "s",
|
||||||
|
},
|
||||||
|
})]);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_flags() {
|
fn format_flags() {
|
||||||
same("{:-}", &[NextArgument(Argument {
|
same("{:-}",
|
||||||
position: ArgumentNext,
|
&[NextArgument(Argument {
|
||||||
format: FormatSpec {
|
position: ArgumentNext,
|
||||||
fill: None,
|
format: FormatSpec {
|
||||||
align: AlignUnknown,
|
fill: None,
|
||||||
flags: (1 << FlagSignMinus as u32),
|
align: AlignUnknown,
|
||||||
precision: CountImplied,
|
flags: (1 << FlagSignMinus as u32),
|
||||||
width: CountImplied,
|
precision: CountImplied,
|
||||||
ty: "",
|
width: CountImplied,
|
||||||
},
|
ty: "",
|
||||||
})]);
|
},
|
||||||
same("{:+#}", &[NextArgument(Argument {
|
})]);
|
||||||
position: ArgumentNext,
|
same("{:+#}",
|
||||||
format: FormatSpec {
|
&[NextArgument(Argument {
|
||||||
fill: None,
|
position: ArgumentNext,
|
||||||
align: AlignUnknown,
|
format: FormatSpec {
|
||||||
flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
|
fill: None,
|
||||||
precision: CountImplied,
|
align: AlignUnknown,
|
||||||
width: CountImplied,
|
flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
|
||||||
ty: "",
|
precision: CountImplied,
|
||||||
},
|
width: CountImplied,
|
||||||
})]);
|
ty: "",
|
||||||
|
},
|
||||||
|
})]);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_mixture() {
|
fn format_mixture() {
|
||||||
same("abcd {3:a} efg", &[String("abcd "), NextArgument(Argument {
|
same("abcd {3:a} efg",
|
||||||
position: ArgumentIs(3),
|
&[String("abcd "),
|
||||||
format: FormatSpec {
|
NextArgument(Argument {
|
||||||
fill: None,
|
position: ArgumentIs(3),
|
||||||
align: AlignUnknown,
|
format: FormatSpec {
|
||||||
flags: 0,
|
fill: None,
|
||||||
precision: CountImplied,
|
align: AlignUnknown,
|
||||||
width: CountImplied,
|
flags: 0,
|
||||||
ty: "a",
|
precision: CountImplied,
|
||||||
},
|
width: CountImplied,
|
||||||
}), String(" efg")]);
|
ty: "a",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
String(" efg")]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,17 @@ pub struct LogDirective {
|
||||||
pub level: u32,
|
pub level: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO",
|
pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO", "DEBUG"];
|
||||||
"DEBUG"];
|
|
||||||
|
|
||||||
/// Parse an individual log level that is either a number or a symbolic log level
|
/// Parse an individual log level that is either a number or a symbolic log level
|
||||||
fn parse_log_level(level: &str) -> Option<u32> {
|
fn parse_log_level(level: &str) -> Option<u32> {
|
||||||
level.parse::<u32>().ok().or_else(|| {
|
level.parse::<u32>()
|
||||||
let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
|
.ok()
|
||||||
pos.map(|p| p as u32 + 1)
|
.or_else(|| {
|
||||||
}).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
|
let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
|
||||||
|
pos.map(|p| p as u32 + 1)
|
||||||
|
})
|
||||||
|
.map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
|
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
|
||||||
|
@ -40,44 +42,48 @@ pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<String>) {
|
||||||
let mods = parts.next();
|
let mods = parts.next();
|
||||||
let filter = parts.next();
|
let filter = parts.next();
|
||||||
if parts.next().is_some() {
|
if parts.next().is_some() {
|
||||||
println!("warning: invalid logging spec '{}', \
|
println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)",
|
||||||
ignoring it (too many '/'s)", spec);
|
spec);
|
||||||
return (dirs, None);
|
return (dirs, None);
|
||||||
}
|
}
|
||||||
mods.map(|m| { for s in m.split(',') {
|
mods.map(|m| {
|
||||||
if s.is_empty() { continue }
|
for s in m.split(',') {
|
||||||
let mut parts = s.split('=');
|
if s.is_empty() {
|
||||||
let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
|
|
||||||
(Some(part0), None, None) => {
|
|
||||||
// if the single argument is a log-level string or number,
|
|
||||||
// treat that as a global fallback
|
|
||||||
match parse_log_level(part0) {
|
|
||||||
Some(num) => (num, None),
|
|
||||||
None => (::MAX_LOG_LEVEL, Some(part0)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
|
|
||||||
(Some(part0), Some(part1), None) => {
|
|
||||||
match parse_log_level(part1) {
|
|
||||||
Some(num) => (num, Some(part0)),
|
|
||||||
_ => {
|
|
||||||
println!("warning: invalid logging spec '{}', \
|
|
||||||
ignoring it", part1);
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
println!("warning: invalid logging spec '{}', \
|
|
||||||
ignoring it", s);
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
};
|
let mut parts = s.split('=');
|
||||||
dirs.push(LogDirective {
|
let (log_level, name) = match (parts.next(),
|
||||||
name: name.map(str::to_owned),
|
parts.next().map(|s| s.trim()),
|
||||||
level: log_level,
|
parts.next()) {
|
||||||
});
|
(Some(part0), None, None) => {
|
||||||
}});
|
// if the single argument is a log-level string or number,
|
||||||
|
// treat that as a global fallback
|
||||||
|
match parse_log_level(part0) {
|
||||||
|
Some(num) => (num, None),
|
||||||
|
None => (::MAX_LOG_LEVEL, Some(part0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
|
||||||
|
(Some(part0), Some(part1), None) => {
|
||||||
|
match parse_log_level(part1) {
|
||||||
|
Some(num) => (num, Some(part0)),
|
||||||
|
_ => {
|
||||||
|
println!("warning: invalid logging spec '{}', ignoring it", part1);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("warning: invalid logging spec '{}', ignoring it", s);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dirs.push(LogDirective {
|
||||||
|
name: name.map(str::to_owned),
|
||||||
|
level: log_level,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
(dirs, filter.map(str::to_owned))
|
(dirs, filter.map(str::to_owned))
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,7 +235,9 @@ pub trait Logger {
|
||||||
fn log(&mut self, record: &LogRecord);
|
fn log(&mut self, record: &LogRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DefaultLogger { handle: Stderr }
|
struct DefaultLogger {
|
||||||
|
handle: Stderr,
|
||||||
|
}
|
||||||
|
|
||||||
/// Wraps the log level with fmt implementations.
|
/// Wraps the log level with fmt implementations.
|
||||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
|
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
|
||||||
|
@ -246,7 +248,7 @@ impl fmt::Display for LogLevel {
|
||||||
let LogLevel(level) = *self;
|
let LogLevel(level) = *self;
|
||||||
match LOG_LEVEL_NAMES.get(level as usize - 1) {
|
match LOG_LEVEL_NAMES.get(level as usize - 1) {
|
||||||
Some(ref name) => fmt::Display::fmt(name, fmt),
|
Some(ref name) => fmt::Display::fmt(name, fmt),
|
||||||
None => fmt::Display::fmt(&level, fmt)
|
None => fmt::Display::fmt(&level, fmt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,11 +303,10 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
|
||||||
// Completely remove the local logger from TLS in case anyone attempts to
|
// Completely remove the local logger from TLS in case anyone attempts to
|
||||||
// frob the slot while we're doing the logging. This will destroy any logger
|
// frob the slot while we're doing the logging. This will destroy any logger
|
||||||
// set during logging.
|
// set during logging.
|
||||||
let mut logger: Box<Logger + Send> = LOCAL_LOGGER.with(|s| {
|
let mut logger: Box<Logger + Send> = LOCAL_LOGGER.with(|s| s.borrow_mut().take())
|
||||||
s.borrow_mut().take()
|
.unwrap_or_else(|| {
|
||||||
}).unwrap_or_else(|| {
|
box DefaultLogger { handle: io::stderr() }
|
||||||
box DefaultLogger { handle: io::stderr() }
|
});
|
||||||
});
|
|
||||||
logger.log(&LogRecord {
|
logger.log(&LogRecord {
|
||||||
level: LogLevel(level),
|
level: LogLevel(level),
|
||||||
args: args,
|
args: args,
|
||||||
|
@ -320,22 +321,21 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
|
||||||
/// safely
|
/// safely
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn log_level() -> u32 { unsafe { LOG_LEVEL } }
|
pub fn log_level() -> u32 {
|
||||||
|
unsafe { LOG_LEVEL }
|
||||||
|
}
|
||||||
|
|
||||||
/// Replaces the thread-local logger with the specified logger, returning the old
|
/// Replaces the thread-local logger with the specified logger, returning the old
|
||||||
/// logger.
|
/// logger.
|
||||||
pub fn set_logger(logger: Box<Logger + Send>) -> Option<Box<Logger + Send>> {
|
pub fn set_logger(logger: Box<Logger + Send>) -> Option<Box<Logger + Send>> {
|
||||||
let mut l = Some(logger);
|
let mut l = Some(logger);
|
||||||
LOCAL_LOGGER.with(|slot| {
|
LOCAL_LOGGER.with(|slot| mem::replace(&mut *slot.borrow_mut(), l.take()))
|
||||||
mem::replace(&mut *slot.borrow_mut(), l.take())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A LogRecord is created by the logging macros, and passed as the only
|
/// A LogRecord is created by the logging macros, and passed as the only
|
||||||
/// argument to Loggers.
|
/// argument to Loggers.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LogRecord<'a> {
|
pub struct LogRecord<'a> {
|
||||||
|
|
||||||
/// The module path of where the LogRecord originated.
|
/// The module path of where the LogRecord originated.
|
||||||
pub module_path: &'a str,
|
pub module_path: &'a str,
|
||||||
|
|
||||||
|
@ -373,7 +373,9 @@ pub fn mod_enabled(level: u32, module: &str) -> bool {
|
||||||
// again to whether they should really be here or not. Hence, despite this
|
// again to whether they should really be here or not. Hence, despite this
|
||||||
// check being expanded manually in the logging macro, this function checks
|
// check being expanded manually in the logging macro, this function checks
|
||||||
// the log level again.
|
// the log level again.
|
||||||
if level > unsafe { LOG_LEVEL } { return false }
|
if level > unsafe { LOG_LEVEL } {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// This assertion should never get tripped unless we're in an at_exit
|
// This assertion should never get tripped unless we're in an at_exit
|
||||||
// handler after logging has been torn down and a logging attempt was made.
|
// handler after logging has been torn down and a logging attempt was made.
|
||||||
|
@ -385,14 +387,11 @@ pub fn mod_enabled(level: u32, module: &str) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enabled(level: u32,
|
fn enabled(level: u32, module: &str, iter: slice::Iter<directive::LogDirective>) -> bool {
|
||||||
module: &str,
|
|
||||||
iter: slice::Iter<directive::LogDirective>)
|
|
||||||
-> bool {
|
|
||||||
// Search for the longest match, the vector is assumed to be pre-sorted.
|
// Search for the longest match, the vector is assumed to be pre-sorted.
|
||||||
for directive in iter.rev() {
|
for directive in iter.rev() {
|
||||||
match directive.name {
|
match directive.name {
|
||||||
Some(ref name) if !module.starts_with(&name[..]) => {},
|
Some(ref name) if !module.starts_with(&name[..]) => {}
|
||||||
Some(..) | None => {
|
Some(..) | None => {
|
||||||
return level <= directive.level
|
return level <= directive.level
|
||||||
}
|
}
|
||||||
|
@ -445,16 +444,14 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_full_path() {
|
fn match_full_path() {
|
||||||
let dirs = [
|
let dirs = [LogDirective {
|
||||||
LogDirective {
|
name: Some("crate2".to_string()),
|
||||||
name: Some("crate2".to_string()),
|
level: 3,
|
||||||
level: 3
|
},
|
||||||
},
|
LogDirective {
|
||||||
LogDirective {
|
name: Some("crate1::mod1".to_string()),
|
||||||
name: Some("crate1::mod1".to_string()),
|
level: 2,
|
||||||
level: 2
|
}];
|
||||||
}
|
|
||||||
];
|
|
||||||
assert!(enabled(2, "crate1::mod1", dirs.iter()));
|
assert!(enabled(2, "crate1::mod1", dirs.iter()));
|
||||||
assert!(!enabled(3, "crate1::mod1", dirs.iter()));
|
assert!(!enabled(3, "crate1::mod1", dirs.iter()));
|
||||||
assert!(enabled(3, "crate2", dirs.iter()));
|
assert!(enabled(3, "crate2", dirs.iter()));
|
||||||
|
@ -463,49 +460,72 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_match() {
|
fn no_match() {
|
||||||
let dirs = [
|
let dirs = [LogDirective {
|
||||||
LogDirective { name: Some("crate2".to_string()), level: 3 },
|
name: Some("crate2".to_string()),
|
||||||
LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
|
level: 3,
|
||||||
];
|
},
|
||||||
|
LogDirective {
|
||||||
|
name: Some("crate1::mod1".to_string()),
|
||||||
|
level: 2,
|
||||||
|
}];
|
||||||
assert!(!enabled(2, "crate3", dirs.iter()));
|
assert!(!enabled(2, "crate3", dirs.iter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_beginning() {
|
fn match_beginning() {
|
||||||
let dirs = [
|
let dirs = [LogDirective {
|
||||||
LogDirective { name: Some("crate2".to_string()), level: 3 },
|
name: Some("crate2".to_string()),
|
||||||
LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
|
level: 3,
|
||||||
];
|
},
|
||||||
|
LogDirective {
|
||||||
|
name: Some("crate1::mod1".to_string()),
|
||||||
|
level: 2,
|
||||||
|
}];
|
||||||
assert!(enabled(3, "crate2::mod1", dirs.iter()));
|
assert!(enabled(3, "crate2::mod1", dirs.iter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_beginning_longest_match() {
|
fn match_beginning_longest_match() {
|
||||||
let dirs = [
|
let dirs = [LogDirective {
|
||||||
LogDirective { name: Some("crate2".to_string()), level: 3 },
|
name: Some("crate2".to_string()),
|
||||||
LogDirective { name: Some("crate2::mod".to_string()), level: 4 },
|
level: 3,
|
||||||
LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
|
},
|
||||||
];
|
LogDirective {
|
||||||
|
name: Some("crate2::mod".to_string()),
|
||||||
|
level: 4,
|
||||||
|
},
|
||||||
|
LogDirective {
|
||||||
|
name: Some("crate1::mod1".to_string()),
|
||||||
|
level: 2,
|
||||||
|
}];
|
||||||
assert!(enabled(4, "crate2::mod1", dirs.iter()));
|
assert!(enabled(4, "crate2::mod1", dirs.iter()));
|
||||||
assert!(!enabled(4, "crate2", dirs.iter()));
|
assert!(!enabled(4, "crate2", dirs.iter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_default() {
|
fn match_default() {
|
||||||
let dirs = [
|
let dirs = [LogDirective {
|
||||||
LogDirective { name: None, level: 3 },
|
name: None,
|
||||||
LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
|
level: 3,
|
||||||
];
|
},
|
||||||
|
LogDirective {
|
||||||
|
name: Some("crate1::mod1".to_string()),
|
||||||
|
level: 2,
|
||||||
|
}];
|
||||||
assert!(enabled(2, "crate1::mod1", dirs.iter()));
|
assert!(enabled(2, "crate1::mod1", dirs.iter()));
|
||||||
assert!(enabled(3, "crate2::mod2", dirs.iter()));
|
assert!(enabled(3, "crate2::mod2", dirs.iter()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn zero_level() {
|
fn zero_level() {
|
||||||
let dirs = [
|
let dirs = [LogDirective {
|
||||||
LogDirective { name: None, level: 3 },
|
name: None,
|
||||||
LogDirective { name: Some("crate1::mod1".to_string()), level: 0 }
|
level: 3,
|
||||||
];
|
},
|
||||||
|
LogDirective {
|
||||||
|
name: Some("crate1::mod1".to_string()),
|
||||||
|
level: 0,
|
||||||
|
}];
|
||||||
assert!(!enabled(1, "crate1::mod1", dirs.iter()));
|
assert!(!enabled(1, "crate1::mod1", dirs.iter()));
|
||||||
assert!(enabled(3, "crate2::mod2", dirs.iter()));
|
assert!(enabled(3, "crate2::mod2", dirs.iter()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -528,6 +528,10 @@ impl<'ast> Map<'ast> {
|
||||||
NodeTraitItem(ti) => PathName(ti.name),
|
NodeTraitItem(ti) => PathName(ti.name),
|
||||||
NodeVariant(v) => PathName(v.node.name),
|
NodeVariant(v) => PathName(v.node.name),
|
||||||
NodeLifetime(lt) => PathName(lt.name),
|
NodeLifetime(lt) => PathName(lt.name),
|
||||||
|
NodeTyParam(tp) => PathName(tp.name),
|
||||||
|
NodeLocal(&Pat { node: PatIdent(_,l,_), .. }) => {
|
||||||
|
PathName(l.node.name)
|
||||||
|
},
|
||||||
_ => panic!("no path elem for {:?}", node)
|
_ => panic!("no path elem for {:?}", node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -988,4 +992,3 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
|
|
||||||
//! A typesafe bitmask flag generator.
|
//! A typesafe bitmask flag generator.
|
||||||
|
|
||||||
#[cfg(test)] #[macro_use] extern crate std;
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
/// The `bitflags!` macro generates a `struct` that holds a set of C-style
|
/// The `bitflags!` macro generates a `struct` that holds a set of C-style
|
||||||
/// bitmask flags. It is useful for creating typesafe wrappers for C APIs.
|
/// bitmask flags. It is useful for creating typesafe wrappers for C APIs.
|
||||||
|
@ -321,7 +323,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bits(){
|
fn test_bits() {
|
||||||
assert_eq!(Flags::empty().bits(), 0b00000000);
|
assert_eq!(Flags::empty().bits(), 0b00000000);
|
||||||
assert_eq!(Flags::FlagA.bits(), 0b00000001);
|
assert_eq!(Flags::FlagA.bits(), 0b00000001);
|
||||||
assert_eq!(Flags::FlagABC.bits(), 0b00000111);
|
assert_eq!(Flags::FlagABC.bits(), 0b00000111);
|
||||||
|
@ -354,7 +356,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_empty(){
|
fn test_is_empty() {
|
||||||
assert!(Flags::empty().is_empty());
|
assert!(Flags::empty().is_empty());
|
||||||
assert!(!Flags::FlagA.is_empty());
|
assert!(!Flags::FlagA.is_empty());
|
||||||
assert!(!Flags::FlagABC.is_empty());
|
assert!(!Flags::FlagABC.is_empty());
|
||||||
|
@ -413,7 +415,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_insert(){
|
fn test_insert() {
|
||||||
let mut e1 = Flags::FlagA;
|
let mut e1 = Flags::FlagA;
|
||||||
let e2 = Flags::FlagA | Flags::FlagB;
|
let e2 = Flags::FlagA | Flags::FlagB;
|
||||||
e1.insert(e2);
|
e1.insert(e2);
|
||||||
|
@ -425,7 +427,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_remove(){
|
fn test_remove() {
|
||||||
let mut e1 = Flags::FlagA | Flags::FlagB;
|
let mut e1 = Flags::FlagA | Flags::FlagB;
|
||||||
let e2 = Flags::FlagA | Flags::FlagC;
|
let e2 = Flags::FlagA | Flags::FlagC;
|
||||||
e1.remove(e2);
|
e1.remove(e2);
|
||||||
|
@ -484,12 +486,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hash() {
|
fn test_hash() {
|
||||||
let mut x = Flags::empty();
|
let mut x = Flags::empty();
|
||||||
let mut y = Flags::empty();
|
let mut y = Flags::empty();
|
||||||
assert!(hash(&x) == hash(&y));
|
assert!(hash(&x) == hash(&y));
|
||||||
x = Flags::all();
|
x = Flags::all();
|
||||||
y = Flags::FlagABC;
|
y = Flags::FlagABC;
|
||||||
assert!(hash(&x) == hash(&y));
|
assert!(hash(&x) == hash(&y));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash<T: Hash>(t: &T) -> u64 {
|
fn hash<T: Hash>(t: &T) -> u64 {
|
||||||
|
|
|
@ -592,6 +592,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
|
||||||
};
|
};
|
||||||
|
|
||||||
substs_wf_in_scope(rcx, origin, &callee.substs, expr.span, expr_region);
|
substs_wf_in_scope(rcx, origin, &callee.substs, expr.span, expr_region);
|
||||||
|
type_must_outlive(rcx, infer::ExprTypeIsNotInScope(callee.ty, expr.span),
|
||||||
|
callee.ty, expr_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check any autoderefs or autorefs that appear.
|
// Check any autoderefs or autorefs that appear.
|
||||||
|
@ -664,6 +666,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &hir::Expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("regionck::visit_expr(e={:?}, repeating_scope={}) - visiting subexprs",
|
||||||
|
expr, rcx.repeating_scope);
|
||||||
match expr.node {
|
match expr.node {
|
||||||
hir::ExprPath(..) => {
|
hir::ExprPath(..) => {
|
||||||
rcx.fcx.opt_node_ty_substs(expr.id, |item_substs| {
|
rcx.fcx.opt_node_ty_substs(expr.id, |item_substs| {
|
||||||
|
|
|
@ -17,9 +17,8 @@ use option::Option::{self, Some, None};
|
||||||
use result;
|
use result;
|
||||||
use sys;
|
use sys;
|
||||||
|
|
||||||
/// A specialized [`Result`][result] type for I/O operations.
|
/// A specialized [`Result`](../result/enum.Result.html) type for I/O
|
||||||
///
|
/// operations.
|
||||||
/// [result]: ../result/enum.Result.html
|
|
||||||
///
|
///
|
||||||
/// This type is broadly used across `std::io` for any operation which may
|
/// This type is broadly used across `std::io` for any operation which may
|
||||||
/// produce an error.
|
/// produce an error.
|
||||||
|
|
|
@ -335,8 +335,7 @@ LLVMRustSetDataLayoutFromTargetMachine(LLVMModuleRef Module,
|
||||||
LLVMTargetMachineRef TMR) {
|
LLVMTargetMachineRef TMR) {
|
||||||
TargetMachine *Target = unwrap(TMR);
|
TargetMachine *Target = unwrap(TMR);
|
||||||
#if LLVM_VERSION_MINOR >= 7
|
#if LLVM_VERSION_MINOR >= 7
|
||||||
if (const DataLayout *DL = Target->getDataLayout())
|
unwrap(Module)->setDataLayout(Target->createDataLayout());
|
||||||
unwrap(Module)->setDataLayout(*DL);
|
|
||||||
#elif LLVM_VERSION_MINOR >= 6
|
#elif LLVM_VERSION_MINOR >= 6
|
||||||
if (const DataLayout *DL = Target->getSubtargetImpl()->getDataLayout())
|
if (const DataLayout *DL = Target->getSubtargetImpl()->getDataLayout())
|
||||||
unwrap(Module)->setDataLayout(DL);
|
unwrap(Module)->setDataLayout(DL);
|
||||||
|
|
22
src/test/run-pass/issue-22814.rs
Normal file
22
src/test/run-pass/issue-22814.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <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.
|
||||||
|
|
||||||
|
trait Test {}
|
||||||
|
|
||||||
|
macro_rules! test {
|
||||||
|
( $($name:ident)+) => (
|
||||||
|
impl<$($name: Test),*> Test for ($($name,)*) {
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test!(A B C);
|
||||||
|
|
||||||
|
fn main() {}
|
20
src/test/run-pass/issue-28999.rs
Normal file
20
src/test/run-pass/issue-28999.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
pub struct Xyz<'a, V> {
|
||||||
|
pub v: (V, &'a u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq<'a, 's, 't, V>(this: &'s Xyz<'a, V>, other: &'t Xyz<'a, V>) -> bool
|
||||||
|
where V: PartialEq {
|
||||||
|
this.v == other.v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue