Commit Graph

37593 Commits

Author SHA1 Message Date
John Hodge
1c502f1d43 README.md - Fix source tarball link 2015-01-28 10:12:54 +08:00
bors
777435990e Auto merge of #21586 - pyfisch:patch-1, r=alexcrichton
Spellfix for `Debug` trait documentation. Change "most all types should implement this" to "all types should implement this". Same fix for deprecated `Show` trait.
2015-01-27 14:03:06 +00:00
bors
d77f6d5366 Auto merge of #21657 - pnkfelix:block-remainder-extents, r=nikomatsakis
Add `CodeExtent::Remainder` variant; pre-req for new scoping/drop rules.

This new enum variant introduces finer-grain code extents, i.e. we now track that a binding lives only for a suffix of a block, and (importantly) will be dropped when it goes out of scope *before* the bindings that occurred earlier in the block.

Both of these notions are neatly captured by marking the block (and each suffix) as an enclosing scope of the next suffix beneath it.

This is work that is part of the foundation for issue #8861.

(It actually has been seen in earlier posted pull requests, in particular #21022; I have just factored it out into its own PR to ease my own near-future rebasing, and also get people used to the new rules.)

----

These finer grained scopes do mean that some code is newly rejected by `rustc`; for example:

```rust
let mut map : HashMap<u8, &u8> = HashMap::new();
let tmp = Box::new(2);
map.insert(43, &*tmp);
```

This will now fail to compile with a message that `*tmp` does not live long enough, because the scope of `tmp` is now strictly smaller than
that of `map`, and the use of `&u8` in map's type requires that the borrowed references are all to data that live at least as long as the map.

The usual fix for a case like this is to move the binding for `tmp` up above that of `map`; note that you can still leave the initialization in the original spot, like so:

```rust
let tmp;
let mut map : HashMap<u8, &u8> = HashMap::new();
tmp = box 2;
map.insert(43, &*tmp);
```

Similarly, one can encounter an analogous situation with `Vec`: one would need to rewrite:

```rust
let mut vec = Vec::new();
let tmp = 'c';
vec.push(&tmp);
```

as:

```rust
let tmp;
let mut vec = Vec::new();
tmp = 'c';
vec.push(&tmp);
```

----

In some corner cases, it does not suffice to reorder the bindings; in particular, when the types for both bindings need to reflect exactly the *same* code extent, and a parent/child relationship between them does not work.

In pnkfelix's experience this has arisen most often when mixing uses of cyclic data structures while also allowing a lifetime parameter `'a` to flow into a type parameter context where the type is *invariant* with respect to the type parameter. An important instance of this is `arena::TypedArena<T>`, which is invariant with respect to `T`.

(The reason that variance is relevant is this: *if* `TypedArena` were covariant with respect to its type parameter, then we could assign it
the longer lifetime when it is initialized, and then convert it to a subtype (via covariance) with a shorter lifetime when necessary.  But `TypedArena` is invariant with respect to its type parameter, and thus if `S` is a subtype of `T` (in particular, if `S` has a lifetime parameter that is shorter than that of `T`), then a `TypedArena<S>` is unrelated to `TypedArena<T>`.)

Concretely, consider code like this:

```rust
struct Node<'a> { sibling: Option<&'a Node<'a>> }
struct Context<'a> {
    // because of this field, `Context<'a>` is invariant with respect to `'a`.
    arena: &'a TypedArena<Node<'a>>,
    ...
}
fn new_ctxt<'a>(arena: &'a TypedArena<Node<'a>>) -> Context<'a> { ... }
fn use_ctxt<'a>(fcx: &'a Context<'a>) { ... }

let arena = TypedArena::new();
let ctxt = new_ctxt(&arena);

use_ctxt(&ctxt);
```

In these situations, if you try to introduce two bindings via two distinct `let` statements, each is (with this commit) assigned a distinct extent, and the region inference system cannot find a single region to assign to the lifetime `'a` that works for both of the bindings. So you get an error that `ctxt` does not live long enough; but moving its binding up above that of `arena` just shifts the error so now the compiler complains that `arena` does not live long enough.

 * SO: What to do? The easiest fix in this case is to ensure that the two bindings *do* get assigned the same static extent, by stuffing both
bindings into the same let statement, like so:

```rust
let (arena, ctxt): (TypedArena, Context);
arena = TypedArena::new();
ctxt = new_ctxt(&arena);

use_ctxt(&ctxt);
```

----

Due to the new code restrictions outlined above, this is a ...

[breaking-change]
2015-01-27 11:07:26 +00:00
Felix S. Klock II
d6bf04a22e Add CodeExtent::Remainder variant; pre-req for new scoping/drop rules.
This new variant introduces finer-grain code extents, i.e. we now
track that a binding lives only for a suffix of a block, and
(importantly) will be dropped when it goes out of scope *before* the
bindings that occurred earlier in the block.

Both of these notions are neatly captured by marking the block (and
each suffix) as an enclosing scope of the next suffix beneath it.

This is work that is part of the foundation for issue #8861.

(It actually has been seen in earlier posted pull requests; I have
just factored it out into its own PR to ease my own rebasing.)

----

These finer grained scopes do mean that some code is newly rejected by
`rustc`; for example:

```rust
let mut map : HashMap<u8, &u8> = HashMap::new();
let tmp = Box::new(2);
map.insert(43, &*tmp);
```

This will now fail to compile with a message that `*tmp` does not live
long enough, because the scope of `tmp` is now strictly smaller than
that of `map`, and the use of `&u8` in map's type requires that the
borrowed references are all to data that live at least as long as the
map.

The usual fix for a case like this is to move the binding for `tmp`
up above that of `map`; note that you can still leave the initialization
in the original spot, like so:

```rust
let tmp;
let mut map : HashMap<u8, &u8> = HashMap::new();
tmp = box 2;
map.insert(43, &*tmp);
```

Similarly, one can encounter an analogous situation with `Vec`: one
would need to rewrite:

```rust
let mut vec = Vec::new();
let tmp = 'c';
vec.push(&tmp);
```

as:

```
let tmp;
let mut vec = Vec::new();
tmp = 'c';
vec.push(&tmp);
```

----

In some corner cases, it does not suffice to reorder the bindings; in
particular, when the types for both bindings need to reflect exactly
the *same* code extent, and a parent/child relationship between them
does not work.

In pnkfelix's experience this has arisen most often when mixing uses
of cyclic data structures while also allowing a lifetime parameter
`'a` to flow into a type parameter context where the type is
*invariant* with respect to the type parameter. An important instance
of this is `arena::TypedArena<T>`, which is invariant with respect
to `T`.

(The reason that variance is relevant is this: *if* `TypedArena` were
covariant with respect to its type parameter, then we could assign it
the longer lifetime when it is initialized, and then convert it to a
subtype (via covariance) with a shorter lifetime when necessary.  But
`TypedArena` is invariant with respect to its type parameter, and thus
if `S` is a subtype of `T` (in particular, if `S` has a lifetime
parameter that is shorter than that of `T`), then a `TypedArena<S>` is
unrelated to `TypedArena<T>`.)

Concretely, consider code like this:

```rust
struct Node<'a> { sibling: Option<&'a Node<'a>> }
struct Context<'a> {
    // because of this field, `Context<'a>` is invariant with respect to `'a`.
    arena: &'a TypedArena<Node<'a>>,
    ...
}
fn new_ctxt<'a>(arena: &'a TypedArena<Node<'a>>) -> Context<'a> { ... }
fn use_ctxt<'a>(fcx: &'a Context<'a>) { ... }

let arena = TypedArena::new();
let ctxt = new_ctxt(&arena);

use_ctxt(&ctxt);
```

In these situations, if you try to introduce two bindings via two
distinct `let` statements, each is (with this commit) assigned a
distinct extent, and the region inference system cannot find a single
region to assign to the lifetime `'a` that works for both of the
bindings. So you get an error that `ctxt` does not live long enough;
but moving its binding up above that of `arena` just shifts the error
so now the compiler complains that `arena` does not live long enough.

SO: What to do? The easiest fix in this case is to ensure that the two
bindings *do* get assigned the same static extent, by stuffing both
bindings into the same let statement, like so:

```rust
let (arena, ctxt): (TypedArena, Context);
arena = TypedArena::new();
ctxt = new_ctxt(&arena);

use_ctxt(&ctxt);
```

Due to the new code rejections outlined above, this is a ...

[breaking-change]
2015-01-27 10:26:52 +01:00
Felix S. Klock II
43d08f861a accommodate new scoping rules in librustc_driver unit tests. 2015-01-27 10:26:52 +01:00
Felix S. Klock II
2c2f0f1216 accommodate new scoping rules in libstd unit tests. 2015-01-27 10:26:52 +01:00
Felix S. Klock II
70192ab779 accommodate new scoping rules in test/compile-fail. 2015-01-27 10:26:52 +01:00
Felix S. Klock II
9fe8d8602d accommodate new scoping rules in test/run-pass. 2015-01-27 10:26:52 +01:00
Felix S. Klock II
86bde933f8 accommodate new scoping rules in rustc and rustdoc source. 2015-01-27 10:26:52 +01:00
bors
e365e4c054 Auto merge of #21564 - steveklabnik:doc_cell, r=alexcrichton 2015-01-27 08:40:39 +00:00
bors
1c87af2eba Auto merge of #21646 - dotdash:default_target_cpu, r=Aatch
Using `generic` as the target cpu limits the generated code to the bare basics for the arch, while we can probably assume that we'll actually be running on somewhat modern hardware. This updates the default target CPUs for the x86 and x86_64 archs to match clang's behaviour.

Refs #20777
2015-01-27 05:15:04 +00:00
bors
a6a6fadbb9 Auto merge of #21543 - alexcrichton:old-io, r=aturon
In preparation for the I/O rejuvination of the standard library, this commit
renames the current `io` module to `old_io` in order to make room for the new
I/O modules. It is expected that the I/O RFCs will land incrementally over time
instead of all at once, and this provides a fresh clean path for new modules to
enter into as well as guaranteeing that all old infrastructure will remain in
place for some time.

As each `old_io` module is replaced it will be deprecated in-place for new
structures in `std::{io, fs, net}` (as appropriate).

This commit does *not* leave a reexport of `old_io as io` as the deprecation
lint does not currently warn on this form of use. This is quite a large breaking
change for all imports in existing code, but all functionality is retained
precisely as-is and path statements simply need to be renamed from `io` to
`old_io`.

[breaking-change]
2015-01-27 02:46:09 +00:00
Alex Crichton
5d836cdf86 std: Rename Writer::write to Writer::write_all
In preparation for upcoming changes to the `Writer` trait (soon to be called
`Write`) this commit renames the current `write` method to `write_all` to match
the semantics of the upcoming `write_all` method. The `write` method will be
repurposed to return a `usize` indicating how much data was written which
differs from the current `write` semantics. In order to head off as much
unintended breakage as possible, the method is being deprecated now in favor of
a new name.

[breaking-change]
2015-01-26 16:01:58 -08:00
Alex Crichton
3a07f859b8 Fallout of io => old_io 2015-01-26 16:01:16 -08:00
Alex Crichton
f72b164510 std: Rename io to old_io
In preparation for the I/O rejuvination of the standard library, this commit
renames the current `io` module to `old_io` in order to make room for the new
I/O modules. It is expected that the I/O RFCs will land incrementally over time
instead of all at once, and this provides a fresh clean path for new modules to
enter into as well as guaranteeing that all old infrastructure will remain in
place for some time.

As each `old_io` module is replaced it will be deprecated in-place for new
structures in `std::{io, fs, net}` (as appropriate).

This commit does *not* leave a reexport of `old_io as io` as the deprecation
lint does not currently warn on this form of use. This is quite a large breaking
change for all imports in existing code, but all functionality is retained
precisely as-is and path statements simply need to be renamed from `io` to
`old_io`.

[breaking-change]
2015-01-26 16:01:16 -08:00
bors
a637365b10 Auto merge of #21606 - arielb1:clean-cast, r=huonw
This also makes the cast error messages somewhat more uniform.
2015-01-26 22:19:44 +00:00
bors
8ec3a833d5 Auto merge of #21617 - alexcrichton:less-quotes, r=nikomatsakis
This ends up propagating all the way out to the output of dep-info which then
makes Cargo think that files are not existent (it thinks the files have quotes
in their name) when they in fact do.
2015-01-26 19:44:12 +00:00
bors
16286f5cf9 Auto merge of #21614 - kvark:typedef, r=huonw
Fixes #21497 

I don't know if this can be tested with built-in tests.
2015-01-26 15:39:13 +00:00
bors
977c44ade0 Auto merge of #21401 - kballard:optimize-shrink-to-fit, r=nikomatsakis
Don't reallocate when capacity is already equal to length

`Vec::shrink_to_fit()` may be called on vectors that are already the
correct length. Calling out to `reallocate()` in this case is a bad idea
because there is no guarantee that `reallocate()` won't allocate a new
buffer anyway, and based on performance seen in external benchmarks, it
seems likely that it is in fact reallocating a new buffer.

Before:

    test string::tests::bench_exact_size_shrink_to_fit         ... bench:        45 ns/iter (+/- 2)

After:

    test string::tests::bench_exact_size_shrink_to_fit         ... bench:        26 ns/iter (+/- 1)
2015-01-26 13:01:00 +00:00
bors
59dcba5d14 Auto merge of #21610 - sfackler:debug-lint, r=alexcrichton
Closes #20855

r? @alexcrichton
2015-01-26 10:26:54 +00:00
Björn Steinbrink
296c74de96 Default to Pentium 4 as the x86 target CPU on Windows/Linux/DragonFly
Limiting ourselves to a generic x86 instruction set doesn't seem useful.
Both users running those systems on original i386 hardware might as well
manually specify a target cpu ;-)

Clang uses the same default.
2015-01-26 09:58:56 +01:00
Björn Steinbrink
bca25aeeb4 Use more specific target CPUs on Darwin
Macs don't come with anything older than a Yonah (32bit) or Core2 (64bit),
so we can default to those targets. Clang does the same.
2015-01-26 09:58:55 +01:00
bors
7615e187c6 Auto merge of #21605 - huonw:omg-muscle-memory, r=eddyb
I'm beginning to suspect it's impossible to avoid accidentally writing
`#[deriving]` at least once in every program, and it results in
non-intuitive error messages: "Foo doesn't have any method in scope
`clone`" despite there being a `#[deriv...(Clone)]` attribute!

Also, lots of documentation around the internet uses `#[deriving]` so
providing this guidance is very helpful (lots of people ask in #rust
about this error).
2015-01-26 07:49:01 +00:00
bors
9252525196 Auto merge of #21598 - eddyb:there-are-no-boxed-closures, r=brson 2015-01-26 04:49:37 +00:00
Eduard Burtescu
9690be5ece Adjust most comments and messages to not use "unboxed". 2015-01-26 04:15:09 +02:00
Eduard Burtescu
e0afa82c67 Remove every mention of "onceness". 2015-01-26 04:15:09 +02:00
Eduard Burtescu
50a370aa2d Remove dead code related to old closures. 2015-01-26 04:15:09 +02:00
Eduard Burtescu
ab9c773cdb librustc: remove unused DefUpvar field. 2015-01-26 04:15:09 +02:00
Eduard Burtescu
11ef6f1349 Remove "unboxed" attribute in code referring to new closures. 2015-01-26 04:15:09 +02:00
bors
47621db62c Auto merge of #21574 - japaric:walk-projections, r=nikomatsakis
closes #21363

r? @nikomatsakis
2015-01-25 23:55:55 +00:00
bors
458a6a2f6e Auto merge of #21561 - edwardw:deref, r=nikomatsakis
As part of #20432, upvar checking is now moved out of regionck to its
own pass and before regionck. But regionck has some type resolution of
its own. Without them, now separated upvar checking may be tripped over
by residue `ty_infer`.

Closes #21306
2015-01-25 21:20:37 +00:00
Steven Fackler
70214915b0 Add a missing fmt::Debug impl lint
Closes #20855
2015-01-25 11:22:41 -08:00
bors
c80e556e15 Auto merge of #21519 - michaelwoerister:misc, r=eddyb
Two minor improvements that have been on my TODO list for a while:
* Clang uses a size of `-1` for arrays of unknown size and we should do that too as it will tell LLVM to omit the size information in debuginfo.
* There was no LLDB test case for handling the optimized enum representation introduced by @luqmana. This PR finally adds one.
2015-01-25 18:46:33 +00:00
bors
d15192317a Auto merge of #21518 - Zoxc:asm-err, r=luqmana
Before:
```
error: invalid operand for inline asm constraint 'i' at line 11
```
Note that 11 is not the line the inline assembly appears in.

After:
```
src/arch/x64/multiboot/bootstrap.rs:203:5: 209:9 error: invalid operand for inline asm constraint 'i'
src/arch/x64/multiboot/bootstrap.rs:203     asm! {
src/arch/x64/multiboot/bootstrap.rs:204         [multiboot => %ecx, mod attsyntax]
src/arch/x64/multiboot/bootstrap.rs:205 
src/arch/x64/multiboot/bootstrap.rs:206         ljmp {size_of::<Descriptor>() => %i}, $bootstrap.64
src/arch/x64/multiboot/bootstrap.rs:207     }
src/arch/x64/multiboot/bootstrap.rs:208 
                                        ...
error: aborting due to previous error
```
2015-01-25 16:09:48 +00:00
bors
102ab57d80 Auto merge of #21582 - FlaPer87:rollup, r=brson
- Successful merges: #21108, #21445, #21498, #21504, #21532, #21535, #21539, #21540, #21541, #21550, #21560, #21573, #21579
- Failed merges:
2015-01-25 13:33:18 +00:00
Flavio Percoco
7e83e46556 assert path ends with executable. On Windows the process executable contains the full path 2015-01-25 13:05:37 +01:00
bors
0899807294 Auto merge of #20613 - dgriffen:master, r=alexcrichton 2015-01-25 10:59:28 +00:00
bors
9bac0179df Auto merge of #20373 - huonw:self-call-lint, r=luqmana
E.g. `fn foo() { foo() }`, or, more subtlely

    impl Foo for Box<Foo+'static> {
        fn bar(&self) {
            self.bar();
        }
    }

The compiler will warn and point out the points where recursion occurs,
if it determines that the function cannot return without calling itself.

Closes #17899.

---

This is highly non-perfect, in particular, my wording above is quite precise, and I have some unresolved questions: This currently will warn about

```rust
fn foo() {
    if bar { loop {} }

    foo()
}
```

even though `foo` may never be called (i.e. our apparent "unconditional" recursion is actually conditional). I don't know if we should handle this case, and ones like it with `panic!()` instead of `loop` (or anything else that "returns" `!`).

However, strictly speaking, it seems to me that changing the above to not warn will require changing

```rust
fn foo() {
    while bar {}
    foo()
}
```

to also not warn since it could be that the `while` is an infinite loop and doesn't ever hit the `foo`.

I'm inclined to think we let these cases warn since true edge cases like the first one seem rare, and if they do occur they seem like they would usually be typos in the function call. (I could imagine someone accidentally having code like `fn foo() { assert!(bar()); foo() /* meant to be boo() */ }` which won't warn if the `loop` case is "fixed".)

(Part of the reason this is unresolved is wanting feedback, part of the reason is I couldn't devise a strategy that worked in all cases.)

---

The name `unconditional_self_calls` is kinda clunky; and this reconstructs the CFG for each function that is linted which may or may not be very expensive, I don't know.
2015-01-25 08:24:47 +00:00
Alex Crichton
0dac568578 syntax: Don't put quotes around filenames in codemap
This ends up propagating all the way out to the output of dep-info which then
makes Cargo think that files are not existent (it thinks the files have quotes
in their name) when they in fact do.
2015-01-24 22:43:11 -08:00
Dzmitry Malyshau
e5632157b1 Associated types support for deriving::generic::TraitDef 2015-01-25 00:54:30 -05:00
bors
43046becce Auto merge of #21558 - alexcrichton:result-debug, r=aturon
This commit relaxes the bound on `Result::unwrap` and `Result::unwrap_err` from
the `Display` trait to the `Debug` trait for generating an error message about
the unwrapping operation.

This commit is a breaking change and any breakage should be mitigated by
ensuring that `Debug` is implemented on the relevant type.

[breaking-change]
2015-01-25 05:50:30 +00:00
bors
70b13a7c7c Auto merge of #21511 - alfie:suffix-cleanup, r=huonw 2015-01-25 00:49:41 +00:00
Alfie John
f67e7470b3 Moving away from deprecated i/u suffixes in libcore 2015-01-25 00:17:41 +00:00
Huon Wilson
ae4e1a190b Tell the compiler to tell us that deriving is dead.
I'm beginning to suspect it's impossible to avoid accidentally writing
`#[deriving]` at least once in every program, and it results in
non-intuitive error messages: "Foo doesn't have any method in scope
`clone`" despite there being a `#[deriv...(Clone)]` attribute!

Also, lots of documentation around the internet uses `#[deriving]` so
providing this guidance is very helpful (lots of people ask in #rust
about this error).

Fixes #21166.
2015-01-25 10:44:56 +11:00
Ariel Ben-Yehuda
e7245252cc Cleanup check_cast. Fixes #21554
This also makes the cast error messages somewhat more uniform.
2015-01-25 01:44:49 +02:00
bors
4e4e8cff16 Auto merge of #21452 - bleibig:bison-grammar, r=nikomatsakis
This adds a new lexer/parser combo for the entire Rust language can be generated with with flex and bison, taken from my project at https://github.com/bleibig/rust-grammar. There is also a testing script that runs the generated parser with all *.rs files in the repository (except for tests in compile-fail or ones that marked as "ignore-test" or "ignore-lexer-test"). If you have flex and bison installed, you can run these tests using the new "check-grammar" make target.

This does not depend on or interact with the existing testing code in the grammar, which only provides and tests a lexer specification.

OS X users should take note that the version of bison that comes with the Xcode toolchain (2.3) is too old to work with this grammar, they need to download and install version 3.0 or later.

The parser builds up an S-expression-based AST, which can be displayed by giving the "-v" argument to parser-lalr (normally it only gives output on error). It is only a rough approximation of what is parsed and doesn't capture every detail and nuance of the program.

Hopefully this should be sufficient for issue #2234, or at least a good starting point.
2015-01-24 22:14:14 +00:00
bors
bb7cc4eb26 Auto merge of #21488 - aturon:os-str, r=alexcrichton
Per [RFC 517](https://github.com/rust-lang/rfcs/pull/575/), this commit introduces platform-native strings. The API is essentially as described in the RFC.

The WTF-8 implementation is adapted from @SimonSapin's [implementation](https://github.com/SimonSapin/rust-wtf8). To make this work, some encodign and decoding functionality in `libcore` is now exported in a "raw" fashion reusable for WTF-8. These exports are *not* reexported in `std`, nor are they stable.
2015-01-24 19:39:52 +00:00
Aaron Turon
c5369ebc7f Add ffi::OsString and OsStr
Per [RFC 517](https://github.com/rust-lang/rfcs/pull/575/), this commit
introduces platform-native strings. The API is essentially as described
in the RFC.

The WTF-8 implementation is adapted from @SimonSapin's
[implementation](https://github.com/SimonSapin/rust-wtf8). To make this
work, some encodign and decoding functionality in `libcore` is now
exported in a "raw" fashion reusable for WTF-8. These exports are *not*
reexported in `std`, nor are they stable.
2015-01-24 10:21:30 -08:00
bors
76fbb35831 Auto merge of #21079 - huonw:chained-cmp-tweaks, r=pnkfelix
First commit is mindless groundwork for the second one, to make the spans (arguably) nicer.

### before

```
require-parens-for-chained-comparison.rs:14:20: 14:22 error: Chained comparison operators require parentheses
require-parens-for-chained-comparison.rs:14     false == false == false;
                                                               ^~
require-parens-for-chained-comparison.rs:17:16: 17:17 error: Chained comparison operators require parentheses
require-parens-for-chained-comparison.rs:17     false == 0 < 2;
                                                           ^
require-parens-for-chained-comparison.rs:20:8: 20:9 error: Chained comparison operators require parentheses
require-parens-for-chained-comparison.rs:20     f<X>();
                                                   ^
require-parens-for-chained-comparison.rs:20:8: 20:9 help: Use ::< instead of < if you meant to specify type arguments.
require-parens-for-chained-comparison.rs:20     f<X>();
                                                   ^
```

### after

```
require-parens-for-chained-comparison.rs:14:11: 14:22 error: chained comparison operators require parentheses
require-parens-for-chained-comparison.rs:14     false == false == false;
                                                      ^~~~~~~~~~~
require-parens-for-chained-comparison.rs:17:11: 17:17 error: chained comparison operators require parentheses
require-parens-for-chained-comparison.rs:17     false == 0 < 2;
                                                      ^~~~~~
require-parens-for-chained-comparison.rs:20:6: 20:9 error: chained comparison operators require parentheses
require-parens-for-chained-comparison.rs:20     f<X>();
                                                 ^~~
require-parens-for-chained-comparison.rs:20:6: 20:9 help: use `::<...>` instead of `<...>` if you meant to specify type arguments
require-parens-for-chained-comparison.rs:20     f<X>();
                                                 ^~~
```
2015-01-24 17:07:43 +00:00
Flavio Percoco
577c4643dd don't run pretty-rpass for tests using #![main] 2015-01-24 15:10:37 +01:00