diff --git a/man/rustc.1 b/man/rustc.1 index f49faf2ec6e3a..00d698e611e34 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -68,7 +68,7 @@ AST nodes and blocks with IDs), or flowgraph= (graphviz formatted flowgraph for node) .TP \fB\-\-dep-info\fR [FILENAME] -Output dependency info to after compiling, in o format suitable +Output dependency info to after compiling, in a format suitable for use by Makefiles. .TP \fB\-\-sysroot\fR PATH diff --git a/mk/docs.mk b/mk/docs.mk index 213565b09ac27..933a0bdc717ca 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -30,7 +30,7 @@ DOCS := index intro tutorial guide guide-ffi guide-macros guide-lifetimes \ guide-tasks guide-container guide-pointers guide-testing \ guide-runtime complement-bugreport \ complement-lang-faq complement-design-faq complement-project-faq rust \ - rustdoc guide-unsafe + rustdoc guide-unsafe guide-strings PDF_DOCS := tutorial rust diff --git a/mk/main.mk b/mk/main.mk index 8f54b2735a575..15e9897d47dbd 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -377,7 +377,7 @@ define SREQ_CMDS ifeq ($$(OSTYPE_$(3)),apple-darwin) LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := DYLD_LIBRARY_PATH else -ifeq ($$(CFG_WINDOWSY_$(2)),1) +ifeq ($$(CFG_WINDOWSY_$(3)),1) LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := PATH else LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := LD_LIBRARY_PATH diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 4de66d8746fbe..583d9249b3547 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -30,7 +30,7 @@ use std::io::fs; use std::from_str::FromStr; use getopts::{optopt, optflag, reqopt}; use common::Config; -use common::{Pretty, DebugInfoGdb, Codegen}; +use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen}; use util::logv; use regex::Regex; @@ -89,9 +89,9 @@ pub fn parse_config(args: Vec ) -> Config { optflag("h", "help", "show this message")); assert!(!args.is_empty()); - let argv0 = (*args.get(0)).clone(); + let argv0 = args[0].clone(); let args_ = args.tail(); - if args.get(1).as_slice() == "-h" || args.get(1).as_slice() == "--help" { + if args[1].as_slice() == "-h" || args[1].as_slice() == "--help" { let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); println!("{}", getopts::usage(message.as_slice(), groups.as_slice())); println!(""); @@ -116,7 +116,7 @@ pub fn parse_config(args: Vec ) -> Config { } let filter = if !matches.free.is_empty() { - let s = matches.free.get(0).as_slice(); + let s = matches.free[0].as_slice(); match regex::Regex::new(s) { Ok(re) => Some(re), Err(e) => { @@ -241,6 +241,16 @@ pub fn run_tests(config: &Config) { os::setenv("RUST_TEST_TASKS","1"); } + match config.mode { + DebugInfoLldb => { + // Some older versions of LLDB seem to have problems with multiple + // instances running in parallel, so only run one test task at a + // time. + os::setenv("RUST_TEST_TASKS", "1"); + } + _ => { /* proceed */ } + } + let opts = test_opts(config); let tests = make_tests(config); // sadly osx needs some file descriptor limits raised for running tests in diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 0c325a0d65aef..c3ac40e8f08d4 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -167,7 +167,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { let proc_res = print_source(config, props, testfile, - (*srcs.get(round)).to_string(), + srcs[round].to_string(), "normal"); if !proc_res.status.success() { @@ -187,9 +187,9 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { let s = File::open(&filepath).read_to_end().unwrap(); String::from_utf8(s).unwrap() } - None => { (*srcs.get(srcs.len() - 2u)).clone() } + None => { srcs[srcs.len() - 2u].clone() } }; - let mut actual = (*srcs.get(srcs.len() - 1u)).clone(); + let mut actual = srcs[srcs.len() - 1u].clone(); if props.pp_exact.is_some() { // Now we have to care about line endings @@ -209,7 +209,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) { if props.no_pretty_expanded { return } // additionally, run `--pretty expanded` and try to build it. - let proc_res = print_source(config, props, testfile, (*srcs.get(round)).clone(), "expanded"); + let proc_res = print_source(config, props, testfile, srcs[round].clone(), "expanded"); if !proc_res.status.success() { fatal_proc_rec("pretty-printing (expanded) failed", &proc_res); } @@ -536,6 +536,16 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) // We don't want to hang when calling `quit` while the process is still running let mut script_str = String::from_str("settings set auto-confirm true\n"); + // Make LLDB emit its version, so we have it documented in the test output + script_str.push_str("version\n"); + + // Switch LLDB into "Rust mode" + script_str.push_str("command script import ./src/etc/lldb_rust_formatters.py\n"); + script_str.push_str("type summary add --no-value "); + script_str.push_str("--python-function lldb_rust_formatters.print_val "); + script_str.push_str("-x \".*\" --category Rust\n"); + script_str.push_str("type category enable Rust\n"); + // Set breakpoints on every line that contains the string "#break" for line in breakpoint_lines.iter() { script_str.push_str(format!("breakpoint set --line {}\n", @@ -692,7 +702,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String]) let mut rest = line.trim(); let mut first = true; let mut failed = false; - for frag in check_fragments.get(i).iter() { + for frag in check_fragments[i].iter() { let found = if first { if rest.starts_with(frag.as_slice()) { Some(0) @@ -742,7 +752,7 @@ fn check_error_patterns(props: &TestProps, } let mut next_err_idx = 0u; - let mut next_err_pat = props.error_patterns.get(next_err_idx); + let mut next_err_pat = &props.error_patterns[next_err_idx]; let mut done = false; let output_to_check = if props.check_stdout { format!("{}{}", proc_res.stdout, proc_res.stderr) @@ -751,14 +761,14 @@ fn check_error_patterns(props: &TestProps, }; for line in output_to_check.as_slice().lines() { if line.contains(next_err_pat.as_slice()) { - debug!("found error pattern {}", *next_err_pat); + debug!("found error pattern {}", next_err_pat); next_err_idx += 1u; if next_err_idx == props.error_patterns.len() { debug!("found all error patterns"); done = true; break; } - next_err_pat = props.error_patterns.get(next_err_idx); + next_err_pat = &props.error_patterns[next_err_idx]; } } if done { return; } @@ -837,13 +847,13 @@ fn check_expected_errors(expected_errors: Vec , for line in proc_res.stderr.as_slice().lines() { let mut was_expected = false; for (i, ee) in expected_errors.iter().enumerate() { - if !*found_flags.get(i) { + if !found_flags[i] { debug!("prefix={} ee.kind={} ee.msg={} line={}", - prefixes.get(i).as_slice(), + prefixes[i].as_slice(), ee.kind, ee.msg, line); - if prefix_matches(line, prefixes.get(i).as_slice()) && + if prefix_matches(line, prefixes[i].as_slice()) && line.contains(ee.kind.as_slice()) && line.contains(ee.msg.as_slice()) { *found_flags.get_mut(i) = true; @@ -867,7 +877,7 @@ fn check_expected_errors(expected_errors: Vec , for (i, &flag) in found_flags.iter().enumerate() { if !flag { - let ee = expected_errors.get(i); + let ee = &expected_errors[i]; fatal_proc_rec(format!("expected {} on line {} not found: {}", ee.kind, ee.line, ee.msg).as_slice(), proc_res); diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index ae58db9077cab..ce037251e46b4 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -31,7 +31,7 @@ You may also be interested in browsing [GitHub's Rust][github-rust] page. ## Does it run on Windows? -Yes. All development happens in lock-step on all 3 target platforms. Using MinGW, not Cygwin. Note that the windows implementation currently has some limitations: in particular 64-bit build is [not fully supported yet][win64], and all executables created by rustc [depends on libgcc DLL at runtime][libgcc]. +Yes. All development happens in lock-step on all 3 target platforms. Using MinGW, not Cygwin. Note that the windows implementation currently has some limitations: in particular 64-bit build is [not fully supported yet][win64], and all executables created by rustc [depend on libgcc DLL at runtime][libgcc]. [win64]: https://github.com/rust-lang/rust/issues/1237 [libgcc]: https://github.com/rust-lang/rust/issues/11782 @@ -68,7 +68,7 @@ Cleanup through RAII-style destructors is more likely to work than in catch bloc ## Why aren't modules type-parametric? -We want to maintain the option to parametrize at runtime. We may make eventually change this limitation, but initially this is how type parameters were implemented. +We want to maintain the option to parametrize at runtime. We may eventually change this limitation, but initially this is how type parameters were implemented. ## Why aren't values type-parametric? Why only items? diff --git a/src/doc/guide-lifetimes.md b/src/doc/guide-lifetimes.md index 1f44b77d56abb..a6cc9cd0bc281 100644 --- a/src/doc/guide-lifetimes.md +++ b/src/doc/guide-lifetimes.md @@ -67,7 +67,7 @@ Now we can call `compute_distance()`: # let on_the_stack : Point = Point{x: 3.0, y: 4.0}; # let on_the_heap : Box = box Point{x: 7.0, y: 9.0}; # fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 } -compute_distance(&on_the_stack, on_the_heap); +compute_distance(&on_the_stack, &*on_the_heap); ~~~ Here, the `&` operator takes the address of the variable @@ -77,10 +77,9 @@ value. We also call this _borrowing_ the local variable `on_the_stack`, because we have created an alias: that is, another name for the same data. -In the case of `on_the_heap`, however, no explicit action is necessary. -The compiler will automatically convert a box point to a reference like &point. -This is another form of borrowing; in this case, the contents of the owned box -are being lent out. +Likewise, in the case of `owned_box`, +the `&` operator is used in conjunction with the `*` operator +to take a reference to the contents of the box. Whenever a caller lends data to a callee, there are some limitations on what the caller can do with the original. For example, if the contents of a diff --git a/src/doc/guide-pointers.md b/src/doc/guide-pointers.md index 0865282209773..17a1114be55f6 100644 --- a/src/doc/guide-pointers.md +++ b/src/doc/guide-pointers.md @@ -279,7 +279,7 @@ fn main() { let origin = &Point { x: 0.0, y: 0.0 }; let p1 = box Point { x: 5.0, y: 3.0 }; - println!("{}", compute_distance(origin, p1)); + println!("{}", compute_distance(origin, &*p1)); } ~~~ diff --git a/src/doc/guide-strings.md b/src/doc/guide-strings.md new file mode 100644 index 0000000000000..4fea8b8039e00 --- /dev/null +++ b/src/doc/guide-strings.md @@ -0,0 +1,127 @@ +% The Strings Guide + +Strings are an important concept to master in any programming language. If you +come from a managed language background, you may be surprised at the complexity +of string handling in a systems programming language. Efficient access and +allocation of memory for a dynamically sized structure involves a lot of +details. Luckily, Rust has lots of tools to help us here. + +A **string** is a sequence of unicode scalar values encoded as a stream of +UTF-8 bytes. All strings are guaranteed to be validly-encoded UTF-8 sequences. +Additionally, strings are not null-terminated and can contain null bytes. + +Rust has two main types of strings: `&str` and `String`. + +# &str + +The first kind is a `&str`. This is pronounced a 'string slice.' String literals +are of the type `&str`: + +```{rust} +let string = "Hello there."; +``` + +Like any Rust type, string slices have an associated lifetime. A string literal +is a `&'static str`. A string slice can be written without an explicit +lifetime in many cases, such as in function arguments. In these cases the +lifetime will be inferred: + +```{rust} +fn takes_slice(slice: &str) { + println!("Got: {}", slice); +} +``` + +Like vector slices, string slices are simply a pointer plus a length. This +means that they're a 'view' into an already-allocated string, such as a +`&'static str` or a `String`. + +# String + +A `String` is a heap-allocated string. This string is growable, and is also +guaranteed to be UTF-8. + +```{rust} +let mut s = "Hello".to_string(); +println!("{}", s); + +s.push_str(", world."); +println!("{}", s); +``` + +You can coerce a `String` into a `&str` with the `as_slice()` method: + +```{rust} +fn takes_slice(slice: &str) { + println!("Got: {}", slice); +} + +fn main() { + let s = "Hello".to_string(); + takes_slice(s.as_slice()); +} +``` + +You can also get a `&str` from a stack-allocated array of bytes: + +```{rust} +use std::str; + +let x: &[u8] = &[b'a', b'b']; +let stack_str: &str = str::from_utf8(x).unwrap(); +``` + +# Best Practices + +## `String` vs. `&str` + +In general, you should prefer `String` when you need ownership, and `&str` when +you just need to borrow a string. This is very similar to using `Vec` vs. `&[T]`, +and `T` vs `&T` in general. + +This means starting off with this: + +```{rust,ignore} +fn foo(s: &str) { +``` + +and only moving to this: + +```{rust,ignore} +fn foo(s: String) { +``` + +If you have good reason. It's not polite to hold on to ownership you don't +need, and it can make your lifetimes more complex. Furthermore, you can pass +either kind of string into `foo` by using `.as_slice()` on any `String` you +need to pass in, so the `&str` version is more flexible. + +## Comparisons + +To compare a String to a constant string, prefer `as_slice()`... + +```{rust} +fn compare(string: String) { + if string.as_slice() == "Hello" { + println!("yes"); + } +} +``` + +... over `to_string()`: + +```{rust} +fn compare(string: String) { + if string == "Hello".to_string() { + println!("yes"); + } +} +``` + +Converting a `String` to a `&str` is cheap, but converting the `&str` to a +`String` involves an allocation. + +# Other Documentation + +* [the `&str` API documentation](/std/str/index.html) +* [the `String` API documentation](std/string/index.html) diff --git a/src/doc/guide.md b/src/doc/guide.md index 1f3aae90aa153..b05d0e8ea350e 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -279,59 +279,12 @@ program doesn't have any dependencies, so we'll only be using the first part of its functionality. Eventually, we'll add more. Since we started off by using Cargo, it'll be easy to add later. -Let's convert Hello World to Cargo. The first thing we need to do to begin using Cargo -is to install Cargo. To do this, we need to build it from source. There are no binaries -yet. - -First, let's go back to our projects directory. We don't want Cargo to -live in our project! - -```{bash} -$ cd .. -``` - -Next, we need these commands: - -```{bash} -$ git clone --recursive https://github.com/rust-lang/cargo -$ cd cargo -$ make -$ make install # may need sudo or admin permissions -``` - -The `--recursive` downloads Cargo's own dependencies. You can't use Cargo to -fetch dependencies until you have Cargo installed! Also, you will need to have -`git` installed. Much of the Rust world assumes `git` usage, so it's a good -thing to have around. Please check out [the git -documentation](http://git-scm.com/book/en/Getting-Started-Installing-Git) for -more on installing `git`. - -We hope to give Cargo a binary installer, similar to Rust's own, so that -this will not be necessary in the future. - -Let's see if that worked. Try this: - -```{bash} -$ cargo -Commands: - build # compile the current project - -Options (for all commands): - --v, [--verbose] --h, [--help] -``` - -If you see this output when you run `cargo`, congrats! Cargo is working. If -not, please [open an issue](https://github.com/rust-lang/cargo/issues/new) or -drop by the Rust IRC, and we can help you out. - -Let's move back into our `hello_world` directory now: - -```{bash} -$ cd .. # move back up into projects -$ cd hello_world # move into hello_world -``` +Let's convert Hello World to Cargo. The first thing we need to do to begin +using Cargo is to install Cargo. Luckily for us, the script we ran to install +Rust includes Cargo by default. If you installed Rust some other way, you may +want to [check the Cargo +README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies) +for specific instructions about installing it. To Cargo-ify our project, we need to do two things: Make a `Cargo.toml` configuration file, and put our source file in the right place. Let's diff --git a/src/doc/index.md b/src/doc/index.md index eb8c59ac030ee..c54f4e00905de 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -13,6 +13,7 @@ li {list-style-type: none; } # Guides +* [Strings](guide-strings.html) * [Pointers](guide-pointers.html) * [References and Lifetimes](guide-lifetimes.html) * [Containers and Iterators](guide-container.html) diff --git a/src/doc/intro.md b/src/doc/intro.md index e8928cb55056c..7dcf8486181ed 100644 --- a/src/doc/intro.md +++ b/src/doc/intro.md @@ -205,7 +205,7 @@ fn main() { spawn(proc() { let numbers = rx.recv(); - println!("{}", *numbers.get(0)); + println!("{}", numbers[0]); }) } ``` @@ -244,11 +244,11 @@ fn main() { spawn(proc() { let numbers = rx.recv(); - println!("{}", numbers.get(0)); + println!("{}", numbers[0]); }); // Try to print a number from the original task - println!("{}", *numbers.get(0)); + println!("{}", numbers[0]); } ``` @@ -256,7 +256,7 @@ The compiler will produce an error indicating that the value is no longer in sco ```text concurrency.rs:12:20: 12:27 error: use of moved value: 'numbers' -concurrency.rs:12 println!("{}", numbers.get(0)); +concurrency.rs:12 println!("{}", numbers[0]); ^~~~~~~ ``` @@ -276,7 +276,7 @@ fn main() { spawn(proc() { let numbers = rx.recv(); - println!("{:d}", *numbers.get(num as uint)); + println!("{:d}", numbers[num as uint]); }) } } @@ -309,7 +309,7 @@ fn main() { spawn(proc() { let numbers = rx.recv(); - println!("{:d}", *numbers.get(num as uint)); + println!("{:d}", (*numbers)[num as uint]); }) } } @@ -364,7 +364,7 @@ fn main() { // See: https://github.com/rust-lang/rust/issues/6515 *numbers.get_mut(num as uint) = *numbers.get_mut(num as uint) + 1; - println!("{}", *numbers.get(num as uint)); + println!("{}", (*numbers)[num as uint]); // When `numbers` goes out of scope the lock is dropped }) diff --git a/src/doc/rust.md b/src/doc/rust.md index 9d5a6fa42a830..9fe61eb3fe3b0 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -3243,7 +3243,7 @@ enum List { Nil, Cons(uint, Box) } fn is_sorted(list: &List) -> bool { match *list { Nil | Cons(_, box Nil) => true, - Cons(x, ref r @ box Cons(y, _)) => (x <= y) && is_sorted(*r) + Cons(x, ref r @ box Cons(y, _)) => (x <= y) && is_sorted(&**r) } } diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md index 10f67876e508f..2b85bc50de3ab 100644 --- a/src/doc/tutorial.md +++ b/src/doc/tutorial.md @@ -716,8 +716,8 @@ When an enum has simple integer discriminators, you can apply the `as` cast operator to convert a variant to its discriminator value as an `int`: ~~~~ -# #[deriving(Show)] enum Direction { North } -println!( "{} => {}", North, North as int ); +# enum Direction { North, East, South, West } +println!( "North => {}", North as int ); ~~~~ It is possible to set the discriminator values to chosen constant values: @@ -748,8 +748,15 @@ includes an identifier of the actual form that it holds, much like the This declaration defines a type `Shape` that can refer to such shapes, and two functions, `Circle` and `Rectangle`, which can be used to construct values of -the type. To create a new Circle, write `Circle(Point { x: 0.0, y: 0.0 }, -10.0)`. +the type. + +To create a new `Circle`, write: + +~~~~ +# struct Point { x: f64, y: f64 } +# enum Shape { Circle(Point, f64), Rectangle(Point, Point) } +let circle = Circle(Point { x: 0.0, y: 0.0 }, 10.0); +~~~~ All of these variant constructors may be used as patterns. The only way to access the contents of an enum instance is the destructuring of a match. For @@ -757,6 +764,7 @@ example: ~~~~ use std::f64; + # struct Point {x: f64, y: f64} # enum Shape { Circle(Point, f64), Rectangle(Point, Point) } fn area(sh: Shape) -> f64 { @@ -765,6 +773,9 @@ fn area(sh: Shape) -> f64 { Rectangle(Point { x, y }, Point { x: x2, y: y2 }) => (x2 - x) * (y2 - y) } } + +let rect = Rectangle(Point { x: 0.0, y: 0.0 }, Point { x: 2.0, y: 2.0 }); +println!("area: {}", area(rect)); ~~~~ Use a lone `_` to ignore an individual field. Ignore all fields of a variant @@ -786,8 +797,9 @@ fn point_from_direction(dir: Direction) -> Point { Enum variants may also be structs. For example: ~~~~ -# #![feature(struct_variant)] +#![feature(struct_variant)] use std::f64; + # struct Point { x: f64, y: f64 } # fn square(x: f64) -> f64 { x * x } enum Shape { @@ -802,7 +814,14 @@ fn area(sh: Shape) -> f64 { } } } -# fn main() {} + +fn main() { + let rect = Rectangle { + top_left: Point { x: 0.0, y: 0.0 }, + bottom_right: Point { x: 2.0, y: -2.0 } + }; + println!("area: {}", area(rect)); +} ~~~~ > *Note:* This feature of the compiler is currently gated behind the @@ -986,6 +1005,10 @@ that are `Send`, but non-`Send` types can still *contain* types with custom destructors. Example of types which are not `Send` are [`Gc`][gc] and [`Rc`][rc], the shared-ownership types. +> *Note:* See a [later chapter](#ownership-escape-hatches) for a discussion about +> [`Gc`][gc] and [`Rc`][rc], and the [chapter about traits](#traits) for +> a discussion about `Send`. + [gc]: http://doc.rust-lang.org/std/gc/struct.Gc.html [rc]: http://doc.rust-lang.org/std/rc/struct.Rc.html @@ -1470,7 +1493,7 @@ Now we can call `compute_distance()` in various ways: # let on_the_stack : Point = Point { x: 3.0, y: 4.0 }; # let on_the_heap : Box = box Point { x: 7.0, y: 9.0 }; # fn compute_distance(p1: &Point, p2: &Point) -> f64 { 0.0 } -compute_distance(&on_the_stack, on_the_heap); +compute_distance(&on_the_stack, &*on_the_heap); ~~~ Here the `&` operator is used to take the address of the variable @@ -1480,11 +1503,9 @@ reference. We also call this _borrowing_ the local variable `on_the_stack`, because we are creating an alias: that is, another route to the same data. -In the case of `owned_box`, however, no -explicit action is necessary. The compiler will automatically convert -a box `box point` to a reference like -`&point`. This is another form of borrowing; in this case, the -contents of the owned box are being lent out. +Likewise, in the case of `owned_box`, +the `&` operator is used in conjunction with the `*` operator +to take a reference to the contents of the box. Whenever a value is borrowed, there are some limitations on what you can do with the original. For example, if the contents of a variable @@ -1647,6 +1668,13 @@ let string = "foobar"; let view: &str = string.slice(0, 3); ~~~ +Square brackets denote indexing into a slice or fixed-size vector: + +~~~~ +let crayons: [&str, ..3] = ["BananaMania", "Beaver", "Bittersweet"]; +println!("Crayon 2 is '{}'", crayons[2]); +~~~~ + Mutable slices also exist, just as there are mutable references. However, there are no mutable string slices. Strings are a multi-byte encoding (UTF-8) of Unicode code points, so they cannot be freely mutated without the ability to @@ -1661,20 +1689,6 @@ view[0] = 5; let ys: &mut [int] = &mut [1i, 2i, 3i]; ~~~ -Square brackets denote indexing into a slice or fixed-size vector: - -~~~~ -# enum Crayon { Almond, AntiqueBrass, Apricot, -# Aquamarine, Asparagus, AtomicTangerine, -# BananaMania, Beaver, Bittersweet }; -# fn draw_scene(c: Crayon) { } -let crayons: [Crayon, ..3] = [BananaMania, Beaver, Bittersweet]; -match crayons[0] { - Bittersweet => draw_scene(crayons[0]), - _ => () -} -~~~~ - A slice or fixed-size vector can be destructured using pattern matching: ~~~~ @@ -1740,6 +1754,8 @@ via dynamic checks and can fail at runtime. The `Rc` and `Gc` types are not sendable, so they cannot be used to share memory between tasks. Safe immutable and mutable shared memory is provided by the `sync::arc` module. +> *Note:* See a [later chapter](#traits) for a discussion about `Send` and sendable types. + # Closures Named functions, like those we've seen so far, may not refer to local @@ -2427,7 +2443,7 @@ as in this version of `print_all` that copies elements. fn print_all(printable_things: Vec) { let mut i = 0; while i < printable_things.len() { - let copy_of_thing = printable_things.get(i).clone(); + let copy_of_thing = printable_things[i].clone(); copy_of_thing.print(); i += 1; } @@ -2611,7 +2627,7 @@ let nonsense = mycircle.radius() * mycircle.area(); ## Deriving implementations for traits -A small number of traits in `std` and `extra` can have implementations +A small number of traits in can have implementations that can be automatically derived. These instances are specified by placing the `deriving` attribute on a data type declaration. For example, the following will mean that `Circle` has an implementation @@ -2620,6 +2636,7 @@ of type `ABC` can be randomly generated and converted to a string: ~~~ extern crate rand; +use std::rand::{task_rng, Rng}; #[deriving(PartialEq)] struct Circle { radius: f64 } @@ -2630,6 +2647,13 @@ enum ABC { A, B, C } fn main() { // Use the Show trait to print "A, B, C." println!("{}, {}, {}", A, B, C); + + let mut rng = task_rng(); + + // Use the Rand trait to generate a random variants. + for _ in range(0i, 10) { + println!("{}", rng.gen::()); + } } ~~~ @@ -3138,8 +3162,8 @@ In Rust terminology, we need a way to refer to other crates. For that, Rust offers you the `extern crate` declaration: ~~~ +// `num` ships with Rust. extern crate num; -// `num` ships with Rust (much like `extra`; more details further down). fn main() { // The rational number '1/2': diff --git a/src/etc/lldb_batchmode.py b/src/etc/lldb_batchmode.py index 85bfc425b587d..06bd2a13d22cd 100644 --- a/src/etc/lldb_batchmode.py +++ b/src/etc/lldb_batchmode.py @@ -31,9 +31,6 @@ import re import atexit -# Terminate the debugger -atexit.register(lambda: lldb.SBDebugger.Terminate()) - # Set this to True for additional output DEBUG_OUTPUT = False diff --git a/src/etc/lldb_rust_formatters.py b/src/etc/lldb_rust_formatters.py new file mode 100644 index 0000000000000..aa223019b5481 --- /dev/null +++ b/src/etc/lldb_rust_formatters.py @@ -0,0 +1,232 @@ +# Copyright 2014 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. + +import lldb + +def print_val(val, internal_dict): + '''Prints the given value with Rust syntax''' + type_class = val.GetType().GetTypeClass() + + if type_class == lldb.eTypeClassStruct: + return print_struct_val(val, internal_dict) + + if type_class == lldb.eTypeClassUnion: + return print_enum_val(val, internal_dict) + + if type_class == lldb.eTypeClassPointer: + return print_pointer_val(val, internal_dict) + + if type_class == lldb.eTypeClassArray: + return print_fixed_size_vec_val(val, internal_dict) + + return val.GetValue() + + +#=-------------------------------------------------------------------------------------------------- +# Type-Specialized Printing Functions +#=-------------------------------------------------------------------------------------------------- + +def print_struct_val(val, internal_dict): + '''Prints a struct, tuple, or tuple struct value with Rust syntax''' + assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct + + if is_vec_slice(val): + return print_vec_slice_val(val, internal_dict) + else: + return print_struct_val_starting_from(0, val, internal_dict) + +def print_vec_slice_val(val, internal_dict): + output = "&[" + + length = val.GetChildAtIndex(1).GetValueAsUnsigned() + + data_ptr_val = val.GetChildAtIndex(0) + data_ptr_type = data_ptr_val.GetType() + assert data_ptr_type.IsPointerType() + + element_type = data_ptr_type.GetPointeeType() + element_type_size = element_type.GetByteSize() + + start_address = data_ptr_val.GetValueAsUnsigned() + + for i in range(length): + address = start_address + i * element_type_size + element_val = val.CreateValueFromAddress( val.GetName() + ("[%s]" % i), address, element_type ) + output += print_val(element_val, internal_dict) + + if i != length - 1: + output += ", " + + output += "]" + return output + +def print_struct_val_starting_from(field_start_index, val, internal_dict): + ''' + Prints a struct, tuple, or tuple struct value with Rust syntax. + Ignores any fields before field_start_index. + ''' + assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct + + t = val.GetType() + has_field_names = type_has_field_names(t) + type_name = extract_type_name(t.GetName()) + output = "" + + if not type_name.startswith("("): + # this is a tuple, so don't print the type name + output += type_name + + if has_field_names: + output += " { \n" + else: + output += "(" + + num_children = val.num_children + + for child_index in range(field_start_index, num_children): + if has_field_names: + field_name = t.GetFieldAtIndex(child_index).GetName() + output += field_name + ": " + + field_val = val.GetChildAtIndex(child_index) + output += print_val(field_val, internal_dict) + + if child_index != num_children - 1: + output += ", " + + if has_field_names: + output += "\n" + + if has_field_names: + output += "}" + else: + output += ")" + + return output + + +def print_enum_val(val, internal_dict): + '''Prints an enum value with Rust syntax''' + + assert val.GetType().GetTypeClass() == lldb.eTypeClassUnion + + if val.num_children == 1: + first_variant_name = val.GetChildAtIndex(0).GetName() + if first_variant_name and first_variant_name.startswith("RUST$ENCODED$ENUM$"): + # Try to extract the + + last_separator_index = first_variant_name.rfind("$") + if last_separator_index == -1: + return "" % first_variant_name + + second_last_separator_index = first_variant_name.rfind("$", 0, last_separator_index) + if second_last_separator_index == -1: + return "" % first_variant_name + + try: + disr_field_index = first_variant_name[second_last_separator_index + 1 : + last_separator_index] + disr_field_index = int(disr_field_index) + except: + return "" % first_variant_name + + disr_val = val.GetChildAtIndex(0).GetChildAtIndex(disr_field_index).GetValueAsUnsigned() + + if disr_val == 0: + null_variant_name = first_variant_name[last_separator_index + 1:] + return null_variant_name + else: + return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict) + else: + return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict) + + # extract the discriminator value by + disr_val = val.GetChildAtIndex(0).GetChildAtIndex(0) + disr_type = disr_val.GetType() + + if disr_type.GetTypeClass() != lldb.eTypeClassEnumeration: + return "" + + variant_index = disr_val.GetValueAsUnsigned() + return print_struct_val_starting_from(1, val.GetChildAtIndex(variant_index), internal_dict) + + +def print_pointer_val(val, internal_dict): + '''Prints a pointer value with Rust syntax''' + assert val.GetType().IsPointerType() + sigil = "&" + type_name = extract_type_name(val.GetType().GetName()) + if type_name and type_name[0:1] in ["&", "~", "*"]: + sigil = type_name[0:1] + + return sigil + hex(val.GetValueAsUnsigned()) #print_val(val.Dereference(), internal_dict) + + +def print_fixed_size_vec_val(val, internal_dict): + assert val.GetType().GetTypeClass() == lldb.eTypeClassArray + + output = "[" + + for i in range(val.num_children): + output += print_val(val.GetChildAtIndex(i), internal_dict) + if i != val.num_children - 1: + output += ", " + + output += "]" + return output + + +#=-------------------------------------------------------------------------------------------------- +# Helper Functions +#=-------------------------------------------------------------------------------------------------- + +unqualified_type_markers = frozenset(["(", "[", "&", "*"]) + +def extract_type_name(qualified_type_name): + '''Extracts the type name from a fully qualified path''' + if qualified_type_name[0] in unqualified_type_markers: + return qualified_type_name + + end_of_search = qualified_type_name.find("<") + if end_of_search < 0: + end_of_search = len(qualified_type_name) + + index = qualified_type_name.rfind("::", 0, end_of_search) + if index < 0: + return qualified_type_name + else: + return qualified_type_name[index + 2:] + + +def type_has_field_names(ty): + '''Returns true of this is a type with field names (struct, struct-like enum variant)''' + # This may also be an enum variant where the first field doesn't have a name but the rest has + if ty.GetNumberOfFields() > 1: + return ty.GetFieldAtIndex(1).GetName() != None + else: + return ty.GetFieldAtIndex(0).GetName() != None + + +def is_vec_slice(val): + ty = val.GetType() + if ty.GetTypeClass() != lldb.eTypeClassStruct: + return False + + if ty.GetNumberOfFields() != 2: + return False + + if ty.GetFieldAtIndex(0).GetName() != "data_ptr": + return False + + if ty.GetFieldAtIndex(1).GetName() != "length": + return False + + type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "") + return type_name.startswith("&[") and type_name.endswith("]") diff --git a/src/etc/vim/doc/rust.txt b/src/etc/vim/doc/rust.txt index 96ed69db63529..80f8c3ca5e1ee 100644 --- a/src/etc/vim/doc/rust.txt +++ b/src/etc/vim/doc/rust.txt @@ -1,7 +1,7 @@ *rust.txt* Filetype plugin for Rust ============================================================================== -CONTENTS *rust* +CONTENTS *rust* *ft-rust* 1. Introduction |rust-intro| 2. Settings |rust-settings| @@ -53,6 +53,18 @@ g:rust_conceal_pub~ let g:rust_conceal_pub = 1 < + *g:rust_fold* +g:rust_fold~ + Set this option to turn on |folding|: > + let g:rust_fold = 1 +< + Value Effect ~ + 0 No folding + 1 Braced blocks are folded. All folds are open by + default. + 2 Braced blocks are folded. 'foldlevel' is left at the + global value (all folds are closed by default). + *g:rust_bang_comment_leader* g:rust_bang_comment_leader~ Set this option to 1 to preserve the leader on multi-line doc comments diff --git a/src/etc/vim/ftplugin/rust.vim b/src/etc/vim/ftplugin/rust.vim index 16ed43415c3ef..39edc1f9a20d7 100644 --- a/src/etc/vim/ftplugin/rust.vim +++ b/src/etc/vim/ftplugin/rust.vim @@ -2,7 +2,7 @@ " Description: Vim syntax file for Rust " Maintainer: Chris Morgan " Maintainer: Kevin Ballard -" Last Change: May 27, 2014 +" Last Change: Jul 07, 2014 if exists("b:did_ftplugin") finish @@ -35,7 +35,9 @@ silent! setlocal formatoptions+=j " otherwise it's better than nothing. setlocal smartindent nocindent -setlocal tabstop=4 shiftwidth=4 expandtab +setlocal tabstop=4 shiftwidth=4 softtabstop=4 expandtab + +setlocal textwidth=99 " This includeexpr isn't perfect, but it's a good start setlocal includeexpr=substitute(v:fname,'::','/','g') @@ -93,7 +95,8 @@ endif " Cleanup {{{1 let b:undo_ftplugin = " - \setlocal formatoptions< comments< commentstring< includeexpr< suffixesadd< + \ setlocal formatoptions< comments< commentstring< includeexpr< suffixesadd< + \|setlocal tabstop< shiftwidth< softtabstop< expandtab< textwidth< \|if exists('b:rust_original_delimitMate_excluded_regions') \|let b:delimitMate_excluded_regions = b:rust_original_delimitMate_excluded_regions \|unlet b:rust_original_delimitMate_excluded_regions diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index 86df9cba4cdf5..1b75538d2f71b 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -3,7 +3,7 @@ " Maintainer: Patrick Walton " Maintainer: Ben Blum " Maintainer: Chris Morgan -" Last Change: 2014 Feb 27 +" Last Change: July 06, 2014 if version < 600 syntax clear @@ -11,6 +11,17 @@ elseif exists("b:current_syntax") finish endif +" Fold settings {{{1 + +if has("folding") && exists('g:rust_fold') && g:rust_fold != 0 + setlocal foldmethod=syntax + if g:rust_fold == 2 + setlocal foldlevel< + else + setlocal foldlevel=99 + endif +endif + " Syntax definitions {{{1 " Basic keywords {{{2 syn keyword rustConditional match if else @@ -213,8 +224,6 @@ syn keyword rustTodo contained TODO FIXME XXX NB NOTE " Trivial folding rules to begin with. " TODO: use the AST to make really good folding syn region rustFoldBraces start="{" end="}" transparent fold -" If you wish to enable this, setlocal foldmethod=syntax -" It's not enabled by default as it would drive some people mad. " Default highlighting {{{1 hi def link rustDecNumber rustNumber diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 56506d798d9df..89f6e934ad259 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -67,7 +67,7 @@ impl PartialEq for Box { impl PartialOrd for Box { #[inline] fn partial_cmp(&self, other: &Box) -> Option { - (**self).partial_cmp(*other) + (**self).partial_cmp(&**other) } #[inline] fn lt(&self, other: &Box) -> bool { *(*self) < *(*other) } @@ -80,7 +80,9 @@ impl PartialOrd for Box { } impl Ord for Box { #[inline] - fn cmp(&self, other: &Box) -> Ordering { (**self).cmp(*other) } + fn cmp(&self, other: &Box) -> Ordering { + (**self).cmp(&**other) + } } impl Eq for Box {} diff --git a/src/libcollections/btree.rs b/src/libcollections/btree.rs index 6ee68f74438fe..e4605527ce550 100644 --- a/src/libcollections/btree.rs +++ b/src/libcollections/btree.rs @@ -365,12 +365,12 @@ impl Leaf { return (Node::new_leaf(self.clone().elts), false); } //If there is an index, insert at that index. - _ => { - if index.unwrap() >= self.elts.len() { + Some(i) => { + if i >= self.elts.len() { self.elts.push(to_insert.clone()); } else { - self.elts.insert(index.unwrap(), to_insert.clone()); + self.elts.insert(i, to_insert.clone()); } } } @@ -526,8 +526,8 @@ impl Branch { self.clone().rightmost_child), outcome); } - _ => { - if index.unwrap() == self.elts.len() { + Some(i) => { + if i == self.elts.len() { let new_outcome = self.clone().rightmost_child.insert(k.clone(), v.clone(), ub.clone()); @@ -535,7 +535,7 @@ impl Branch { outcome = new_outcome.val1(); } else { - let new_outcome = self.elts.get(index.unwrap()).left.clone().insert(k.clone(), + let new_outcome = self.elts.get(i).left.clone().insert(k.clone(), v.clone(), ub.clone()); new_branch = new_outcome.clone().val0(); @@ -547,11 +547,11 @@ impl Branch { //If we have a leaf, we do not need to resize the tree, //so we can return false. LeafNode(..) => { - if index.unwrap() == self.elts.len() { + if i == self.elts.len() { self.rightmost_child = box new_branch.clone(); } else { - self.elts.get_mut(index.unwrap()).left = box new_branch.clone(); + self.elts.get_mut(i).left = box new_branch.clone(); } return (Node::new_branch(self.clone().elts, self.clone().rightmost_child), @@ -589,13 +589,13 @@ impl Branch { self.clone().rightmost_child), false); } - _ => { - self.elts.insert(new_elt_index.unwrap(), new_elt); - if new_elt_index.unwrap() + 1 >= self.elts.len() { + Some(i) => { + self.elts.insert(i, new_elt); + if i + 1 >= self.elts.len() { self.rightmost_child = branch.clone().rightmost_child; } else { - self.elts.get_mut(new_elt_index.unwrap() + 1).left = + self.elts.get_mut(i + 1).left = branch.clone().rightmost_child; } } diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index 226dd5a2356c9..48ea1bd1c0150 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -87,12 +87,14 @@ impl Rawlink { } /// Convert the `Rawlink` into an Option value - fn resolve_immut(&self) -> Option<&T> { - unsafe { self.p.to_option() } + fn resolve_immut<'a>(&self) -> Option<&'a T> { + unsafe { + mem::transmute(self.p.to_option()) + } } /// Convert the `Rawlink` into an Option value - fn resolve(&mut self) -> Option<&mut T> { + fn resolve<'a>(&mut self) -> Option<&'a mut T> { if self.p.is_null() { None } else { @@ -278,6 +280,23 @@ impl DList { /// Move the last element to the front of the list. /// /// If the list is empty, do nothing. + /// + /// # Example + /// + /// ```rust + /// use std::collections::{DList, Deque}; + /// + /// let mut dl = DList::new(); + /// dl.push_back(1i); + /// dl.push_back(2); + /// dl.push_back(3); + /// + /// dl.rotate_forward(); + /// + /// for e in dl.iter() { + /// println!("{}", e); // prints 3, then 1, then 2 + /// } + /// ``` #[inline] pub fn rotate_forward(&mut self) { self.pop_back_node().map(|tail| { @@ -288,6 +307,23 @@ impl DList { /// Move the first element to the back of the list. /// /// If the list is empty, do nothing. + /// + /// # Example + /// + /// ```rust + /// use std::collections::{DList, Deque}; + /// + /// let mut dl = DList::new(); + /// dl.push_back(1i); + /// dl.push_back(2); + /// dl.push_back(3); + /// + /// dl.rotate_backward(); + /// + /// for e in dl.iter() { + /// println!("{}", e); // prints 2, then 3, then 1 + /// } + /// ``` #[inline] pub fn rotate_backward(&mut self) { self.pop_front_node().map(|head| { @@ -298,6 +334,25 @@ impl DList { /// Add all elements from `other` to the end of the list /// /// O(1) + /// + /// # Example + /// + /// ```rust + /// use std::collections::{DList, Deque}; + /// + /// let mut a = DList::new(); + /// let mut b = DList::new(); + /// a.push_back(1i); + /// a.push_back(2); + /// b.push_back(3i); + /// b.push_back(4); + /// + /// a.append(b); + /// + /// for e in a.iter() { + /// println!("{}", e); // prints 1, then 2, then 3, then 4 + /// } + /// ``` pub fn append(&mut self, mut other: DList) { match self.list_tail.resolve() { None => *self = other, @@ -320,6 +375,25 @@ impl DList { /// Add all elements from `other` to the beginning of the list /// /// O(1) + /// + /// # Example + /// + /// ```rust + /// use std::collections::{DList, Deque}; + /// + /// let mut a = DList::new(); + /// let mut b = DList::new(); + /// a.push_back(1i); + /// a.push_back(2); + /// b.push_back(3i); + /// b.push_back(4); + /// + /// a.prepend(b); + /// + /// for e in a.iter() { + /// println!("{}", e); // prints 3, then 4, then 1, then 2 + /// } + /// ``` #[inline] pub fn prepend(&mut self, mut other: DList) { mem::swap(self, &mut other); @@ -330,6 +404,25 @@ impl DList { /// or at the end. /// /// O(N) + /// + /// # Example + /// + /// ```rust + /// use std::collections::{DList, Deque}; + /// + /// let mut a: DList = DList::new(); + /// a.push_back(2i); + /// a.push_back(4); + /// a.push_back(7); + /// a.push_back(8); + /// + /// // insert 11 before the first odd number in the list + /// a.insert_when(11, |&e, _| e % 2 == 1); + /// + /// for e in a.iter() { + /// println!("{}", e); // prints 2, then 4, then 11, then 7, then 8 + /// } + /// ``` pub fn insert_when(&mut self, elt: T, f: |&T, &T| -> bool) { { let mut it = self.mut_iter(); diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 40cf8495a4059..1c5aa8a323bab 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -277,21 +277,33 @@ impl Iterator> for Permutations { /// Extension methods for vector slices with cloneable elements pub trait CloneableVector { - /// Copy `self` into a new owned vector - fn to_owned(&self) -> Vec; + /// Copy `self` into a new vector + fn to_vec(&self) -> Vec; + + /// Deprecated. Use `to_vec` + #[deprecated = "Replaced by `to_vec`"] + fn to_owned(&self) -> Vec { + self.to_vec() + } /// Convert `self` into an owned vector, not making a copy if possible. - fn into_owned(self) -> Vec; + fn into_vec(self) -> Vec; + + /// Deprecated. Use `into_vec` + #[deprecated = "Replaced by `into_vec`"] + fn into_owned(self) -> Vec { + self.into_vec() + } } /// Extension methods for vector slices impl<'a, T: Clone> CloneableVector for &'a [T] { /// Returns a copy of `v`. #[inline] - fn to_owned(&self) -> Vec { Vec::from_slice(*self) } + fn to_vec(&self) -> Vec { Vec::from_slice(*self) } #[inline(always)] - fn into_owned(self) -> Vec { self.to_owned() } + fn into_vec(self) -> Vec { self.to_vec() } } /// Extension methods for vectors containing `Clone` elements. @@ -325,7 +337,7 @@ impl<'a,T:Clone> ImmutableCloneableVector for &'a [T] { fn permutations(self) -> Permutations { Permutations{ swaps: ElementSwaps::new(self.len()), - v: self.to_owned(), + v: self.to_vec(), } } @@ -888,7 +900,7 @@ mod tests { fn test_slice() { // Test fixed length vector. let vec_fixed = [1i, 2, 3, 4]; - let v_a = vec_fixed.slice(1u, vec_fixed.len()).to_owned(); + let v_a = vec_fixed.slice(1u, vec_fixed.len()).to_vec(); assert_eq!(v_a.len(), 3u); let v_a = v_a.as_slice(); assert_eq!(v_a[0], 2); @@ -897,7 +909,7 @@ mod tests { // Test on stack. let vec_stack = &[1i, 2, 3]; - let v_b = vec_stack.slice(1u, 3u).to_owned(); + let v_b = vec_stack.slice(1u, 3u).to_vec(); assert_eq!(v_b.len(), 2u); let v_b = v_b.as_slice(); assert_eq!(v_b[0], 2); @@ -905,7 +917,7 @@ mod tests { // Test `Box<[T]>` let vec_unique = vec![1i, 2, 3, 4, 5, 6]; - let v_d = vec_unique.slice(1u, 6u).to_owned(); + let v_d = vec_unique.slice(1u, 6u).to_vec(); assert_eq!(v_d.len(), 5u); let v_d = v_d.as_slice(); assert_eq!(v_d[0], 2); @@ -1132,7 +1144,7 @@ mod tests { let (min_size, max_opt) = it.size_hint(); assert_eq!(min_size, 1); assert_eq!(max_opt.unwrap(), 1); - assert_eq!(it.next(), Some(v.as_slice().to_owned())); + assert_eq!(it.next(), Some(v.as_slice().to_vec())); assert_eq!(it.next(), None); } { @@ -1141,7 +1153,7 @@ mod tests { let (min_size, max_opt) = it.size_hint(); assert_eq!(min_size, 1); assert_eq!(max_opt.unwrap(), 1); - assert_eq!(it.next(), Some(v.as_slice().to_owned())); + assert_eq!(it.next(), Some(v.as_slice().to_vec())); assert_eq!(it.next(), None); } { diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 85921f1176a3a..1e29679f8a79e 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -55,10 +55,10 @@ other languages. # Representation -Rust's string type, `str`, is a sequence of unicode codepoints encoded as a -stream of UTF-8 bytes. All safely-created strings are guaranteed to be validly -encoded UTF-8 sequences. Additionally, strings are not null-terminated -and can contain null codepoints. +Rust's string type, `str`, is a sequence of unicode scalar values encoded as a +stream of UTF-8 bytes. All strings are guaranteed to be validly encoded UTF-8 +sequences. Additionally, strings are not null-terminated and can contain null +bytes. The actual representation of strings have direct mappings to vectors: `&str` is the same as `&[u8]`. @@ -808,6 +808,7 @@ impl OwnedStr for String { #[cfg(test)] mod tests { use std::iter::AdditiveIterator; + use std::iter::range; use std::default::Default; use std::char::Char; use std::clone::Clone; @@ -1610,6 +1611,30 @@ mod tests { assert_eq!(pos, v.len()); } + #[test] + fn test_chars_decoding() { + let mut bytes = [0u8, ..4]; + for c in range(0u32, 0x110000).filter_map(|c| ::core::char::from_u32(c)) { + let len = c.encode_utf8(bytes); + let s = ::core::str::from_utf8(bytes.slice_to(len)).unwrap(); + if Some(c) != s.chars().next() { + fail!("character {:x}={} does not decode correctly", c as u32, c); + } + } + } + + #[test] + fn test_chars_rev_decoding() { + let mut bytes = [0u8, ..4]; + for c in range(0u32, 0x110000).filter_map(|c| ::core::char::from_u32(c)) { + let len = c.encode_utf8(bytes); + let s = ::core::str::from_utf8(bytes.slice_to(len)).unwrap(); + if Some(c) != s.chars().rev().next() { + fail!("character {:x}={} does not decode correctly", c as u32, c); + } + } + } + #[test] fn test_iterator_clone() { let s = "ศไทย中华Việt Nam"; @@ -2240,16 +2265,26 @@ mod tests { #[cfg(test)] mod bench { use test::Bencher; + use test::black_box; use super::*; + use std::option::{None, Some}; use std::iter::{Iterator, DoubleEndedIterator}; use std::collections::Collection; #[bench] fn char_iterator(b: &mut Bencher) { let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; - let len = s.char_len(); - b.iter(|| assert_eq!(s.chars().count(), len)); + b.iter(|| s.chars().count()); + } + + #[bench] + fn char_iterator_for(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + + b.iter(|| { + for ch in s.chars() { black_box(ch) } + }); } #[bench] @@ -2260,17 +2295,24 @@ mod bench { Mary had a little lamb, Little lamb Mary had a little lamb, Little lamb Mary had a little lamb, Little lamb"; - let len = s.char_len(); - b.iter(|| assert_eq!(s.chars().count(), len)); + b.iter(|| s.chars().count()); } #[bench] fn char_iterator_rev(b: &mut Bencher) { let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; - let len = s.char_len(); - b.iter(|| assert_eq!(s.chars().rev().count(), len)); + b.iter(|| s.chars().rev().count()); + } + + #[bench] + fn char_iterator_rev_for(b: &mut Bencher) { + let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; + + b.iter(|| { + for ch in s.chars().rev() { black_box(ch) } + }); } #[bench] diff --git a/src/libcollections/treemap.rs b/src/libcollections/treemap.rs index 3d4973373e267..ad5ad13167c0e 100644 --- a/src/libcollections/treemap.rs +++ b/src/libcollections/treemap.rs @@ -11,6 +11,22 @@ //! An ordered map and set implemented as self-balancing binary search //! trees. The only requirement for the types is that the key implements //! `Ord`. +//! +//! ## Example +//! +//! ```{rust} +//! use std::collections::TreeSet; +//! +//! let mut tree_set = TreeSet::new(); +//! +//! tree_set.insert(2i); +//! tree_set.insert(1i); +//! tree_set.insert(3i); +//! +//! for i in tree_set.iter() { +//! println!("{}", i) // prints 1, then 2, then 3 +//! } +//! ``` use core::prelude::*; @@ -500,7 +516,7 @@ define_iterator! { fn deref<'a, K, V>(node: &'a Option>>) -> *const TreeNode { match *node { Some(ref n) => { - let n: &TreeNode = *n; + let n: &TreeNode = &**n; n as *const TreeNode } None => ptr::null() @@ -587,6 +603,22 @@ impl<'a, T> Iterator<&'a T> for RevSetItems<'a, T> { /// A implementation of the `Set` trait on top of the `TreeMap` container. The /// only requirement is that the type of the elements contained ascribes to the /// `Ord` trait. +/// +/// ## Example +/// +/// ```{rust} +/// use std::collections::TreeSet; +/// +/// let mut tree_set = TreeSet::new(); +/// +/// tree_set.insert(2i); +/// tree_set.insert(1i); +/// tree_set.insert(3i); +/// +/// for i in tree_set.iter() { +/// println!("{}", i) // prints 1, then 2, then 3 +/// } +/// ``` #[deriving(Clone)] pub struct TreeSet { map: TreeMap diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 1e96588dac5f8..96228531ae54f 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -42,7 +42,7 @@ pub static PTR_MARKER: u8 = 0; /// vec.push(2i); /// /// assert_eq!(vec.len(), 2); -/// assert_eq!(vec.get(0), &1); +/// assert_eq!(vec[0], 1); /// /// assert_eq!(vec.pop(), Some(2)); /// assert_eq!(vec.len(), 1); @@ -363,6 +363,21 @@ impl Clone for Vec { } } +impl Index for Vec { + #[inline] + fn index<'a>(&'a self, index: &uint) -> &'a T { + self.get(*index) + } +} + +// FIXME(#12825) Indexing will always try IndexMut first and that causes issues. +/*impl IndexMut for Vec { + #[inline] + fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut T { + self.get_mut(*index) + } +}*/ + impl FromIterator for Vec { #[inline] fn from_iter>(mut iterator: I) -> Vec { @@ -422,8 +437,8 @@ impl Collection for Vec { } impl CloneableVector for Vec { - fn to_owned(&self) -> Vec { self.clone() } - fn into_owned(self) -> Vec { self } + fn to_vec(&self) -> Vec { self.clone() } + fn into_vec(self) -> Vec { self } } // FIXME: #13996: need a way to mark the return value as `noalias` @@ -731,9 +746,12 @@ impl Vec { /// # Example /// /// ```rust + /// #![allow(deprecated)] + /// /// let vec = vec!(1i, 2, 3); /// assert!(vec.get(1) == &2); /// ``` + #[deprecated="prefer using indexing, e.g., vec[0]"] #[inline] pub fn get<'a>(&'a self, index: uint) -> &'a T { &self.as_slice()[index] @@ -1847,6 +1865,19 @@ mod tests { v.truncate(0); } + #[test] + fn test_index() { + let vec = vec!(1i, 2, 3); + assert!(vec[1] == 2); + } + + #[test] + #[should_fail] + fn test_index_out_of_bounds() { + let vec = vec!(1i, 2, 3); + let _ = vec[3]; + } + #[bench] fn bench_new(b: &mut Bencher) { b.iter(|| { diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 53179df4cb9b3..8a1962c2bbd79 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -749,6 +749,7 @@ pub trait DerefMut: Deref { #[lang="fn"] pub trait Fn { /// This is called when the call operator is used. + #[rust_call_abi_hack] fn call(&self, args: Args) -> Result; } @@ -756,6 +757,7 @@ pub trait Fn { #[lang="fn_mut"] pub trait FnMut { /// This is called when the call operator is used. + #[rust_call_abi_hack] fn call_mut(&mut self, args: Args) -> Result; } @@ -763,5 +765,7 @@ pub trait FnMut { #[lang="fn_once"] pub trait FnOnce { /// This is called when the call operator is used. + #[rust_call_abi_hack] fn call_once(self, args: Args) -> Result; } + diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index d8ab89fd504f5..d27689eeaf417 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -35,6 +35,7 @@ pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Drop, Deref, DerefMut}; pub use ops::{Shl, Shr}; pub use ops::{Index, IndexMut}; +pub use ops::{Fn, FnMut, FnOnce}; pub use option::{Option, Some, None}; pub use result::{Result, Ok, Err}; diff --git a/src/libcore/str.rs b/src/libcore/str.rs index aa2050dacf1aa..c6aff9c8bdac8 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -97,47 +97,110 @@ impl<'a> CharEq for &'a [char] { Section: Iterators */ -/// External iterator for a string's characters. -/// Use with the `std::iter` module. +/// Iterator for the char (representing *Unicode Scalar Values*) of a string +/// +/// Created with the method `.chars()`. #[deriving(Clone)] pub struct Chars<'a> { - /// The slice remaining to be iterated - string: &'a str, + iter: slice::Items<'a, u8> +} + +// Return the initial codepoint accumulator for the first byte. +// The first byte is special, only want bottom 5 bits for width 2, 4 bits +// for width 3, and 3 bits for width 4 +macro_rules! utf8_first_byte( + ($byte:expr, $width:expr) => (($byte & (0x7F >> $width)) as u32) +) + +// return the value of $ch updated with continuation byte $byte +macro_rules! utf8_acc_cont_byte( + ($ch:expr, $byte:expr) => (($ch << 6) | ($byte & CONT_MASK) as u32) +) + +macro_rules! utf8_is_cont_byte( + ($byte:expr) => (($byte & !CONT_MASK) == TAG_CONT_U8) +) + +#[inline] +fn unwrap_or_0(opt: Option<&u8>) -> u8 { + match opt { + Some(&byte) => byte, + None => 0, + } } impl<'a> Iterator for Chars<'a> { #[inline] fn next(&mut self) -> Option { - // Decode the next codepoint, then update - // the slice to be just the remaining part - if self.string.len() != 0 { - let CharRange {ch, next} = self.string.char_range_at(0); - unsafe { - self.string = raw::slice_unchecked(self.string, next, self.string.len()); + // Decode UTF-8, using the valid UTF-8 invariant + let x = match self.iter.next() { + None => return None, + Some(&next_byte) if next_byte < 128 => return Some(next_byte as char), + Some(&next_byte) => next_byte, + }; + + // Multibyte case follows + // Decode from a byte combination out of: [[[x y] z] w] + // NOTE: Performance is sensitive to the exact formulation here + let init = utf8_first_byte!(x, 2); + let y = unwrap_or_0(self.iter.next()); + let mut ch = utf8_acc_cont_byte!(init, y); + if x >= 0xE0 { + // [[x y z] w] case + // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid + let z = unwrap_or_0(self.iter.next()); + let y_z = utf8_acc_cont_byte!((y & CONT_MASK) as u32, z); + ch = init << 12 | y_z; + if x >= 0xF0 { + // [x y z w] case + // use only the lower 3 bits of `init` + let w = unwrap_or_0(self.iter.next()); + ch = (init & 7) << 18 | utf8_acc_cont_byte!(y_z, w); } - Some(ch) - } else { - None + } + + // str invariant says `ch` is a valid Unicode Scalar Value + unsafe { + Some(mem::transmute(ch)) } } #[inline] fn size_hint(&self) -> (uint, Option) { - (self.string.len().saturating_add(3)/4, Some(self.string.len())) + let (len, _) = self.iter.size_hint(); + (len.saturating_add(3) / 4, Some(len)) } } impl<'a> DoubleEndedIterator for Chars<'a> { #[inline] fn next_back(&mut self) -> Option { - if self.string.len() != 0 { - let CharRange {ch, next} = self.string.char_range_at_reverse(self.string.len()); - unsafe { - self.string = raw::slice_unchecked(self.string, 0, next); + let w = match self.iter.next_back() { + None => return None, + Some(&back_byte) if back_byte < 128 => return Some(back_byte as char), + Some(&back_byte) => back_byte, + }; + + // Multibyte case follows + // Decode from a byte combination out of: [x [y [z w]]] + let mut ch; + let z = unwrap_or_0(self.iter.next_back()); + ch = utf8_first_byte!(z, 2); + if utf8_is_cont_byte!(z) { + let y = unwrap_or_0(self.iter.next_back()); + ch = utf8_first_byte!(y, 3); + if utf8_is_cont_byte!(y) { + let x = unwrap_or_0(self.iter.next_back()); + ch = utf8_first_byte!(x, 4); + ch = utf8_acc_cont_byte!(ch, y); } - Some(ch) - } else { - None + ch = utf8_acc_cont_byte!(ch, z); + } + ch = utf8_acc_cont_byte!(ch, w); + + // str invariant says `ch` is a valid Unicode Scalar Value + unsafe { + Some(mem::transmute(ch)) } } } @@ -146,18 +209,23 @@ impl<'a> DoubleEndedIterator for Chars<'a> { /// Use with the `std::iter` module. #[deriving(Clone)] pub struct CharOffsets<'a> { - /// The original string to be iterated - string: &'a str, + front_offset: uint, iter: Chars<'a>, } impl<'a> Iterator<(uint, char)> for CharOffsets<'a> { #[inline] fn next(&mut self) -> Option<(uint, char)> { - // Compute the byte offset by using the pointer offset between - // the original string slice and the iterator's remaining part - let offset = self.iter.string.as_ptr() as uint - self.string.as_ptr() as uint; - self.iter.next().map(|ch| (offset, ch)) + let (pre_len, _) = self.iter.iter.size_hint(); + match self.iter.next() { + None => None, + Some(ch) => { + let index = self.front_offset; + let (len, _) = self.iter.iter.size_hint(); + self.front_offset += pre_len - len; + Some((index, ch)) + } + } } #[inline] @@ -169,11 +237,14 @@ impl<'a> Iterator<(uint, char)> for CharOffsets<'a> { impl<'a> DoubleEndedIterator<(uint, char)> for CharOffsets<'a> { #[inline] fn next_back(&mut self) -> Option<(uint, char)> { - self.iter.next_back().map(|ch| { - let offset = self.iter.string.len() + - self.iter.string.as_ptr() as uint - self.string.as_ptr() as uint; - (offset, ch) - }) + match self.iter.next_back() { + None => None, + Some(ch) => { + let (len, _) = self.iter.iter.size_hint(); + let index = self.front_offset + len; + Some((index, ch)) + } + } } } @@ -672,9 +743,9 @@ fn run_utf8_validation_iterator(iter: &mut slice::Items) -> bool { // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / // %xF4 %x80-8F 2( UTF8-tail ) match w { - 2 => if second & 192 != TAG_CONT_U8 {err!()}, + 2 => if second & !CONT_MASK != TAG_CONT_U8 {err!()}, 3 => { - match (first, second, next!() & 192) { + match (first, second, next!() & !CONT_MASK) { (0xE0 , 0xA0 .. 0xBF, TAG_CONT_U8) | (0xE1 .. 0xEC, 0x80 .. 0xBF, TAG_CONT_U8) | (0xED , 0x80 .. 0x9F, TAG_CONT_U8) | @@ -683,7 +754,7 @@ fn run_utf8_validation_iterator(iter: &mut slice::Items) -> bool { } } 4 => { - match (first, second, next!() & 192, next!() & 192) { + match (first, second, next!() & !CONT_MASK, next!() & !CONT_MASK) { (0xF0 , 0x90 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) | (0xF1 .. 0xF3, 0x80 .. 0xBF, TAG_CONT_U8, TAG_CONT_U8) | (0xF4 , 0x80 .. 0x8F, TAG_CONT_U8, TAG_CONT_U8) => {} @@ -880,19 +951,10 @@ pub struct CharRange { pub next: uint, } -// Return the initial codepoint accumulator for the first byte. -// The first byte is special, only want bottom 5 bits for width 2, 4 bits -// for width 3, and 3 bits for width 4 -macro_rules! utf8_first_byte( - ($byte:expr, $width:expr) => (($byte & (0x7F >> $width)) as u32) -) - -// return the value of $ch updated with continuation byte $byte -macro_rules! utf8_acc_cont_byte( - ($ch:expr, $byte:expr) => (($ch << 6) | ($byte & 63u8) as u32) -) - -static TAG_CONT_U8: u8 = 128u8; +/// Mask of the value bits of a continuation byte +static CONT_MASK: u8 = 0b0011_1111u8; +/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte +static TAG_CONT_U8: u8 = 0b1000_0000u8; /// Unsafe operations pub mod raw { @@ -1608,7 +1670,7 @@ impl<'a> StrSlice<'a> for &'a str { #[inline] fn chars(&self) -> Chars<'a> { - Chars{string: *self} + Chars{iter: self.as_bytes().iter()} } #[inline] @@ -1618,7 +1680,7 @@ impl<'a> StrSlice<'a> for &'a str { #[inline] fn char_indices(&self) -> CharOffsets<'a> { - CharOffsets{string: *self, iter: self.chars()} + CharOffsets{front_offset: 0, iter: self.chars()} } #[inline] @@ -1828,7 +1890,7 @@ impl<'a> StrSlice<'a> for &'a str { // Multibyte case is a fn to allow char_range_at_reverse to inline cleanly fn multibyte_char_range_at_reverse(s: &str, mut i: uint) -> CharRange { // while there is a previous byte == 10...... - while i > 0 && s.as_bytes()[i] & 192u8 == TAG_CONT_U8 { + while i > 0 && s.as_bytes()[i] & !CONT_MASK == TAG_CONT_U8 { i -= 1u; } diff --git a/src/libdebug/repr.rs b/src/libdebug/repr.rs index 9755d54a13205..b72cc43b28c60 100644 --- a/src/libdebug/repr.rs +++ b/src/libdebug/repr.rs @@ -466,7 +466,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> { _offset: uint, inner: *const TyDesc) -> bool { - match *self.var_stk.get(self.var_stk.len() - 1) { + match self.var_stk[self.var_stk.len() - 1] { Matched => { if i != 0 { try!(self, self.writer.write(", ".as_bytes())); @@ -484,7 +484,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> { _disr_val: Disr, n_fields: uint, _name: &str) -> bool { - match *self.var_stk.get(self.var_stk.len() - 1) { + match self.var_stk[self.var_stk.len() - 1] { Matched => { if n_fields > 0 { try!(self, self.writer.write([')' as u8])); diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index eaec31a45f421..bf39fd566e52d 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -51,7 +51,7 @@ //! fn main() { //! let args: Vec = os::args(); //! -//! let program = args.get(0).clone(); +//! let program = args[0].clone(); //! //! let opts = [ //! optopt("o", "", "set output file name", "NAME"), @@ -67,7 +67,7 @@ //! } //! let output = matches.opt_str("o"); //! let input = if !matches.free.is_empty() { -//! (*matches.free.get(0)).clone() +//! matches.free[0].clone() //! } else { //! print_usage(program.as_slice(), opts); //! return; @@ -275,7 +275,7 @@ impl OptGroup { impl Matches { fn opt_vals(&self, nm: &str) -> Vec { match find_opt(self.opts.as_slice(), Name::from_str(nm)) { - Some(id) => (*self.vals.get(id)).clone(), + Some(id) => self.vals[id].clone(), None => fail!("No option '{}' defined", nm) } } @@ -285,7 +285,7 @@ impl Matches { if vals.is_empty() { None } else { - Some((*vals.get(0)).clone()) + Some(vals[0].clone()) } } @@ -304,7 +304,7 @@ impl Matches { for nm in names.iter() { match find_opt(self.opts.as_slice(), Name::from_str(nm.as_slice())) { - Some(id) if !self.vals.get(id).is_empty() => return true, + Some(id) if !self.vals[id].is_empty() => return true, _ => (), }; } @@ -344,8 +344,8 @@ impl Matches { if vals.is_empty() { return None::; } - match vals.get(0) { - &Val(ref s) => Some((*s).clone()), + match vals[0] { + Val(ref s) => Some((*s).clone()), _ => None } } @@ -361,8 +361,8 @@ impl Matches { if vals.is_empty() { return None; } - match vals.get(0) { - &Val(ref s) => Some((*s).clone()), + match vals[0] { + Val(ref s) => Some((*s).clone()), _ => Some(def.to_string()) } } @@ -560,8 +560,8 @@ pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result { names = vec!(Long(tail.to_string())); } else { names = - vec!(Long((*tail_eq.get(0)).to_string())); - i_arg = Some((*tail_eq.get(1)).to_string()); + vec!(Long(tail_eq[0].to_string())); + i_arg = Some(tail_eq[1].to_string()); } } else { let mut j = 1; @@ -583,7 +583,7 @@ pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result { None => { let arg_follows = last_valid_opt_id.is_some() && - match opts.get(last_valid_opt_id.unwrap()) + match opts[last_valid_opt_id.unwrap()] .hasarg { Yes | Maybe => true, @@ -609,7 +609,7 @@ pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result { Some(id) => id, None => return Err(UnrecognizedOption(nm.to_string())) }; - match opts.get(optid).hasarg { + match opts[optid].hasarg { No => { if !i_arg.is_none() { return Err(UnexpectedArgument(nm.to_string())); @@ -646,16 +646,16 @@ pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result { } i = 0u; while i < n_opts { - let n = vals.get(i).len(); - let occ = opts.get(i).occur; + let n = vals[i].len(); + let occ = opts[i].occur; if occ == Req { if n == 0 { - return Err(OptionMissing(opts.get(i).name.to_string())); + return Err(OptionMissing(opts[i].name.to_string())); } } if occ != Multi { if n > 1 { - return Err(OptionDuplicated(opts.get(i).name.to_string())); + return Err(OptionDuplicated(opts[i].name.to_string())); } } i += 1; diff --git a/src/libglob/lib.rs b/src/libglob/lib.rs index c28eb51d59d44..d539283f0a717 100644 --- a/src/libglob/lib.rs +++ b/src/libglob/lib.rs @@ -154,7 +154,7 @@ impl Iterator for Paths { if self.require_dir && !path.is_dir() { continue; } return Some(path); } - let ref pattern = *self.dir_patterns.get(idx); + let ref pattern = self.dir_patterns[idx]; if pattern.matches_with(match path.filename_str() { // this ugly match needs to go here to avoid a borrowck error @@ -250,21 +250,21 @@ impl Pattern { let mut i = 0; while i < chars.len() { - match *chars.get(i) { + match chars[i] { '?' => { tokens.push(AnyChar); i += 1; } '*' => { // *, **, ***, ****, ... are all equivalent - while i < chars.len() && *chars.get(i) == '*' { + while i < chars.len() && chars[i] == '*' { i += 1; } tokens.push(AnySequence); } '[' => { - if i <= chars.len() - 4 && *chars.get(i + 1) == '!' { + if i <= chars.len() - 4 && chars[i + 1] == '!' { match chars.slice_from(i + 3).position_elem(&']') { None => (), Some(j) => { @@ -276,7 +276,7 @@ impl Pattern { } } } - else if i <= chars.len() - 3 && *chars.get(i + 1) != '!' { + else if i <= chars.len() - 3 && chars[i + 1] != '!' { match chars.slice_from(i + 2).position_elem(&']') { None => (), Some(j) => { @@ -507,7 +507,7 @@ fn fill_todo(todo: &mut Vec<(Path, uint)>, patterns: &[Pattern], idx: uint, path // the current and parent directory respectively requires that // the pattern has a leading dot, even if the `MatchOptions` field // `require_literal_leading_dot` is not set. - if pattern.tokens.len() > 0 && pattern.tokens.get(0) == &Char('.') { + if pattern.tokens.len() > 0 && pattern.tokens[0] == Char('.') { for &special in [".", ".."].iter() { if pattern.matches_with(special, options) { add(todo, path.join(special)); diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index a3653fa973590..3c93a795071a6 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -168,7 +168,7 @@ impl<'a> dot::Labeller<'a, Nd, Ed<'a>> for Graph { dot::Id::new(format!("N{}", n)) } fn node_label<'a>(&'a self, n: &Nd) -> dot::LabelText<'a> { - dot::LabelStr(str::Slice(self.nodes.get(*n).as_slice())) + dot::LabelStr(str::Slice(self.nodes[*n].as_slice())) } fn edge_label<'a>(&'a self, _: &Ed) -> dot::LabelText<'a> { dot::LabelStr(str::Slice("⊆")) @@ -225,7 +225,7 @@ impl<'a> dot::Labeller<'a, Nd<'a>, Ed<'a>> for Graph { } fn node_label<'a>(&'a self, n: &Nd<'a>) -> dot::LabelText<'a> { let &(i, _) = n; - dot::LabelStr(str::Slice(self.nodes.get(i).as_slice())) + dot::LabelStr(str::Slice(self.nodes[i].as_slice())) } fn edge_label<'a>(&'a self, _: &Ed<'a>) -> dot::LabelText<'a> { dot::LabelStr(str::Slice("⊆")) @@ -238,8 +238,8 @@ impl<'a> dot::GraphWalk<'a, Nd<'a>, Ed<'a>> for Graph { } fn edges(&'a self) -> dot::Edges<'a,Ed<'a>> { self.edges.iter() - .map(|&(i,j)|((i, self.nodes.get(i).as_slice()), - (j, self.nodes.get(j).as_slice()))) + .map(|&(i,j)|((i, self.nodes[i].as_slice()), + (j, self.nodes[j].as_slice()))) .collect() } fn source(&self, e: &Ed<'a>) -> Nd<'a> { let &(s,_) = e; s } @@ -455,12 +455,12 @@ impl<'a> LabelText<'a> { } /// Puts `prefix` on a line above this label, with a blank line separator. - pub fn prefix_line(self, prefix: LabelText) -> LabelText { + pub fn prefix_line(self, prefix: LabelText) -> LabelText<'static> { prefix.suffix_line(self) } /// Puts `suffix` on a line below this label, with a blank line separator. - pub fn suffix_line(self, suffix: LabelText) -> LabelText { + pub fn suffix_line(self, suffix: LabelText) -> LabelText<'static> { let prefix = self.pre_escaped_content().into_string(); let suffix = suffix.pre_escaped_content(); EscStr(str::Owned(prefix.append(r"\n\n").append(suffix.as_slice()))) diff --git a/src/libgraphviz/maybe_owned_vec.rs b/src/libgraphviz/maybe_owned_vec.rs index bd19f19cec6b2..9e52af72138bb 100644 --- a/src/libgraphviz/maybe_owned_vec.rs +++ b/src/libgraphviz/maybe_owned_vec.rs @@ -109,7 +109,7 @@ impl<'b,T> slice::Vector for MaybeOwnedVector<'b,T> { } impl<'a,T> FromIterator for MaybeOwnedVector<'a,T> { - fn from_iter>(iterator: I) -> MaybeOwnedVector { + fn from_iter>(iterator: I) -> MaybeOwnedVector<'a,T> { // If we are building from scratch, might as well build the // most flexible variant. Growable(FromIterator::from_iter(iterator)) @@ -124,15 +124,15 @@ impl<'a,T:fmt::Show> fmt::Show for MaybeOwnedVector<'a,T> { impl<'a,T:Clone> CloneableVector for MaybeOwnedVector<'a,T> { /// Returns a copy of `self`. - fn to_owned(&self) -> Vec { - self.as_slice().to_owned() + fn to_vec(&self) -> Vec { + self.as_slice().to_vec() } /// Convert `self` into an owned slice, not making a copy if possible. - fn into_owned(self) -> Vec { + fn into_vec(self) -> Vec { match self { - Growable(v) => v.as_slice().to_owned(), - Borrowed(v) => v.to_owned(), + Growable(v) => v.as_slice().to_vec(), + Borrowed(v) => v.to_vec(), } } } @@ -140,7 +140,7 @@ impl<'a,T:Clone> CloneableVector for MaybeOwnedVector<'a,T> { impl<'a, T: Clone> Clone for MaybeOwnedVector<'a, T> { fn clone(&self) -> MaybeOwnedVector<'a, T> { match *self { - Growable(ref v) => Growable(v.to_owned()), + Growable(ref v) => Growable(v.to_vec()), Borrowed(v) => Borrowed(v) } } diff --git a/src/libgreen/sched.rs b/src/libgreen/sched.rs index 7603b0a8013c7..7151a78eacd43 100644 --- a/src/libgreen/sched.rs +++ b/src/libgreen/sched.rs @@ -959,13 +959,13 @@ impl CleanupJob { type UnsafeTaskReceiver = raw::Closure; trait ClosureConverter { fn from_fn(|&mut Scheduler, Box|) -> Self; - fn to_fn(self) -> |&mut Scheduler, Box|; + fn to_fn(self) -> |&mut Scheduler, Box|:'static ; } impl ClosureConverter for UnsafeTaskReceiver { fn from_fn(f: |&mut Scheduler, Box|) -> UnsafeTaskReceiver { unsafe { mem::transmute(f) } } - fn to_fn(self) -> |&mut Scheduler, Box| { + fn to_fn(self) -> |&mut Scheduler, Box|:'static { unsafe { mem::transmute(self) } } } diff --git a/src/libnum/bigint.rs b/src/libnum/bigint.rs index 046ba96f45a38..acba750aaf4ac 100644 --- a/src/libnum/bigint.rs +++ b/src/libnum/bigint.rs @@ -8,13 +8,53 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! - -A Big integer (signed version: `BigInt`, unsigned version: `BigUint`). - -A `BigUint` is represented as an array of `BigDigit`s. -A `BigInt` is a combination of `BigUint` and `Sign`. -*/ +//! A Big integer (signed version: `BigInt`, unsigned version: `BigUint`). +//! +//! A `BigUint` is represented as an array of `BigDigit`s. +//! A `BigInt` is a combination of `BigUint` and `Sign`. +//! +//! Common numerical operations are overloaded, so we can treat them +//! the same way we treat other numbers. +//! +//! ## Example +//! +//! ```rust +//! use num::bigint::BigUint; +//! use std::num::{Zero, One}; +//! use std::mem::replace; +//! +//! // Calculate large fibonacci numbers. +//! fn fib(n: uint) -> BigUint { +//! let mut f0: BigUint = Zero::zero(); +//! let mut f1: BigUint = One::one(); +//! for _ in range(0, n) { +//! let f2 = f0 + f1; +//! // This is a low cost way of swapping f0 with f1 and f1 with f2. +//! f0 = replace(&mut f1, f2); +//! } +//! f0 +//! } +//! +//! // This is a very large number. +//! println!("fib(1000) = {}", fib(1000)); +//! ``` +//! +//! It's easy to generate large random numbers: +//! +//! ```rust +//! use num::bigint::{ToBigInt, RandBigInt}; +//! use std::rand; +//! +//! let mut rng = rand::task_rng(); +//! let a = rng.gen_bigint(1000u); +//! +//! let low = -10000i.to_bigint().unwrap(); +//! let high = 10000i.to_bigint().unwrap(); +//! let b = rng.gen_bigint_range(&low, &high); +//! +//! // Probably an even larger number. +//! println!("{}", a * b); +//! ``` use Integer; use rand::Rng; @@ -28,15 +68,11 @@ use std::num::{Zero, One, ToStrRadix, FromStrRadix}; use std::string::String; use std::{uint, i64, u64}; -/** -A `BigDigit` is a `BigUint`'s composing element. -*/ +/// A `BigDigit` is a `BigUint`'s composing element. pub type BigDigit = u32; -/** -A `DoubleBigDigit` is the internal type used to do the computations. Its -size is the double of the size of `BigDigit`. -*/ +/// A `DoubleBigDigit` is the internal type used to do the computations. Its +/// size is the double of the size of `BigDigit`. pub type DoubleBigDigit = u64; pub static ZERO_BIG_DIGIT: BigDigit = 0; @@ -70,12 +106,10 @@ pub mod BigDigit { } } -/** -A big unsigned integer type. - -A `BigUint`-typed value `BigUint { data: vec!(a, b, c) }` represents a number -`(a + b * BigDigit::base + c * BigDigit::base^2)`. -*/ +/// A big unsigned integer type. +/// +/// A `BigUint`-typed value `BigUint { data: vec!(a, b, c) }` represents a number +/// `(a + b * BigDigit::base + c * BigDigit::base^2)`. #[deriving(Clone)] pub struct BigUint { data: Vec @@ -460,11 +494,9 @@ impl Integer for BigUint { } } - /** - * Calculates the Greatest Common Divisor (GCD) of the number and `other` - * - * The result is always positive - */ + /// Calculates the Greatest Common Divisor (GCD) of the number and `other`. + /// + /// The result is always positive. #[inline] fn gcd(&self, other: &BigUint) -> BigUint { // Use Euclid's algorithm @@ -478,17 +510,15 @@ impl Integer for BigUint { return n; } - /** - * Calculates the Lowest Common Multiple (LCM) of the number and `other` - */ + /// Calculates the Lowest Common Multiple (LCM) of the number and `other`. #[inline] fn lcm(&self, other: &BigUint) -> BigUint { ((*self * *other) / self.gcd(other)) } - /// Returns `true` if the number can be divided by `other` without leaving a remainder + /// Returns `true` if the number can be divided by `other` without leaving a remainder. #[inline] fn divides(&self, other: &BigUint) -> bool { (*self % *other).is_zero() } - /// Returns `true` if the number is divisible by `2` + /// Returns `true` if the number is divisible by `2`. #[inline] fn is_even(&self) -> bool { // Considering only the last digit. @@ -498,7 +528,7 @@ impl Integer for BigUint { } } - /// Returns `true` if the number is not divisible by `2` + /// Returns `true` if the number is not divisible by `2`. #[inline] fn is_odd(&self) -> bool { !self.is_even() } } @@ -1068,33 +1098,29 @@ impl Integer for BigInt { } } - /** - * Calculates the Greatest Common Divisor (GCD) of the number and `other` - * - * The result is always positive - */ + /// Calculates the Greatest Common Divisor (GCD) of the number and `other`. + /// + /// The result is always positive. #[inline] fn gcd(&self, other: &BigInt) -> BigInt { BigInt::from_biguint(Plus, self.data.gcd(&other.data)) } - /** - * Calculates the Lowest Common Multiple (LCM) of the number and `other` - */ + /// Calculates the Lowest Common Multiple (LCM) of the number and `other`. #[inline] fn lcm(&self, other: &BigInt) -> BigInt { BigInt::from_biguint(Plus, self.data.lcm(&other.data)) } - /// Returns `true` if the number can be divided by `other` without leaving a remainder + /// Returns `true` if the number can be divided by `other` without leaving a remainder. #[inline] fn divides(&self, other: &BigInt) -> bool { self.data.divides(&other.data) } - /// Returns `true` if the number is divisible by `2` + /// Returns `true` if the number is divisible by `2`. #[inline] fn is_even(&self) -> bool { self.data.is_even() } - /// Returns `true` if the number is not divisible by `2` + /// Returns `true` if the number is not divisible by `2`. #[inline] fn is_odd(&self) -> bool { self.data.is_odd() } } diff --git a/src/libnum/integer.rs b/src/libnum/integer.rs index d958d40d3d114..bcaebbd136809 100644 --- a/src/libnum/integer.rs +++ b/src/libnum/integer.rs @@ -8,18 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Integer trait and functions +//! Integer trait and functions. pub trait Integer: Num + PartialOrd + Div + Rem { - /// Simultaneous truncated integer division and modulus - #[inline] - fn div_rem(&self, other: &Self) -> (Self, Self) { - (*self / *other, *self % *other) - } - - /// Floored integer division + /// Floored integer division. /// /// # Examples /// @@ -61,25 +55,103 @@ pub trait Integer: Num + PartialOrd /// ~~~ fn mod_floor(&self, other: &Self) -> Self; - /// Simultaneous floored integer division and modulus - fn div_mod_floor(&self, other: &Self) -> (Self, Self) { - (self.div_floor(other), self.mod_floor(other)) - } - - /// Greatest Common Divisor (GCD) + /// Greatest Common Divisor (GCD). + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert_eq!(6i.gcd(&8), 2); + /// assert_eq!(7i.gcd(&3), 1); + /// ~~~ fn gcd(&self, other: &Self) -> Self; - /// Lowest Common Multiple (LCM) + /// Lowest Common Multiple (LCM). + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert_eq!(7i.lcm(&3), 21); + /// assert_eq!(2i.lcm(&4), 4); + /// ~~~ fn lcm(&self, other: &Self) -> Self; - /// Returns `true` if `other` divides evenly into `self` + /// Returns `true` if `other` divides evenly into `self`. + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert_eq!(9i.divides(&3), true); + /// assert_eq!(3i.divides(&9), false); + /// ~~~ fn divides(&self, other: &Self) -> bool; - /// Returns `true` if the number is even + /// Returns `true` if the number is even. + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert_eq!(3i.is_even(), false); + /// assert_eq!(4i.is_even(), true); + /// ~~~ fn is_even(&self) -> bool; - /// Returns `true` if the number is odd + /// Returns `true` if the number is odd. + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert_eq!(3i.is_odd(), true); + /// assert_eq!(4i.is_odd(), false); + /// ~~~ fn is_odd(&self) -> bool; + + /// Simultaneous truncated integer division and modulus. + /// Returns `(quotient, remainder)`. + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert_eq!(( 8i).div_rem( &3), ( 2, 2)); + /// assert_eq!(( 8i).div_rem(&-3), (-2, 2)); + /// assert_eq!((-8i).div_rem( &3), (-2, -2)); + /// assert_eq!((-8i).div_rem(&-3), ( 2, -2)); + /// + /// assert_eq!(( 1i).div_rem( &2), ( 0, 1)); + /// assert_eq!(( 1i).div_rem(&-2), ( 0, 1)); + /// assert_eq!((-1i).div_rem( &2), ( 0, -1)); + /// assert_eq!((-1i).div_rem(&-2), ( 0, -1)); + /// ~~~ + #[inline] + fn div_rem(&self, other: &Self) -> (Self, Self) { + (*self / *other, *self % *other) + } + + /// Simultaneous floored integer division and modulus. + /// Returns `(quotient, remainder)`. + /// + /// # Examples + /// + /// ~~~ + /// # use num::Integer; + /// assert_eq!(( 8i).div_mod_floor( &3), ( 2, 2)); + /// assert_eq!(( 8i).div_mod_floor(&-3), (-3, -1)); + /// assert_eq!((-8i).div_mod_floor( &3), (-3, 1)); + /// assert_eq!((-8i).div_mod_floor(&-3), ( 2, -2)); + /// + /// assert_eq!(( 1i).div_mod_floor( &2), ( 0, 1)); + /// assert_eq!(( 1i).div_mod_floor(&-2), (-1, -1)); + /// assert_eq!((-1i).div_mod_floor( &2), (-1, 1)); + /// assert_eq!((-1i).div_mod_floor(&-2), ( 0, -1)); + /// ~~~ + fn div_mod_floor(&self, other: &Self) -> (Self, Self) { + (self.div_floor(other), self.mod_floor(other)) + } } /// Simultaneous integer division and modulus diff --git a/src/libregex/parse.rs b/src/libregex/parse.rs index 109d32f69b967..d53fed7aa80fc 100644 --- a/src/libregex/parse.rs +++ b/src/libregex/parse.rs @@ -235,7 +235,7 @@ impl<'a> Parser<'a> { // left paren, let's grab the old flags and see if we // need a capture. let (cap, cap_name, oldflags) = { - let paren = self.stack.get(altfrom-1); + let paren = &self.stack[altfrom-1]; (paren.capture(), paren.capture_name(), paren.flags()) }; try!(self.alternate(altfrom)); @@ -464,7 +464,7 @@ impl<'a> Parser<'a> { Some(i) => i, None => return None, }; - if *self.chars.get(closer-1) != ':' { + if self.chars[closer-1] != ':' { return None } if closer - self.chari <= 3 { @@ -519,7 +519,7 @@ impl<'a> Parser<'a> { max = Some(min); } else { let pieces: Vec<&str> = inner.as_slice().splitn(',', 1).collect(); - let (smin, smax) = (*pieces.get(0), *pieces.get(1)); + let (smin, smax) = (pieces[0], pieces[1]); if smin.len() == 0 { return self.err("Max repetitions cannot be specified \ without min repetitions.") @@ -931,7 +931,7 @@ impl<'a> Parser<'a> { if self.chari + offset >= self.chars.len() { return None } - Some(*self.chars.get(self.chari + offset)) + Some(self.chars[self.chari + offset]) } fn peek_is(&self, offset: uint, is: char) -> bool { @@ -939,7 +939,7 @@ impl<'a> Parser<'a> { } fn cur(&self) -> char { - *self.chars.get(self.chari) + self.chars[self.chari] } fn slice(&self, start: uint, end: uint) -> String { diff --git a/src/libregex/re.rs b/src/libregex/re.rs index 054cbb0fcd63d..8e4145b2a3198 100644 --- a/src/libregex/re.rs +++ b/src/libregex/re.rs @@ -207,7 +207,7 @@ impl Regex { pub fn find(&self, text: &str) -> Option<(uint, uint)> { let caps = exec(self, Location, text); if has_match(&caps) { - Some((caps.get(0).unwrap(), caps.get(1).unwrap())) + Some((caps[0].unwrap(), caps[1].unwrap())) } else { None } @@ -699,11 +699,11 @@ impl<'t> Captures<'t> { /// original string matched. pub fn pos(&self, i: uint) -> Option<(uint, uint)> { let (s, e) = (i * 2, i * 2 + 1); - if e >= self.locs.len() || self.locs.get(s).is_none() { + if e >= self.locs.len() || self.locs[s].is_none() { // VM guarantees that each pair of locations are both Some or None. return None } - Some((self.locs.get(s).unwrap(), self.locs.get(e).unwrap())) + Some((self.locs[s].unwrap(), self.locs[e].unwrap())) } /// Returns the matched string for the capture group `i`. @@ -851,7 +851,7 @@ impl<'r, 't> Iterator> for FindCaptures<'r, 't> { if !has_match(&caps) { return None } else { - (caps.get(0).unwrap(), caps.get(1).unwrap()) + (caps[0].unwrap(), caps[1].unwrap()) }; // Don't accept empty matches immediately following a match. @@ -893,7 +893,7 @@ impl<'r, 't> Iterator<(uint, uint)> for FindMatches<'r, 't> { if !has_match(&caps) { return None } else { - (caps.get(0).unwrap(), caps.get(1).unwrap()) + (caps[0].unwrap(), caps[1].unwrap()) }; // Don't accept empty matches immediately following a match. @@ -922,5 +922,5 @@ fn exec_slice(re: &Regex, which: MatchKind, #[inline] fn has_match(caps: &CaptureLocs) -> bool { - caps.len() >= 2 && caps.get(0).is_some() && caps.get(1).is_some() + caps.len() >= 2 && caps[0].is_some() && caps[1].is_some() } diff --git a/src/libregex/vm.rs b/src/libregex/vm.rs index 782078ced497b..b37000df02dbe 100644 --- a/src/libregex/vm.rs +++ b/src/libregex/vm.rs @@ -123,7 +123,7 @@ impl<'r, 't> Nfa<'r, 't> { // Make sure multi-line mode isn't enabled for it, otherwise we can't // drop the initial .*? let prefix_anchor = - match *self.prog.insts.get(1) { + match self.prog.insts[1] { EmptyBegin(flags) if flags & FLAG_MULTI == 0 => true, _ => false, }; @@ -192,7 +192,7 @@ impl<'r, 't> Nfa<'r, 't> { fn step(&self, groups: &mut [Option], nlist: &mut Threads, caps: &mut [Option], pc: uint) -> StepState { - match *self.prog.insts.get(pc) { + match self.prog.insts[pc] { Match => { match self.which { Exists => { @@ -259,7 +259,7 @@ impl<'r, 't> Nfa<'r, 't> { // // We make a minor optimization by indicating that the state is "empty" // so that its capture groups are not filled in. - match *self.prog.insts.get(pc) { + match self.prog.insts[pc] { EmptyBegin(flags) => { let multi = flags & FLAG_MULTI > 0; nlist.add(pc, groups, true); @@ -481,8 +481,8 @@ impl Threads { #[inline] fn contains(&self, pc: uint) -> bool { - let s = *self.sparse.get(pc); - s < self.size && self.queue.get(s).pc == pc + let s = self.sparse[pc]; + s < self.size && self.queue[s].pc == pc } #[inline] @@ -492,7 +492,7 @@ impl Threads { #[inline] fn pc(&self, i: uint) -> uint { - self.queue.get(i).pc + self.queue[i].pc } #[inline] diff --git a/src/libregex_macros/lib.rs b/src/libregex_macros/lib.rs index 6545163fdbb68..7163dfa3b16ab 100644 --- a/src/libregex_macros/lib.rs +++ b/src/libregex_macros/lib.rs @@ -623,7 +623,7 @@ fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option { _ => { cx.span_err(entry.span, format!( "expected string literal but got `{}`", - pprust::lit_to_string(lit)).as_slice()); + pprust::lit_to_string(&*lit)).as_slice()); return None } } @@ -631,7 +631,7 @@ fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option { _ => { cx.span_err(entry.span, format!( "expected string literal but got `{}`", - pprust::expr_to_string(entry)).as_slice()); + pprust::expr_to_string(&*entry)).as_slice()); return None } }; diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 6fa8a1530234e..cc73cdce6a8c3 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -186,6 +186,22 @@ pub mod write { } }; + let code_model = match sess.opts.cg.code_model.as_slice() { + "default" => llvm::CodeModelDefault, + "small" => llvm::CodeModelSmall, + "kernel" => llvm::CodeModelKernel, + "medium" => llvm::CodeModelMedium, + "large" => llvm::CodeModelLarge, + _ => { + sess.err(format!("{} is not a valid code model", + sess.opts + .cg + .code_model).as_slice()); + sess.abort_if_errors(); + return; + } + }; + let tm = sess.targ_cfg .target_strs .target_triple @@ -195,7 +211,7 @@ pub mod write { target_feature(sess).with_c_str(|features| { llvm::LLVMRustCreateTargetMachine( t, cpu, features, - llvm::CodeModelDefault, + code_model, reloc_model, opt_level, true /* EnableSegstk */, @@ -555,15 +571,27 @@ pub fn find_crate_name(sess: Option<&Session>, }; // Look in attributes 100% of the time to make sure the attribute is marked - // as used. After doing this, however, favor crate names from the command - // line. + // as used. After doing this, however, we still prioritize a crate name from + // the command line over one found in the #[crate_name] attribute. If we + // find both we ensure that they're the same later on as well. let attr_crate_name = attrs.iter().find(|at| at.check_name("crate_name")) .and_then(|at| at.value_str().map(|s| (at, s))); match sess { Some(sess) => { match sess.opts.crate_name { - Some(ref s) => return validate(s.clone(), None), + Some(ref s) => { + match attr_crate_name { + Some((attr, ref name)) if s.as_slice() != name.get() => { + let msg = format!("--crate-name and #[crate_name] \ + are required to match, but `{}` \ + != `{}`", s, name); + sess.span_err(attr.span, msg.as_slice()); + } + _ => {}, + } + return validate(s.clone(), None); + } None => {} } } @@ -1238,7 +1266,7 @@ fn link_args(cmd: &mut Command, abi::OsMacos | abi::OsiOS => { let morestack = lib_path.join("libmorestack.a"); - let mut v = "-Wl,-force_load,".as_bytes().to_owned(); + let mut v = b"-Wl,-force_load,".to_vec(); v.push_all(morestack.as_vec()); cmd.arg(v.as_slice()); } @@ -1531,7 +1559,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session, add_dynamic_crate(cmd, sess, src.dylib.unwrap()) } cstore::RequireStatic => { - add_static_crate(cmd, sess, tmpdir, cnum, src.rlib.unwrap()) + add_static_crate(cmd, sess, tmpdir, src.rlib.unwrap()) } } @@ -1548,7 +1576,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session, // Adds the static "rlib" versions of all crates to the command line. fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path, - cnum: ast::CrateNum, cratepath: Path) { + cratepath: Path) { // When performing LTO on an executable output, all of the // bytecode from the upstream libraries has already been // included in our object file output. We need to modify all of @@ -1564,7 +1592,8 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session, // If we're not doing LTO, then our job is simply to just link // against the archive. if sess.lto() { - let name = sess.cstore.get_crate_data(cnum).name.clone(); + let name = cratepath.filename_str().unwrap(); + let name = name.slice(3, name.len() - 5); // chop off lib/.rlib time(sess.time_passes(), format!("altering {}.rlib", name).as_slice(), (), |()| { diff --git a/src/librustc/back/lto.rs b/src/librustc/back/lto.rs index 6184ea4591f08..c51f1615d5980 100644 --- a/src/librustc/back/lto.rs +++ b/src/librustc/back/lto.rs @@ -54,17 +54,19 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, }; let archive = ArchiveRO::open(&path).expect("wanted an rlib"); - debug!("reading {}", name); + let file = path.filename_str().unwrap(); + let file = file.slice(3, file.len() - 5); // chop off lib/.rlib + debug!("reading {}", file); let bc = time(sess.time_passes(), format!("read {}.bytecode.deflate", name).as_slice(), (), |_| { archive.read(format!("{}.bytecode.deflate", - name).as_slice()) + file).as_slice()) }); let bc = bc.expect("missing compressed bytecode in archive!"); let bc = time(sess.time_passes(), - format!("inflate {}.bc", name).as_slice(), + format!("inflate {}.bc", file).as_slice(), (), |_| { match flate::inflate_bytes(bc) { diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 5f3bbf481056a..1b806e1c257dc 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -110,5 +110,68 @@ register_diagnostics!( E0091, E0092, E0093, - E0094 + E0094, + E0095, + E0096, + E0097, + E0098, + E0099, + E0100, + E0101, + E0102, + E0103, + E0104, + E0105, + E0106, + E0107, + E0108, + E0109, + E0110, + E0111, + E0112, + E0113, + E0114, + E0115, + E0116, + E0117, + E0118, + E0119, + E0120, + E0121, + E0122, + E0123, + E0124, + E0125, + E0126, + E0127, + E0128, + E0129, + E0130, + E0131, + E0132, + E0133, + E0134, + E0135, + E0136, + E0137, + E0138, + E0139, + E0140, + E0141, + E0142, + E0143, + E0144, + E0145, + E0146, + E0147, + E0148, + E0149, + E0150, + E0151, + E0152, + E0153, + E0154, + E0155, + E0156, + E0157 ) diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs index 345877d9ab6c4..ee611293475f9 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -332,8 +332,12 @@ cgoptions!( "prefer dynamic linking to static linking"), no_integrated_as: bool = (false, parse_bool, "use an external assembler rather than LLVM's integrated one"), + no_redzone: bool = (false, parse_bool, + "disable the use of the redzone"), relocation_model: String = ("pic".to_string(), parse_string, "choose the relocation model to use (llc -relocation-model for details)"), + code_model: String = ("default".to_string(), parse_string, + "choose the code model to use (llc -code-model for details)"), metadata: Vec = (Vec::new(), parse_list, "metadata to mangle symbol names with"), extra_filename: String = ("".to_string(), parse_string, diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 87693658afd03..81ace4d015c85 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -799,7 +799,7 @@ fn print_flowgraph(variants: Vec, let ty_cx = &analysis.ty_cx; let cfg = match code { blocks::BlockCode(block) => cfg::CFG::new(ty_cx, &*block), - blocks::FnLikeCode(fn_like) => cfg::CFG::new(ty_cx, fn_like.body()), + blocks::FnLikeCode(fn_like) => cfg::CFG::new(ty_cx, &*fn_like.body()), }; debug!("cfg: {:?}", cfg); @@ -936,6 +936,7 @@ pub struct OutputFilenames { pub out_directory: Path, pub out_filestem: String, pub single_output_file: Option, + extra: String, } impl OutputFilenames { @@ -948,7 +949,7 @@ impl OutputFilenames { } pub fn temp_path(&self, flavor: link::OutputType) -> Path { - let base = self.out_directory.join(self.out_filestem.as_slice()); + let base = self.out_directory.join(self.filestem()); match flavor { link::OutputTypeBitcode => base.with_extension("bc"), link::OutputTypeAssembly => base.with_extension("s"), @@ -959,8 +960,11 @@ impl OutputFilenames { } pub fn with_extension(&self, extension: &str) -> Path { - let stem = self.out_filestem.as_slice(); - self.out_directory.join(stem).with_extension(extension) + self.out_directory.join(self.filestem()).with_extension(extension) + } + + fn filestem(&self) -> String { + format!("{}{}", self.out_filestem, self.extra) } } @@ -1000,6 +1004,7 @@ pub fn build_output_filenames(input: &Input, out_directory: dirpath, out_filestem: stem, single_output_file: None, + extra: sess.opts.cg.extra_filename.clone(), } } @@ -1018,6 +1023,7 @@ pub fn build_output_filenames(input: &Input, out_directory: out_file.dir_path(), out_filestem: out_file.filestem_str().unwrap().to_string(), single_output_file: ofile, + extra: sess.opts.cg.extra_filename.clone(), } } } diff --git a/src/librustc/driver/mod.rs b/src/librustc/driver/mod.rs index 3fd402c90fdd8..e433c3df8644c 100644 --- a/src/librustc/driver/mod.rs +++ b/src/librustc/driver/mod.rs @@ -36,7 +36,7 @@ pub mod config; pub fn main_args(args: &[String]) -> int { - let owned_args = args.to_owned(); + let owned_args = args.to_vec(); monitor(proc() run_compiler(owned_args.as_slice())); 0 } diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs index 8b92166388d86..9f15c9a9b3fa0 100644 --- a/src/librustc/front/feature_gate.rs +++ b/src/librustc/front/feature_gate.rs @@ -67,6 +67,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("quad_precision_float", Removed), ("rustc_diagnostic_macros", Active), + ("unboxed_closures", Active), // A temporary feature gate used to enable parser extensions needed // to bootstrap fix for #5723. @@ -327,6 +328,12 @@ impl<'a> Visitor<()> for Context<'a> { ast::ExprUnary(ast::UnBox, _) => { self.gate_box(e.span); } + ast::ExprUnboxedFn(..) => { + self.gate_feature("unboxed_closures", + e.span, + "unboxed closures are a work-in-progress \ + feature with known bugs"); + } _ => {} } visit::walk_expr(self, e, ()); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 92d1c176a1b92..2a7f7e8c54dd1 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -68,42 +68,42 @@ pub mod back { } pub mod middle { - pub mod def; - pub mod trans; - pub mod ty; - pub mod ty_fold; - pub mod subst; - pub mod resolve; - pub mod resolve_lifetime; - pub mod typeck; + pub mod astencode; + pub mod borrowck; + pub mod cfg; + pub mod check_const; pub mod check_loop; pub mod check_match; - pub mod check_const; pub mod check_static; - pub mod borrowck; + pub mod const_eval; pub mod dataflow; - pub mod mem_categorization; - pub mod liveness; - pub mod kind; + pub mod dead; + pub mod def; + pub mod dependency_format; + pub mod effect; + pub mod entry; + pub mod expr_use_visitor; pub mod freevars; - pub mod pat_util; - pub mod region; - pub mod const_eval; - pub mod astencode; + pub mod graph; + pub mod intrinsicck; + pub mod kind; pub mod lang_items; + pub mod liveness; + pub mod mem_categorization; + pub mod pat_util; pub mod privacy; - pub mod entry; - pub mod effect; pub mod reachable; - pub mod graph; - pub mod cfg; - pub mod dead; - pub mod expr_use_visitor; - pub mod dependency_format; - pub mod weak_lang_items; + pub mod region; + pub mod resolve; + pub mod resolve_lifetime; pub mod save; - pub mod intrinsicck; pub mod stability; + pub mod subst; + pub mod trans; + pub mod ty; + pub mod ty_fold; + pub mod typeck; + pub mod weak_lang_items; } pub mod front { diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 62236d753ad26..3f4f512369971 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1433,6 +1433,9 @@ impl LintPass for Stability { } fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { + // if the expression was produced by a macro expansion, + if e.span.expn_info.is_some() { return } + let id = match e.node { ast::ExprPath(..) | ast::ExprStruct(..) => { match cx.tcx.def_map.borrow().find(&e.id) { @@ -1448,6 +1451,9 @@ impl LintPass for Stability { typeck::MethodStatic(def_id) => { def_id } + typeck::MethodStaticUnboxedClosure(def_id) => { + def_id + } typeck::MethodParam(typeck::MethodParam { trait_id: trait_id, method_num: index, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 61aaf068c1098..7d9ec29d70144 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -317,6 +317,12 @@ impl<'a> Context<'a> { &self.tcx.sess } + /// Get the level of `lint` at the current position of the lint + /// traversal. + pub fn current_level(&self, lint: &'static Lint) -> Level { + self.lints.levels.find(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl) + } + fn lookup_and_emit(&self, lint: &'static Lint, span: Option, msg: &str) { let (level, src) = match self.lints.levels.find(&LintId::of(lint)) { None => return, diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index cdeecf3a080fe..216a575f2fb2b 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -138,10 +138,11 @@ pub enum astencode_tag { // Reserves 0x40 -- 0x5f tag_table_vtable_map = 0x50, tag_table_adjustments = 0x51, tag_table_moves_map = 0x52, - tag_table_capture_map = 0x53 + tag_table_capture_map = 0x53, + tag_table_unboxed_closure_type = 0x54, } static first_astencode_tag: uint = tag_ast as uint; -static last_astencode_tag: uint = tag_table_capture_map as uint; +static last_astencode_tag: uint = tag_table_unboxed_closure_type as uint; impl astencode_tag { pub fn from_uint(value : uint) -> Option { let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag; @@ -155,6 +156,10 @@ pub static tag_item_trait_method_sort: uint = 0x60; pub static tag_item_impl_type_basename: uint = 0x61; +pub static tag_crate_triple: uint = 0x66; + +pub static tag_dylib_dependency_formats: uint = 0x67; + // Language items are a top-level directory (for speed). Hierarchy: // // tag_lang_items @@ -199,10 +204,6 @@ pub static tag_plugin_registrar_fn: uint = 0x8b; pub static tag_exported_macros: uint = 0x8c; pub static tag_macro_def: uint = 0x8d; -pub static tag_crate_triple: uint = 0x66; - -pub static tag_dylib_dependency_formats: uint = 0x67; - pub static tag_method_argument_names: uint = 0x8e; pub static tag_method_argument_name: uint = 0x8f; @@ -211,7 +212,6 @@ pub static tag_reachable_extern_fn_id: uint = 0x91; pub static tag_items_data_item_stability: uint = 0x92; - #[deriving(Clone, Show)] pub struct LinkMeta { pub crate_name: String, @@ -223,3 +223,7 @@ pub static tag_region_param_def_ident: uint = 0x91; pub static tag_region_param_def_def_id: uint = 0x92; pub static tag_region_param_def_space: uint = 0x93; pub static tag_region_param_def_index: uint = 0x94; + +pub static tag_unboxed_closures: uint = 0x95; +pub static tag_unboxed_closure: uint = 0x96; +pub static tag_unboxed_closure_type: uint = 0x97; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 5ab8eeeb36055..0adc8e915c679 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -132,7 +132,8 @@ pub fn get_method(tcx: &ty::ctxt, def: ast::DefId) -> ty::Method { pub fn get_method_name_and_explicit_self(cstore: &cstore::CStore, def: ast::DefId) - -> (ast::Ident, ast::ExplicitSelf_) + -> (ast::Ident, + ty::ExplicitSelfCategory) { let cdata = cstore.get_crate_data(def.krate); decoder::get_method_name_and_explicit_self(cstore.intr.clone(), &*cdata, def.node) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index cc41223688ee0..094e83d2a4770 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -724,7 +724,7 @@ pub fn get_enum_variants(intr: Rc, cdata: Cmd, id: ast::NodeId, }).collect() } -fn get_explicit_self(item: ebml::Doc) -> ast::ExplicitSelf_ { +fn get_explicit_self(item: ebml::Doc) -> ty::ExplicitSelfCategory { fn get_mutability(ch: u8) -> ast::Mutability { match ch as char { 'i' => ast::MutImmutable, @@ -738,12 +738,15 @@ fn get_explicit_self(item: ebml::Doc) -> ast::ExplicitSelf_ { let explicit_self_kind = string.as_bytes()[0]; match explicit_self_kind as char { - 's' => ast::SelfStatic, - 'v' => ast::SelfValue(special_idents::self_), - '~' => ast::SelfUniq(special_idents::self_), + 's' => ty::StaticExplicitSelfCategory, + 'v' => ty::ByValueExplicitSelfCategory, + '~' => ty::ByBoxExplicitSelfCategory, // FIXME(#4846) expl. region - '&' => ast::SelfRegion(None, get_mutability(string.as_bytes()[1]), - special_idents::self_), + '&' => { + ty::ByReferenceExplicitSelfCategory( + ty::ReEmpty, + get_mutability(string.as_bytes()[1])) + } _ => fail!("unknown self type code: `{}`", explicit_self_kind as char) } } @@ -761,11 +764,11 @@ pub fn get_impl_methods(cdata: Cmd, impl_id: ast::NodeId) -> Vec { methods } -pub fn get_method_name_and_explicit_self( - intr: Rc, - cdata: Cmd, - id: ast::NodeId) -> (ast::Ident, ast::ExplicitSelf_) -{ +pub fn get_method_name_and_explicit_self(intr: Rc, + cdata: Cmd, + id: ast::NodeId) + -> (ast::Ident, + ty::ExplicitSelfCategory) { let method_doc = lookup_item(id, cdata.data()); let name = item_name(&*intr, method_doc); let explicit_self = get_explicit_self(method_doc); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 87333499ec3a2..439455ff3d15c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -43,6 +43,7 @@ use syntax::ast_map::{PathElem, PathElems}; use syntax::ast_map; use syntax::ast_util::*; use syntax::ast_util; +use syntax::ast_util::PostExpansionMethod; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::diagnostic::SpanHandler; @@ -208,6 +209,18 @@ fn encode_variant_id(ebml_w: &mut Encoder, vid: DefId) { ebml_w.end_tag(); } +pub fn write_closure_type(ecx: &EncodeContext, + ebml_w: &mut Encoder, + closure_type: &ty::ClosureTy) { + let ty_str_ctxt = &tyencode::ctxt { + diag: ecx.diag, + ds: def_to_string, + tcx: ecx.tcx, + abbrevs: &ecx.type_abbrevs + }; + tyencode::enc_closure_ty(ebml_w.writer, ty_str_ctxt, closure_type); +} + pub fn write_type(ecx: &EncodeContext, ebml_w: &mut Encoder, typ: ty::t) { @@ -301,8 +314,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext, ebml_w: &mut Encoder, id: NodeId, variants: &[P], - index: &mut Vec>, - generics: &ast::Generics) { + index: &mut Vec>) { debug!("encode_enum_variant_info(id={:?})", id); let mut disr_val = 0; @@ -330,10 +342,6 @@ fn encode_enum_variant_info(ecx: &EncodeContext, encode_stability(ebml_w, stab); match variant.node.kind { - ast::TupleVariantKind(ref args) - if args.len() > 0 && generics.ty_params.len() == 0 => { - encode_symbol(ecx, ebml_w, variant.node.id); - } ast::TupleVariantKind(_) => {}, ast::StructVariantKind(_) => { let fields = ty::lookup_struct_fields(ecx.tcx, def_id); @@ -401,7 +409,7 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext, for base_impl_did in implementations.borrow().iter() { for &method_did in impl_methods.get(base_impl_did).iter() { let m = ty::method(ecx.tcx, method_did); - if m.explicit_self == ast::SelfStatic { + if m.explicit_self == ty::StaticExplicitSelfCategory { encode_reexported_static_method(ebml_w, exp, m.def_id, m.ident); } } @@ -420,7 +428,7 @@ fn encode_reexported_static_trait_methods(ecx: &EncodeContext, match ecx.tcx.trait_methods_cache.borrow().find(&exp.def_id) { Some(methods) => { for m in methods.iter() { - if m.explicit_self == ast::SelfStatic { + if m.explicit_self == ty::StaticExplicitSelfCategory { encode_reexported_static_method(ebml_w, exp, m.def_id, m.ident); } } @@ -622,15 +630,22 @@ fn encode_visibility(ebml_w: &mut Encoder, visibility: Visibility) { ebml_w.end_tag(); } -fn encode_explicit_self(ebml_w: &mut Encoder, explicit_self: ast::ExplicitSelf_) { +fn encode_explicit_self(ebml_w: &mut Encoder, + explicit_self: &ty::ExplicitSelfCategory) { ebml_w.start_tag(tag_item_trait_method_explicit_self); // Encode the base self type. - match explicit_self { - SelfStatic => { ebml_w.writer.write(&[ 's' as u8 ]); } - SelfValue(_) => { ebml_w.writer.write(&[ 'v' as u8 ]); } - SelfUniq(_) => { ebml_w.writer.write(&[ '~' as u8 ]); } - SelfRegion(_, m, _) => { + match *explicit_self { + ty::StaticExplicitSelfCategory => { + ebml_w.writer.write(&[ 's' as u8 ]); + } + ty::ByValueExplicitSelfCategory => { + ebml_w.writer.write(&[ 'v' as u8 ]); + } + ty::ByBoxExplicitSelfCategory => { + ebml_w.writer.write(&[ '~' as u8 ]); + } + ty::ByReferenceExplicitSelfCategory(_, m) => { // FIXME(#4846) encode custom lifetime ebml_w.writer.write(&['&' as u8]); encode_mutability(ebml_w, m); @@ -747,10 +762,10 @@ fn encode_method_ty_fields(ecx: &EncodeContext, tag_item_method_tps); encode_method_fty(ecx, ebml_w, &method_ty.fty); encode_visibility(ebml_w, method_ty.vis); - encode_explicit_self(ebml_w, method_ty.explicit_self); + encode_explicit_self(ebml_w, &method_ty.explicit_self); let fn_style = method_ty.fty.fn_style; match method_ty.explicit_self { - ast::SelfStatic => { + ty::StaticExplicitSelfCategory => { encode_family(ebml_w, fn_style_static_method_family(fn_style)); } _ => encode_family(ebml_w, style_fn_family(fn_style)) @@ -798,7 +813,7 @@ fn encode_info_for_method(ecx: &EncodeContext, } else { encode_symbol(ecx, ebml_w, m.def_id.node); } - encode_method_argument_names(ebml_w, method_fn_decl(&*ast_method)); + encode_method_argument_names(ebml_w, &*ast_method.pe_fn_decl()); } ebml_w.end_tag(); @@ -999,7 +1014,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_stability(ebml_w, stab); ebml_w.end_tag(); } - ItemEnum(ref enum_definition, ref generics) => { + ItemEnum(ref enum_definition, _) => { add_to_index(item, ebml_w, index); ebml_w.start_tag(tag_items_data_item); @@ -1026,8 +1041,7 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w, item.id, (*enum_definition).variants.as_slice(), - index, - generics); + index); } ItemStruct(struct_def, _) => { let fields = ty::lookup_struct_fields(tcx, def_id); @@ -1205,7 +1219,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_path(ebml_w, path.clone().chain(Some(elem).move_iter())); match method_ty.explicit_self { - SelfStatic => { + ty::StaticExplicitSelfCategory => { encode_family(ebml_w, fn_style_static_method_family( method_ty.fty.fn_style)); @@ -1232,7 +1246,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_attributes(ebml_w, m.attrs.as_slice()); // If this is a static method, we've already encoded // this. - if method_ty.explicit_self != SelfStatic { + if method_ty.explicit_self != ty::StaticExplicitSelfCategory { // FIXME: I feel like there is something funny going on. let pty = ty::lookup_item_type(tcx, method_def_id); encode_bounds_and_type(ebml_w, ecx, &pty); @@ -1240,7 +1254,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_method_sort(ebml_w, 'p'); encode_inlined_item(ecx, ebml_w, IIMethodRef(def_id, true, &*m)); - encode_method_argument_names(ebml_w, method_fn_decl(m)); + encode_method_argument_names(ebml_w, &*m.pe_fn_decl()); } } @@ -1610,6 +1624,26 @@ fn encode_macro_defs(ecx: &EncodeContext, ebml_w.end_tag(); } +fn encode_unboxed_closures<'a>( + ecx: &'a EncodeContext, + ebml_w: &'a mut Encoder) { + ebml_w.start_tag(tag_unboxed_closures); + for (unboxed_closure_id, unboxed_closure_type) in + ecx.tcx.unboxed_closure_types.borrow().iter() { + if unboxed_closure_id.krate != LOCAL_CRATE { + continue + } + + ebml_w.start_tag(tag_unboxed_closure); + encode_def_id(ebml_w, *unboxed_closure_id); + ebml_w.start_tag(tag_unboxed_closure_type); + write_closure_type(ecx, ebml_w, unboxed_closure_type); + ebml_w.end_tag(); + ebml_w.end_tag(); + } + ebml_w.end_tag(); +} + struct ImplVisitor<'a,'b,'c> { ecx: &'a EncodeContext<'b>, ebml_w: &'a mut Encoder<'c>, @@ -1779,6 +1813,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate) native_lib_bytes: u64, plugin_registrar_fn_bytes: u64, macro_defs_bytes: u64, + unboxed_closure_bytes: u64, impl_bytes: u64, misc_bytes: u64, item_bytes: u64, @@ -1793,6 +1828,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate) native_lib_bytes: 0, plugin_registrar_fn_bytes: 0, macro_defs_bytes: 0, + unboxed_closure_bytes: 0, impl_bytes: 0, misc_bytes: 0, item_bytes: 0, @@ -1865,6 +1901,11 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate) encode_macro_defs(&ecx, krate, &mut ebml_w); stats.macro_defs_bytes = ebml_w.writer.tell().unwrap() - i; + // Encode the types of all unboxed closures in this crate. + i = ebml_w.writer.tell().unwrap(); + encode_unboxed_closures(&ecx, &mut ebml_w); + stats.unboxed_closure_bytes = ebml_w.writer.tell().unwrap() - i; + // Encode the def IDs of impls, for coherence checking. i = ebml_w.writer.tell().unwrap(); encode_impls(&ecx, krate, &mut ebml_w); @@ -1903,6 +1944,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate) println!(" native bytes: {}", stats.native_lib_bytes); println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes); println!(" macro def bytes: {}", stats.macro_defs_bytes); + println!(" unboxed closure bytes: {}", stats.unboxed_closure_bytes); println!(" impl bytes: {}", stats.impl_bytes); println!(" misc bytes: {}", stats.misc_bytes); println!(" item bytes: {}", stats.item_bytes); diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index c15148f75df22..99b98b690fa66 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -46,7 +46,7 @@ impl<'a> FileSearch<'a> { FileMatches => found = true, FileDoesntMatch => () } - visited_dirs.insert(path.as_vec().to_owned()); + visited_dirs.insert(path.as_vec().to_vec()); } debug!("filesearch: searching lib path"); @@ -59,7 +59,7 @@ impl<'a> FileSearch<'a> { } } - visited_dirs.insert(tlib_path.as_vec().to_owned()); + visited_dirs.insert(tlib_path.as_vec().to_vec()); // Try RUST_PATH if !found { let rustpath = rust_path(); @@ -67,10 +67,10 @@ impl<'a> FileSearch<'a> { let tlib_path = make_rustpkg_lib_path( self.sysroot, path, self.triple); debug!("is {} in visited_dirs? {:?}", tlib_path.display(), - visited_dirs.contains_equiv(&tlib_path.as_vec().to_owned())); + visited_dirs.contains_equiv(&tlib_path.as_vec().to_vec())); if !visited_dirs.contains_equiv(&tlib_path.as_vec()) { - visited_dirs.insert(tlib_path.as_vec().to_owned()); + visited_dirs.insert(tlib_path.as_vec().to_vec()); // Don't keep searching the RUST_PATH if one match turns up -- // if we did, we'd get a "multiple matching crates" error match f(&tlib_path) { diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 4156329331471..ffa0cca753904 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -130,6 +130,16 @@ fn data_log_string(data: &[u8], pos: uint) -> String { buf } +pub fn parse_ty_closure_data(data: &[u8], + crate_num: ast::CrateNum, + pos: uint, + tcx: &ty::ctxt, + conv: conv_did) + -> ty::ClosureTy { + let mut st = parse_state_from_data(data, crate_num, pos, tcx); + parse_closure_ty(&mut st, conv) +} + pub fn parse_ty_data(data: &[u8], crate_num: ast::CrateNum, pos: uint, tcx: &ty::ctxt, conv: conv_did) -> ty::t { debug!("parse_ty_data {}", data_log_string(data, pos)); @@ -420,6 +430,10 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { assert_eq!(next(st), ']'); return ty::mk_struct(st.tcx, did, substs); } + 'k' => { + let did = parse_def(st, NominalType, |x,y| conv(x,y)); + return ty::mk_unboxed_closure(st.tcx, did); + } 'e' => { return ty::mk_err(); } @@ -502,12 +516,14 @@ fn parse_closure_ty(st: &mut PState, conv: conv_did) -> ty::ClosureTy { let store = parse_trait_store(st, |x,y| conv(x,y)); let bounds = parse_bounds(st, |x,y| conv(x,y)); let sig = parse_sig(st, |x,y| conv(x,y)); + let abi = parse_abi_set(st); ty::ClosureTy { fn_style: fn_style, onceness: onceness, store: store, bounds: bounds.builtin_bounds, - sig: sig + sig: sig, + abi: abi, } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index b207543398aaa..15e4e85ddb711 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -267,7 +267,7 @@ fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) { } ty::ty_closure(ref f) => { mywrite!(w, "f"); - enc_closure_ty(w, cx, *f); + enc_closure_ty(w, cx, &**f); } ty::ty_bare_fn(ref f) => { mywrite!(w, "F"); @@ -284,6 +284,9 @@ fn enc_sty(w: &mut MemWriter, cx: &ctxt, st: &ty::sty) { enc_substs(w, cx, substs); mywrite!(w, "]"); } + ty::ty_unboxed_closure(def) => { + mywrite!(w, "k{}", (cx.ds)(def)); + } ty::ty_err => { mywrite!(w, "e"); } @@ -316,7 +319,7 @@ pub fn enc_bare_fn_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::BareFnTy) { enc_fn_sig(w, cx, &ft.sig); } -fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) { +pub fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) { enc_fn_style(w, ft.fn_style); enc_onceness(w, ft.onceness); enc_trait_store(w, cx, ft.store); @@ -324,6 +327,7 @@ fn enc_closure_ty(w: &mut MemWriter, cx: &ctxt, ft: &ty::ClosureTy) { trait_bounds: Vec::new()}; enc_bounds(w, cx, &bounds); enc_fn_sig(w, cx, &ft.sig); + enc_abi(w, ft.abi); } fn enc_fn_sig(w: &mut MemWriter, cx: &ctxt, fsig: &ty::FnSig) { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index d58023a48756f..722715405bce4 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -31,6 +31,7 @@ use middle::{ty, typeck}; use util::ppaux::ty_to_string; use syntax::{ast, ast_map, ast_util, codemap, fold}; +use syntax::ast_util::PostExpansionMethod; use syntax::codemap::Span; use syntax::fold::Folder; use syntax::parse::token; @@ -136,7 +137,7 @@ pub fn decode_inlined_item(cdata: &cstore::crate_metadata, let ident = match ii { ast::IIItem(i) => i.ident, ast::IIForeign(i) => i.ident, - ast::IIMethod(_, _, m) => ast_util::method_ident(&*m), + ast::IIMethod(_, _, m) => m.pe_ident(), }; debug!("Fn named: {}", token::get_ident(ident)); debug!("< Decoded inlined fn: {}::{}", @@ -608,6 +609,9 @@ impl tr for MethodOrigin { fn tr(&self, xcx: &ExtendedDecodeContext) -> MethodOrigin { match *self { typeck::MethodStatic(did) => typeck::MethodStatic(did.tr(xcx)), + typeck::MethodStaticUnboxedClosure(did) => { + typeck::MethodStaticUnboxedClosure(did.tr(xcx)) + } typeck::MethodParam(ref mp) => { typeck::MethodParam( typeck::MethodParam { @@ -695,8 +699,18 @@ pub fn encode_vtable_origin(ecx: &e::EncodeContext, }) }) } + typeck::vtable_unboxed_closure(def_id) => { + ebml_w.emit_enum_variant("vtable_unboxed_closure", + 2u, + 1u, + |ebml_w| { + ebml_w.emit_enum_variant_arg(0u, |ebml_w| { + Ok(ebml_w.emit_def_id(def_id)) + }) + }) + } typeck::vtable_error => { - ebml_w.emit_enum_variant("vtable_error", 2u, 3u, |_ebml_w| { + ebml_w.emit_enum_variant("vtable_error", 3u, 3u, |_ebml_w| { Ok(()) }) } @@ -770,7 +784,8 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> { self.read_enum("vtable_origin", |this| { this.read_enum_variant(["vtable_static", "vtable_param", - "vtable_error"], + "vtable_error", + "vtable_unboxed_closure"], |this, i| { Ok(match i { 0 => { @@ -797,6 +812,13 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> { ) } 2 => { + typeck::vtable_unboxed_closure( + this.read_enum_variant_arg(0u, |this| { + Ok(this.read_def_id_noxcx(cdata)) + }).unwrap() + ) + } + 3 => { typeck::vtable_error } _ => fail!("bad enum variant") @@ -837,6 +859,9 @@ impl<'a> get_ty_str_ctxt for e::EncodeContext<'a> { } trait ebml_writer_helpers { + fn emit_closure_type(&mut self, + ecx: &e::EncodeContext, + closure_type: &ty::ClosureTy); fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t); fn emit_tys(&mut self, ecx: &e::EncodeContext, tys: &[ty::t]); fn emit_type_param_def(&mut self, @@ -850,6 +875,14 @@ trait ebml_writer_helpers { } impl<'a> ebml_writer_helpers for Encoder<'a> { + fn emit_closure_type(&mut self, + ecx: &e::EncodeContext, + closure_type: &ty::ClosureTy) { + self.emit_opaque(|this| { + Ok(e::write_closure_type(ecx, this, closure_type)) + }); + } + fn emit_ty(&mut self, ecx: &e::EncodeContext, ty: ty::t) { self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty))); } @@ -1126,6 +1159,18 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) }) } + + for unboxed_closure_type in tcx.unboxed_closure_types + .borrow() + .find(&ast_util::local_def(id)) + .iter() { + ebml_w.tag(c::tag_table_unboxed_closure_type, |ebml_w| { + ebml_w.id(id); + ebml_w.tag(c::tag_table_val, |ebml_w| { + ebml_w.emit_closure_type(ecx, *unboxed_closure_type) + }) + }) + } } trait doc_decoder_helpers { @@ -1149,6 +1194,8 @@ trait ebml_decoder_decoder_helpers { -> ty::Polytype; fn read_substs(&mut self, xcx: &ExtendedDecodeContext) -> subst::Substs; fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment; + fn read_unboxed_closure_type(&mut self, xcx: &ExtendedDecodeContext) + -> ty::ClosureTy; fn convert_def_id(&mut self, xcx: &ExtendedDecodeContext, source: DefIdSource, @@ -1321,6 +1368,18 @@ impl<'a> ebml_decoder_decoder_helpers for reader::Decoder<'a> { }).unwrap() } + fn read_unboxed_closure_type(&mut self, xcx: &ExtendedDecodeContext) + -> ty::ClosureTy { + self.read_opaque(|this, doc| { + Ok(tydecode::parse_ty_closure_data( + doc.data, + xcx.dcx.cdata.cnum, + doc.start, + xcx.dcx.tcx, + |s, a| this.convert_def_id(xcx, s, a))) + }).unwrap() + } + fn convert_def_id(&mut self, xcx: &ExtendedDecodeContext, source: tydecode::DefIdSource, @@ -1441,6 +1500,15 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext, let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(xcx); dcx.tcx.adjustments.borrow_mut().insert(id, adj); } + c::tag_table_unboxed_closure_type => { + let unboxed_closure_type = + val_dsr.read_unboxed_closure_type(xcx); + dcx.tcx + .unboxed_closure_types + .borrow_mut() + .insert(ast_util::local_def(id), + unboxed_closure_type); + } _ => { xcx.dcx.tcx.sess.bug( format!("unknown tag found in side tables: {:x}", @@ -1556,7 +1624,7 @@ fn test_simplification() { return alist {eq_fn: eq_int, data: Vec::new()}; } ).unwrap(); - let item_in = e::IIItemRef(item); + let item_in = e::IIItemRef(&*item); let item_out = simplify_ast(item_in); let item_exp = ast::IIItem(quote_item!(cx, fn new_int_alist() -> alist { @@ -1565,7 +1633,8 @@ fn test_simplification() { ).unwrap()); match (item_out, item_exp) { (ast::IIItem(item_out), ast::IIItem(item_exp)) => { - assert!(pprust::item_to_string(item_out) == pprust::item_to_string(item_exp)); + assert!(pprust::item_to_string(&*item_out) == + pprust::item_to_string(&*item_exp)); } _ => fail!() } diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index cfec67bf3a395..2aa0818b177cf 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -172,7 +172,7 @@ impl<'a> CheckLoanCtxt<'a> { //! are issued for future scopes and thus they may have been //! *issued* but not yet be in effect. - self.dfcx_loans.each_bit_on_entry_frozen(scope_id, |loan_index| { + self.dfcx_loans.each_bit_on_entry(scope_id, |loan_index| { let loan = &self.all_loans[loan_index]; op(loan) }) @@ -271,7 +271,7 @@ impl<'a> CheckLoanCtxt<'a> { //! we encounter `scope_id`. let mut result = Vec::new(); - self.dfcx_loans.each_gen_bit_frozen(scope_id, |loan_index| { + self.dfcx_loans.each_gen_bit(scope_id, |loan_index| { result.push(loan_index); true }); @@ -832,3 +832,4 @@ impl<'a> CheckLoanCtxt<'a> { self.bccx.loan_path_to_string(loan_path)).as_slice()); } } + diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 77b3cfafa63af..5604d33496d9d 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -216,8 +216,13 @@ pub fn build_borrowck_dataflow_data_for_fn<'a>( let p = input.fn_parts; - let dataflow_data = build_borrowck_dataflow_data( - &mut bccx, &p.kind, p.decl, input.cfg, p.body, p.span, p.id); + let dataflow_data = build_borrowck_dataflow_data(&mut bccx, + &p.kind, + &*p.decl, + input.cfg, + &*p.body, + p.span, + p.id); (bccx, dataflow_data) } diff --git a/src/librustc/middle/borrowck/move_data.rs b/src/librustc/middle/borrowck/move_data.rs index a9c312fc0a455..6ec3f82ad68e7 100644 --- a/src/librustc/middle/borrowck/move_data.rs +++ b/src/librustc/middle/borrowck/move_data.rs @@ -576,7 +576,7 @@ impl<'a> FlowedMoveData<'a> { * Iterates through each path moved by `id` */ - self.dfcx_moves.each_gen_bit_frozen(id, |index| { + self.dfcx_moves.each_gen_bit(id, |index| { let move = self.move_data.moves.borrow(); let move = move.get(index); let moved_path = move.path; @@ -592,7 +592,7 @@ impl<'a> FlowedMoveData<'a> { let mut ret = None; for loan_path_index in self.move_data.path_map.borrow().find(&*loan_path).iter() { - self.dfcx_moves.each_gen_bit_frozen(id, |move_index| { + self.dfcx_moves.each_gen_bit(id, |move_index| { let move = self.move_data.moves.borrow(); let move = move.get(move_index); if move.path == **loan_path_index { @@ -637,7 +637,7 @@ impl<'a> FlowedMoveData<'a> { let mut ret = true; - self.dfcx_moves.each_bit_on_entry_frozen(id, |index| { + self.dfcx_moves.each_bit_on_entry(id, |index| { let move = self.move_data.moves.borrow(); let move = move.get(index); let moved_path = move.path; @@ -693,7 +693,7 @@ impl<'a> FlowedMoveData<'a> { } }; - self.dfcx_assign.each_bit_on_entry_frozen(id, |index| { + self.dfcx_assign.each_bit_on_entry(id, |index| { let assignment = self.move_data.var_assignments.borrow(); let assignment = assignment.get(index); if assignment.path == loan_path_index && !f(assignment) { diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 0d8729071ef6b..208a9d057166e 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -446,6 +446,7 @@ impl<'a> CFGBuilder<'a> { ast::ExprMac(..) | ast::ExprFnBlock(..) | ast::ExprProc(..) | + ast::ExprUnboxedFn(..) | ast::ExprLit(..) | ast::ExprPath(..) => { self.straightline(expr, pred, []) diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index c855d59d50851..ac8faaa6c6db5 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -42,7 +42,9 @@ impl<'a> Visitor for CheckLoopVisitor<'a> { ast::ExprLoop(ref b, _) => { self.visit_block(&**b, Loop); } - ast::ExprFnBlock(_, ref b) | ast::ExprProc(_, ref b) => { + ast::ExprFnBlock(_, ref b) | + ast::ExprProc(_, ref b) | + ast::ExprUnboxedFn(_, ref b) => { self.visit_block(&**b, Closure); } ast::ExprBreak(_) => self.require_loop("break", cx, e.span), diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 832b222ef1641..67208e3337286 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -9,7 +9,7 @@ // except according to those terms. use middle::const_eval::{compare_const_vals, const_bool, const_float, const_nil, const_val}; -use middle::const_eval::{eval_const_expr, lookup_const_by_id}; +use middle::const_eval::{const_expr_to_pat, eval_const_expr, lookup_const_by_id}; use middle::def::*; use middle::pat_util::*; use middle::ty::*; @@ -21,8 +21,9 @@ use std::iter::range_inclusive; use syntax::ast::*; use syntax::ast_util::{is_unguarded, walk_pat}; use syntax::codemap::{Span, Spanned, DUMMY_SP}; -use syntax::owned_slice::OwnedSlice; +use syntax::fold::{Folder, noop_fold_pat}; use syntax::print::pprust::pat_to_string; +use syntax::parse::token; use syntax::visit; use syntax::visit::{Visitor, FnKind}; use util::ppaux::ty_to_string; @@ -47,7 +48,9 @@ impl fmt::Show for Matrix { let &Matrix(ref m) = self; let pretty_printed_matrix: Vec> = m.iter().map(|row| { - row.iter().map(|&pat| pat_to_string(pat)).collect::>() + row.iter() + .map(|&pat| pat_to_string(&*pat)) + .collect::>() }).collect(); let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0u); @@ -74,6 +77,12 @@ impl fmt::Show for Matrix { } } +impl FromIterator>> for Matrix { + fn from_iter>>>(mut iterator: T) -> Matrix { + Matrix(iterator.collect()) + } +} + pub struct MatchCheckCtxt<'a> { pub tcx: &'a ty::ctxt } @@ -118,10 +127,8 @@ impl<'a> Visitor<()> for MatchCheckCtxt<'a> { } pub fn check_crate(tcx: &ty::ctxt, krate: &Crate) { - let mut cx = MatchCheckCtxt { tcx: tcx, }; - + let mut cx = MatchCheckCtxt { tcx: tcx }; visit::walk_crate(&mut cx, krate, ()); - tcx.sess.abort_if_errors(); } @@ -153,48 +160,49 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) { // If the type *is* empty, it's vacuously exhaustive return; } - let m: Matrix = Matrix(arms + + let mut static_inliner = StaticInliner { tcx: cx.tcx }; + let matrix: Matrix = arms .iter() .filter(|&arm| is_unguarded(arm)) .flat_map(|arm| arm.pats.iter()) - .map(|pat| vec!(pat.clone())) - .collect()); - check_exhaustive(cx, ex.span, &m); + .map(|pat| vec![static_inliner.fold_pat(*pat)]) + .collect(); + check_exhaustive(cx, ex.span, &matrix); }, _ => () } } +fn is_expr_const_nan(tcx: &ty::ctxt, expr: &Expr) -> bool { + match eval_const_expr(tcx, expr) { + const_float(f) => f.is_nan(), + _ => false + } +} + // Check for unreachable patterns fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) { let mut seen = Matrix(vec!()); + let mut static_inliner = StaticInliner { tcx: cx.tcx }; for arm in arms.iter() { for pat in arm.pats.iter() { + let inlined = static_inliner.fold_pat(*pat); + // Check that we do not match against a static NaN (#6804) - let pat_matches_nan: |&Pat| -> bool = |p| { - let opt_def = cx.tcx.def_map.borrow().find_copy(&p.id); - match opt_def { - Some(DefStatic(did, false)) => { - let const_expr = lookup_const_by_id(cx.tcx, did).unwrap(); - match eval_const_expr(cx.tcx, &*const_expr) { - const_float(f) if f.is_nan() => true, - _ => false - } + walk_pat(&*inlined, |p| { + match p.node { + PatLit(expr) if is_expr_const_nan(cx.tcx, &*expr) => { + span_warn!(cx.tcx.sess, pat.span, E0003, + "unmatchable NaN in pattern, \ + use the is_nan method in a guard instead"); } - _ => false - } - }; - - walk_pat(&**pat, |p| { - if pat_matches_nan(p) { - span_warn!(cx.tcx.sess, p.span, E0003, - "unmatchable NaN in pattern, use the is_nan method in a guard instead" - ); + _ => () } true }); - let v = vec!(*pat); + let v = vec![inlined]; match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) { NotUseful => span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"), Useful => (), @@ -216,8 +224,8 @@ fn raw_pat(p: Gc) -> Gc { } } -fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) { - match is_useful(cx, m, [wild()], ConstructWitness) { +fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix) { + match is_useful(cx, matrix, [wild()], ConstructWitness) { UsefulWithWitness(pats) => { let witness = match pats.as_slice() { [witness] => witness, @@ -249,16 +257,26 @@ fn const_val_to_expr(value: &const_val) -> Gc { } } -fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path { - ty::with_path(tcx, id, |mut path| Path { - global: false, - segments: path.last().map(|elem| PathSegment { - identifier: Ident::new(elem.name()), - lifetimes: vec!(), - types: OwnedSlice::empty() - }).move_iter().collect(), - span: DUMMY_SP, - }) +pub struct StaticInliner<'a> { + pub tcx: &'a ty::ctxt +} + +impl<'a> Folder for StaticInliner<'a> { + fn fold_pat(&mut self, pat: Gc) -> Gc { + match pat.node { + PatIdent(..) | PatEnum(..) => { + let def = self.tcx.def_map.borrow().find_copy(&pat.id); + match def { + Some(DefStatic(did, _)) => { + let const_expr = lookup_const_by_id(self.tcx, did).unwrap(); + const_expr_to_pat(self.tcx, const_expr) + }, + _ => noop_fold_pat(pat, self) + } + } + _ => noop_fold_pat(pat, self) + } + } } /// Constructs a partial witness for a pattern given a list of @@ -281,9 +299,11 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor, ty::ty_enum(cid, _) | ty::ty_struct(cid, _) => { let (vid, is_structure) = match ctor { - &Variant(vid) => (vid, - ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()), - _ => (cid, true) + &Variant(vid) => + (vid, ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()), + _ => + (cid, ty::lookup_struct_fields(cx.tcx, cid).iter() + .any(|field| field.name != token::special_idents::unnamed_field.name)) }; if is_structure { let fields = ty::lookup_struct_fields(cx.tcx, vid); @@ -457,8 +477,7 @@ fn is_useful(cx: &MatchCheckCtxt, matrix @ &Matrix(ref rows): &Matrix, }, Some(constructor) => { - let matrix = Matrix(rows.iter().filter_map(|r| - default(cx, r.as_slice())).collect()); + let matrix = rows.iter().filter_map(|r| default(cx, r.as_slice())).collect(); match is_useful(cx, &matrix, v.tail(), witness) { UsefulWithWitness(pats) => { let arity = constructor_arity(cx, &constructor, left_ty); @@ -504,25 +523,23 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: Gc, match pat.node { PatIdent(..) => match cx.tcx.def_map.borrow().find(&pat.id) { - Some(&DefStatic(did, false)) => { - let const_expr = lookup_const_by_id(cx.tcx, did).unwrap(); - vec!(ConstantValue(eval_const_expr(cx.tcx, &*const_expr))) - }, + Some(&DefStatic(..)) => + cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"), Some(&DefStruct(_)) => vec!(Single), Some(&DefVariant(_, id, _)) => vec!(Variant(id)), _ => vec!() }, PatEnum(..) => match cx.tcx.def_map.borrow().find(&pat.id) { - Some(&DefStatic(did, false)) => { - let const_expr = lookup_const_by_id(cx.tcx, did).unwrap(); - vec!(ConstantValue(eval_const_expr(cx.tcx, &*const_expr))) - }, + Some(&DefStatic(..)) => + cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"), Some(&DefVariant(_, id, _)) => vec!(Variant(id)), _ => vec!(Single) }, PatStruct(..) => match cx.tcx.def_map.borrow().find(&pat.id) { + Some(&DefStatic(..)) => + cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"), Some(&DefVariant(_, id, _)) => vec!(Variant(id)), _ => vec!(Single) }, @@ -581,7 +598,7 @@ pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) -> } fn range_covered_by_constructor(ctor: &Constructor, - from: &const_val,to: &const_val) -> Option { + from: &const_val, to: &const_val) -> Option { let (c_from, c_to) = match *ctor { ConstantValue(ref value) => (value, value), ConstantRange(ref from, ref to) => (from, to), @@ -619,44 +636,22 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc], &PatIdent(_, _, _) => { let opt_def = cx.tcx.def_map.borrow().find_copy(&pat_id); match opt_def { + Some(DefStatic(..)) => + cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"), Some(DefVariant(_, id, _)) => if *constructor == Variant(id) { Some(vec!()) } else { None }, - Some(DefStatic(did, _)) => { - let const_expr = lookup_const_by_id(cx.tcx, did).unwrap(); - let e_v = eval_const_expr(cx.tcx, &*const_expr); - match range_covered_by_constructor(constructor, &e_v, &e_v) { - Some(true) => Some(vec!()), - Some(false) => None, - None => { - cx.tcx.sess.span_err(pat_span, "mismatched types between arms"); - None - } - } - } - _ => { - Some(Vec::from_elem(arity, wild())) - } + _ => Some(Vec::from_elem(arity, wild())) } } &PatEnum(_, ref args) => { let def = cx.tcx.def_map.borrow().get_copy(&pat_id); match def { - DefStatic(did, _) => { - let const_expr = lookup_const_by_id(cx.tcx, did).unwrap(); - let e_v = eval_const_expr(cx.tcx, &*const_expr); - match range_covered_by_constructor(constructor, &e_v, &e_v) { - Some(true) => Some(vec!()), - Some(false) => None, - None => { - cx.tcx.sess.span_err(pat_span, "mismatched types between arms"); - None - } - } - } + DefStatic(..) => + cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"), DefVariant(_, id, _) if *constructor != Variant(id) => None, DefVariant(..) | DefFn(..) | DefStruct(..) => { Some(match args { @@ -672,6 +667,8 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc], // Is this a struct or an enum variant? let def = cx.tcx.def_map.borrow().get_copy(&pat_id); let class_id = match def { + DefStatic(..) => + cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"), DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) { Some(variant_id) } else { @@ -780,7 +777,8 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) { LocalFor => "`for` loop" }; - match is_refutable(cx, loc.pat) { + let mut static_inliner = StaticInliner { tcx: cx.tcx }; + match is_refutable(cx, static_inliner.fold_pat(loc.pat)) { Some(pat) => { span_err!(cx.tcx.sess, loc.pat.span, E0005, "refutable pattern in {} binding: `{}` not covered", diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 7567e73b01de9..4d256549a6465 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -13,8 +13,8 @@ use metadata::csearch; use middle::astencode; - use middle::def; +use middle::pat_util::def_to_path; use middle::ty; use middle::typeck::astconv; use util::nodemap::{DefIdMap}; @@ -26,7 +26,7 @@ use syntax::visit; use syntax::{ast, ast_map, ast_util}; use std::rc::Rc; -use std::gc::Gc; +use std::gc::{Gc, GC}; // // This pass classifies expressions by their constant-ness. @@ -303,6 +303,57 @@ pub enum const_val { const_nil } +pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: Gc) -> Gc { + let pat = match expr.node { + ExprTup(ref exprs) => + PatTup(exprs.iter().map(|&expr| const_expr_to_pat(tcx, expr)).collect()), + + ExprCall(callee, ref args) => { + let def = tcx.def_map.borrow().get_copy(&callee.id); + tcx.def_map.borrow_mut().find_or_insert(expr.id, def); + let path = match def { + def::DefStruct(def_id) => def_to_path(tcx, def_id), + def::DefVariant(_, variant_did, _) => def_to_path(tcx, variant_did), + _ => unreachable!() + }; + let pats = args.iter().map(|&expr| const_expr_to_pat(tcx, expr)).collect(); + PatEnum(path, Some(pats)) + } + + ExprStruct(ref path, ref fields, None) => { + let field_pats = fields.iter().map(|field| FieldPat { + ident: field.ident.node, + pat: const_expr_to_pat(tcx, field.expr) + }).collect(); + PatStruct(path.clone(), field_pats, false) + } + + ExprVec(ref exprs) => { + let pats = exprs.iter().map(|&expr| const_expr_to_pat(tcx, expr)).collect(); + PatVec(pats, None, vec![]) + } + + ExprPath(ref path) => { + let opt_def = tcx.def_map.borrow().find_copy(&expr.id); + match opt_def { + Some(def::DefStruct(..)) => + PatStruct(path.clone(), vec![], false), + Some(def::DefVariant(..)) => + PatEnum(path.clone(), None), + _ => { + match lookup_const(tcx, &*expr) { + Some(actual) => return const_expr_to_pat(tcx, actual), + _ => unreachable!() + } + } + } + } + + _ => PatLit(expr) + }; + box (GC) Pat { id: expr.id, node: pat, span: expr.span } +} + pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val { match eval_const_expr_partial(tcx, e) { Ok(r) => r, diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index b28c0158584e6..7c5b001354dbb 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -48,9 +48,6 @@ pub struct DataFlowContext<'a, O> { /// equal to bits_per_id/uint::BITS rounded up. words_per_id: uint, - // mapping from cfg node index to bitset index. - index_to_bitset: Vec>, - // mapping from node to cfg node index // FIXME (#6298): Shouldn't this go with CFG? nodeid_to_index: NodeMap, @@ -98,58 +95,7 @@ fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap) -> CFGIndex { impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { fn has_bitset_for_nodeid(&self, n: ast::NodeId) -> bool { assert!(n != ast::DUMMY_NODE_ID); - match self.nodeid_to_index.find(&n) { - None => false, - Some(&cfgidx) => self.has_bitset_for_cfgidx(cfgidx), - } - } - fn has_bitset_for_cfgidx(&self, cfgidx: CFGIndex) -> bool { - let node_id = cfgidx.node_id(); - node_id < self.index_to_bitset.len() && - self.index_to_bitset.get(node_id).is_some() - } - fn get_bitset_index(&self, cfgidx: CFGIndex) -> uint { - let node_id = cfgidx.node_id(); - self.index_to_bitset.get(node_id).unwrap() - } - fn get_or_create_bitset_index(&mut self, cfgidx: CFGIndex) -> uint { - assert!(self.words_per_id > 0); - let len = self.gens.len() / self.words_per_id; - let expanded; - let n; - if self.index_to_bitset.len() <= cfgidx.node_id() { - self.index_to_bitset.grow_set(cfgidx.node_id(), &None, Some(len)); - expanded = true; - n = len; - } else { - let entry = self.index_to_bitset.get_mut(cfgidx.node_id()); - match *entry { - None => { - *entry = Some(len); - expanded = true; - n = len; - } - Some(bitidx) => { - expanded = false; - n = bitidx; - } - } - } - if expanded { - let entry = if self.oper.initial_value() { uint::MAX } else {0}; - for _ in range(0, self.words_per_id) { - self.gens.push(0); - self.kills.push(0); - self.on_entry.push(entry); - } - } - - let start = n * self.words_per_id; - let end = start + self.words_per_id; - let len = self.gens.len(); - assert!(start < len); - assert!(end <= len); - n + self.nodeid_to_index.contains_key(&n) } } @@ -165,8 +111,9 @@ impl<'a, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, O> { }; if self.has_bitset_for_nodeid(id) { + assert!(self.bits_per_id > 0); let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); - let (start, end) = self.compute_id_range_frozen(cfgidx); + let (start, end) = self.compute_id_range(cfgidx); let on_entry = self.on_entry.slice(start, end); let entry_str = bits_to_string(on_entry); @@ -243,14 +190,19 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { id_range: IdRange, bits_per_id: uint) -> DataFlowContext<'a, O> { let words_per_id = (bits_per_id + uint::BITS - 1) / uint::BITS; + let num_nodes = cfg.graph.all_nodes().len(); debug!("DataFlowContext::new(analysis_name: {:s}, id_range={:?}, \ - bits_per_id={:?}, words_per_id={:?})", - analysis_name, id_range, bits_per_id, words_per_id); + bits_per_id={:?}, words_per_id={:?}) \ + num_nodes: {}", + analysis_name, id_range, bits_per_id, words_per_id, + num_nodes); - let gens = Vec::new(); - let kills = Vec::new(); - let on_entry = Vec::new(); + let entry = if oper.initial_value() { uint::MAX } else {0}; + + let gens = Vec::from_elem(num_nodes * words_per_id, 0); + let kills = Vec::from_elem(num_nodes * words_per_id, 0); + let on_entry = Vec::from_elem(num_nodes * words_per_id, entry); let nodeid_to_index = build_nodeid_to_index(decl, cfg); @@ -258,7 +210,6 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { tcx: tcx, analysis_name: analysis_name, words_per_id: words_per_id, - index_to_bitset: Vec::new(), nodeid_to_index: nodeid_to_index, bits_per_id: bits_per_id, oper: oper, @@ -273,6 +224,8 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { debug!("{:s} add_gen(id={:?}, bit={:?})", self.analysis_name, id, bit); assert!(self.nodeid_to_index.contains_key(&id)); + assert!(self.bits_per_id > 0); + let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); let (start, end) = self.compute_id_range(cfgidx); let gens = self.gens.mut_slice(start, end); @@ -284,32 +237,21 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { debug!("{:s} add_kill(id={:?}, bit={:?})", self.analysis_name, id, bit); assert!(self.nodeid_to_index.contains_key(&id)); + assert!(self.bits_per_id > 0); + let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); let (start, end) = self.compute_id_range(cfgidx); let kills = self.kills.mut_slice(start, end); set_bit(kills, bit); } - fn apply_gen_kill(&mut self, cfgidx: CFGIndex, bits: &mut [uint]) { + fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [uint]) { //! Applies the gen and kill sets for `cfgidx` to `bits` debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [before]", self.analysis_name, cfgidx, mut_bits_to_string(bits)); - let (start, end) = self.compute_id_range(cfgidx); - let gens = self.gens.slice(start, end); - bitwise(bits, gens, &Union); - let kills = self.kills.slice(start, end); - bitwise(bits, kills, &Subtract); - - debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [after]", - self.analysis_name, cfgidx, mut_bits_to_string(bits)); - } + assert!(self.bits_per_id > 0); - fn apply_gen_kill_frozen(&self, cfgidx: CFGIndex, bits: &mut [uint]) { - //! Applies the gen and kill sets for `cfgidx` to `bits` - //! Only useful after `propagate()` has been called. - debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [before]", - self.analysis_name, cfgidx, mut_bits_to_string(bits)); - let (start, end) = self.compute_id_range_frozen(cfgidx); + let (start, end) = self.compute_id_range(cfgidx); let gens = self.gens.slice(start, end); bitwise(bits, gens, &Union); let kills = self.kills.slice(start, end); @@ -319,15 +261,8 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { self.analysis_name, cfgidx, mut_bits_to_string(bits)); } - fn compute_id_range_frozen(&self, cfgidx: CFGIndex) -> (uint, uint) { - let n = self.get_bitset_index(cfgidx); - let start = n * self.words_per_id; - let end = start + self.words_per_id; - (start, end) - } - - fn compute_id_range(&mut self, cfgidx: CFGIndex) -> (uint, uint) { - let n = self.get_or_create_bitset_index(cfgidx); + fn compute_id_range(&self, cfgidx: CFGIndex) -> (uint, uint) { + let n = cfgidx.node_id(); let start = n * self.words_per_id; let end = start + self.words_per_id; @@ -340,10 +275,10 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { } - pub fn each_bit_on_entry_frozen(&self, - id: ast::NodeId, - f: |uint| -> bool) - -> bool { + pub fn each_bit_on_entry(&self, + id: ast::NodeId, + f: |uint| -> bool) + -> bool { //! Iterates through each bit that is set on entry to `id`. //! Only useful after `propagate()` has been called. if !self.has_bitset_for_nodeid(id) { @@ -360,17 +295,21 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { -> bool { //! Iterates through each bit that is set on entry/exit to `cfgidx`. //! Only useful after `propagate()` has been called. - if !self.has_bitset_for_cfgidx(cfgidx) { + + if self.bits_per_id == 0 { + // Skip the surprisingly common degenerate case. (Note + // compute_id_range requires self.words_per_id > 0.) return true; } - let (start, end) = self.compute_id_range_frozen(cfgidx); + + let (start, end) = self.compute_id_range(cfgidx); let on_entry = self.on_entry.slice(start, end); let temp_bits; let slice = match e { Entry => on_entry, Exit => { - let mut t = on_entry.to_owned(); - self.apply_gen_kill_frozen(cfgidx, t.as_mut_slice()); + let mut t = on_entry.to_vec(); + self.apply_gen_kill(cfgidx, t.as_mut_slice()); temp_bits = t; temp_bits.as_slice() } @@ -380,15 +319,21 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { self.each_bit(slice, f) } - pub fn each_gen_bit_frozen(&self, id: ast::NodeId, f: |uint| -> bool) - -> bool { + pub fn each_gen_bit(&self, id: ast::NodeId, f: |uint| -> bool) + -> bool { //! Iterates through each bit in the gen set for `id`. - //! Only useful after `propagate()` has been called. if !self.has_bitset_for_nodeid(id) { return true; } + + if self.bits_per_id == 0 { + // Skip the surprisingly common degenerate case. (Note + // compute_id_range requires self.words_per_id > 0.) + return true; + } + let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); - let (start, end) = self.compute_id_range_frozen(cfgidx); + let (start, end) = self.compute_id_range(cfgidx); let gens = self.gens.slice(start, end); debug!("{:s} each_gen_bit(id={:?}, gens={})", self.analysis_name, id, bits_to_string(gens)); @@ -397,6 +342,8 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { fn each_bit(&self, words: &[uint], f: |uint| -> bool) -> bool { //! Helper for iterating over the bits in a bit set. + //! Returns false on the first call to `f` that returns false; + //! if all calls to `f` return true, then returns true. for (word_index, &word) in words.iter().enumerate() { if word != 0 { @@ -445,7 +392,7 @@ impl<'a, O:DataFlowOperator> DataFlowContext<'a, O> { cfg.graph.each_edge(|_edge_index, edge| { let flow_exit = edge.source(); let (start, end) = self.compute_id_range(flow_exit); - let mut orig_kills = self.kills.slice(start, end).to_owned(); + let mut orig_kills = self.kills.slice(start, end).to_vec(); let mut changed = false; for &node_id in edge.data.exiting_scopes.iter() { @@ -527,6 +474,8 @@ impl<'a, 'b, O:DataFlowOperator> PropagationContext<'a, 'b, O> { in_out: &mut [uint]) { debug!("DataFlowContext::walk_cfg(in_out={}) {:s}", bits_to_string(in_out), self.dfcx.analysis_name); + assert!(self.dfcx.bits_per_id > 0); + cfg.graph.each_node(|node_index, node| { debug!("DataFlowContext::walk_cfg idx={} id={} begin in_out={}", node_index, node.data.id, bits_to_string(in_out)); @@ -570,6 +519,8 @@ impl<'a, 'b, O:DataFlowOperator> PropagationContext<'a, 'b, O> { let cfgidx = edge.target(); debug!("{:s} propagate_bits_into_entry_set_for(pred_bits={}, {} to {})", self.dfcx.analysis_name, bits_to_string(pred_bits), source, cfgidx); + assert!(self.dfcx.bits_per_id > 0); + let (start, end) = self.dfcx.compute_id_range(cfgidx); let changed = { // (scoping mutable borrow of self.dfcx.on_entry) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index d84c62f744edc..9fc589ddf59eb 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -22,8 +22,7 @@ use util::nodemap::NodeSet; use std::collections::HashSet; use syntax::ast; use syntax::ast_map; -use syntax::ast_util; -use syntax::ast_util::{local_def, is_local}; +use syntax::ast_util::{local_def, is_local, PostExpansionMethod}; use syntax::attr::AttrMetaMethods; use syntax::attr; use syntax::codemap; @@ -105,6 +104,7 @@ impl<'a> MarkSymbolVisitor<'a> { None => self.check_def_id(def_id) } } + typeck::MethodStaticUnboxedClosure(_) => {} typeck::MethodParam(typeck::MethodParam { trait_id: trait_id, method_num: index, @@ -213,7 +213,7 @@ impl<'a> MarkSymbolVisitor<'a> { visit::walk_trait_method(self, &*trait_method, ctxt); } ast_map::NodeMethod(method) => { - visit::walk_block(self, ast_util::method_body(&*method), ctxt); + visit::walk_block(self, &*method.pe_body(), ctxt); } ast_map::NodeForeignItem(foreign_item) => { visit::walk_foreign_item(self, &*foreign_item, ctxt); @@ -521,8 +521,9 @@ impl<'a> Visitor<()> for DeadVisitor<'a> { // Overwrite so that we don't warn the trait method itself. fn visit_trait_method(&mut self, trait_method: &ast::TraitMethod, _: ()) { match *trait_method { - ast::Provided(ref method) => visit::walk_block(self, - ast_util::method_body(&**method), ()), + ast::Provided(ref method) => { + visit::walk_block(self, &*method.pe_body(), ()) + } ast::Required(_) => () } } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 415135a2d048f..e6160038b1d8c 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -17,7 +17,7 @@ use middle::typeck::MethodCall; use util::ppaux; use syntax::ast; -use syntax::ast_util; +use syntax::ast_util::PostExpansionMethod; use syntax::codemap::Span; use syntax::visit; use syntax::visit::Visitor; @@ -49,10 +49,9 @@ impl<'a> EffectCheckVisitor<'a> { match self.unsafe_context { SafeContext => { // Report an error. - self.tcx.sess.span_err(span, - format!("{} requires unsafe function or \ - block", - description).as_slice()) + span_err!(self.tcx.sess, span, E0133, + "{} requires unsafe function or block", + description); } UnsafeBlock(block_id) => { // OK, but record this. @@ -73,14 +72,14 @@ impl<'a> EffectCheckVisitor<'a> { match ty::get(base_type).sty { ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { ty::ty_str => { - self.tcx.sess.span_err(e.span, - "modification of string types is not allowed"); + span_err!(self.tcx.sess, e.span, E0134, + "modification of string types is not allowed"); } _ => {} }, ty::ty_str => { - self.tcx.sess.span_err(e.span, - "modification of string types is not allowed"); + span_err!(self.tcx.sess, e.span, E0135, + "modification of string types is not allowed"); } _ => {} } @@ -95,7 +94,7 @@ impl<'a> Visitor<()> for EffectCheckVisitor<'a> { visit::FkItemFn(_, _, fn_style, _) => (true, fn_style == ast::UnsafeFn), visit::FkMethod(_, _, method) => - (true, ast_util::method_fn_style(method) == ast::UnsafeFn), + (true, method.pe_fn_style() == ast::UnsafeFn), _ => (false, false), }; diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index 9a5f226bb73ce..3debdc158fe26 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -87,9 +87,8 @@ fn find_item(item: &Item, ctxt: &mut EntryContext) { if ctxt.main_fn.is_none() { ctxt.main_fn = Some((item.id, item.span)); } else { - ctxt.session.span_err( - item.span, - "multiple 'main' functions"); + span_err!(ctxt.session, item.span, E0136, + "multiple 'main' functions"); } } else { // This isn't main @@ -102,9 +101,8 @@ fn find_item(item: &Item, ctxt: &mut EntryContext) { if ctxt.attr_main_fn.is_none() { ctxt.attr_main_fn = Some((item.id, item.span)); } else { - ctxt.session.span_err( - item.span, - "multiple 'main' functions"); + span_err!(ctxt.session, item.span, E0137, + "multiple functions with a #[main] attribute"); } } @@ -112,9 +110,8 @@ fn find_item(item: &Item, ctxt: &mut EntryContext) { if ctxt.start_fn.is_none() { ctxt.start_fn = Some((item.id, item.span)); } else { - ctxt.session.span_err( - item.span, - "multiple 'start' functions"); + span_err!(ctxt.session, item.span, E0138, + "multiple 'start' functions"); } } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 1e06b3b1fd463..b911e636da091 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -20,7 +20,7 @@ use middle::freevars; use middle::pat_util; use middle::ty; use middle::typeck::{MethodCall, MethodObject, MethodOrigin, MethodParam}; -use middle::typeck::{MethodStatic}; +use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure}; use middle::typeck; use util::ppaux::Repr; @@ -160,6 +160,9 @@ impl OverloadedCallType { MethodStatic(def_id) => { OverloadedCallType::from_method_id(tcx, def_id) } + MethodStaticUnboxedClosure(def_id) => { + OverloadedCallType::from_method_id(tcx, def_id) + } MethodParam(ref method_param) => { OverloadedCallType::from_trait_id(tcx, method_param.trait_id) } @@ -439,6 +442,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { } ast::ExprFnBlock(..) | + ast::ExprUnboxedFn(..) | ast::ExprProc(..) => { self.walk_captures(expr) } diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs index 614972f3d5776..f6887718ec137 100644 --- a/src/librustc/middle/freevars.rs +++ b/src/librustc/middle/freevars.rs @@ -16,7 +16,7 @@ use middle::def; use middle::resolve; use middle::ty; -use util::nodemap::{NodeMap, NodeSet}; +use util::nodemap::{DefIdSet, NodeMap, NodeSet}; use syntax::codemap::Span; use syntax::{ast}; @@ -39,8 +39,11 @@ pub struct freevar_entry { pub def: def::Def, //< The variable being accessed free. pub span: Span //< First span where it is accessed (there can be multiple) } + pub type freevar_map = NodeMap>; +pub type UnboxedClosureList = DefIdSet; + struct CollectFreevarsVisitor<'a> { seen: NodeSet, refs: Vec, @@ -54,7 +57,8 @@ impl<'a> Visitor for CollectFreevarsVisitor<'a> { fn visit_expr(&mut self, expr: &ast::Expr, depth: int) { match expr.node { - ast::ExprFnBlock(..) | ast::ExprProc(..) => { + ast::ExprFnBlock(..) | ast::ExprProc(..) | + ast::ExprUnboxedFn(..) => { visit::walk_expr(self, expr, depth + 1) } ast::ExprPath(..) => { @@ -125,8 +129,8 @@ impl<'a> Visitor<()> for AnnotateFreevarsVisitor<'a> { // efficient as it fully recomputes the free variables at every // node of interest rather than building up the free variables in // one pass. This could be improved upon if it turns out to matter. -pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate) -> - freevar_map { +pub fn annotate_freevars(def_map: &resolve::DefMap, krate: &ast::Crate) + -> freevar_map { let mut visitor = AnnotateFreevarsVisitor { def_map: def_map, freevars: NodeMap::new(), diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 93913f8427111..6669147b0dcac 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -94,14 +94,12 @@ impl<'a> IntrinsicCheckingVisitor<'a> { fn check_transmute(&self, span: Span, from: ty::t, to: ty::t) { if type_size_is_affected_by_type_parameters(self.tcx, from) { - self.tcx.sess.span_err(span, - "cannot transmute from a type that \ - contains type parameters"); + span_err!(self.tcx.sess, span, E0139, + "cannot transmute from a type that contains type parameters"); } if type_size_is_affected_by_type_parameters(self.tcx, to) { - self.tcx.sess.span_err(span, - "cannot transmute to a type that contains \ - type parameters"); + span_err!(self.tcx.sess, span, E0140, + "cannot transmute to a type that contains type parameters"); } let restriction = TransmuteRestriction { diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 4f7cb742d8f86..d2a5342c17ee8 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -92,22 +92,20 @@ fn check_struct_safe_for_destructor(cx: &mut Context, let struct_ty = ty::mk_struct(cx.tcx, struct_did, subst::Substs::empty()); if !ty::type_is_sendable(cx.tcx, struct_ty) { - cx.tcx.sess.span_err(span, - "cannot implement a destructor on a \ - structure that does not satisfy Send"); - cx.tcx.sess.span_note(span, - "use \"#[unsafe_destructor]\" on the \ - implementation to force the compiler to \ - allow this"); + span_err!(cx.tcx.sess, span, E0125, + "cannot implement a destructor on a \ + structure that does not satisfy Send"); + span_note!(cx.tcx.sess, span, + "use \"#[unsafe_destructor]\" on the implementation \ + to force the compiler to allow this"); } } else { - cx.tcx.sess.span_err(span, - "cannot implement a destructor on a structure \ - with type parameters"); - cx.tcx.sess.span_note(span, - "use \"#[unsafe_destructor]\" on the \ - implementation to force the compiler to \ - allow this"); + span_err!(cx.tcx.sess, span, E0141, + "cannot implement a destructor on a structure \ + with type parameters"); + span_note!(cx.tcx.sess, span, + "use \"#[unsafe_destructor]\" on the implementation \ + to force the compiler to allow this"); } } @@ -124,14 +122,12 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id); debug!("checking impl with self type {}", ty::get(self_ty).sty); check_builtin_bounds(cx, self_ty, trait_def.bounds, |missing| { - cx.tcx.sess.span_err(self_type.span, - format!("the type `{}', which does not fulfill `{}`, cannot implement this \ - trait", - ty_to_string(cx.tcx, self_ty), - missing.user_string(cx.tcx)).as_slice()); - cx.tcx.sess.span_note(self_type.span, - format!("types implementing this trait must fulfill `{}`", - trait_def.bounds.user_string(cx.tcx)).as_slice()); + span_err!(cx.tcx.sess, self_type.span, E0142, + "the type `{}', which does not fulfill `{}`, cannot implement this trait", + ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx)); + span_note!(cx.tcx.sess, self_type.span, + "types implementing this trait must fulfill `{}`", + trait_def.bounds.user_string(cx.tcx)); }); // If this is a destructor, check kinds. @@ -191,10 +187,9 @@ fn with_appropriate_checker(cx: &Context, } fn check_for_bare(cx: &Context, fv: &freevar_entry) { - cx.tcx.sess.span_err( - fv.span, - "can't capture dynamic environment in a fn item; \ - use the || { ... } closure form instead"); + span_err!(cx.tcx.sess, fv.span, E0143, + "can't capture dynamic environment in a fn item; \ + use the || {} closure form instead", "{ ... }"); } // same check is done in resolve.rs, but shouldn't be done let fty = ty::node_id_to_type(cx.tcx, id); @@ -216,6 +211,9 @@ fn with_appropriate_checker(cx: &Context, ty::ty_bare_fn(_) => { b(check_for_bare) } + + ty::ty_unboxed_closure(_) => {} + ref s => { cx.tcx.sess.bug(format!("expect fn type in kind checker, not \ {:?}", @@ -321,7 +319,9 @@ fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) { Some(method) => { let is_object_call = match method.origin { typeck::MethodObject(..) => true, - typeck::MethodStatic(..) | typeck::MethodParam(..) => false + typeck::MethodStatic(..) | + typeck::MethodStaticUnboxedClosure(..) | + typeck::MethodParam(..) => false }; (&method.substs.types, is_object_call) } @@ -489,12 +489,11 @@ pub fn check_typaram_bounds(cx: &Context, ty, type_param_def.bounds.builtin_bounds, |missing| { - cx.tcx.sess.span_err( - sp, - format!("instantiating a type parameter with an incompatible type \ - `{}`, which does not fulfill `{}`", - ty_to_string(cx.tcx, ty), - missing.user_string(cx.tcx)).as_slice()); + span_err!(cx.tcx.sess, sp, E0144, + "instantiating a type parameter with an incompatible type \ + `{}`, which does not fulfill `{}`", + ty_to_string(cx.tcx, ty), + missing.user_string(cx.tcx)); }); } @@ -506,36 +505,32 @@ pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t, // Emit a less mysterious error message in this case. match referenced_ty { Some(rty) => { - cx.tcx.sess.span_err(sp, - format!("cannot implicitly borrow variable of type `{}` in a \ - bounded stack closure (implicit reference does not \ - fulfill `{}`)", - ty_to_string(cx.tcx, rty), - missing.user_string(cx.tcx)).as_slice()) + span_err!(cx.tcx.sess, sp, E0145, + "cannot implicitly borrow variable of type `{}` in a \ + bounded stack closure (implicit reference does not fulfill `{}`)", + ty_to_string(cx.tcx, rty), missing.user_string(cx.tcx)); } None => { - cx.tcx.sess.span_err(sp, - format!("cannot capture variable of type `{}`, which does \ - not fulfill `{}`, in a bounded closure", - ty_to_string(cx.tcx, ty), - missing.user_string(cx.tcx)).as_slice()) + span_err!(cx.tcx.sess, sp, E0146, + "cannot capture variable of type `{}`, which does \ + not fulfill `{}`, in a bounded closure", + ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx)); } } - cx.tcx.sess.span_note( - sp, - format!("this closure's environment must satisfy `{}`", - bounds.user_string(cx.tcx)).as_slice()); + span_note!(cx.tcx.sess, sp, + "this closure's environment must satisfy `{}`", + bounds.user_string(cx.tcx)); }); } pub fn check_trait_cast_bounds(cx: &Context, sp: Span, ty: ty::t, bounds: ty::BuiltinBounds) { check_builtin_bounds(cx, ty, bounds, |missing| { - cx.tcx.sess.span_err(sp, - format!("cannot pack type `{}`, which does not fulfill \ - `{}`, as a trait bounded by {}", - ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx), - bounds.user_string(cx.tcx)).as_slice()); + span_err!(cx.tcx.sess, sp, E0147, + "cannot pack type `{}`, which does not fulfill `{}`, as a trait bounded by {}", + ty_to_string(cx.tcx, ty), + missing.user_string(cx.tcx), + bounds.user_string(cx.tcx)); }); } @@ -544,26 +539,26 @@ fn check_copy(cx: &Context, ty: ty::t, sp: Span, reason: &str) { ty_to_string(cx.tcx, ty), ty::type_contents(cx.tcx, ty).to_string()); if ty::type_moves_by_default(cx.tcx, ty) { - cx.tcx.sess.span_err( - sp, - format!("copying a value of non-copyable type `{}`", - ty_to_string(cx.tcx, ty)).as_slice()); - cx.tcx.sess.span_note(sp, format!("{}", reason).as_slice()); + span_err!(cx.tcx.sess, sp, E0148, + "copying a value of non-copyable type `{}`", + ty_to_string(cx.tcx, ty)); + span_note!(cx.tcx.sess, sp, "{}", reason.as_slice()); } } pub fn check_static(tcx: &ty::ctxt, ty: ty::t, sp: Span) -> bool { if !ty::type_is_static(tcx, ty) { match ty::get(ty).sty { - ty::ty_param(..) => { - tcx.sess.span_err(sp, - format!("value may contain references; \ - add `'static` bound to `{}`", - ty_to_string(tcx, ty)).as_slice()); - } - _ => { - tcx.sess.span_err(sp, "value may contain references"); - } + ty::ty_param(..) => { + span_err!(tcx.sess, sp, E0149, + "value may contain references; \ + add `'static` bound to `{}`", + ty_to_string(tcx, ty)); + } + _ => { + span_err!(tcx.sess, sp, E0150, + "value may contain references"); + } } false } else { @@ -680,11 +675,9 @@ pub fn check_cast_for_escaping_regions( // Ensure that `ty` has a statically known size (i.e., it has the `Sized` bound). fn check_sized(tcx: &ty::ctxt, ty: ty::t, name: String, sp: Span) { if !ty::type_is_sized(tcx, ty) { - tcx.sess.span_err(sp, - format!("variable `{}` has dynamically sized type \ - `{}`", - name, - ty_to_string(tcx, ty)).as_slice()); + span_err!(tcx.sess, sp, E0151, + "variable `{}` has dynamically sized type `{}`", + name, ty_to_string(tcx, ty)); } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 1a1d47b254770..9abc9226c1364 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -27,6 +27,7 @@ use middle::weak_lang_items; use syntax::ast; use syntax::ast_util::local_def; use syntax::attr::AttrMetaMethods; +use syntax::codemap::{DUMMY_SP, Span}; use syntax::parse::token::InternedString; use syntax::visit::Visitor; use syntax::visit; @@ -122,7 +123,7 @@ impl<'a> Visitor<()> for LanguageItemCollector<'a> { match item_index { Some(item_index) => { - self.collect_item(item_index, local_def(item.id)) + self.collect_item(item_index, local_def(item.id), item.span) } None => {} } @@ -147,13 +148,13 @@ impl<'a> LanguageItemCollector<'a> { } } - pub fn collect_item(&mut self, item_index: uint, item_def_id: ast::DefId) { + pub fn collect_item(&mut self, item_index: uint, + item_def_id: ast::DefId, span: Span) { // Check for duplicates. match self.items.items.get(item_index) { &Some(original_def_id) if original_def_id != item_def_id => { - self.session.err(format!("duplicate entry for `{}`", - LanguageItems::item_name( - item_index)).as_slice()); + span_err!(self.session, span, E0152, + "duplicate entry for `{}`", LanguageItems::item_name(item_index)); } &Some(_) | &None => { // OK. @@ -173,7 +174,7 @@ impl<'a> LanguageItemCollector<'a> { crate_store.iter_crate_data(|crate_number, _crate_metadata| { each_lang_item(crate_store, crate_number, |node_id, item_index| { let def_id = ast::DefId { krate: crate_number, node: node_id }; - self.collect_item(item_index, def_id); + self.collect_item(item_index, def_id, DUMMY_SP); true }); }) diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 79742d3173434..737b952151b67 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -448,7 +448,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { } visit::walk_expr(ir, expr, ()); } - ExprFnBlock(..) | ExprProc(..) => { + ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) => { // Interesting control flow (for loops can contain labeled // breaks or continues) ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); @@ -941,8 +941,11 @@ impl<'a> Liveness<'a> { self.propagate_through_expr(&**e, succ) } - ExprFnBlock(_, ref blk) | ExprProc(_, ref blk) => { - debug!("{} is an ExprFnBlock or ExprProc", expr_to_string(expr)); + ExprFnBlock(_, ref blk) | + ExprProc(_, ref blk) | + ExprUnboxedFn(_, ref blk) => { + debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn", + expr_to_string(expr)); /* The next-node for a break is the successor of the entire @@ -1411,8 +1414,8 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) | ExprAgain(..) | ExprLit(_) | ExprBlock(..) | ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) | - ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprPath(..) | - ExprBox(..) => { + ExprParen(..) | ExprFnBlock(..) | ExprProc(..) | ExprUnboxedFn(..) | + ExprPath(..) | ExprBox(..) => { visit::walk_expr(this, expr, ()); } ExprForLoop(..) => fail!("non-desugared expr_for_loop") diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index e928704b0ccf6..baf7f2dd77650 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -473,7 +473,8 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { ast::ExprAddrOf(..) | ast::ExprCall(..) | ast::ExprAssign(..) | ast::ExprAssignOp(..) | - ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprRet(..) | + ast::ExprFnBlock(..) | ast::ExprProc(..) | + ast::ExprUnboxedFn(..) | ast::ExprRet(..) | ast::ExprUnary(..) | ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) | ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) | @@ -578,6 +579,20 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> { })) } } + ty::ty_unboxed_closure(_) => { + // FIXME #2152 allow mutation of moved upvars + Ok(Rc::new(cmt_ { + id: id, + span: span, + cat: cat_copied_upvar(CopiedUpvar { + upvar_id: var_id, + onceness: ast::Many, + capturing_proc: fn_node_id, + }), + mutbl: McImmutable, + ty: expr_ty + })) + } _ => { self.tcx().sess.span_bug( span, diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 2d53d742ee44b..faaffc7525786 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -10,12 +10,14 @@ use middle::def::*; use middle::resolve; +use middle::ty; use std::collections::HashMap; use std::gc::{Gc, GC}; use syntax::ast::*; use syntax::ast_util::{walk_pat}; use syntax::codemap::{Span, DUMMY_SP}; +use syntax::owned_slice::OwnedSlice; pub type PatIdMap = HashMap; @@ -116,3 +118,15 @@ pub fn simple_identifier<'a>(pat: &'a Pat) -> Option<&'a Ident> { pub fn wild() -> Gc { box (GC) Pat { id: 0, node: PatWild, span: DUMMY_SP } } + +pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path { + ty::with_path(tcx, id, |mut path| Path { + global: false, + segments: path.last().map(|elem| PathSegment { + identifier: Ident::new(elem.name()), + lifetimes: vec!(), + types: OwnedSlice::empty() + }).move_iter().collect(), + span: DUMMY_SP, + }) +} diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 580e7b2db57c2..cdb3f9dbb1dbf 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -21,13 +21,12 @@ use lint; use middle::resolve; use middle::ty; use middle::typeck::{MethodCall, MethodMap, MethodOrigin, MethodParam}; -use middle::typeck::{MethodStatic, MethodObject}; +use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject}; use util::nodemap::{NodeMap, NodeSet}; use syntax::ast; use syntax::ast_map; -use syntax::ast_util; -use syntax::ast_util::{is_local, local_def}; +use syntax::ast_util::{is_local, local_def, PostExpansionMethod}; use syntax::attr; use syntax::codemap::Span; use syntax::parse::token; @@ -264,10 +263,10 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> { if public_ty || public_trait { for method in methods.iter() { - let meth_public = match ast_util::method_explicit_self(&**method).node { + let meth_public = match method.pe_explicit_self().node { ast::SelfStatic => public_ty, _ => true, - } && ast_util::method_vis(&**method) == ast::Public; + } && method.pe_vis() == ast::Public; if meth_public || tr.is_some() { self.exported_items.insert(method.id); } @@ -457,8 +456,8 @@ impl<'a> PrivacyVisitor<'a> { let imp = self.tcx.map.get_parent_did(closest_private_id); match ty::impl_trait_ref(self.tcx, imp) { Some(..) => return Allowable, - _ if ast_util::method_vis(&**m) == ast::Public => return Allowable, - _ => ast_util::method_vis(&**m) + _ if m.pe_vis() == ast::Public => return Allowable, + _ => m.pe_vis() } } Some(ast_map::NodeTraitMethod(_)) => { @@ -773,6 +772,7 @@ impl<'a> PrivacyVisitor<'a> { MethodStatic(method_id) => { self.check_static_method(span, method_id, ident) } + MethodStaticUnboxedClosure(_) => {} // Trait methods are always all public. The only controlling factor // is whether the trait itself is accessible or not. MethodParam(MethodParam { trait_id: trait_id, .. }) | @@ -1079,7 +1079,7 @@ impl<'a> SanePrivacyVisitor<'a> { "visibility qualifiers have no effect on trait \ impls"); for m in methods.iter() { - check_inherited(m.span, ast_util::method_vis(&**m), ""); + check_inherited(m.span, m.pe_vis(), ""); } } @@ -1111,7 +1111,7 @@ impl<'a> SanePrivacyVisitor<'a> { for m in methods.iter() { match *m { ast::Provided(ref m) => { - check_inherited(m.span, ast_util::method_vis(&**m), + check_inherited(m.span, m.pe_vis(), "unnecessary visibility"); } ast::Required(ref m) => { @@ -1149,7 +1149,7 @@ impl<'a> SanePrivacyVisitor<'a> { match item.node { ast::ItemImpl(_, _, _, ref methods) => { for m in methods.iter() { - check_inherited(tcx, m.span, ast_util::method_vis(&**m)); + check_inherited(tcx, m.span, m.pe_vis()); } } ast::ItemForeignMod(ref fm) => { @@ -1175,7 +1175,7 @@ impl<'a> SanePrivacyVisitor<'a> { match *m { ast::Required(..) => {} ast::Provided(ref m) => check_inherited(tcx, m.span, - ast_util::method_vis(&**m)), + m.pe_vis()), } } } @@ -1345,7 +1345,7 @@ impl<'a> Visitor<()> for VisiblePrivateTypesVisitor<'a> { // methods will be visible as `Public::foo`. let mut found_pub_static = false; for method in methods.iter() { - if ast_util::method_explicit_self(&**method).node == ast::SelfStatic && + if method.pe_explicit_self().node == ast::SelfStatic && self.exported_items.contains(&method.id) { found_pub_static = true; visit::walk_method_helper(self, &**method, ()); diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index d9324574da73f..e404ce8566375 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -26,7 +26,7 @@ use std::collections::HashSet; use syntax::abi; use syntax::ast; use syntax::ast_map; -use syntax::ast_util::is_local; +use syntax::ast_util::{is_local, PostExpansionMethod}; use syntax::ast_util; use syntax::attr::{InlineAlways, InlineHint, InlineNever, InlineNone}; use syntax::attr; @@ -68,7 +68,7 @@ fn item_might_be_inlined(item: &ast::Item) -> bool { fn method_might_be_inlined(tcx: &ty::ctxt, method: &ast::Method, impl_src: ast::DefId) -> bool { if attributes_specify_inlining(method.attrs.as_slice()) || - generics_require_inlining(ast_util::method_generics(&*method)) { + generics_require_inlining(method.pe_generics()) { return true } if is_local(impl_src) { @@ -200,7 +200,7 @@ impl<'a> ReachableContext<'a> { } } Some(ast_map::NodeMethod(method)) => { - if generics_require_inlining(ast_util::method_generics(&*method)) || + if generics_require_inlining(method.pe_generics()) || attributes_specify_inlining(method.attrs.as_slice()) { true } else { @@ -316,14 +316,14 @@ impl<'a> ReachableContext<'a> { // Keep going, nothing to get exported } ast::Provided(ref method) => { - visit::walk_block(self, ast_util::method_body(&**method), ()) + visit::walk_block(self, &*method.pe_body(), ()) } } } ast_map::NodeMethod(method) => { let did = self.tcx.map.get_parent_did(search_item); if method_might_be_inlined(self.tcx, &*method, did) { - visit::walk_block(self, ast_util::method_body(&*method), ()) + visit::walk_block(self, &*method.pe_body(), ()) } } // Nothing to recurse on for these diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index df4d3b7efe432..822a43f2619dc 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -314,6 +314,16 @@ impl RegionMaps { self.sub_free_region(sub_fr, super_fr) } + (ty::ReEarlyBound(param_id_a, param_space_a, index_a, _), + ty::ReEarlyBound(param_id_b, param_space_b, index_b, _)) => { + // This case is used only to make sure that explicitly- + // specified `Self` types match the real self type in + // implementations. + param_id_a == param_id_b && + param_space_a == param_space_b && + index_a == index_b + } + _ => { false } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 6c6ac81b98530..a0adbf6e920ea 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -11,19 +11,19 @@ #![allow(non_camel_case_types)] use driver::session::Session; +use lint; use metadata::csearch; use metadata::decoder::{DefLike, DlDef, DlField, DlImpl}; use middle::def::*; use middle::lang_items::LanguageItems; use middle::pat_util::pat_bindings; use middle::subst::{ParamSpace, FnSpace, TypeSpace}; -use lint; +use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory}; use util::nodemap::{NodeMap, DefIdSet, FnvHashMap}; use syntax::ast::*; use syntax::ast; -use syntax::ast_util; -use syntax::ast_util::{local_def}; +use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::ast_util::{walk_pat, trait_method_to_ty_method}; use syntax::ext::mtwt; use syntax::parse::token::special_names; @@ -288,6 +288,24 @@ enum ModulePrefixResult { PrefixFound(Rc, uint) } +#[deriving(Clone, Eq, PartialEq)] +enum MethodIsStaticFlag { + MethodIsNotStatic, + MethodIsStatic, +} + +impl MethodIsStaticFlag { + fn from_explicit_self_category(explicit_self_category: + ExplicitSelfCategory) + -> MethodIsStaticFlag { + if explicit_self_category == StaticExplicitSelfCategory { + MethodIsStatic + } else { + MethodIsNotStatic + } + } +} + #[deriving(PartialEq)] enum NameSearchType { /// We're doing a name search in order to resolve a `use` directive. @@ -806,7 +824,8 @@ struct Resolver<'a> { graph_root: NameBindings, - method_map: RefCell>, + method_map: RefCell>, + structs: FnvHashMap>, // The number of imports that are currently unresolved. @@ -1299,20 +1318,20 @@ impl<'a> Resolver<'a> { // For each method... for method in methods.iter() { // Add the method to the module. - let ident = ast_util::method_ident(&**method); + let ident = method.pe_ident(); let method_name_bindings = self.add_child(ident, new_parent.clone(), ForbidDuplicateValues, method.span); - let def = match ast_util::method_explicit_self(&**method).node { + let def = match method.pe_explicit_self().node { SelfStatic => { // Static methods become // `def_static_method`s. DefStaticMethod(local_def(method.id), FromImpl(local_def( item.id)), - ast_util::method_fn_style(&**method)) + method.pe_fn_style()) } _ => { // Non-static methods become @@ -1321,7 +1340,7 @@ impl<'a> Resolver<'a> { } }; - let is_public = ast_util::method_vis(&**method) == ast::Public; + let is_public = method.pe_vis() == ast::Public; method_name_bindings.define_value(def, method.span, is_public); @@ -1362,17 +1381,19 @@ impl<'a> Resolver<'a> { let ident = ty_m.ident; // Add it as a name in the trait module. - let def = match ty_m.explicit_self.node { + let (def, static_flag) = match ty_m.explicit_self.node { SelfStatic => { // Static methods become `def_static_method`s. - DefStaticMethod(local_def(ty_m.id), + (DefStaticMethod(local_def(ty_m.id), FromTrait(local_def(item.id)), - ty_m.fn_style) + ty_m.fn_style), + MethodIsStatic) } _ => { // Non-static methods become `def_method`s. - DefMethod(local_def(ty_m.id), - Some(local_def(item.id))) + (DefMethod(local_def(ty_m.id), + Some(local_def(item.id))), + MethodIsNotStatic) } }; @@ -1383,8 +1404,9 @@ impl<'a> Resolver<'a> { ty_m.span); method_name_bindings.define_value(def, ty_m.span, true); - self.method_map.borrow_mut().insert((ident.name, def_id), - ty_m.explicit_self.node); + self.method_map + .borrow_mut() + .insert((ident.name, def_id), static_flag); } name_bindings.define_type(DefTrait(def_id), sp, is_public); @@ -1600,6 +1622,12 @@ impl<'a> Resolver<'a> { if is_exported { self.external_exports.insert(def.def_id()); } + + let kind = match def { + DefStruct(..) | DefTy(..) => ImplModuleKind, + _ => NormalModuleKind + }; + match def { DefMod(def_id) | DefForeignMod(def_id) | DefStruct(def_id) | DefTy(def_id) => { @@ -1618,7 +1646,7 @@ impl<'a> Resolver<'a> { child_name_bindings.define_module(parent_link, Some(def_id), - NormalModuleKind, + kind, true, is_public, DUMMY_SP); @@ -1671,7 +1699,11 @@ impl<'a> Resolver<'a> { trait method '{}'", token::get_ident(method_name)); - self.method_map.borrow_mut().insert((method_name.name, def_id), explicit_self); + self.method_map + .borrow_mut() + .insert((method_name.name, def_id), + MethodIsStaticFlag::from_explicit_self_category( + explicit_self)); if is_exported { self.external_exports.insert(method_def_id); @@ -3679,6 +3711,13 @@ impl<'a> Resolver<'a> { this.resolve_type(&*argument.ty); } + match ty_m.explicit_self.node { + SelfExplicit(ref typ, _) => { + this.resolve_type(&**typ) + } + _ => {} + } + this.resolve_type(&*ty_m.decl.output); }); } @@ -3977,14 +4016,17 @@ impl<'a> Resolver<'a> { this.record_def(path_id, (def, lp)); } Some((DefStruct(_), _)) => { - this.session.span_err(t.span, - "super-struct is defined \ - in a different crate") + span_err!(this.session, t.span, E0154, + "super-struct is defined in a different crate"); }, - Some(_) => this.session.span_err(t.span, - "super-struct is not a struct type"), - None => this.session.span_err(t.span, - "super-struct could not be resolved"), + Some(_) => { + span_err!(this.session, t.span, E0155, + "super-struct is not a struct type"); + } + None => { + span_err!(this.session, t.span, E0156, + "super-struct could not be resolved"); + } } }, _ => this.session.span_bug(t.span, "path not mapped to a TyPath") @@ -4004,15 +4046,21 @@ impl<'a> Resolver<'a> { fn resolve_method(&mut self, rib_kind: RibKind, method: &Method) { - let method_generics = ast_util::method_generics(method); + let method_generics = method.pe_generics(); let type_parameters = HasTypeParameters(method_generics, FnSpace, method.id, rib_kind); - self.resolve_function(rib_kind, Some(ast_util::method_fn_decl(method)), + match method.pe_explicit_self().node { + SelfExplicit(ref typ, _) => self.resolve_type(&**typ), + _ => {} + } + + self.resolve_function(rib_kind, + Some(method.pe_fn_decl()), type_parameters, - ast_util::method_body(method)); + method.pe_body()); } fn with_current_self_type(&mut self, self_type: &Ty, f: |&mut Resolver| -> T) -> T { @@ -4083,7 +4131,7 @@ impl<'a> Resolver<'a> { fn check_trait_method(&self, method: &Method) { // If there is a TraitRef in scope for an impl, then the method must be in the trait. for &(did, ref trait_ref) in self.current_trait_ref.iter() { - let method_name = ast_util::method_ident(method).name; + let method_name = method.pe_ident().name; if self.method_map.borrow().find(&(method_name, did)).is_none() { let path_str = self.path_idents_to_string(&trait_ref.path); @@ -4252,17 +4300,13 @@ impl<'a> Resolver<'a> { if path.segments .iter() .any(|s| !s.lifetimes.is_empty()) { - self.session.span_err(path.span, - "lifetime parameters \ - are not allowed on \ - this type") + span_err!(self.session, path.span, E0157, + "lifetime parameters are not allowed on this type"); } else if path.segments .iter() .any(|s| s.types.len() > 0) { - self.session.span_err(path.span, - "type parameters are \ - not allowed on this \ - type") + span_err!(self.session, path.span, E0153, + "type parameters are not allowed on this type"); } } None => { @@ -4353,7 +4397,7 @@ impl<'a> Resolver<'a> { let ident = path1.node; let renamed = mtwt::resolve(ident); - match self.resolve_bare_identifier_pattern(ident) { + match self.resolve_bare_identifier_pattern(ident, pattern.span) { FoundStructOrEnumVariant(def, lp) if mode == RefutableMode => { debug!("(resolving pattern) resolving `{}` to \ @@ -4517,7 +4561,7 @@ impl<'a> Resolver<'a> { }); } - fn resolve_bare_identifier_pattern(&mut self, name: Ident) + fn resolve_bare_identifier_pattern(&mut self, name: Ident, span: Span) -> BareIdentifierPatternResolution { let module = self.current_module.clone(); match self.resolve_item_in_lexical_scope(module, @@ -4544,6 +4588,11 @@ impl<'a> Resolver<'a> { def @ DefStatic(_, false) => { return FoundConst(def, LastMod(AllPublic)); } + DefStatic(_, true) => { + self.resolve_error(span, + "mutable static variables cannot be referenced in a pattern"); + return BareIdentifierPatternUnresolved; + } _ => { return BareIdentifierPatternUnresolved; } @@ -4767,7 +4816,7 @@ impl<'a> Resolver<'a> { match containing_module.def_id.get() { Some(def_id) => { match self.method_map.borrow().find(&(ident.name, def_id)) { - Some(x) if *x == SelfStatic => (), + Some(&MethodIsStatic) => (), None => (), _ => { debug!("containing module was a trait or impl \ @@ -5039,7 +5088,7 @@ impl<'a> Resolver<'a> { let path_str = self.path_idents_to_string(&trait_ref.path); match method_map.find(&(name, did)) { - Some(&SelfStatic) => return StaticTraitMethod(path_str), + Some(&MethodIsStatic) => return StaticTraitMethod(path_str), Some(_) => return TraitMethod, None => {} } @@ -5209,7 +5258,8 @@ impl<'a> Resolver<'a> { } ExprFnBlock(fn_decl, block) | - ExprProc(fn_decl, block) => { + ExprProc(fn_decl, block) | + ExprUnboxedFn(fn_decl, block) => { self.resolve_function(FunctionRibKind(expr.id, block.id), Some(fn_decl), NoTypeParameters, block); diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index a492b4ab9525e..9f1f4057be6b9 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -43,6 +43,7 @@ use std::os; use syntax::ast; use syntax::ast_util; +use syntax::ast_util::PostExpansionMethod; use syntax::ast::{NodeId,DefId}; use syntax::ast_map::NodeItem; use syntax::attr; @@ -333,7 +334,7 @@ impl <'l> DxrVisitor<'l> { }, }; - qualname.push_str(get_ident(ast_util::method_ident(&*method)).get()); + qualname.push_str(get_ident(method.pe_ident()).get()); let qualname = qualname.as_slice(); // record the decl for this def (if it has one) @@ -349,18 +350,18 @@ impl <'l> DxrVisitor<'l> { decl_id, scope_id); - let m_decl = ast_util::method_fn_decl(&*method); - self.process_formals(&m_decl.inputs, qualname, e); + self.process_formals(&method.pe_fn_decl().inputs, qualname, e); // walk arg and return types - for arg in m_decl.inputs.iter() { + for arg in method.pe_fn_decl().inputs.iter() { self.visit_ty(&*arg.ty, e); } - self.visit_ty(m_decl.output, e); + self.visit_ty(&*method.pe_fn_decl().output, e); // walk the fn body - self.visit_block(ast_util::method_body(&*method), DxrVisitorEnv::new_nested(method.id)); + self.visit_block(&*method.pe_body(), + DxrVisitorEnv::new_nested(method.id)); - self.process_generic_params(ast_util::method_generics(&*method), + self.process_generic_params(method.pe_generics(), method.span, qualname, method.id, @@ -841,7 +842,8 @@ impl <'l> DxrVisitor<'l> { let method_map = self.analysis.ty_cx.method_map.borrow(); let method_callee = method_map.get(&typeck::MethodCall::expr(ex.id)); let (def_id, decl_id) = match method_callee.origin { - typeck::MethodStatic(def_id) => { + typeck::MethodStatic(def_id) | + typeck::MethodStaticUnboxedClosure(def_id) => { // method invoked on an object with a concrete type (not a static method) let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx, def_id); @@ -1136,10 +1138,11 @@ impl<'l> Visitor for DxrVisitor<'l> { } }, ast::ViewItemExternCrate(ident, ref s, id) => { - let name = get_ident(ident).get().to_owned(); + let name = get_ident(ident); + let name = name.get(); let s = match *s { - Some((ref s, _)) => s.get().to_owned(), - None => name.to_owned(), + Some((ref s, _)) => s.get().to_string(), + None => name.to_string(), }; let sub_span = self.span.sub_span_after_keyword(i.span, keywords::Crate); let cnum = match self.sess.cstore.find_extern_mod_stmt_cnum(id) { @@ -1150,7 +1153,7 @@ impl<'l> Visitor for DxrVisitor<'l> { sub_span, id, cnum, - name.as_slice(), + name, s.as_slice(), e.cur_scope); }, @@ -1273,9 +1276,9 @@ impl<'l> Visitor for DxrVisitor<'l> { // process collected paths for &(id, ref p, ref immut, ref_kind) in self.collected_paths.iter() { let value = if *immut { - self.span.snippet(p.span).into_owned() + self.span.snippet(p.span).into_string() } else { - "".to_owned() + "".to_string() }; let sub_span = self.span.span_for_first_ident(p.span); let def_map = self.analysis.ty_cx.def_map.borrow(); @@ -1330,7 +1333,7 @@ impl<'l> Visitor for DxrVisitor<'l> { let value = self.span.snippet(l.span); for &(id, ref p, ref immut, _) in self.collected_paths.iter() { - let value = if *immut { value.to_owned() } else { "".to_owned() }; + let value = if *immut { value.to_string() } else { "".to_string() }; let types = self.analysis.ty_cx.node_types.borrow(); let typ = ppaux::ty_to_string(&self.analysis.ty_cx, *types.get(&(id as uint))); // Get the span only for the name of the variable (I hope the path diff --git a/src/librustc/middle/save/recorder.rs b/src/librustc/middle/save/recorder.rs index 7869aec1683c2..1af6fde02afa4 100644 --- a/src/librustc/middle/save/recorder.rs +++ b/src/librustc/middle/save/recorder.rs @@ -170,7 +170,7 @@ impl<'a> FmtStrs<'a> { String::from_str(v) } ))); - Some(strs.fold(String::new(), |s, ss| s.append(ss.as_slice()))).map(|s| s.into_owned()) + Some(strs.fold(String::new(), |s, ss| s.append(ss.as_slice()))) } pub fn record_without_span(&mut self, @@ -503,7 +503,7 @@ impl<'a> FmtStrs<'a> { }; let (dcn, dck) = match declid { Some(declid) => (s!(declid.node), s!(declid.krate)), - None => ("".to_owned(), "".to_owned()) + None => ("".to_string(), "".to_string()) }; self.check_and_record(MethodCall, span, diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 5c2a70a46fdc8..ef0709316f0af 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -317,6 +317,9 @@ impl VecPerParamSpace { VecPerParamSpace::empty().with_vec(TypeSpace, types) } + /// `t` is the type space. + /// `s` is the self space. + /// `f` is the fn space. pub fn new(t: Vec, s: Vec, f: Vec) -> VecPerParamSpace { let type_limit = t.len(); let self_limit = t.len() + s.len(); diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 958d2cd377431..aeb171c068a85 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -195,6 +195,7 @@ use llvm::{ValueRef, BasicBlockRef}; use middle::const_eval; use middle::def; use middle::check_match; +use middle::check_match::StaticInliner; use middle::lang_items::StrEqFnLangItem; use middle::pat_util::*; use middle::resolve::DefMap; @@ -225,14 +226,9 @@ use std::gc::{Gc}; use syntax::ast; use syntax::ast::Ident; use syntax::codemap::Span; +use syntax::fold::Folder; use syntax::parse::token::InternedString; -// An option identifying a literal: either an expression or a DefId of a static expression. -enum Lit { - ExprLit(Gc), - ConstLit(ast::DefId), // the def ID of the constant -} - #[deriving(PartialEq)] pub enum VecLenOpt { vec_len_eq, @@ -242,24 +238,15 @@ pub enum VecLenOpt { // An option identifying a branch (either a literal, an enum variant or a // range) enum Opt { - lit(Lit), + lit(Gc), var(ty::Disr, Rc, ast::DefId), range(Gc, Gc), vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint)) } -fn lit_to_expr(tcx: &ty::ctxt, a: &Lit) -> Gc { - match *a { - ExprLit(existing_a_expr) => existing_a_expr, - ConstLit(a_const) => const_eval::lookup_const_by_id(tcx, a_const).unwrap() - } -} - fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool { match (a, b) { - (&lit(a), &lit(b)) => { - let a_expr = lit_to_expr(tcx, &a); - let b_expr = lit_to_expr(tcx, &b); + (&lit(a_expr), &lit(b_expr)) => { match const_eval::compare_lit_exprs(tcx, &*a_expr, &*b_expr) { Some(val1) => val1 == 0, None => fail!("compare_list_exprs: type mismatch"), @@ -286,20 +273,13 @@ pub enum opt_result<'a> { range_result(Result<'a>, Result<'a>), } -fn trans_opt<'a>(bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> { +fn trans_opt<'a>(mut bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> { let _icx = push_ctxt("match::trans_opt"); let ccx = bcx.ccx(); - let mut bcx = bcx; match *o { - lit(ExprLit(ref lit_expr)) => { - let lit_datum = unpack_datum!(bcx, expr::trans(bcx, &**lit_expr)); - let lit_datum = lit_datum.assert_rvalue(bcx); // literals are rvalues - let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx)); - return single_result(Result::new(bcx, lit_datum.val)); - } - lit(l @ ConstLit(ref def_id)) => { - let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_to_expr(bcx.tcx(), &l).id); - let (llval, _) = consts::get_const_val(bcx.ccx(), *def_id); + lit(lit_expr) => { + let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_expr.id); + let (llval, _) = consts::const_expr(ccx, &*lit_expr, true); let lit_datum = immediate_rvalue(llval, lit_ty); let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx)); return single_result(Result::new(bcx, lit_datum.val)); @@ -491,7 +471,7 @@ fn enter_default<'a, 'b>( // Collect all of the matches that can match against anything. enter_match(bcx, dm, m, col, val, |pats| { - if pat_is_binding_or_wild(dm, pats[col]) { + if pat_is_binding_or_wild(dm, &*pats[col]) { Some(Vec::from_slice(pats.slice_to(col)).append(pats.slice_from(col + 1))) } else { None @@ -546,11 +526,12 @@ fn enter_opt<'a, 'b>( let _indenter = indenter(); let ctor = match opt { - &lit(x) => check_match::ConstantValue(const_eval::eval_const_expr( - bcx.tcx(), lit_to_expr(bcx.tcx(), &x))), - &range(ref lo, ref hi) => check_match::ConstantRange( - const_eval::eval_const_expr(bcx.tcx(), &**lo), - const_eval::eval_const_expr(bcx.tcx(), &**hi) + &lit(expr) => check_match::ConstantValue( + const_eval::eval_const_expr(bcx.tcx(), &*expr) + ), + &range(lo, hi) => check_match::ConstantRange( + const_eval::eval_const_expr(bcx.tcx(), &*lo), + const_eval::eval_const_expr(bcx.tcx(), &*hi) ), &vec_len(len, _, _) => check_match::Slice(len), &var(_, _, def_id) => check_match::Variant(def_id) @@ -647,7 +628,7 @@ fn get_options(bcx: &Block, m: &[Match], col: uint) -> Vec { let cur = *br.pats.get(col); match cur.node { ast::PatLit(l) => { - add_to_set(ccx.tcx(), &mut found, lit(ExprLit(l))); + add_to_set(ccx.tcx(), &mut found, lit(l)); } ast::PatIdent(..) => { // This is either an enum variant or a variable binding. @@ -657,10 +638,6 @@ fn get_options(bcx: &Block, m: &[Match], col: uint) -> Vec { add_to_set(ccx.tcx(), &mut found, variant_opt(bcx, cur.id)); } - Some(def::DefStatic(const_did, false)) => { - add_to_set(ccx.tcx(), &mut found, - lit(ConstLit(const_did))); - } _ => {} } } @@ -674,10 +651,6 @@ fn get_options(bcx: &Block, m: &[Match], col: uint) -> Vec { add_to_set(ccx.tcx(), &mut found, variant_opt(bcx, cur.id)); } - Some(def::DefStatic(const_did, false)) => { - add_to_set(ccx.tcx(), &mut found, - lit(ConstLit(const_did))); - } _ => {} } } @@ -1445,10 +1418,11 @@ fn trans_match_inner<'a>(scope_cx: &'a Block<'a>, bindings_map: create_bindings_map(bcx, *arm.pats.get(0)) }).collect(); + let mut static_inliner = StaticInliner { tcx: scope_cx.tcx() }; let mut matches = Vec::new(); for arm_data in arm_datas.iter() { - matches.extend(arm_data.arm.pats.iter().map(|p| Match { - pats: vec!(*p), + matches.extend(arm_data.arm.pats.iter().map(|&p| Match { + pats: vec![static_inliner.fold_pat(p)], data: arm_data, bound_ptrs: Vec::new(), })); @@ -1752,8 +1726,6 @@ fn bind_irrefutable_pat<'a>( } } } - Some(def::DefStatic(_, false)) => { - } _ => { // Nothing to do here. } diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 3ee61b1d67596..54c30e721548d 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -163,6 +163,12 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr { return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor) } + ty::ty_unboxed_closure(def_id) => { + let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id); + let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); + return Univariant(mk_struct(cx, upvar_types.as_slice(), false), + false) + } ty::ty_enum(def_id, ref substs) => { let cases = get_cases(cx.tcx(), def_id, substs); let hint = ty::lookup_repr_hint(cx.tcx(), def_id); @@ -668,11 +674,10 @@ pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr) } /** - * Begin initializing a new value of the given case of the given - * representation. The fields, if any, should then be initialized via - * `trans_field_ptr`. + * Set the discriminant for a new value of the given case of the given + * representation. */ -pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) { +pub fn trans_set_discr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) { match *r { CEnum(ity, min, max) => { assert_discr_in_range(ity, min, max, discr); diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 6bcc9b9b745b7..7d7922ebfa90c 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -29,17 +29,16 @@ use back::link::{mangle_exported_name}; use back::{link, abi}; use driver::config; use driver::config::{NoDebugInfo, FullDebugInfo}; -use driver::session::Session; use driver::driver::{CrateAnalysis, CrateTranslation}; +use driver::session::Session; +use lint; +use llvm::{BasicBlockRef, ModuleRef, ValueRef, Vector, get_param}; use llvm; -use llvm::{ModuleRef, ValueRef, BasicBlockRef}; -use llvm::{Vector}; use metadata::{csearch, encoder, loader}; -use lint; use middle::astencode; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; -use middle::weak_lang_items; use middle::subst; +use middle::weak_lang_items; use middle::subst::Subst; use middle::trans::_match; use middle::trans::adt; @@ -81,8 +80,8 @@ use std::c_str::ToCStr; use std::cell::{Cell, RefCell}; use std::rc::Rc; use std::{i8, i16, i32, i64}; -use std::gc::Gc; -use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustIntrinsic}; +use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustCall}; +use syntax::abi::{RustIntrinsic, Abi}; use syntax::ast_util::{local_def, is_local}; use syntax::attr::AttrMetaMethods; use syntax::attr; @@ -193,6 +192,14 @@ fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, _ => {} } + if ccx.tcx.sess.opts.cg.no_redzone { + unsafe { + llvm::LLVMAddFunctionAttribute(llfn, + llvm::FunctionIndex as c_uint, + llvm::NoRedZoneAttribute as uint64_t) + } + } + llvm::SetFunctionCallConv(llfn, cc); // Function addresses in Rust are never significant, allowing functions to be merged. llvm::SetUnnamedAddr(llfn, true); @@ -246,13 +253,32 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De } pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef { - let (inputs, output, has_env) = match ty::get(fn_ty).sty { - ty::ty_bare_fn(ref f) => (f.sig.inputs.clone(), f.sig.output, false), - ty::ty_closure(ref f) => (f.sig.inputs.clone(), f.sig.output, true), + let (inputs, output, abi, env) = match ty::get(fn_ty).sty { + ty::ty_bare_fn(ref f) => { + (f.sig.inputs.clone(), f.sig.output, f.abi, None) + } + ty::ty_closure(ref f) => { + (f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx))) + } + ty::ty_unboxed_closure(closure_did) => { + let unboxed_closure_types = ccx.tcx + .unboxed_closure_types + .borrow(); + let function_type = unboxed_closure_types.get(&closure_did); + let llenvironment_type = type_of(ccx, fn_ty).ptr_to(); + (function_type.sig.inputs.clone(), + function_type.sig.output, + RustCall, + Some(llenvironment_type)) + } _ => fail!("expected closure or fn") }; - let llfty = type_of_rust_fn(ccx, has_env, inputs.as_slice(), output); + let llfty = type_of_rust_fn(ccx, env, inputs.as_slice(), output, abi); + debug!("decl_rust_fn(input count={},type={})", + inputs.len(), + ccx.tn.type_to_string(llfty)); + let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, output); let attrs = get_fn_llvm_attributes(ccx, fn_ty); for &(idx, attr) in attrs.iter() { @@ -666,6 +692,14 @@ pub fn iter_structural_ty<'r, } }) } + ty::ty_unboxed_closure(def_id) => { + let repr = adt::represent_type(cx.ccx(), t); + let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id); + for (i, upvar) in upvars.iter().enumerate() { + let llupvar = adt::trans_field_ptr(cx, &*repr, av, 0, i); + cx = f(cx, llupvar, upvar.ty); + } + } ty::ty_vec(_, Some(n)) => { let unit_ty = ty::sequence_element_type(cx.tcx(), t); let (base, len) = tvec::get_fixed_base_and_byte_len(cx, av, unit_ty, n); @@ -862,7 +896,7 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val ty::ty_bare_fn(ref fn_ty) => { match fn_ty.abi.for_target(ccx.sess().targ_cfg.os, ccx.sess().targ_cfg.arch) { - Some(Rust) => { + Some(Rust) | Some(RustCall) => { get_extern_rust_fn(ccx, t, name.as_slice(), did) } Some(RustIntrinsic) => { @@ -1142,13 +1176,11 @@ pub fn arrayalloca(cx: &Block, ty: Type, v: ValueRef) -> ValueRef { // slot where the return value of the function must go. pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t) -> ValueRef { - unsafe { - if type_of::return_uses_outptr(fcx.ccx, output_type) { - llvm::LLVMGetParam(fcx.llfn, 0) - } else { - let lloutputtype = type_of::type_of(fcx.ccx, output_type); - AllocaFcx(fcx, lloutputtype, "__make_return_pointer") - } + if type_of::return_uses_outptr(fcx.ccx, output_type) { + get_param(fcx.llfn, 0) + } else { + let lloutputtype = type_of::type_of(fcx.ccx, output_type); + AllocaFcx(fcx, lloutputtype, "__make_return_pointer") } } @@ -1205,9 +1237,7 @@ pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext, }; if has_env { - fcx.llenv = Some(unsafe { - llvm::LLVMGetParam(fcx.llfn, fcx.env_arg_pos() as c_uint) - }); + fcx.llenv = Some(get_param(fcx.llfn, fcx.env_arg_pos() as c_uint)) } fcx @@ -1272,16 +1302,85 @@ pub fn create_datums_for_fn_args(fcx: &FunctionContext, -> Vec { let _icx = push_ctxt("create_datums_for_fn_args"); - // Return an array wrapping the ValueRefs that we get from - // llvm::LLVMGetParam for each argument into datums. + // Return an array wrapping the ValueRefs that we get from `get_param` for + // each argument into datums. arg_tys.iter().enumerate().map(|(i, &arg_ty)| { - let llarg = unsafe { - llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as c_uint) - }; + let llarg = get_param(fcx.llfn, fcx.arg_pos(i) as c_uint); datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty)) }).collect() } +/// Creates rvalue datums for each of the incoming function arguments and +/// tuples the arguments. These will later be stored into appropriate lvalue +/// datums. +fn create_datums_for_fn_args_under_call_abi< + 'a>( + mut bcx: &'a Block<'a>, + arg_scope: cleanup::CustomScopeIndex, + arg_tys: &[ty::t]) + -> Vec { + let mut result = Vec::new(); + for (i, &arg_ty) in arg_tys.iter().enumerate() { + if i < arg_tys.len() - 1 { + // Regular argument. + let llarg = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(i) as c_uint); + result.push(datum::Datum::new(llarg, arg_ty, arg_kind(bcx.fcx, + arg_ty))); + continue + } + + // This is the last argument. Tuple it. + match ty::get(arg_ty).sty { + ty::ty_tup(ref tupled_arg_tys) => { + let tuple_args_scope_id = cleanup::CustomScope(arg_scope); + let tuple = + unpack_datum!(bcx, + datum::lvalue_scratch_datum(bcx, + arg_ty, + "tupled_args", + false, + tuple_args_scope_id, + (), + |(), + mut bcx, + llval| { + for (j, &tupled_arg_ty) in + tupled_arg_tys.iter().enumerate() { + let llarg = + get_param(bcx.fcx.llfn, + bcx.fcx.arg_pos(i + j) as c_uint); + let lldest = GEPi(bcx, llval, [0, j]); + let datum = datum::Datum::new( + llarg, + tupled_arg_ty, + arg_kind(bcx.fcx, tupled_arg_ty)); + bcx = datum.store_to(bcx, lldest); + } + bcx + })); + let tuple = unpack_datum!(bcx, + tuple.to_expr_datum() + .to_rvalue_datum(bcx, + "argtuple")); + result.push(tuple); + } + ty::ty_nil => { + let mode = datum::Rvalue::new(datum::ByValue); + result.push(datum::Datum::new(C_nil(bcx.ccx()), + ty::mk_nil(), + mode)) + } + _ => { + bcx.tcx().sess.bug("last argument of a function with \ + `rust-call` ABI isn't a tuple?!") + } + }; + + } + + result +} + fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>, arg_scope: cleanup::CustomScopeIndex, bcx: &'a Block<'a>, @@ -1314,6 +1413,59 @@ fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>, bcx } +fn copy_unboxed_closure_args_to_allocas<'a>( + mut bcx: &'a Block<'a>, + arg_scope: cleanup::CustomScopeIndex, + args: &[ast::Arg], + arg_datums: Vec, + monomorphized_arg_types: &[ty::t]) + -> &'a Block<'a> { + let _icx = push_ctxt("copy_unboxed_closure_args_to_allocas"); + let arg_scope_id = cleanup::CustomScope(arg_scope); + + assert_eq!(arg_datums.len(), 1); + + let arg_datum = arg_datums.move_iter().next().unwrap(); + + // Untuple the rest of the arguments. + let tuple_datum = + unpack_datum!(bcx, + arg_datum.to_lvalue_datum_in_scope(bcx, + "argtuple", + arg_scope_id)); + let empty = Vec::new(); + let untupled_arg_types = match ty::get(monomorphized_arg_types[0]).sty { + ty::ty_tup(ref types) => types.as_slice(), + ty::ty_nil => empty.as_slice(), + _ => { + bcx.tcx().sess.span_bug(args[0].pat.span, + "first arg to `rust-call` ABI function \ + wasn't a tuple?!") + } + }; + for j in range(0, args.len()) { + let tuple_element_type = untupled_arg_types[j]; + let tuple_element_datum = + tuple_datum.get_element(tuple_element_type, + |llval| GEPi(bcx, llval, [0, j])); + let tuple_element_datum = tuple_element_datum.to_expr_datum(); + let tuple_element_datum = + unpack_datum!(bcx, + tuple_element_datum.to_rvalue_datum(bcx, + "arg")); + bcx = _match::store_arg(bcx, + args[j].pat, + tuple_element_datum, + arg_scope_id); + + if bcx.fcx.ccx.sess().opts.debuginfo == FullDebugInfo { + debuginfo::create_argument_metadata(bcx, &args[j]); + } + } + + bcx +} + // Ties up the llstaticallocas -> llloadenv -> lltop edges, // and builds the return block. pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>, @@ -1371,6 +1523,12 @@ pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) { Ret(ret_cx, retval); } +#[deriving(Clone, Eq, PartialEq)] +pub enum IsUnboxedClosureFlag { + NotUnboxedClosure, + IsUnboxedClosure, +} + // trans_closure: Builds an LLVM function out of a source function. // If the function closes over its environment a closure will be // returned. @@ -1381,7 +1539,11 @@ pub fn trans_closure(ccx: &CrateContext, param_substs: ¶m_substs, id: ast::NodeId, _attributes: &[ast::Attribute], + arg_types: Vec, output_type: ty::t, + abi: Abi, + has_env: bool, + is_unboxed_closure: IsUnboxedClosureFlag, maybe_load_env: <'a> |&'a Block<'a>| -> &'a Block<'a>) { ccx.stats.n_closures.set(ccx.stats.n_closures.get() + 1); @@ -1391,11 +1553,6 @@ pub fn trans_closure(ccx: &CrateContext, debug!("trans_closure(..., param_substs={})", param_substs.repr(ccx.tcx())); - let has_env = match ty::get(ty::node_id_to_type(ccx.tcx(), id)).sty { - ty::ty_closure(_) => true, - _ => false - }; - let arena = TypedArena::new(); let fcx = new_fn_ctxt(ccx, llfndecl, @@ -1413,14 +1570,44 @@ pub fn trans_closure(ccx: &CrateContext, let block_ty = node_id_type(bcx, body.id); // Set up arguments to the function. - let arg_tys = ty::ty_fn_args(node_id_type(bcx, id)); - let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice()); + let monomorphized_arg_types = + arg_types.iter() + .map(|at| monomorphize_type(bcx, *at)) + .collect::>(); + for monomorphized_arg_type in monomorphized_arg_types.iter() { + debug!("trans_closure: monomorphized_arg_type: {}", + ty_to_string(ccx.tcx(), *monomorphized_arg_type)); + } + debug!("trans_closure: function lltype: {}", + bcx.fcx.ccx.tn.val_to_string(bcx.fcx.llfn)); + + let arg_datums = if abi != RustCall { + create_datums_for_fn_args(&fcx, + monomorphized_arg_types.as_slice()) + } else { + create_datums_for_fn_args_under_call_abi( + bcx, + arg_scope, + monomorphized_arg_types.as_slice()) + }; - bcx = copy_args_to_allocas(&fcx, - arg_scope, - bcx, - decl.inputs.as_slice(), - arg_datums); + bcx = match is_unboxed_closure { + NotUnboxedClosure => { + copy_args_to_allocas(&fcx, + arg_scope, + bcx, + decl.inputs.as_slice(), + arg_datums) + } + IsUnboxedClosure => { + copy_unboxed_closure_args_to_allocas( + bcx, + arg_scope, + decl.inputs.as_slice(), + arg_datums, + monomorphized_arg_types.as_slice()) + } + }; bcx = maybe_load_env(bcx); @@ -1480,9 +1667,23 @@ pub fn trans_fn(ccx: &CrateContext, let _s = StatRecorder::new(ccx, ccx.tcx.map.path_to_string(id).to_string()); debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx())); let _icx = push_ctxt("trans_fn"); - let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx(), id)); - trans_closure(ccx, decl, body, llfndecl, - param_substs, id, attrs, output_type, |bcx| bcx); + let fn_ty = ty::node_id_to_type(ccx.tcx(), id); + let arg_types = ty::ty_fn_args(fn_ty); + let output_type = ty::ty_fn_ret(fn_ty); + let abi = ty::ty_fn_abi(fn_ty); + trans_closure(ccx, + decl, + body, + llfndecl, + param_substs, + id, + attrs, + arg_types, + output_type, + abi, + false, + NotUnboxedClosure, + |bcx| bcx); } pub fn trans_enum_variant(ccx: &CrateContext, @@ -1502,6 +1703,59 @@ pub fn trans_enum_variant(ccx: &CrateContext, llfndecl); } +pub fn trans_named_tuple_constructor<'a>(mut bcx: &'a Block<'a>, + ctor_ty: ty::t, + disr: ty::Disr, + args: callee::CallArgs, + dest: expr::Dest) -> Result<'a> { + + let ccx = bcx.fcx.ccx; + let tcx = &ccx.tcx; + + let result_ty = match ty::get(ctor_ty).sty { + ty::ty_bare_fn(ref bft) => bft.sig.output, + _ => ccx.sess().bug( + format!("trans_enum_variant_constructor: \ + unexpected ctor return type {}", + ctor_ty.repr(tcx)).as_slice()) + }; + + // Get location to store the result. If the user does not care about + // the result, just make a stack slot + let llresult = match dest { + expr::SaveIn(d) => d, + expr::Ignore => { + if !type_is_zero_size(ccx, result_ty) { + alloc_ty(bcx, result_ty, "constructor_result") + } else { + C_undef(type_of::type_of(ccx, result_ty)) + } + } + }; + + if !type_is_zero_size(ccx, result_ty) { + let repr = adt::represent_type(ccx, result_ty); + + match args { + callee::ArgExprs(exprs) => { + let fields = exprs.iter().map(|x| *x).enumerate().collect::>(); + bcx = expr::trans_adt(bcx, &*repr, disr, fields.as_slice(), + None, expr::SaveIn(llresult)); + } + _ => ccx.sess().bug("expected expr as arguments for variant/struct tuple constructor") + } + } + + // If the caller doesn't care about the result + // drop the temporary we made + let bcx = match dest { + expr::SaveIn(_) => bcx, + expr::Ignore => glue::drop_ty(bcx, llresult, result_ty) + }; + + Result::new(bcx, llresult) +} + pub fn trans_tuple_struct(ccx: &CrateContext, _fields: &[ast::StructField], ctor_id: ast::NodeId, @@ -1544,7 +1798,6 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext, if !type_is_zero_size(fcx.ccx, result_ty) { let repr = adt::represent_type(ccx, result_ty); - adt::trans_start_init(bcx, &*repr, fcx.llretptr.get().unwrap(), disr); for (i, arg_datum) in arg_datums.move_iter().enumerate() { let lldestptr = adt::trans_field_ptr(bcx, &*repr, @@ -1553,36 +1806,12 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext, i); arg_datum.store_to(bcx, lldestptr); } + adt::trans_set_discr(bcx, &*repr, fcx.llretptr.get().unwrap(), disr); } finish_fn(&fcx, bcx, result_ty); } -fn trans_enum_def(ccx: &CrateContext, enum_definition: &ast::EnumDef, - sp: Span, id: ast::NodeId, vi: &[Rc], - i: &mut uint) { - for variant in enum_definition.variants.iter() { - let disr_val = vi[*i].disr_val; - *i += 1; - - match variant.node.kind { - ast::TupleVariantKind(ref args) if args.len() > 0 => { - let llfn = get_item_val(ccx, variant.node.id); - trans_enum_variant(ccx, id, &**variant, args.as_slice(), - disr_val, ¶m_substs::empty(), llfn); - } - ast::TupleVariantKind(_) => { - // Nothing to do. - } - ast::StructVariantKind(struct_def) => { - trans_struct_def(ccx, struct_def); - } - } - } - - enum_variant_size_lint(ccx, enum_definition, sp, id); -} - fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span, id: ast::NodeId) { let mut sizes = Vec::new(); // does no allocation if no pushes, thankfully @@ -1649,7 +1878,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { let _icx = push_ctxt("trans_item"); match item.node { ast::ItemFn(ref decl, _fn_style, abi, ref generics, ref body) => { - if abi != Rust { + if abi != Rust { let llfndecl = get_item_val(ccx, item.id); foreign::trans_rust_fn_with_foreign_abi( ccx, &**decl, &**body, item.attrs.as_slice(), llfndecl, item.id); @@ -1675,12 +1904,8 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { ast::ItemMod(ref m) => { trans_mod(ccx, m); } - ast::ItemEnum(ref enum_definition, ref generics) => { - if !generics.is_type_parameterized() { - let vi = ty::enum_variants(ccx.tcx(), local_def(item.id)); - let mut i = 0; - trans_enum_def(ccx, enum_definition, item.span, item.id, vi.as_slice(), &mut i); - } + ast::ItemEnum(ref enum_definition, _) => { + enum_variant_size_lint(ccx, enum_definition, item.span, item.id); } ast::ItemStatic(_, m, ref expr) => { // Recurse on the expression to catch items in blocks @@ -1707,11 +1932,6 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { ast::ItemForeignMod(ref foreign_mod) => { foreign::trans_foreign_mod(ccx, foreign_mod); } - ast::ItemStruct(struct_def, ref generics) => { - if !generics.is_type_parameterized() { - trans_struct_def(ccx, struct_def); - } - } ast::ItemTrait(..) => { // Inside of this trait definition, we won't be actually translating any // functions, but the trait still needs to be walked. Otherwise default @@ -1724,20 +1944,6 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { } } -pub fn trans_struct_def(ccx: &CrateContext, struct_def: Gc) { - // If this is a tuple-like struct, translate the constructor. - match struct_def.ctor_id { - // We only need to translate a constructor if there are fields; - // otherwise this is a unit-like struct. - Some(ctor_id) if struct_def.fields.len() > 0 => { - let llfndecl = get_item_val(ccx, ctor_id); - trans_tuple_struct(ccx, struct_def.fields.as_slice(), - ctor_id, ¶m_substs::empty(), llfndecl); - } - Some(_) | None => {} - } -} - // Translate a module. Doing this amounts to translating the items in the // module; there ends up being no artifact (aside from linkage names) of // separate modules in the compiled program. That's because modules exist @@ -1784,7 +1990,7 @@ fn register_fn(ccx: &CrateContext, -> ValueRef { match ty::get(node_type).sty { ty::ty_bare_fn(ref f) => { - assert!(f.abi == Rust); + assert!(f.abi == Rust || f.abi == RustCall); } _ => fail!("expected bare rust fn") }; @@ -1794,15 +2000,30 @@ fn register_fn(ccx: &CrateContext, llfn } -pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) -> Vec<(uint, u64)> { +pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) + -> Vec<(uint, u64)> { use middle::ty::{BrAnon, ReLateBound}; - let (fn_sig, has_env) = match ty::get(fn_ty).sty { - ty::ty_closure(ref f) => (f.sig.clone(), true), - ty::ty_bare_fn(ref f) => (f.sig.clone(), false), + let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty { + ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true), + ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false), + ty::ty_unboxed_closure(closure_did) => { + let unboxed_closure_types = ccx.tcx + .unboxed_closure_types + .borrow(); + let function_type = unboxed_closure_types.get(&closure_did); + (function_type.sig.clone(), RustCall, true) + } _ => fail!("expected closure or function.") }; + // These have an odd calling convention, so we skip them for now. + // + // FIXME(pcwalton): We don't have to skip them; just untuple the result. + if abi == RustCall { + return Vec::new() + } + // Since index 0 is the return value of the llvm func, we start // at either 1 or 2 depending on whether there's an env slot or not let mut first_arg_offset = if has_env { 2 } else { 1 }; @@ -1978,16 +2199,16 @@ pub fn create_entry_wrapper(ccx: &CrateContext, vec!( opaque_rust_main, - llvm::LLVMGetParam(llfn, 0), - llvm::LLVMGetParam(llfn, 1) + get_param(llfn, 0), + get_param(llfn, 1) ) }; (start_fn, args) } else { debug!("using user-defined start fn"); let args = vec!( - llvm::LLVMGetParam(llfn, 0 as c_uint), - llvm::LLVMGetParam(llfn, 1 as c_uint) + get_param(llfn, 0 as c_uint), + get_param(llfn, 1 as c_uint) ); (rust_main, args) diff --git a/src/librustc/middle/trans/basic_block.rs b/src/librustc/middle/trans/basic_block.rs index 13b8ed4df6b82..013350717171c 100644 --- a/src/librustc/middle/trans/basic_block.rs +++ b/src/librustc/middle/trans/basic_block.rs @@ -31,7 +31,7 @@ impl BasicBlock { } } - pub fn pred_iter(self) -> Preds { + pub fn pred_iter(self) -> Preds<'static> { self.as_value().user_iter() .filter(|user| user.is_a_terminator_inst()) .map(|user| user.get_parent().unwrap()) diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index db2d17c85db5f..e2ad8b4fd4680 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -19,18 +19,21 @@ use arena::TypedArena; use back::abi; use back::link; +use driver::session; +use llvm::{ValueRef, get_param}; use llvm; -use llvm::ValueRef; use metadata::csearch; use middle::def; use middle::subst; use middle::subst::{Subst, VecPerParamSpace}; +use middle::trans::adt; use middle::trans::base; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::callee; use middle::trans::cleanup; use middle::trans::cleanup::CleanupMethods; +use middle::trans::closure; use middle::trans::common; use middle::trans::common::*; use middle::trans::datum::*; @@ -52,6 +55,7 @@ use util::ppaux::Repr; use std::gc::Gc; use syntax::ast; +use syntax::ast_map; use synabi = syntax::abi; pub struct MethodData { @@ -62,6 +66,10 @@ pub struct MethodData { pub enum CalleeData { Closure(Datum), + // Constructor for enum variant/tuple-like-struct + // i.e. Some, Ok + NamedTupleConstructor(subst::Substs, ty::Disr), + // Represents a (possibly monomorphized) top-level fn item or method // item. Note that this is just the fn-ptr and is not a Rust closure // value (which is a pair). @@ -74,7 +82,7 @@ pub enum CalleeData { pub struct Callee<'a> { pub bcx: &'a Block<'a>, - pub data: CalleeData + pub data: CalleeData, } fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> { @@ -97,12 +105,18 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> { match ty::get(datum.ty).sty { ty::ty_bare_fn(..) => { let llval = datum.to_llscalarish(bcx); - return Callee {bcx: bcx, data: Fn(llval)}; + return Callee { + bcx: bcx, + data: Fn(llval), + }; } ty::ty_closure(..) => { let datum = unpack_datum!( bcx, datum.to_lvalue_datum(bcx, "callee", expr.id)); - return Callee {bcx: bcx, data: Closure(datum)}; + return Callee { + bcx: bcx, + data: Closure(datum), + }; } _ => { bcx.tcx().sess.span_bug( @@ -115,7 +129,10 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> { } fn fn_callee<'a>(bcx: &'a Block<'a>, llfn: ValueRef) -> Callee<'a> { - return Callee {bcx: bcx, data: Fn(llfn)}; + return Callee { + bcx: bcx, + data: Fn(llfn), + }; } fn trans_def<'a>(bcx: &'a Block<'a>, def: def::Def, ref_expr: &ast::Expr) @@ -123,6 +140,23 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> { debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx())); let expr_ty = node_id_type(bcx, ref_expr.id); match def { + def::DefFn(did, _) if { + let def_id = if did.krate != ast::LOCAL_CRATE { + inline::maybe_instantiate_inline(bcx.ccx(), did) + } else { + did + }; + match bcx.tcx().map.find(def_id.node) { + Some(ast_map::NodeStructCtor(_)) => true, + _ => false + } + } => { + let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + Callee { + bcx: bcx, + data: NamedTupleConstructor(substs, 0) + } + } def::DefFn(did, _) if match ty::get(expr_ty).sty { ty::ty_bare_fn(ref f) => f.abi == synabi::RustIntrinsic, _ => false @@ -147,14 +181,23 @@ fn trans<'a>(bcx: &'a Block<'a>, expr: &ast::Expr) -> Callee<'a> { ref_expr.id)) } def::DefVariant(tid, vid, _) => { - // nullary variants are not callable - assert!(ty::enum_variant_with_id(bcx.tcx(), - tid, - vid).args.len() > 0u); - fn_callee(bcx, trans_fn_ref(bcx, vid, ExprId(ref_expr.id))) + let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid); + let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + + // Nullary variants are not callable + assert!(vinfo.args.len() > 0u); + + Callee { + bcx: bcx, + data: NamedTupleConstructor(substs, vinfo.disr_val) + } } - def::DefStruct(def_id) => { - fn_callee(bcx, trans_fn_ref(bcx, def_id, ExprId(ref_expr.id))) + def::DefStruct(_) => { + let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + Callee { + bcx: bcx, + data: NamedTupleConstructor(substs, 0) + } } def::DefStatic(..) | def::DefArg(..) | @@ -206,9 +249,14 @@ fn trans_fn_ref_with_vtables_to_callee<'a>(bcx: &'a Block<'a>, substs: subst::Substs, vtables: typeck::vtable_res) -> Callee<'a> { - Callee {bcx: bcx, - data: Fn(trans_fn_ref_with_vtables(bcx, def_id, ExprId(ref_id), - substs, vtables))} + Callee { + bcx: bcx, + data: Fn(trans_fn_ref_with_vtables(bcx, + def_id, + ExprId(ref_id), + substs, + vtables)), + } } fn resolve_default_method_vtables(bcx: &Block, @@ -304,9 +352,7 @@ pub fn trans_unboxing_shim(bcx: &Block, let boxed_self_kind = arg_kind(&fcx, boxed_self_type); // Create a datum for self. - let llboxedself = unsafe { - llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(0) as u32) - }; + let llboxedself = get_param(fcx.llfn, fcx.arg_pos(0) as u32); let llboxedself = Datum::new(llboxedself, boxed_self_type, boxed_self_kind); @@ -340,9 +386,7 @@ pub fn trans_unboxing_shim(bcx: &Block, // Now call the function. let mut llshimmedargs = vec!(llself.val); for i in range(1, arg_types.len()) { - llshimmedargs.push(unsafe { - llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as u32) - }); + llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32)); } bcx = trans_call_inner(bcx, None, @@ -402,9 +446,6 @@ pub fn trans_fn_ref_with_vtables( assert!(substs.types.all(|t| !ty::type_needs_infer(*t))); - // Polytype of the function item (may have type params) - let fn_tpt = ty::lookup_item_type(tcx, def_id); - // Load the info for the appropriate trait if necessary. match ty::trait_of_method(tcx, def_id) { None => {} @@ -465,6 +506,12 @@ pub fn trans_fn_ref_with_vtables( } }; + // If this is an unboxed closure, redirect to it. + match closure::get_or_create_declaration_if_unboxed_closure(ccx, def_id) { + None => {} + Some(llfn) => return llfn, + } + // Check whether this fn has an inlined copy and, if so, redirect // def_id to the local id of the inlined copy. let def_id = { @@ -475,8 +522,27 @@ pub fn trans_fn_ref_with_vtables( } }; - // We must monomorphise if the fn has type parameters or is a default method. - let must_monomorphise = !substs.types.is_empty() || is_default; + // We must monomorphise if the fn has type parameters, is a default method, + // or is a named tuple constructor. + let must_monomorphise = if !substs.types.is_empty() || is_default { + true + } else if def_id.krate == ast::LOCAL_CRATE { + let map_node = session::expect( + ccx.sess(), + tcx.map.find(def_id.node), + || "local item should be in ast map".to_string()); + + match map_node { + ast_map::NodeVariant(v) => match v.node.kind { + ast::TupleVariantKind(ref args) => args.len() > 0, + _ => false + }, + ast_map::NodeStructCtor(_) => true, + _ => false + } + } else { + false + }; // Create a monomorphic version of generic functions if must_monomorphise { @@ -509,6 +575,9 @@ pub fn trans_fn_ref_with_vtables( return val; } + // Polytype of the function item (may have type params) + let fn_tpt = ty::lookup_item_type(tcx, def_id); + // Find the actual function pointer. let mut val = { if def_id.krate == ast::LOCAL_CRATE { @@ -546,7 +615,10 @@ pub fn trans_fn_ref_with_vtables( let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty); let llptrty = llty.ptr_to(); if val_ty(val) != llptrty { + debug!("trans_fn_ref_with_vtables(): casting pointer!"); val = BitCast(bcx, val, llptrty); + } else { + debug!("trans_fn_ref_with_vtables(): not casting pointer!"); } val @@ -660,7 +732,7 @@ pub fn trans_call_inner<'a>( let (abi, ret_ty) = match ty::get(callee_ty).sty { ty::ty_bare_fn(ref f) => (f.abi, f.sig.output), - ty::ty_closure(ref f) => (synabi::Rust, f.sig.output), + ty::ty_closure(ref f) => (f.abi, f.sig.output), _ => fail!("expected bare rust fn or closure in trans_call_inner") }; @@ -689,6 +761,14 @@ pub fn trans_call_inner<'a>( arg_cleanup_scope, args, dest.unwrap(), substs); } + NamedTupleConstructor(substs, disr) => { + assert!(dest.is_some()); + fcx.pop_custom_cleanup_scope(arg_cleanup_scope); + + let ctor_ty = callee_ty.subst(bcx.tcx(), &substs); + return base::trans_named_tuple_constructor(bcx, ctor_ty, disr, + args, dest.unwrap()); + } }; // Intrinsics should not become actual functions. @@ -723,7 +803,7 @@ pub fn trans_call_inner<'a>( // and done, either the return value of the function will have been // written in opt_llretslot (if it is Some) or `llresult` will be // set appropriately (otherwise). - if abi == synabi::Rust { + if abi == synabi::Rust || abi == synabi::RustCall { let mut llargs = Vec::new(); // Push the out-pointer if we use an out-pointer for this @@ -742,9 +822,13 @@ pub fn trans_call_inner<'a>( } // Push the arguments. - bcx = trans_args(bcx, args, callee_ty, &mut llargs, + bcx = trans_args(bcx, + args, + callee_ty, + &mut llargs, cleanup::CustomScope(arg_cleanup_scope), - llself.is_some()); + llself.is_some(), + abi); fcx.pop_custom_cleanup_scope(arg_cleanup_scope); @@ -779,8 +863,13 @@ pub fn trans_call_inner<'a>( ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, &**x)).collect(), _ => fail!("expected arg exprs.") }; - bcx = trans_args(bcx, args, callee_ty, &mut llargs, - cleanup::CustomScope(arg_cleanup_scope), false); + bcx = trans_args(bcx, + args, + callee_ty, + &mut llargs, + cleanup::CustomScope(arg_cleanup_scope), + false, + abi); fcx.pop_custom_cleanup_scope(arg_cleanup_scope); bcx = foreign::trans_native_call(bcx, callee_ty, llfn, opt_llretslot.unwrap(), @@ -821,15 +910,130 @@ pub enum CallArgs<'a> { // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of // the right-hand-side (if any). ArgOverloadedOp(Datum, Option<(Datum, ast::NodeId)>), + + // Supply value of arguments as a list of expressions that must be + // translated, for overloaded call operators. + ArgOverloadedCall(&'a [Gc]), } -pub fn trans_args<'a>(cx: &'a Block<'a>, - args: CallArgs, - fn_ty: ty::t, - llargs: &mut Vec , - arg_cleanup_scope: cleanup::ScopeId, - ignore_self: bool) - -> &'a Block<'a> { +fn trans_args_under_call_abi<'a>( + mut bcx: &'a Block<'a>, + arg_exprs: &[Gc], + fn_ty: ty::t, + llargs: &mut Vec, + arg_cleanup_scope: cleanup::ScopeId, + ignore_self: bool) + -> &'a Block<'a> { + // Translate the `self` argument first. + let arg_tys = ty::ty_fn_args(fn_ty); + if !ignore_self { + let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0])); + llargs.push(unpack_result!(bcx, { + trans_arg_datum(bcx, + *arg_tys.get(0), + arg_datum, + arg_cleanup_scope, + DontAutorefArg) + })) + } + + // Now untuple the rest of the arguments. + let tuple_expr = arg_exprs[1]; + let tuple_type = node_id_type(bcx, tuple_expr.id); + + match ty::get(tuple_type).sty { + ty::ty_tup(ref field_types) => { + let tuple_datum = unpack_datum!(bcx, + expr::trans(bcx, &*tuple_expr)); + let tuple_lvalue_datum = + unpack_datum!(bcx, + tuple_datum.to_lvalue_datum(bcx, + "args", + tuple_expr.id)); + let repr = adt::represent_type(bcx.ccx(), tuple_type); + let repr_ptr = &*repr; + for i in range(0, field_types.len()) { + let arg_datum = tuple_lvalue_datum.get_element( + *field_types.get(i), + |srcval| { + adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i) + }); + let arg_datum = arg_datum.to_expr_datum(); + let arg_datum = + unpack_datum!(bcx, arg_datum.to_rvalue_datum(bcx, "arg")); + let arg_datum = + unpack_datum!(bcx, arg_datum.to_appropriate_datum(bcx)); + llargs.push(arg_datum.add_clean(bcx.fcx, arg_cleanup_scope)); + } + } + ty::ty_nil => {} + _ => { + bcx.sess().span_bug(tuple_expr.span, + "argument to `.call()` wasn't a tuple?!") + } + }; + + bcx +} + +fn trans_overloaded_call_args<'a>( + mut bcx: &'a Block<'a>, + arg_exprs: &[Gc], + fn_ty: ty::t, + llargs: &mut Vec, + arg_cleanup_scope: cleanup::ScopeId, + ignore_self: bool) + -> &'a Block<'a> { + // Translate the `self` argument first. + let arg_tys = ty::ty_fn_args(fn_ty); + if !ignore_self { + let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0])); + llargs.push(unpack_result!(bcx, { + trans_arg_datum(bcx, + *arg_tys.get(0), + arg_datum, + arg_cleanup_scope, + DontAutorefArg) + })) + } + + // Now untuple the rest of the arguments. + let tuple_type = *arg_tys.get(1); + match ty::get(tuple_type).sty { + ty::ty_tup(ref field_types) => { + for (i, &field_type) in field_types.iter().enumerate() { + let arg_datum = + unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[i + 1])); + llargs.push(unpack_result!(bcx, { + trans_arg_datum(bcx, + field_type, + arg_datum, + arg_cleanup_scope, + DontAutorefArg) + })) + } + } + ty::ty_nil => {} + _ => { + bcx.sess().span_bug(arg_exprs[0].span, + "argument to `.call()` wasn't a tuple?!") + } + }; + + bcx +} + +pub fn trans_args<'a>( + cx: &'a Block<'a>, + args: CallArgs, + fn_ty: ty::t, + llargs: &mut Vec , + arg_cleanup_scope: cleanup::ScopeId, + ignore_self: bool, + abi: synabi::Abi) + -> &'a Block<'a> { + debug!("trans_args(abi={})", abi); + let _icx = push_ctxt("trans_args"); let arg_tys = ty::ty_fn_args(fn_ty); let variadic = ty::fn_is_variadic(fn_ty); @@ -841,6 +1045,17 @@ pub fn trans_args<'a>(cx: &'a Block<'a>, // to cast her view of the arguments to the caller's view. match args { ArgExprs(arg_exprs) => { + if abi == synabi::RustCall { + // This is only used for direct calls to the `call`, + // `call_mut` or `call_once` functions. + return trans_args_under_call_abi(cx, + arg_exprs, + fn_ty, + llargs, + arg_cleanup_scope, + ignore_self) + } + let num_formal_args = arg_tys.len(); for (i, arg_expr) in arg_exprs.iter().enumerate() { if i == 0 && ignore_self { @@ -861,6 +1076,14 @@ pub fn trans_args<'a>(cx: &'a Block<'a>, })); } } + ArgOverloadedCall(arg_exprs) => { + return trans_overloaded_call_args(cx, + arg_exprs, + fn_ty, + llargs, + arg_cleanup_scope, + ignore_self) + } ArgOverloadedOp(lhs, rhs) => { assert!(!variadic); diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index f2400f6bfefe3..ed6050b6543bc 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -16,6 +16,7 @@ use llvm::ValueRef; use middle::def; use middle::freevars; use middle::lang_items::ClosureExchangeMallocFnLangItem; +use middle::trans::adt; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::common::*; @@ -31,6 +32,7 @@ use util::ppaux::ty_to_string; use arena::TypedArena; use syntax::ast; +use syntax::ast_util; // ___Good to know (tm)__________________________________________________ // @@ -285,7 +287,6 @@ fn load_environment<'a>(bcx: &'a Block<'a>, let def_id = freevar.def.def_id(); bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvarptr); - for &env_pointer_alloca in env_pointer_alloca.iter() { debuginfo::create_captured_var_metadata( bcx, @@ -303,6 +304,26 @@ fn load_environment<'a>(bcx: &'a Block<'a>, bcx } +fn load_unboxed_closure_environment<'a>( + bcx: &'a Block<'a>, + freevars: &Vec) + -> &'a Block<'a> { + let _icx = push_ctxt("closure::load_environment"); + + if freevars.len() == 0 { + return bcx + } + + let llenv = bcx.fcx.llenv.unwrap(); + for (i, freevar) in freevars.iter().enumerate() { + let upvar_ptr = GEPi(bcx, llenv, [0, i]); + let def_id = freevar.def.def_id(); + bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr); + } + + bcx +} + fn fill_fn_pair(bcx: &Block, pair: ValueRef, llfn: ValueRef, llenvptr: ValueRef) { Store(bcx, llfn, GEPi(bcx, pair, [0u, abi::fn_field_code])); let llenvptr = PointerCast(bcx, llenvptr, Type::i8p(bcx.ccx())); @@ -352,20 +373,149 @@ pub fn trans_expr_fn<'a>( let freevar_mode = freevars::get_capture_mode(tcx, id); let freevars: Vec = - freevars::with_freevars( - tcx, id, - |fv| fv.iter().map(|&fv| fv).collect()); - - let ClosureResult {llbox, cdata_ty, bcx} = - build_closure(bcx, freevar_mode, &freevars, store); - trans_closure(ccx, decl, body, llfn, - bcx.fcx.param_substs, id, - [], ty::ty_fn_ret(fty), + freevars::with_freevars(tcx, + id, + |fv| fv.iter().map(|&fv| fv).collect()); + + let ClosureResult { + llbox, + cdata_ty, + bcx + } = build_closure(bcx, freevar_mode, &freevars, store); + trans_closure(ccx, + decl, + body, + llfn, + bcx.fcx.param_substs, + id, + [], + ty::ty_fn_args(fty), + ty::ty_fn_ret(fty), + ty::ty_fn_abi(fty), + true, + NotUnboxedClosure, |bcx| load_environment(bcx, cdata_ty, &freevars, store)); fill_fn_pair(bcx, dest_addr, llfn, llbox); bcx } +/// Returns the LLVM function declaration for an unboxed closure, creating it +/// if necessary. If the ID does not correspond to a closure ID, returns None. +pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext, + closure_id: ast::DefId) + -> Option { + if !ccx.tcx.unboxed_closure_types.borrow().contains_key(&closure_id) { + // Not an unboxed closure. + return None + } + + match ccx.unboxed_closure_vals.borrow().find(&closure_id) { + Some(llfn) => { + debug!("get_or_create_declaration_if_unboxed_closure(): found \ + closure"); + return Some(*llfn) + } + None => {} + } + + let function_type = ty::mk_unboxed_closure(&ccx.tcx, closure_id); + let symbol = ccx.tcx.map.with_path(closure_id.node, |path| { + mangle_internal_name_by_path_and_seq(path, "unboxed_closure") + }); + + let llfn = decl_internal_rust_fn(ccx, function_type, symbol.as_slice()); + + // set an inline hint for all closures + set_inline_hint(llfn); + + debug!("get_or_create_declaration_if_unboxed_closure(): inserting new \ + closure {} (type {})", + closure_id, + ccx.tn.type_to_string(val_ty(llfn))); + ccx.unboxed_closure_vals.borrow_mut().insert(closure_id, llfn); + + Some(llfn) +} + +pub fn trans_unboxed_closure<'a>( + mut bcx: &'a Block<'a>, + decl: &ast::FnDecl, + body: &ast::Block, + id: ast::NodeId, + dest: expr::Dest) + -> &'a Block<'a> { + let _icx = push_ctxt("closure::trans_unboxed_closure"); + + debug!("trans_unboxed_closure()"); + + let closure_id = ast_util::local_def(id); + let llfn = get_or_create_declaration_if_unboxed_closure( + bcx.ccx(), + closure_id).unwrap(); + + // Untuple the arguments. + let unboxed_closure_types = bcx.tcx().unboxed_closure_types.borrow(); + let /*mut*/ function_type = (*unboxed_closure_types.get(&closure_id)).clone(); + /*function_type.sig.inputs = + match ty::get(*function_type.sig.inputs.get(0)).sty { + ty::ty_tup(ref tuple_types) => { + tuple_types.iter().map(|x| (*x).clone()).collect() + } + _ => { + bcx.tcx().sess.span_bug(body.span, + "unboxed closure wasn't a tuple?!") + } + };*/ + let function_type = ty::mk_closure(bcx.tcx(), function_type); + + let freevars: Vec = + freevars::with_freevars(bcx.tcx(), + id, + |fv| fv.iter().map(|&fv| fv).collect()); + let freevars_ptr = &freevars; + + trans_closure(bcx.ccx(), + decl, + body, + llfn, + bcx.fcx.param_substs, + id, + [], + ty::ty_fn_args(function_type), + ty::ty_fn_ret(function_type), + ty::ty_fn_abi(function_type), + true, + IsUnboxedClosure, + |bcx| load_unboxed_closure_environment(bcx, freevars_ptr)); + + // Don't hoist this to the top of the function. It's perfectly legitimate + // to have a zero-size unboxed closure (in which case dest will be + // `Ignore`) and we must still generate the closure body. + let dest_addr = match dest { + expr::SaveIn(p) => p, + expr::Ignore => { + debug!("trans_unboxed_closure() ignoring result"); + return bcx + } + }; + + let repr = adt::represent_type(bcx.ccx(), node_id_type(bcx, id)); + + // Create the closure. + for freevar in freevars_ptr.iter() { + let datum = expr::trans_local_var(bcx, freevar.def); + let upvar_slot_dest = adt::trans_field_ptr(bcx, + &*repr, + dest_addr, + 0, + 0); + bcx = datum.store_to(bcx, upvar_slot_dest); + } + adt::trans_set_discr(bcx, &*repr, dest_addr, 0); + + bcx +} + pub fn get_wrapper_for_bare_fn(ccx: &CrateContext, closure_ty: ty::t, def: def::Def, diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 945185f595342..320e291e92865 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -71,7 +71,8 @@ pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool { } match ty::get(ty).sty { ty::ty_bot => true, - ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) => { + ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) | + ty::ty_unboxed_closure(..) => { let llty = sizing_type_of(ccx, ty); llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type) } @@ -632,12 +633,6 @@ pub fn C_bytes(ccx: &CrateContext, bytes: &[u8]) -> ValueRef { } } -pub fn get_param(fndecl: ValueRef, param: uint) -> ValueRef { - unsafe { - llvm::LLVMGetParam(fndecl, param as c_uint) - } -} - pub fn const_get_elt(cx: &CrateContext, v: ValueRef, us: &[c_uint]) -> ValueRef { unsafe { @@ -792,6 +787,9 @@ pub fn resolve_vtable_under_param_substs(tcx: &ty::ctxt, typeck::vtable_param(n_param, n_bound) => { find_vtable(tcx, param_substs, n_param, n_bound) } + typeck::vtable_unboxed_closure(def_id) => { + typeck::vtable_unboxed_closure(def_id) + } typeck::vtable_error => typeck::vtable_error } } diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 8c55f33a0d46d..be39d435ee458 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -117,6 +117,10 @@ pub struct CrateContext { pub int_type: Type, pub opaque_vec_type: Type, pub builder: BuilderRef_res, + + /// Holds the LLVM values for closure IDs. + pub unboxed_closure_vals: RefCell>, + /// Set when at least one function uses GC. Needed so that /// decl_gc_metadata knows whether to link to the module metadata, which /// is not emitted by LLVM's GC pass when no functions use GC. @@ -225,6 +229,7 @@ impl CrateContext { int_type: Type::from_ref(ptr::mut_null()), opaque_vec_type: Type::from_ref(ptr::mut_null()), builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), + unboxed_closure_vals: RefCell::new(DefIdMap::new()), uses_gc: false, dbg_cx: dbg_cx, eh_personality: RefCell::new(None), diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 6e81c10c4a0a9..47e941755460f 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -207,6 +207,7 @@ use std::rc::{Rc, Weak}; use syntax::util::interner::Interner; use syntax::codemap::{Span, Pos}; use syntax::{abi, ast, codemap, ast_util, ast_map}; +use syntax::ast_util::PostExpansionMethod; use syntax::owned_slice::OwnedSlice; use syntax::parse::token; use syntax::parse::token::special_idents; @@ -451,7 +452,8 @@ impl TypeMap { onceness, store, ref bounds, - ref sig }) => { + ref sig, + abi: _ }) => { if fn_style == ast::UnsafeFn { unique_type_id.push_str("unsafe "); } @@ -798,15 +800,16 @@ pub fn create_global_var_metadata(cx: &CrateContext, var_item).as_slice()) }; - let filename = span_start(cx, span).file.name.clone(); - let file_metadata = file_metadata(cx, filename.as_slice()); + let (file_metadata, line_number) = if span != codemap::DUMMY_SP { + let loc = span_start(cx, span); + (file_metadata(cx, loc.file.name.as_slice()), loc.line as c_uint) + } else { + (UNKNOWN_FILE_METADATA, UNKNOWN_LINE_NUMBER) + }; let is_local_to_unit = is_node_local_to_unit(cx, node_id); - let loc = span_start(cx, span); - let variable_type = ty::node_id_to_type(cx.tcx(), node_id); let type_metadata = type_metadata(cx, variable_type, span); - let namespace_node = namespace_for_item(cx, ast_util::local_def(node_id)); let var_name = token::get_ident(ident).get().to_string(); let linkage_name = @@ -821,7 +824,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, var_name, linkage_name, file_metadata, - loc.line as c_uint, + line_number, type_metadata, is_local_to_unit, global, @@ -1138,17 +1141,18 @@ pub fn create_function_debug_context(cx: &CrateContext, } } ast_map::NodeMethod(ref method) => { - (ast_util::method_ident(&**method), - ast_util::method_fn_decl(&**method), - ast_util::method_generics(&**method), - ast_util::method_body(&**method), + (method.pe_ident(), + method.pe_fn_decl(), + method.pe_generics(), + method.pe_body(), method.span, true) } ast_map::NodeExpr(ref expr) => { match expr.node { ast::ExprFnBlock(fn_decl, top_level_block) | - ast::ExprProc(fn_decl, top_level_block) => { + ast::ExprProc(fn_decl, top_level_block) | + ast::ExprUnboxedFn(fn_decl, top_level_block) => { let name = format!("fn{}", token::gensym("fn")); let name = token::str_to_ident(name.as_slice()); (name, fn_decl, @@ -1167,10 +1171,10 @@ pub fn create_function_debug_context(cx: &CrateContext, ast_map::NodeTraitMethod(ref trait_method) => { match **trait_method { ast::Provided(ref method) => { - (ast_util::method_ident(&**method), - ast_util::method_fn_decl(&**method), - ast_util::method_generics(&**method), - ast_util::method_body(&**method), + (method.pe_ident(), + method.pe_fn_decl(), + method.pe_generics(), + method.pe_body(), method.span, true) } @@ -3600,7 +3604,8 @@ fn populate_scope_map(cx: &CrateContext, } ast::ExprFnBlock(ref decl, ref block) | - ast::ExprProc(ref decl, ref block) => { + ast::ExprProc(ref decl, ref block) | + ast::ExprUnboxedFn(ref decl, ref block) => { with_new_scope(cx, block.span, scope_stack, @@ -3875,6 +3880,9 @@ fn push_debuginfo_type_name(cx: &CrateContext, push_debuginfo_type_name(cx, sig.output, true, output); } }, + ty::ty_unboxed_closure(_) => { + output.push_str("closure"); + } ty::ty_err | ty::ty_infer(_) | ty::ty_param(_) => { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 60bf80191cb10..68f577faefed0 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -783,12 +783,14 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>, expr_to_string(expr), expr_ty.repr(tcx)); closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest) } + ast::ExprUnboxedFn(decl, body) => { + closure::trans_unboxed_closure(bcx, &*decl, &*body, expr.id, dest) + } ast::ExprCall(ref f, ref args) => { if bcx.tcx().is_method_call(expr.id) { - let callee_datum = unpack_datum!(bcx, trans(bcx, &**f)); trans_overloaded_call(bcx, expr, - callee_datum, + *f, args.as_slice(), Some(dest)) } else { @@ -874,8 +876,8 @@ fn trans_def_dps_unadjusted<'a>( // Nullary variant. let ty = expr_ty(bcx, ref_expr); let repr = adt::represent_type(bcx.ccx(), ty); - adt::trans_start_init(bcx, &*repr, lldest, - variant_info.disr_val); + adt::trans_set_discr(bcx, &*repr, lldest, + variant_info.disr_val); return bcx; } } @@ -884,7 +886,7 @@ fn trans_def_dps_unadjusted<'a>( match ty::get(ty).sty { ty::ty_struct(did, _) if ty::has_dtor(bcx.tcx(), did) => { let repr = adt::represent_type(bcx.ccx(), ty); - adt::trans_start_init(bcx, &*repr, lldest, 0); + adt::trans_set_discr(bcx, &*repr, lldest, 0); } _ => {} } @@ -1096,7 +1098,7 @@ fn trans_rec_or_struct<'a>( * Note that `fields` may be empty; the base expression must always be * evaluated for side-effects. */ -struct StructBaseInfo { +pub struct StructBaseInfo { /// The base expression; will be evaluated after all explicit fields. expr: Gc, /// The indices of fields to copy paired with their types. @@ -1112,14 +1114,12 @@ struct StructBaseInfo { * - `optbase` contains information on the base struct (if any) from * which remaining fields are copied; see comments on `StructBaseInfo`. */ -fn trans_adt<'a>( - bcx: &'a Block<'a>, - repr: &adt::Repr, - discr: ty::Disr, - fields: &[(uint, Gc)], - optbase: Option, - dest: Dest) - -> &'a Block<'a> { +pub fn trans_adt<'a>(bcx: &'a Block<'a>, + repr: &adt::Repr, + discr: ty::Disr, + fields: &[(uint, Gc)], + optbase: Option, + dest: Dest) -> &'a Block<'a> { let _icx = push_ctxt("trans_adt"); let fcx = bcx.fcx; let mut bcx = bcx; @@ -1141,8 +1141,6 @@ fn trans_adt<'a>( // failure occur before the ADT as a whole is ready. let custom_cleanup_scope = fcx.push_custom_cleanup_scope(); - adt::trans_start_init(bcx, repr, addr, discr); - for &(i, ref e) in fields.iter() { let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i); let e_ty = expr_ty_adjusted(bcx, &**e); @@ -1164,6 +1162,8 @@ fn trans_adt<'a>( } } + adt::trans_set_discr(bcx, repr, addr, discr); + fcx.pop_custom_cleanup_scope(custom_cleanup_scope); return bcx; @@ -1502,54 +1502,18 @@ fn trans_overloaded_op<'a, 'b>( fn trans_overloaded_call<'a>( mut bcx: &'a Block<'a>, expr: &ast::Expr, - callee: Datum, + callee: Gc, args: &[Gc], dest: Option) -> &'a Block<'a> { - // Evaluate and tuple the arguments. - let tuple_type = ty::mk_tup(bcx.tcx(), - args.iter() - .map(|e| ty::expr_ty_adjusted(bcx.tcx(), &**e)) - .collect()); - let repr = adt::represent_type(bcx.ccx(), tuple_type); - let numbered_fields: Vec<(uint, Gc)> = - args.iter().enumerate().map(|(i, arg)| (i, *arg)).collect(); - let argument_scope = bcx.fcx.push_custom_cleanup_scope(); - let tuple_datum = - unpack_datum!(bcx, - lvalue_scratch_datum(bcx, - tuple_type, - "tupled_arguments", - false, - cleanup::CustomScope( - argument_scope), - (), - |(), bcx, addr| { - trans_adt(bcx, - &*repr, - 0, - numbered_fields.as_slice(), - None, - SaveIn(addr)) - })); - let method_call = MethodCall::expr(expr.id); let method_type = bcx.tcx() .method_map .borrow() .get(&method_call) .ty; - let callee_rvalue = unpack_datum!(bcx, - callee.to_rvalue_datum(bcx, "callee")); - let tuple_datum = tuple_datum.to_expr_datum(); - let tuple_rvalue = unpack_datum!(bcx, - tuple_datum.to_rvalue_datum(bcx, - "tuple")); - let argument_values = [ - callee_rvalue.add_clean(bcx.fcx, - cleanup::CustomScope(argument_scope)), - tuple_rvalue.add_clean(bcx.fcx, cleanup::CustomScope(argument_scope)) - ]; + let mut all_args = vec!(callee); + all_args.push_all(args); unpack_result!(bcx, callee::trans_call_inner(bcx, Some(expr_info(expr)), @@ -1562,10 +1526,9 @@ fn trans_overloaded_call<'a>( None, arg_cleanup_scope) }, - callee::ArgVals(argument_values), + callee::ArgOverloadedCall( + all_args.as_slice()), dest)); - - bcx.fcx.pop_custom_cleanup_scope(argument_scope); bcx } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 56fbccefede5e..d7630d7ec3ab3 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -10,8 +10,8 @@ use back::{link}; +use llvm::{ValueRef, CallConv, Linkage, get_param}; use llvm; -use llvm::{ValueRef, CallConv, Linkage}; use middle::weak_lang_items; use middle::trans::base::push_ctxt; use middle::trans::base; @@ -27,7 +27,7 @@ use middle::ty; use std::cmp; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; -use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, System}; +use syntax::abi::{RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System}; use syntax::codemap::Span; use syntax::parse::token::{InternedString, special_idents}; use syntax::parse::token; @@ -84,6 +84,11 @@ pub fn llvm_calling_convention(ccx: &CrateContext, ccx.sess().unimpl("foreign functions with Rust ABI"); } + RustCall => { + // FIXME(#3678) Implement linking to foreign fns with Rust ABI + ccx.sess().unimpl("foreign functions with RustCall ABI"); + } + // It's the ABI's job to select this, not us. System => ccx.sess().bug("system abi should be selected elsewhere"), @@ -646,7 +651,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext, // If there is an out pointer on the foreign function let foreign_outptr = { if tys.fn_ty.ret_ty.is_indirect() { - Some(llvm::LLVMGetParam(llwrapfn, next_foreign_arg(false))) + Some(get_param(llwrapfn, next_foreign_arg(false))) } else { None } @@ -708,7 +713,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext, // skip padding let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some()); - let mut llforeign_arg = llvm::LLVMGetParam(llwrapfn, foreign_index); + let mut llforeign_arg = get_param(llwrapfn, foreign_index); debug!("llforeign_arg {}{}: {}", "#", i, ccx.tn.val_to_string(llforeign_arg)); diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 40065d0bc5053..7afba95a98b57 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -15,8 +15,8 @@ use back::abi; use back::link::*; +use llvm::{ValueRef, True, get_param}; use llvm; -use llvm::{ValueRef, True}; use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem}; use middle::subst; use middle::trans::adt; @@ -178,33 +178,12 @@ pub fn lazily_emit_visit_glue(ccx: &CrateContext, ti: &tydesc_info) -> ValueRef } // See [Note-arg-mode] -pub fn call_visit_glue(bcx: &Block, v: ValueRef, tydesc: ValueRef, - static_ti: Option<&tydesc_info>) { - let _icx = push_ctxt("call_tydesc_glue_full"); - let ccx = bcx.ccx(); - // NB: Don't short-circuit even if this block is unreachable because - // GC-based cleanup needs to the see that the roots are live. - if bcx.unreachable.get() && !ccx.sess().no_landing_pads() { return; } - - let static_glue_fn = static_ti.map(|sti| lazily_emit_visit_glue(ccx, sti)); - - // When static type info is available, avoid casting to a generic pointer. - let llrawptr = if static_glue_fn.is_none() { - PointerCast(bcx, v, Type::i8p(ccx)) - } else { - v - }; +pub fn call_visit_glue(bcx: &Block, v: ValueRef, tydesc: ValueRef) { + let _icx = push_ctxt("call_visit_glue"); - let llfn = { - match static_glue_fn { - None => { - // Select out the glue function to call from the tydesc - let llfnptr = GEPi(bcx, tydesc, [0u, abi::tydesc_field_visit_glue]); - Load(bcx, llfnptr) - } - Some(sgf) => sgf - } - }; + // Select the glue function to call from the tydesc + let llfn = Load(bcx, GEPi(bcx, tydesc, [0u, abi::tydesc_field_visit_glue])); + let llrawptr = PointerCast(bcx, v, Type::i8p(bcx.ccx())); Call(bcx, llfn, [llrawptr], []); } @@ -353,6 +332,7 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<' } } } + ty::ty_unboxed_closure(..) => iter_structural_ty(bcx, v0, t, drop_ty), ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => { let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]); let env = Load(bcx, box_cell_v); @@ -502,7 +482,7 @@ fn make_generic_glue(ccx: &CrateContext, // llfn is expected be declared to take a parameter of the appropriate // type, so we don't need to explicitly cast the function parameter. - let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, fcx.arg_pos(0) as c_uint) }; + let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint); let bcx = helper(bcx, llrawptr0, t); finish_fn(&fcx, bcx, ty::mk_nil()); diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index d64eeb727e733..bf39f3a6aa385 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -16,7 +16,7 @@ use middle::trans::common::*; use middle::ty; use syntax::ast; -use syntax::ast_util::local_def; +use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::ast_util; pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) @@ -128,12 +128,11 @@ pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) let impl_tpt = ty::lookup_item_type(ccx.tcx(), impl_did); let unparameterized = impl_tpt.generics.types.is_empty() && - ast_util::method_generics(&*mth).ty_params.is_empty(); + mth.pe_generics().ty_params.is_empty(); if unparameterized { let llfn = get_item_val(ccx, mth.id); - trans_fn(ccx, ast_util::method_fn_decl(&*mth), - ast_util::method_body(&*mth), llfn, + trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), llfn, ¶m_substs::empty(), mth.id, []); } local_def(mth.id) diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index bb33a5e4f8d2f..bf8893904caba 100644 --- a/src/librustc/middle/trans/intrinsic.rs +++ b/src/librustc/middle/trans/intrinsic.rs @@ -29,6 +29,7 @@ use middle::trans::machine; use middle::trans::machine::llsize_of; use middle::trans::type_::Type; use middle::ty; +use syntax::abi::RustIntrinsic; use syntax::ast; use syntax::parse::token; use util::ppaux::ty_to_string; @@ -193,8 +194,13 @@ pub fn trans_intrinsic_call<'a>(mut bcx: &'a Block<'a>, node: ast::NodeId, // Push the arguments. let mut llargs = Vec::new(); - bcx = callee::trans_args(bcx, args, callee_ty, &mut llargs, - cleanup::CustomScope(cleanup_scope), false); + bcx = callee::trans_args(bcx, + args, + callee_ty, + &mut llargs, + cleanup::CustomScope(cleanup_scope), + false, + RustIntrinsic); fcx.pop_custom_cleanup_scope(cleanup_scope); @@ -290,7 +296,7 @@ pub fn trans_intrinsic_call<'a>(mut bcx: &'a Block<'a>, node: ast::NodeId, let td = *llargs.get(0); let visitor = *llargs.get(1); let td = PointerCast(bcx, td, ccx.tydesc_type().ptr_to()); - glue::call_visit_glue(bcx, visitor, td, None); + glue::call_visit_glue(bcx, visitor, td); C_nil(ccx) } (_, "offset") => { diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 092a524e48a18..53f89c9d8b879 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -13,6 +13,7 @@ use back::abi; use llvm; use llvm::ValueRef; use metadata::csearch; +use middle::subst::VecPerParamSpace; use middle::subst; use middle::trans::base::*; use middle::trans::build::*; @@ -35,9 +36,10 @@ use util::ppaux::Repr; use std::c_str::ToCStr; use std::gc::Gc; -use syntax::abi::Rust; +use syntax::abi::{Rust, RustCall}; use syntax::parse::token; -use syntax::{ast, ast_map, visit, ast_util}; +use syntax::{ast, ast_map, visit}; +use syntax::ast_util::PostExpansionMethod; /** The main "translation" pass for methods. Generates code @@ -65,11 +67,15 @@ pub fn trans_impl(ccx: &CrateContext, return; } for method in methods.iter() { - if ast_util::method_generics(&**method).ty_params.len() == 0u { + if method.pe_generics().ty_params.len() == 0u { let llfn = get_item_val(ccx, method.id); - trans_fn(ccx, ast_util::method_fn_decl(&**method), - ast_util::method_body(&**method), - llfn, ¶m_substs::empty(), method.id, []); + trans_fn(ccx, + &*method.pe_fn_decl(), + &*method.pe_body(), + llfn, + ¶m_substs::empty(), + method.id, + []); } else { let mut v = TransItemVisitor{ ccx: ccx }; visit::walk_method_helper(&mut v, &**method, ()); @@ -99,10 +105,13 @@ pub fn trans_method_callee<'a>( }; match origin { - typeck::MethodStatic(did) => { + typeck::MethodStatic(did) | + typeck::MethodStaticUnboxedClosure(did) => { Callee { bcx: bcx, - data: Fn(callee::trans_fn_ref(bcx, did, MethodCall(method_call))) + data: Fn(callee::trans_fn_ref(bcx, + did, + MethodCall(method_call))), } } typeck::MethodParam(typeck::MethodParam { @@ -160,7 +169,7 @@ pub fn trans_static_method_callee(bcx: &Block, ast_map::NodeTraitMethod(method) => { let ident = match *method { ast::Required(ref m) => m.ident, - ast::Provided(ref m) => ast_util::method_ident(&**m) + ast::Provided(ref m) => m.pe_ident() }; ident.name } @@ -195,6 +204,9 @@ pub fn trans_static_method_callee(bcx: &Block, let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to(); PointerCast(bcx, llfn, llty) } + typeck::vtable_unboxed_closure(_) => { + bcx.tcx().sess.bug("can't call a closure vtable in a static way"); + } _ => { fail!("vtable_param left in monomorphized \ function's vtable substs"); @@ -220,12 +232,13 @@ fn method_with_name(ccx: &CrateContext, *meth_did } -fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>, - method_call: MethodCall, - trait_id: ast::DefId, - n_method: uint, - vtbl: typeck::vtable_origin) - -> Callee<'a> { +fn trans_monomorphized_callee<'a>( + bcx: &'a Block<'a>, + method_call: MethodCall, + trait_id: ast::DefId, + n_method: uint, + vtbl: typeck::vtable_origin) + -> Callee<'a> { let _icx = push_ctxt("meth::trans_monomorphized_callee"); match vtbl { typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => { @@ -248,6 +261,26 @@ fn trans_monomorphized_callee<'a>(bcx: &'a Block<'a>, Callee { bcx: bcx, data: Fn(llfn) } } + typeck::vtable_unboxed_closure(closure_def_id) => { + // The static region and type parameters are lies, but we're in + // trans so it doesn't matter. + // + // FIXME(pcwalton): Is this true in the case of type parameters? + let callee_substs = get_callee_substitutions_for_unboxed_closure( + bcx, + closure_def_id); + + let llfn = trans_fn_ref_with_vtables(bcx, + closure_def_id, + MethodCall(method_call), + callee_substs, + VecPerParamSpace::empty()); + + Callee { + bcx: bcx, + data: Fn(llfn), + } + } typeck::vtable_param(..) => { bcx.tcx().sess.bug( "vtable_param left in monomorphized function's vtable substs"); @@ -380,8 +413,12 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>, debug!("(translating trait callee) loading method"); // Replace the self type (&Self or Box) with an opaque pointer. let llcallee_ty = match ty::get(callee_ty).sty { - ty::ty_bare_fn(ref f) if f.abi == Rust => { - type_of_rust_fn(ccx, true, f.sig.inputs.slice_from(1), f.sig.output) + ty::ty_bare_fn(ref f) if f.abi == Rust || f.abi == RustCall => { + type_of_rust_fn(ccx, + Some(Type::i8p(ccx)), + f.sig.inputs.slice_from(1), + f.sig.output, + f.abi) } _ => { ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn"); @@ -404,6 +441,26 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>, }; } +/// Creates the self type and (fake) callee substitutions for an unboxed +/// closure with the given def ID. The static region and type parameters are +/// lies, but we're in trans so it doesn't matter. +fn get_callee_substitutions_for_unboxed_closure(bcx: &Block, + def_id: ast::DefId) + -> subst::Substs { + let self_ty = ty::mk_unboxed_closure(bcx.tcx(), def_id); + subst::Substs::erased( + VecPerParamSpace::new(Vec::new(), + vec![ + ty::mk_rptr(bcx.tcx(), + ty::ReStatic, + ty::mt { + ty: self_ty, + mutbl: ast::MutMutable, + }) + ], + Vec::new())) +} + /// Creates a returns a dynamic vtable for the given type and vtable origin. /// This is used only for objects. fn get_vtable(bcx: &Block, @@ -431,6 +488,21 @@ fn get_vtable(bcx: &Block, typeck::vtable_static(id, substs, sub_vtables) => { emit_vtable_methods(bcx, id, substs, sub_vtables).move_iter() } + typeck::vtable_unboxed_closure(closure_def_id) => { + let callee_substs = + get_callee_substitutions_for_unboxed_closure( + bcx, + closure_def_id); + + let llfn = trans_fn_ref_with_vtables( + bcx, + closure_def_id, + ExprId(0), + callee_substs, + VecPerParamSpace::empty()); + + (vec!(llfn)).move_iter() + } _ => ccx.sess().bug("get_vtable: expected a static origin"), } }); @@ -502,15 +574,12 @@ fn emit_vtable_methods(bcx: &Block, ExprId(0), substs.clone(), vtables.clone()); - match m.explicit_self { - ast::SelfValue(_) => { - fn_ref = trans_unboxing_shim(bcx, - fn_ref, - &*m, - m_id, - substs.clone()); - }, - _ => {} + if m.explicit_self == ty::ByValueExplicitSelfCategory { + fn_ref = trans_unboxing_shim(bcx, + fn_ref, + &*m, + m_id, + substs.clone()); } fn_ref } diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 7687e82654a92..dac3b6bd8eee4 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -25,8 +25,7 @@ use util::ppaux::Repr; use syntax::abi; use syntax::ast; use syntax::ast_map; -use syntax::ast_util; -use syntax::ast_util::local_def; +use syntax::ast_util::{local_def, PostExpansionMethod}; use std::hash::{sip, Hash}; pub fn monomorphic_fn(ccx: &CrateContext, @@ -182,8 +181,7 @@ pub fn monomorphic_fn(ccx: &CrateContext, ast_map::NodeMethod(mth) => { let d = mk_lldecl(); set_llvm_fn_attrs(mth.attrs.as_slice(), d); - trans_fn(ccx, ast_util::method_fn_decl(&*mth), - ast_util::method_body(&*mth), d, &psubsts, mth.id, []); + trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d, &psubsts, mth.id, []); d } ast_map::NodeTraitMethod(method) => { @@ -191,8 +189,8 @@ pub fn monomorphic_fn(ccx: &CrateContext, ast::Provided(mth) => { let d = mk_lldecl(); set_llvm_fn_attrs(mth.attrs.as_slice(), d); - trans_fn(ccx, ast_util::method_fn_decl(&*mth), - ast_util::method_body(&*mth), d, &psubsts, mth.id, []); + trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d, + &psubsts, mth.id, []); d } _ => { @@ -256,6 +254,13 @@ pub fn make_vtable_id(_ccx: &CrateContext, } } + &typeck::vtable_unboxed_closure(def_id) => { + MonoId { + def: def_id, + params: subst::VecPerParamSpace::empty(), + } + } + // can't this be checked at the callee? _ => fail!("make_vtable_id needs vtable_static") } diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index bc156fc37917c..7d8700b942609 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -9,8 +9,7 @@ // except according to those terms. use back::link::mangle_internal_name_by_path_and_seq; -use llvm; -use llvm::{ValueRef}; +use llvm::{ValueRef, get_param}; use middle::trans::adt; use middle::trans::base::*; use middle::trans::build::*; @@ -316,14 +315,10 @@ impl<'a, 'b> Reflector<'a, 'b> { None, &arena); let bcx = init_function(&fcx, false, ty::mk_u64()); - let arg = unsafe { - // - // we know the return type of llfdecl is an int here, so - // no need for a special check to see if the return type - // is immediate. - // - llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint) - }; + // we know the return type of llfdecl is an int here, so + // no need for a special check to see if the return type + // is immediate. + let arg = get_param(llfdecl, fcx.arg_pos(0u) as c_uint); let arg = BitCast(bcx, arg, llptrty); let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx))); Store(bcx, ret, fcx.llretptr.get().unwrap()); @@ -366,6 +361,7 @@ impl<'a, 'b> Reflector<'a, 'b> { // Miscellaneous extra types ty::ty_infer(_) => self.leaf("infer"), ty::ty_err => self.leaf("err"), + ty::ty_unboxed_closure(..) => self.leaf("err"), ty::ty_param(ref p) => { let extra = vec!(self.c_uint(p.idx)); self.visit("param", extra.as_slice()) diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index f54ab190d5ef8..94c376c09c86a 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -39,10 +39,56 @@ pub fn type_of_explicit_arg(ccx: &CrateContext, arg_ty: ty::t) -> Type { } } -pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool, - inputs: &[ty::t], output: ty::t) -> Type { +/// Yields the types of the "real" arguments for this function. For most +/// functions, these are simply the types of the arguments. For functions with +/// the `RustCall` ABI, however, this untuples the arguments of the function. +fn untuple_arguments_if_necessary(ccx: &CrateContext, + inputs: &[ty::t], + abi: abi::Abi) + -> Vec { + if abi != abi::RustCall { + return inputs.iter().map(|x| (*x).clone()).collect() + } + + if inputs.len() == 0 { + return Vec::new() + } + + let mut result = Vec::new(); + for (i, &arg_prior_to_tuple) in inputs.iter().enumerate() { + if i < inputs.len() - 1 { + result.push(arg_prior_to_tuple); + } + } + + match ty::get(inputs[inputs.len() - 1]).sty { + ty::ty_tup(ref tupled_arguments) => { + debug!("untuple_arguments_if_necessary(): untupling arguments"); + for &tupled_argument in tupled_arguments.iter() { + result.push(tupled_argument); + } + } + ty::ty_nil => {} + _ => { + ccx.tcx().sess.bug("argument to function with \"rust-call\" ABI \ + is neither a tuple nor unit") + } + } + + result +} + +pub fn type_of_rust_fn(cx: &CrateContext, + llenvironment_type: Option, + inputs: &[ty::t], + output: ty::t, + abi: abi::Abi) + -> Type { let mut atys: Vec = Vec::new(); + // First, munge the inputs, if this has the `rust-call` ABI. + let inputs = untuple_arguments_if_necessary(cx, inputs, abi); + // Arg 0: Output pointer. // (if the output type is non-immediate) let use_out_pointer = return_uses_outptr(cx, output); @@ -52,8 +98,9 @@ pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool, } // Arg 1: Environment - if has_env { - atys.push(Type::i8p(cx)); + match llenvironment_type { + None => {} + Some(llenvironment_type) => atys.push(llenvironment_type), } // ... then explicit args. @@ -72,16 +119,19 @@ pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool, pub fn type_of_fn_from_ty(cx: &CrateContext, fty: ty::t) -> Type { match ty::get(fty).sty { ty::ty_closure(ref f) => { - type_of_rust_fn(cx, true, f.sig.inputs.as_slice(), f.sig.output) + type_of_rust_fn(cx, + Some(Type::i8p(cx)), + f.sig.inputs.as_slice(), + f.sig.output, + f.abi) } ty::ty_bare_fn(ref f) => { - if f.abi == abi::Rust { + if f.abi == abi::Rust || f.abi == abi::RustCall { type_of_rust_fn(cx, - false, + None, f.sig.inputs.as_slice(), - f.sig.output) - } else if f.abi == abi::RustIntrinsic { - cx.sess().bug("type_of_fn_from_ty given intrinsic") + f.sig.output, + f.abi) } else { foreign::lltype_for_foreign_fn(cx, fty) } @@ -142,7 +192,7 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { Type::array(&sizing_type_of(cx, mt.ty), size as u64) } - ty::ty_tup(..) | ty::ty_enum(..) => { + ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_unboxed_closure(..) => { let repr = adt::represent_type(cx, t); adt::sizing_type_of(cx, &*repr) } @@ -223,6 +273,13 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { let name = llvm_type_name(cx, an_enum, did, tps); adt::incomplete_type_of(cx, &*repr, name.as_slice()) } + ty::ty_unboxed_closure(did) => { + // Only create the named struct, but don't fill it in. We + // fill it in *after* placing it into the type cache. + let repr = adt::represent_type(cx, t); + let name = llvm_type_name(cx, an_unboxed_closure, did, []); + adt::incomplete_type_of(cx, &*repr, name.as_slice()) + } ty::ty_box(typ) => { Type::at_box(cx, type_of(cx, typ)).ptr_to() } @@ -299,7 +356,8 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { // If this was an enum or struct, fill in the type now. match ty::get(t).sty { - ty::ty_enum(..) | ty::ty_struct(..) if !ty::type_is_simd(cx.tcx(), t) => { + ty::ty_enum(..) | ty::ty_struct(..) | ty::ty_unboxed_closure(..) + if !ty::type_is_simd(cx.tcx(), t) => { let repr = adt::represent_type(cx, t); adt::finish_type_of(cx, &*repr, &mut llty); } @@ -310,7 +368,11 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { } // Want refinements! (Or case classes, I guess -pub enum named_ty { a_struct, an_enum } +pub enum named_ty { + a_struct, + an_enum, + an_unboxed_closure, +} pub fn llvm_type_name(cx: &CrateContext, what: named_ty, @@ -319,8 +381,9 @@ pub fn llvm_type_name(cx: &CrateContext, -> String { let name = match what { - a_struct => { "struct" } - an_enum => { "enum" } + a_struct => "struct", + an_enum => "enum", + an_unboxed_closure => return "closure".to_string(), }; let base = ty::item_path_str(cx.tcx(), did); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index dc69e3fd6399d..9b55ee657fc00 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -18,7 +18,7 @@ use lint; use middle::const_eval; use middle::def; use middle::dependency_format; -use middle::lang_items::OpaqueStructLangItem; +use middle::lang_items::{FnMutTraitLangItem, OpaqueStructLangItem}; use middle::lang_items::{TyDescStructLangItem, TyVisitorTraitLangItem}; use middle::freevars; use middle::resolve; @@ -85,7 +85,7 @@ pub struct Method { pub ident: ast::Ident, pub generics: ty::Generics, pub fty: BareFnTy, - pub explicit_self: ast::ExplicitSelf_, + pub explicit_self: ExplicitSelfCategory, pub vis: ast::Visibility, pub def_id: ast::DefId, pub container: MethodContainer, @@ -98,7 +98,7 @@ impl Method { pub fn new(ident: ast::Ident, generics: ty::Generics, fty: BareFnTy, - explicit_self: ast::ExplicitSelf_, + explicit_self: ExplicitSelfCategory, vis: ast::Visibility, def_id: ast::DefId, container: MethodContainer, @@ -311,6 +311,9 @@ pub struct ctxt { /// (inferred) variance. pub item_variance_map: RefCell>>, + /// True if the variance has been computed yet; false otherwise. + pub variance_computed: Cell, + /// A mapping from the def ID of an enum or struct type to the def ID /// of the method that implements its destructor. If the type is not /// present in this map, it does not have a destructor. This map is @@ -367,6 +370,10 @@ pub struct ctxt { pub dependency_formats: RefCell, + /// Records the type of each unboxed closure. The def ID is the ID of the + /// expression defining the unboxed closure. + pub unboxed_closure_types: RefCell>, + pub node_lint_levels: RefCell>, @@ -451,6 +458,7 @@ pub struct ClosureTy { pub store: TraitStore, pub bounds: BuiltinBounds, pub sig: FnSig, + pub abi: abi::Abi, } /** @@ -733,6 +741,7 @@ pub enum sty { ty_closure(Box), ty_trait(Box), ty_struct(DefId, Substs), + ty_unboxed_closure(DefId), ty_tup(Vec), ty_param(ParamTy), // type parameter @@ -1051,10 +1060,11 @@ pub fn mk_ctxt(s: Session, region_maps: middle::region::RegionMaps, lang_items: middle::lang_items::LanguageItems, stability: stability::Index) - -> ctxt { + -> ctxt { ctxt { named_region_map: named_region_map, item_variance_map: RefCell::new(DefIdMap::new()), + variance_computed: Cell::new(false), interner: RefCell::new(FnvHashMap::new()), next_id: Cell::new(primitives::LAST_PRIMITIVE_ID), sess: s, @@ -1102,6 +1112,7 @@ pub fn mk_ctxt(s: Session, method_map: RefCell::new(FnvHashMap::new()), vtable_map: RefCell::new(FnvHashMap::new()), dependency_formats: RefCell::new(HashMap::new()), + unboxed_closure_types: RefCell::new(DefIdMap::new()), node_lint_levels: RefCell::new(HashMap::new()), transmute_restrictions: RefCell::new(Vec::new()), stability: RefCell::new(stability) @@ -1160,7 +1171,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { } match &st { &ty_nil | &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) | - &ty_str => {} + &ty_str | &ty_unboxed_closure(_) => {} // You might think that we could just return ty_err for // any type containing ty_err as a component, and get // rid of the has_ty_err flag -- likewise for ty_bot (with @@ -1425,6 +1436,10 @@ pub fn mk_struct(cx: &ctxt, struct_id: ast::DefId, substs: Substs) -> t { mk_t(cx, ty_struct(struct_id, substs)) } +pub fn mk_unboxed_closure(cx: &ctxt, closure_id: ast::DefId) -> t { + mk_t(cx, ty_unboxed_closure(closure_id)) +} + pub fn mk_var(cx: &ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) } pub fn mk_int_var(cx: &ctxt, v: IntVid) -> t { mk_infer(cx, IntVar(v)) } @@ -1455,7 +1470,7 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) { } match get(ty).sty { ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_str | ty_infer(_) | ty_param(_) | ty_err => { + ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_) | ty_err => { } ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f), ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => { @@ -1563,7 +1578,7 @@ pub fn type_is_vec(ty: t) -> bool { pub fn type_is_structural(ty: t) -> bool { match get(ty).sty { ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_closure(_) | - ty_vec(_, Some(_)) => true, + ty_vec(_, Some(_)) | ty_unboxed_closure(_) => true, _ => type_is_slice(ty) | type_is_trait(ty) } } @@ -2034,7 +2049,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { } ty_closure(ref c) => { - closure_contents(cx, *c) + closure_contents(cx, &**c) } ty_box(typ) => { @@ -2078,6 +2093,12 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { apply_lang_items(cx, did, res) } + ty_unboxed_closure(did) => { + let upvars = unboxed_closure_upvars(cx, did); + TypeContents::union(upvars.as_slice(), + |f| tc_ty(cx, f.ty, cache)) + } + ty_tup(ref tys) => { TypeContents::union(tys.as_slice(), |ty| tc_ty(cx, *ty, cache)) @@ -2319,6 +2340,11 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool { r } + ty_unboxed_closure(did) => { + let upvars = unboxed_closure_upvars(cx, did); + upvars.iter().any(|f| type_requires(cx, seen, r_ty, f.ty)) + } + ty_tup(ref ts) => { ts.iter().any(|t| type_requires(cx, seen, r_ty, *t)) } @@ -2423,6 +2449,7 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability { seen.pop(); r } + ty_enum(did, ref substs) => { seen.push(did); let vs = enum_variants(cx, did); @@ -2441,6 +2468,14 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability { r } + ty_unboxed_closure(did) => { + let upvars = unboxed_closure_upvars(cx, did); + find_nonrepresentable(cx, + sp, + seen, + upvars.iter().map(|f| f.ty)) + } + _ => Representable, } } @@ -2651,6 +2686,15 @@ pub fn ty_fn_sig(fty: t) -> FnSig { } } +/// Returns the ABI of the given function. +pub fn ty_fn_abi(fty: t) -> abi::Abi { + match get(fty).sty { + ty_bare_fn(ref f) => f.abi, + ty_closure(ref f) => f.abi, + _ => fail!("ty_fn_abi() called on non-fn type"), + } +} + // Type accessors for substructures of types pub fn ty_fn_args(fty: t) -> Vec { match get(fty).sty { @@ -2665,6 +2709,11 @@ pub fn ty_fn_args(fty: t) -> Vec { pub fn ty_closure_store(fty: t) -> TraitStore { match get(fty).sty { ty_closure(ref f) => f.store, + ty_unboxed_closure(_) => { + // Close enough for the purposes of all the callers of this + // function (which is soon to be deprecated anyhow). + UniqTraitStore + } ref s => { fail!("ty_closure_store() called on non-closure type: {:?}", s) } @@ -2812,11 +2861,14 @@ pub fn adjust_ty(cx: &ctxt, ty::ty_bare_fn(ref b) => { ty::mk_closure( cx, - ty::ClosureTy {fn_style: b.fn_style, - onceness: ast::Many, - store: store, - bounds: ty::all_builtin_bounds(), - sig: b.sig.clone()}) + ty::ClosureTy { + fn_style: b.fn_style, + onceness: ast::Many, + store: store, + bounds: ty::all_builtin_bounds(), + sig: b.sig.clone(), + abi: b.abi, + }) } ref b => { cx.sess.bug( @@ -2986,6 +3038,14 @@ pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin) typeck::MethodStatic(did) => { ty::lookup_item_type(tcx, did).generics.types.clone() } + typeck::MethodStaticUnboxedClosure(_) => { + match tcx.lang_items.require(FnMutTraitLangItem) { + Ok(def_id) => { + lookup_trait_def(tcx, def_id).generics.types.clone() + } + Err(s) => tcx.sess.fatal(s.as_slice()), + } + } typeck::MethodParam(typeck::MethodParam{trait_id: trt_id, method_num: n_mth, ..}) | typeck::MethodObject(typeck::MethodObject{trait_id: trt_id, @@ -3100,6 +3160,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprMatch(..) | ast::ExprFnBlock(..) | ast::ExprProc(..) | + ast::ExprUnboxedFn(..) | ast::ExprBlock(..) | ast::ExprRepeat(..) | ast::ExprVstore(_, ast::ExprVstoreSlice) | @@ -3246,6 +3307,7 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String { ty_struct(id, _) => { format!("struct {}", item_path_str(cx, id)) } + ty_unboxed_closure(_) => "closure".to_string(), ty_tup(_) => "tuple".to_string(), ty_infer(TyVar(_)) => "inferred type".to_string(), ty_infer(IntVar(_)) => "integral variable".to_string(), @@ -3613,7 +3675,8 @@ pub fn ty_to_def_id(ty: t) -> Option { match get(ty).sty { ty_trait(box TyTrait { def_id: id, .. }) | ty_struct(id, _) | - ty_enum(id, _) => Some(id), + ty_enum(id, _) | + ty_unboxed_closure(id) => Some(id), _ => None } } @@ -4042,6 +4105,34 @@ pub fn struct_fields(cx: &ctxt, did: ast::DefId, substs: &Substs) }).collect() } +pub struct UnboxedClosureUpvar { + pub def: def::Def, + pub span: Span, + pub ty: t, +} + +// Returns a list of `UnboxedClosureUpvar`s for each upvar. +pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId) + -> Vec { + if closure_id.krate == ast::LOCAL_CRATE { + match tcx.freevars.borrow().find(&closure_id.node) { + None => tcx.sess.bug("no freevars for unboxed closure?!"), + Some(ref freevars) => { + freevars.iter().map(|freevar| { + let freevar_def_id = freevar.def.def_id(); + UnboxedClosureUpvar { + def: freevar.def, + span: freevar.span, + ty: node_id_to_type(tcx, freevar_def_id.node), + } + }).collect() + } + } + } else { + tcx.sess.bug("unimplemented cross-crate closure upvars") + } +} + pub fn is_binopable(cx: &ctxt, ty: t, op: ast::BinOp) -> bool { static tycat_other: int = 0; static tycat_bool: int = 1; @@ -4619,6 +4710,10 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { } ty_infer(_) => unreachable!(), ty_err => byte!(23), + ty_unboxed_closure(d) => { + byte!(24); + did(&mut state, d); + } } }); @@ -4767,3 +4862,65 @@ impl mc::Typer for ty::ctxt { self.upvar_borrow_map.borrow().get_copy(&upvar_id) } } + +/// The category of explicit self. +#[deriving(Clone, Eq, PartialEq)] +pub enum ExplicitSelfCategory { + StaticExplicitSelfCategory, + ByValueExplicitSelfCategory, + ByReferenceExplicitSelfCategory(Region, ast::Mutability), + ByBoxExplicitSelfCategory, +} + +/// Pushes all the lifetimes in the given type onto the given list. A +/// "lifetime in a type" is a lifetime specified by a reference or a lifetime +/// in a list of type substitutions. This does *not* traverse into nominal +/// types, nor does it resolve fictitious types. +pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, + typ: t) { + walk_ty(typ, |typ| { + match get(typ).sty { + ty_rptr(region, _) => accumulator.push(region), + ty_enum(_, ref substs) | + ty_trait(box TyTrait { + substs: ref substs, + .. + }) | + ty_struct(_, ref substs) => { + match substs.regions { + subst::ErasedRegions => {} + subst::NonerasedRegions(ref regions) => { + for region in regions.iter() { + accumulator.push(*region) + } + } + } + } + ty_closure(ref closure_ty) => { + match closure_ty.store { + RegionTraitStore(region, _) => accumulator.push(region), + UniqTraitStore => {} + } + } + ty_nil | + ty_bot | + ty_bool | + ty_char | + ty_int(_) | + ty_uint(_) | + ty_float(_) | + ty_box(_) | + ty_uniq(_) | + ty_str | + ty_vec(_, _) | + ty_ptr(_) | + ty_bare_fn(_) | + ty_tup(_) | + ty_param(_) | + ty_infer(_) | + ty_unboxed_closure(_) | + ty_err => {} + } + }) +} + diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index c90d9af9b78eb..e2b984959060c 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -220,6 +220,9 @@ impl TypeFoldable for typeck::vtable_origin { typeck::vtable_param(n, b) => { typeck::vtable_param(n, b) } + typeck::vtable_unboxed_closure(def_id) => { + typeck::vtable_unboxed_closure(def_id) + } typeck::vtable_error => { typeck::vtable_error } @@ -326,6 +329,7 @@ pub fn super_fold_closure_ty(this: &mut T, fn_style: fty.fn_style, onceness: fty.onceness, bounds: fty.bounds, + abi: fty.abi, } } @@ -388,6 +392,9 @@ pub fn super_fold_sty(this: &mut T, ty::ty_struct(did, ref substs) => { ty::ty_struct(did, substs.fold_with(this)) } + ty::ty_unboxed_closure(did) => { + ty::ty_unboxed_closure(did) + } ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_str | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | ty::ty_err | ty::ty_infer(_) | diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 5ed92b305be0d..e129492dbc2f8 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -52,13 +52,14 @@ use middle::const_eval; use middle::def; use middle::lang_items::FnMutTraitLangItem; -use rl = middle::resolve_lifetime; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::ty; -use middle::typeck::TypeAndSubsts; -use middle::typeck::lookup_def_tcx; +use middle::ty_fold::TypeFolder; +use middle::typeck::rscope::{ExplicitRscope, ImpliedSingleRscope}; use middle::typeck::rscope::RegionScope; -use middle::typeck::rscope; +use middle::typeck::{TypeAndSubsts, infer, lookup_def_tcx, rscope}; +use middle::typeck; +use rl = middle::resolve_lifetime; use util::ppaux::Repr; use std::rc::Rc; @@ -129,8 +130,8 @@ pub fn opt_ast_region_to_region( match rscope.anon_regions(default_span, 1) { Err(()) => { debug!("optional region in illegal location"); - this.tcx().sess.span_err( - default_span, "missing lifetime specifier"); + span_err!(this.tcx().sess, default_span, E0106, + "missing lifetime specifier"); ty::ReStatic } @@ -187,12 +188,9 @@ fn ast_path_substs( rscope.anon_regions(path.span, expected_num_region_params); if supplied_num_region_params != 0 || anon_regions.is_err() { - tcx.sess.span_err( - path.span, - format!("wrong number of lifetime parameters: \ - expected {} but found {}", - expected_num_region_params, - supplied_num_region_params).as_slice()); + span_err!(tcx.sess, path.span, E0107, + "wrong number of lifetime parameters: expected {} but found {}", + expected_num_region_params, supplied_num_region_params); } match anon_regions { @@ -235,10 +233,10 @@ fn ast_path_substs( if supplied_ty_param_count > required_ty_param_count && !this.tcx().sess.features.default_type_params.get() { - this.tcx().sess.span_err(path.span, "default type parameters are \ - experimental and possibly buggy"); - this.tcx().sess.span_note(path.span, "add #![feature(default_type_params)] \ - to the crate attributes to enable"); + span_err!(this.tcx().sess, path.span, E0108, + "default type parameters are experimental and possibly buggy"); + span_note!(this.tcx().sess, path.span, + "add #![feature(default_type_params)] to the crate attributes to enable"); } let tps = path.segments.iter().flat_map(|s| s.types.iter()) @@ -309,16 +307,14 @@ fn check_path_args(tcx: &ty::ctxt, flags: uint) { if (flags & NO_TPS) != 0u { if !path.segments.iter().all(|s| s.types.is_empty()) { - tcx.sess.span_err( - path.span, + span_err!(tcx.sess, path.span, E0109, "type parameters are not allowed on this type"); } } if (flags & NO_REGIONS) != 0u { if !path.segments.last().unwrap().lifetimes.is_empty() { - tcx.sess.span_err( - path.span, + span_err!(tcx.sess, path.span, E0110, "region parameters are not allowed on this type"); } } @@ -359,8 +355,8 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option { Some(ty::mk_mach_float(ft)) } ast::TyStr => { - tcx.sess.span_err(ast_ty.span, - "bare `str` is not a type"); + span_err!(tcx.sess, ast_ty.span, E0037, + "bare `str` is not a type"); // return /something/ so they can at least get more errors Some(ty::mk_uniq(tcx, ty::mk_str(tcx))) } @@ -408,10 +404,8 @@ pub fn ast_ty_to_builtin_ty 1 { - this.tcx() - .sess - .span_err(path.span, - "`Box` has only one type parameter") + span_err!(this.tcx().sess, path.span, E0047, + "`Box` has only one type parameter"); } for inner_ast_type in path.segments @@ -428,16 +422,12 @@ pub fn ast_ty_to_builtin_ty { - this.tcx() - .sess - .span_err(path.span, - "`Box` is not a type"); + span_err!(this.tcx().sess, path.span, E0111, + "`Box` is not a type"); ty::mk_err() } ty::ty_vec(_, None) => { - this.tcx() - .sess - .span_err(path.span, + span_err!(this.tcx().sess, path.span, E0112, "`Box<[T]>` is not a type"); ty::mk_err() } @@ -445,9 +435,8 @@ pub fn ast_ty_to_builtin_ty`"); + span_err!(this.tcx().sess, path.span, E0113, + "not enough type parameters supplied to `Box`"); Some(ty::mk_err()) } def::DefTy(did) | def::DefStruct(did) @@ -456,10 +445,8 @@ pub fn ast_ty_to_builtin_ty 1 { - this.tcx() - .sess - .span_err(path.span, - "`Gc` has only one type parameter") + span_err!(this.tcx().sess, path.span, E0048, + "`Gc` has only one type parameter"); } for inner_ast_type in path.segments @@ -476,17 +463,13 @@ pub fn ast_ty_to_builtin_ty { - this.tcx() - .sess - .span_err(path.span, - "`Gc` is not a type"); + span_err!(this.tcx().sess, path.span, E0114, + "`Gc` is not a type"); ty::mk_err() } ty::ty_vec(_, None) => { - this.tcx() - .sess - .span_err(path.span, - "`Gc<[T]>` is not a type"); + span_err!(this.tcx().sess, path.span, E0115, + "`Gc<[T]>` is not a type"); ty::mk_err() } _ => ty::mk_box(this.tcx(), typ), @@ -762,6 +745,7 @@ pub fn ast_ty_to_ty( bounds, store, &*f.decl, + abi::Rust, None); ty::mk_closure(tcx, fn_decl) } @@ -780,6 +764,7 @@ pub fn ast_ty_to_ty( bounds, ty::UniqTraitStore, &*f.decl, + abi::Rust, None); ty::mk_closure(tcx, fn_decl) } @@ -879,9 +864,9 @@ pub fn ast_ty_to_ty( } ast::TyInfer => { // TyInfer also appears as the type of arguments or return - // values in a ExprFnBlock or ExprProc, or as the type of - // local variables. Both of these cases are handled specially - // and will not descend into this routine. + // values in a ExprFnBlock, ExprProc, or ExprUnboxedFn, or as + // the type of local variables. Both of these cases are + // handled specially and will not descend into this routine. this.ty_infer(ast_ty.span) } } @@ -900,62 +885,92 @@ pub fn ty_of_arg(this: &AC, rscope: &RS, a: &ast:: } } -struct SelfInfo { +struct SelfInfo<'a> { untransformed_self_ty: ty::t, - explicit_self: ast::ExplicitSelf + explicit_self: ast::ExplicitSelf, } pub fn ty_of_method( - this: &AC, - id: ast::NodeId, - fn_style: ast::FnStyle, - untransformed_self_ty: ty::t, - explicit_self: ast::ExplicitSelf, - decl: &ast::FnDecl) - -> ty::BareFnTy -{ - ty_of_method_or_bare_fn(this, id, fn_style, abi::Rust, Some(SelfInfo { + this: &AC, + id: ast::NodeId, + fn_style: ast::FnStyle, + untransformed_self_ty: ty::t, + explicit_self: ast::ExplicitSelf, + decl: &ast::FnDecl, + abi: abi::Abi) + -> (ty::BareFnTy, ty::ExplicitSelfCategory) { + let self_info = Some(SelfInfo { untransformed_self_ty: untransformed_self_ty, - explicit_self: explicit_self - }), decl) + explicit_self: explicit_self, + }); + let (bare_fn_ty, optional_explicit_self_category) = + ty_of_method_or_bare_fn(this, + id, + fn_style, + abi, + self_info, + decl); + (bare_fn_ty, optional_explicit_self_category.unwrap()) } pub fn ty_of_bare_fn(this: &AC, id: ast::NodeId, fn_style: ast::FnStyle, abi: abi::Abi, decl: &ast::FnDecl) -> ty::BareFnTy { - ty_of_method_or_bare_fn(this, id, fn_style, abi, None, decl) + let (bare_fn_ty, _) = + ty_of_method_or_bare_fn(this, id, fn_style, abi, None, decl); + bare_fn_ty } -fn ty_of_method_or_bare_fn(this: &AC, id: ast::NodeId, - fn_style: ast::FnStyle, abi: abi::Abi, - opt_self_info: Option, - decl: &ast::FnDecl) -> ty::BareFnTy { +fn ty_of_method_or_bare_fn( + this: &AC, + id: ast::NodeId, + fn_style: ast::FnStyle, + abi: abi::Abi, + opt_self_info: Option, + decl: &ast::FnDecl) + -> (ty::BareFnTy, + Option) { debug!("ty_of_method_or_bare_fn"); - // new region names that appear inside of the fn decl are bound to - // that function type + // New region names that appear inside of the arguments of the function + // declaration are bound to that function type. let rb = rscope::BindingRscope::new(id); - let self_ty = opt_self_info.and_then(|self_info| { - match self_info.explicit_self.node { - ast::SelfStatic => None, - ast::SelfValue(_) => { - Some(self_info.untransformed_self_ty) - } - ast::SelfRegion(ref lifetime, mutability, _) => { - let region = - opt_ast_region_to_region(this, &rb, - self_info.explicit_self.span, - lifetime); - Some(ty::mk_rptr(this.tcx(), region, - ty::mt {ty: self_info.untransformed_self_ty, - mutbl: mutability})) - } - ast::SelfUniq(_) => { - Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty)) + // `implied_output_region` is the region that will be assumed for any + // region parameters in the return type. In accordance with the rules for + // lifetime elision, we can determine it in two ways. First (determined + // here), if self is by-reference, then the implied output region is the + // region of the self parameter. + let mut explicit_self_category_result = None; + let (self_ty, mut implied_output_region) = match opt_self_info { + None => (None, None), + Some(self_info) => { + // Figure out and record the explicit self category. + let explicit_self_category = + determine_explicit_self_category(this, &rb, &self_info); + explicit_self_category_result = Some(explicit_self_category); + match explicit_self_category { + ty::StaticExplicitSelfCategory => (None, None), + ty::ByValueExplicitSelfCategory => { + (Some(self_info.untransformed_self_ty), None) + } + ty::ByReferenceExplicitSelfCategory(region, mutability) => { + (Some(ty::mk_rptr(this.tcx(), + region, + ty::mt { + ty: self_info.untransformed_self_ty, + mutbl: mutability + })), + Some(region)) + } + ty::ByBoxExplicitSelfCategory => { + (Some(ty::mk_uniq(this.tcx(), + self_info.untransformed_self_ty)), + None) + } } } - }); + }; // HACK(eddyb) replace the fake self type in the AST with the actual type. let input_tys = if self_ty.is_some() { @@ -964,15 +979,50 @@ fn ty_of_method_or_bare_fn(this: &AC, id: ast::NodeId, decl.inputs.as_slice() }; let input_tys = input_tys.iter().map(|a| ty_of_arg(this, &rb, a, None)); + let self_and_input_tys: Vec<_> = + self_ty.move_iter().chain(input_tys).collect(); + + // Second, if there was exactly one lifetime (either a substitution or a + // reference) in the arguments, then any anonymous regions in the output + // have that lifetime. + if implied_output_region.is_none() { + let mut self_and_input_tys_iter = self_and_input_tys.iter(); + if self_ty.is_some() { + // Skip the first argument if `self` is present. + drop(self_and_input_tys_iter.next()) + } - let self_and_input_tys = self_ty.move_iter().chain(input_tys).collect(); + let mut accumulator = Vec::new(); + for input_type in self_and_input_tys_iter { + ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type) + } + if accumulator.len() == 1 { + implied_output_region = Some(*accumulator.get(0)); + } + } let output_ty = match decl.output.node { ast::TyInfer => this.ty_infer(decl.output.span), - _ => ast_ty_to_ty(this, &rb, &*decl.output) + _ => { + match implied_output_region { + Some(implied_output_region) => { + let rb = ImpliedSingleRscope { + region: implied_output_region, + }; + ast_ty_to_ty(this, &rb, &*decl.output) + } + None => { + // All regions must be explicitly specified in the output + // if the lifetime elision rules do not apply. This saves + // the user from potentially-confusing errors. + let rb = ExplicitRscope; + ast_ty_to_ty(this, &rb, &*decl.output) + } + } + } }; - return ty::BareFnTy { + (ty::BareFnTy { fn_style: fn_style, abi: abi, sig: ty::FnSig { @@ -981,7 +1031,83 @@ fn ty_of_method_or_bare_fn(this: &AC, id: ast::NodeId, output: output_ty, variadic: decl.variadic } - }; + }, explicit_self_category_result) +} + +fn determine_explicit_self_category( + this: &AC, + rscope: &RS, + self_info: &SelfInfo) + -> ty::ExplicitSelfCategory { + match self_info.explicit_self.node { + ast::SelfStatic => ty::StaticExplicitSelfCategory, + ast::SelfValue(_) => ty::ByValueExplicitSelfCategory, + ast::SelfRegion(ref lifetime, mutability, _) => { + let region = + opt_ast_region_to_region(this, + rscope, + self_info.explicit_self.span, + lifetime); + ty::ByReferenceExplicitSelfCategory(region, mutability) + } + ast::SelfUniq(_) => ty::ByBoxExplicitSelfCategory, + ast::SelfExplicit(ast_type, _) => { + let explicit_type = ast_ty_to_ty(this, rscope, &*ast_type); + + { + let inference_context = infer::new_infer_ctxt(this.tcx()); + let expected_self = self_info.untransformed_self_ty; + let actual_self = explicit_type; + let result = infer::mk_eqty( + &inference_context, + false, + infer::Misc(self_info.explicit_self.span), + expected_self, + actual_self); + match result { + Ok(_) => { + inference_context.resolve_regions_and_report_errors(); + return ty::ByValueExplicitSelfCategory + } + Err(_) => {} + } + } + + match ty::get(explicit_type).sty { + ty::ty_rptr(region, tm) => { + typeck::require_same_types( + this.tcx(), + None, + false, + self_info.explicit_self.span, + self_info.untransformed_self_ty, + tm.ty, + || "not a valid type for `self`".to_owned()); + return ty::ByReferenceExplicitSelfCategory(region, + tm.mutbl) + } + ty::ty_uniq(typ) => { + typeck::require_same_types( + this.tcx(), + None, + false, + self_info.explicit_self.span, + self_info.untransformed_self_ty, + typ, + || "not a valid type for `self`".to_owned()); + return ty::ByBoxExplicitSelfCategory + } + _ => { + this.tcx() + .sess + .span_err(self_info.explicit_self.span, + "not a valid type for `self`"); + return ty::ByValueExplicitSelfCategory + } + } + } + } } pub fn ty_of_closure( @@ -992,6 +1118,7 @@ pub fn ty_of_closure( bounds: ty::BuiltinBounds, store: ty::TraitStore, decl: &ast::FnDecl, + abi: abi::Abi, expected_sig: Option) -> ty::ClosureTy { @@ -1026,6 +1153,7 @@ pub fn ty_of_closure( onceness: onceness, store: store, bounds: bounds, + abi: abi, sig: ty::FnSig {binder_id: id, inputs: input_tys, output: output_ty, @@ -1098,3 +1226,4 @@ fn conv_builtin_bounds(tcx: &ty::ctxt, (&None, ty::UniqTraitStore) => ty::empty_builtin_bounds(), } } + diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 4787837093844..1805c18eaf10c 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -87,10 +87,11 @@ use middle::ty; use middle::typeck::astconv::AstConv; use middle::typeck::check::{FnCtxt, PreferMutLvalue, impl_self_ty}; use middle::typeck::check; +use middle::typeck::infer::MiscVariable; use middle::typeck::infer; use middle::typeck::MethodCallee; use middle::typeck::{MethodOrigin, MethodParam}; -use middle::typeck::{MethodStatic, MethodObject}; +use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject}; use middle::typeck::{param_index}; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::TypeAndSubsts; @@ -100,9 +101,7 @@ use util::ppaux::Repr; use std::collections::HashSet; use std::rc::Rc; -use syntax::ast::{DefId, SelfValue, SelfRegion}; -use syntax::ast::{SelfUniq, SelfStatic}; -use syntax::ast::{MutMutable, MutImmutable}; +use syntax::ast::{DefId, MutImmutable, MutMutable}; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token; @@ -267,15 +266,15 @@ fn construct_transformed_self_ty_for_object( obj_substs.types.pop(subst::SelfSpace).unwrap(); match method_ty.explicit_self { - ast::SelfStatic => { + StaticExplicitSelfCategory => { tcx.sess.span_bug(span, "static method for object type receiver"); } - ast::SelfValue(_) => { + ByValueExplicitSelfCategory => { let tr = ty::mk_trait(tcx, trait_def_id, obj_substs, ty::empty_builtin_bounds()); ty::mk_uniq(tcx, tr) } - ast::SelfRegion(..) | ast::SelfUniq(..) => { + ByReferenceExplicitSelfCategory(..) | ByBoxExplicitSelfCategory => { let transformed_self_ty = *method_ty.fty.sig.inputs.get(0); match ty::get(transformed_self_ty).sty { ty::ty_rptr(r, mt) => { // must be SelfRegion @@ -343,7 +342,7 @@ struct Candidate { #[deriving(Clone)] pub enum RcvrMatchCondition { RcvrMatchesIfObject(ast::DefId), - RcvrMatchesIfSubtype(ty::t) + RcvrMatchesIfSubtype(ty::t), } impl<'a> LookupContext<'a> { @@ -443,7 +442,9 @@ impl<'a> LookupContext<'a> { } _ => {} }, - ty_enum(did, _) | ty_struct(did, _) => { + ty_enum(did, _) | + ty_struct(did, _) | + ty_unboxed_closure(did) => { if self.check_traits == CheckTraitsAndInherentMethods { self.push_inherent_impl_candidates_for_type(did); } @@ -467,6 +468,10 @@ impl<'a> LookupContext<'a> { ty_param(p) => { self.push_inherent_candidates_from_param(self_ty, restrict_to, p); } + ty_unboxed_closure(closure_did) => { + self.push_unboxed_closure_call_candidates_if_applicable( + closure_did); + } _ => { /* No bound methods in these types */ } } @@ -499,11 +504,89 @@ impl<'a> LookupContext<'a> { let opt_applicable_traits = self.fcx.ccx.trait_map.find(&expr_id); for applicable_traits in opt_applicable_traits.move_iter() { for trait_did in applicable_traits.iter() { + debug!("push_extension_candidates() found trait: {}", + if trait_did.krate == ast::LOCAL_CRATE { + self.fcx.ccx.tcx.map.node_to_string(trait_did.node) + } else { + "(external)".to_string() + }); self.push_extension_candidate(*trait_did); } } } + fn push_unboxed_closure_call_candidate_if_applicable( + &mut self, + trait_did: DefId, + closure_did: DefId, + closure_function_type: &ClosureTy) { + let method = + ty::trait_methods(self.tcx(), trait_did).get(0).clone(); + + let vcx = self.fcx.vtable_context(); + let region_params = + vec!(vcx.infcx.next_region_var(MiscVariable(self.span))); + + // Get the tupled type of the arguments. + let arguments_type = *closure_function_type.sig.inputs.get(0); + let return_type = closure_function_type.sig.output; + + let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(), + closure_did); + self.extension_candidates.push(Candidate { + rcvr_match_condition: + RcvrMatchesIfSubtype(unboxed_closure_type), + rcvr_substs: subst::Substs::new_trait( + vec![arguments_type, return_type], + region_params, + *vcx.infcx.next_ty_vars(1).get(0)), + method_ty: method, + origin: MethodStaticUnboxedClosure(closure_did), + }); + } + + fn push_unboxed_closure_call_candidates_if_applicable( + &mut self, + closure_did: DefId) { + // FIXME(pcwalton): Try `Fn` and `FnOnce` too. + let trait_did = match self.tcx().lang_items.fn_mut_trait() { + Some(trait_did) => trait_did, + None => return, + }; + + match self.tcx() + .unboxed_closure_types + .borrow() + .find(&closure_did) { + None => {} // Fall through to try inherited. + Some(closure_function_type) => { + self.push_unboxed_closure_call_candidate_if_applicable( + trait_did, + closure_did, + closure_function_type); + return + } + } + + match self.fcx + .inh + .unboxed_closure_types + .borrow() + .find(&closure_did) { + Some(closure_function_type) => { + self.push_unboxed_closure_call_candidate_if_applicable( + trait_did, + closure_did, + closure_function_type); + return + } + None => {} + } + + self.tcx().sess.bug("didn't find unboxed closure type in tcx map or \ + inherited map, so there") + } + fn push_inherent_candidates_from_object(&mut self, did: DefId, substs: &subst::Substs) { @@ -618,7 +701,7 @@ impl<'a> LookupContext<'a> { let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); match trait_methods.iter().position(|m| { - m.explicit_self != ast::SelfStatic && + m.explicit_self != ty::StaticExplicitSelfCategory && m.ident.name == self.m_name }) { Some(pos) => { let method = trait_methods.get(pos).clone(); @@ -928,7 +1011,8 @@ impl<'a> LookupContext<'a> { ty_infer(FloatVar(_)) | ty_param(..) | ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | - ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) | ty_tup(..) | + ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) | + ty_unboxed_closure(..) | ty_tup(..) | ty_str | ty_vec(..) | ty_trait(..) | ty_closure(..) => { self.search_for_some_kind_of_autorefd_method( AutoPtr, autoderefs, [MutImmutable, MutMutable], @@ -1023,7 +1107,10 @@ impl<'a> LookupContext<'a> { if self.report_statics == ReportStaticMethods { // lookup should only be called with ReportStaticMethods if a regular lookup failed - assert!(relevant_candidates.iter().all(|c| c.method_ty.explicit_self == SelfStatic)); + assert!(relevant_candidates.iter() + .all(|c| { + c.method_ty.explicit_self == ty::StaticExplicitSelfCategory + })); self.tcx().sess.fileline_note(self.span, "found defined static methods, maybe a `self` is missing?"); @@ -1100,7 +1187,8 @@ impl<'a> LookupContext<'a> { self.enforce_drop_trait_limitations(candidate); // static methods should never have gotten this far: - assert!(candidate.method_ty.explicit_self != SelfStatic); + assert!(candidate.method_ty.explicit_self != + ty::StaticExplicitSelfCategory); // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh @@ -1210,19 +1298,25 @@ impl<'a> LookupContext<'a> { */ match candidate.origin { - MethodStatic(..) | MethodParam(..) => { + MethodStatic(..) | + MethodParam(..) | + MethodStaticUnboxedClosure(..) => { return; // not a call to a trait instance } MethodObject(..) => {} } match candidate.method_ty.explicit_self { - ast::SelfStatic => { // reason (a) above - span_err!(self.tcx().sess, self.span, E0037, - "cannot call a method without a receiver through an object"); + ty::StaticExplicitSelfCategory => { // reason (a) above + self.tcx().sess.span_err( + self.span, + "cannot call a method without a receiver \ + through an object"); } - ast::SelfValue(_) | ast::SelfRegion(..) | ast::SelfUniq(_) => {} + ty::ByValueExplicitSelfCategory | + ty::ByReferenceExplicitSelfCategory(..) | + ty::ByBoxExplicitSelfCategory => {} } // reason (a) above @@ -1262,6 +1356,7 @@ impl<'a> LookupContext<'a> { MethodStatic(method_id) => { bad = self.tcx().destructors.borrow().contains(&method_id); } + MethodStaticUnboxedClosure(_) => bad = false, // FIXME: does this properly enforce this on everything now // that self has been merged in? -sully MethodParam(MethodParam { trait_id: trait_id, .. }) | @@ -1284,12 +1379,12 @@ impl<'a> LookupContext<'a> { self.ty_to_string(rcvr_ty), candidate.repr(self.tcx())); return match candidate.method_ty.explicit_self { - SelfStatic => { + StaticExplicitSelfCategory => { debug!("(is relevant?) explicit self is static"); self.report_statics == ReportStaticMethods } - SelfValue(_) => { + ByValueExplicitSelfCategory => { debug!("(is relevant?) explicit self is by-value"); match ty::get(rcvr_ty).sty { ty::ty_uniq(typ) => { @@ -1312,7 +1407,7 @@ impl<'a> LookupContext<'a> { } } - SelfRegion(_, m, _) => { + ByReferenceExplicitSelfCategory(_, m) => { debug!("(is relevant?) explicit self is a region"); match ty::get(rcvr_ty).sty { ty::ty_rptr(_, mt) => { @@ -1332,7 +1427,7 @@ impl<'a> LookupContext<'a> { } } - SelfUniq(_) => { + ByBoxExplicitSelfCategory => { debug!("(is relevant?) explicit self is a unique pointer"); match ty::get(rcvr_ty).sty { ty::ty_uniq(typ) => { @@ -1403,6 +1498,9 @@ impl<'a> LookupContext<'a> { }; self.report_static_candidate(idx, did) } + MethodStaticUnboxedClosure(did) => { + self.report_static_candidate(idx, did) + } MethodParam(ref mp) => { self.report_param_candidate(idx, (*mp).trait_id) } @@ -1480,3 +1578,6 @@ impl Repr for RcvrMatchCondition { } } } + + + diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 7441f89ac8a60..557fd522fa918 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -114,7 +114,7 @@ use lint; use util::common::{block_query, indenter, loop_query}; use util::ppaux; use util::ppaux::{UserString, Repr}; -use util::nodemap::{FnvHashMap, NodeMap}; +use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; use std::cell::{Cell, RefCell}; use std::collections::HashMap; @@ -125,7 +125,7 @@ use syntax::abi; use syntax::ast::{Provided, Required}; use syntax::ast; use syntax::ast_map; -use syntax::ast_util::local_def; +use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::ast_util; use syntax::attr; use syntax::codemap::Span; @@ -167,6 +167,7 @@ pub struct Inherited<'a> { method_map: MethodMap, vtable_map: vtable_map, upvar_borrow_map: RefCell, + unboxed_closure_types: RefCell>, } /// When type-checking an expression, we propagate downward @@ -273,6 +274,7 @@ impl<'a> Inherited<'a> { method_map: RefCell::new(FnvHashMap::new()), vtable_map: RefCell::new(FnvHashMap::new()), upvar_borrow_map: RefCell::new(HashMap::new()), + unboxed_closure_types: RefCell::new(DefIdMap::new()), } } } @@ -757,16 +759,19 @@ fn check_method_body(ccx: &CrateCtxt, let method_def_id = local_def(method.id); let method_ty = ty::method(ccx.tcx, method_def_id); let method_generics = &method_ty.generics; - let m_body = ast_util::method_body(&*method); let param_env = ty::construct_parameter_environment(ccx.tcx, method_generics, - m_body.id); + method.pe_body().id); let fty = ty::node_id_to_type(ccx.tcx, method.id); - check_bare_fn(ccx, ast_util::method_fn_decl(&*method), - m_body, method.id, fty, param_env); + check_bare_fn(ccx, + &*method.pe_fn_decl(), + &*method.pe_body(), + method.id, + fty, + param_env); } fn check_impl_methods_against_trait(ccx: &CrateCtxt, @@ -794,7 +799,7 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt, compare_impl_method(ccx.tcx, &*impl_method_ty, impl_method.span, - ast_util::method_body(&**impl_method).id, + impl_method.pe_body().id, &**trait_method_ty, &impl_trait_ref.substs); } @@ -817,7 +822,7 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt, for trait_method in trait_methods.iter() { let is_implemented = impl_methods.iter().any( - |m| ast_util::method_ident(&**m).name == trait_method.ident.name); + |m| m.pe_ident().name == trait_method.ident.name); let is_provided = provided_methods.iter().any( |m| m.ident.name == trait_method.ident.name); @@ -864,19 +869,26 @@ fn compare_impl_method(tcx: &ty::ctxt, // inscrutable, particularly for cases where one method has no // self. match (&trait_m.explicit_self, &impl_m.explicit_self) { - (&ast::SelfStatic, &ast::SelfStatic) => {} - (&ast::SelfStatic, _) => { - span_err!(tcx.sess, impl_m_span, E0047, - "method `{}` has a `{}` declaration in the impl, but not in the trait", - token::get_ident(trait_m.ident), - pprust::explicit_self_to_string(impl_m.explicit_self)); + (&ty::StaticExplicitSelfCategory, + &ty::StaticExplicitSelfCategory) => {} + (&ty::StaticExplicitSelfCategory, _) => { + tcx.sess.span_err( + impl_m_span, + format!("method `{}` has a `{}` declaration in the impl, \ + but not in the trait", + token::get_ident(trait_m.ident), + ppaux::explicit_self_category_to_str( + &impl_m.explicit_self)).as_slice()); return; } - (_, &ast::SelfStatic) => { - span_err!(tcx.sess, impl_m_span, E0048, - "method `{}` has a `{}` declaration in the trait, but not in the impl", - token::get_ident(trait_m.ident), - pprust::explicit_self_to_string(trait_m.explicit_self)); + (_, &ty::StaticExplicitSelfCategory) => { + tcx.sess.span_err( + impl_m_span, + format!("method `{}` has a `{}` declaration in the trait, \ + but not in the impl", + token::get_ident(trait_m.ident), + ppaux::explicit_self_category_to_str( + &trait_m.explicit_self)).as_slice()); return; } _ => { @@ -1241,7 +1253,8 @@ impl<'a> FnCtxt<'a> { pub fn vtable_context<'a>(&'a self) -> VtableContext<'a> { VtableContext { infcx: self.infcx(), - param_env: &self.inh.param_env + param_env: &self.inh.param_env, + unboxed_closure_types: &self.inh.unboxed_closure_types, } } } @@ -1851,7 +1864,8 @@ fn check_argument_types(fcx: &FnCtxt, for (i, arg) in args.iter().take(t).enumerate() { let is_block = match arg.node { ast::ExprFnBlock(..) | - ast::ExprProc(..) => true, + ast::ExprProc(..) | + ast::ExprUnboxedFn(..) => true, _ => false }; @@ -2365,7 +2379,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, if ty::type_is_integral(lhs_t) && ast_util::is_shift_binop(op) { // Shift is a special case: rhs must be uint, no matter what lhs is - check_expr_has_type(fcx, rhs, ty::mk_uint()); + check_expr_has_type(fcx, &*rhs, ty::mk_uint()); fcx.write_ty(expr.id, lhs_t); return; } @@ -2504,6 +2518,47 @@ fn check_expr_with_unifier(fcx: &FnCtxt, }) } + fn check_unboxed_closure(fcx: &FnCtxt, + expr: &ast::Expr, + decl: &ast::FnDecl, + body: ast::P) { + // The `RegionTraitStore` is a lie, but we ignore it so it doesn't + // matter. + // + // FIXME(pcwalton): Refactor this API. + let mut fn_ty = astconv::ty_of_closure( + fcx, + expr.id, + ast::NormalFn, + ast::Many, + ty::empty_builtin_bounds(), + ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable), + decl, + abi::RustCall, + None); + + let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx, + local_def(expr.id)); + fcx.write_ty(expr.id, closure_type); + + check_fn(fcx.ccx, + ast::NormalFn, + &fn_ty.sig, + decl, + expr.id, + &*body, + fcx.inh); + + // Tuple up the arguments and insert the resulting function type into + // the `unboxed_closure_types` table. + fn_ty.sig.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.inputs)]; + + fcx.inh + .unboxed_closure_types + .borrow_mut() + .insert(local_def(expr.id), fn_ty); + } + fn check_expr_fn(fcx: &FnCtxt, expr: &ast::Expr, store: ty::TraitStore, @@ -2567,6 +2622,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, expected_bounds, store, decl, + abi::Rust, expected_sig); let fty_sig = fn_ty.sig.clone(); let fty = ty::mk_closure(tcx, fn_ty); @@ -2583,8 +2639,13 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ty::UniqTraitStore => (ast::NormalFn, expr.id) }; - check_fn(fcx.ccx, inherited_style, &fty_sig, - &*decl, id, &*body, fcx.inh); + check_fn(fcx.ccx, + inherited_style, + &fty_sig, + decl, + id, + &*body, + fcx.inh); } @@ -2952,7 +3013,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, } ast::ExprLit(lit) => { - let typ = check_lit(fcx, lit, expected); + let typ = check_lit(fcx, &*lit, expected); fcx.write_ty(id, typ); } ast::ExprBinary(op, ref lhs, ref rhs) => { @@ -3159,8 +3220,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt, fcx.write_bot(id); } ast::ExprParen(a) => { - check_expr_with_expectation_and_lvalue_pref(fcx, a, expected, lvalue_pref); - fcx.write_ty(id, fcx.expr_ty(a)); + check_expr_with_expectation_and_lvalue_pref(fcx, + &*a, + expected, + lvalue_pref); + fcx.write_ty(id, fcx.expr_ty(&*a)); } ast::ExprAssign(ref lhs, ref rhs) => { check_expr_with_lvalue_pref(fcx, &**lhs, PreferMutLvalue); @@ -3228,6 +3292,12 @@ fn check_expr_with_unifier(fcx: &FnCtxt, body.clone(), expected); } + ast::ExprUnboxedFn(ref decl, ref body) => { + check_unboxed_closure(fcx, + expr, + &**decl, + *body); + } ast::ExprProc(ref decl, ref body) => { check_expr_fn(fcx, expr, @@ -3321,8 +3391,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, Some(ref fs) if i < fs.len() => ExpectHasType(*fs.get(i)), _ => NoExpectation }; - check_expr_with_expectation(fcx, *e, opt_hint); - let t = fcx.expr_ty(*e); + check_expr_with_expectation(fcx, &**e, opt_hint); + let t = fcx.expr_ty(&**e); err_field = err_field || ty::type_is_error(t); bot_field = bot_field || ty::type_is_bot(t); t @@ -3669,8 +3739,8 @@ fn check_block_with_expected(fcx: &FnCtxt, e.span, "unreachable expression".to_string()); } - check_expr_with_expectation(fcx, e, expected); - let ety = fcx.expr_ty(e); + check_expr_with_expectation(fcx, &*e, expected); + let ety = fcx.expr_ty(&*e); fcx.write_ty(blk.id, ety); if any_err { fcx.write_error(blk.id); @@ -4789,3 +4859,4 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { }); } } + diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 180dac5382805..22d52d0b7d2a0 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -587,7 +587,9 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { visit::walk_expr(rcx, expr, ()); } - ast::ExprFnBlock(_, ref body) | ast::ExprProc(_, ref body) => { + ast::ExprFnBlock(_, ref body) | + ast::ExprProc(_, ref body) | + ast::ExprUnboxedFn(_, ref body) => { check_expr_fn_block(rcx, expr, &**body); } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index d2a1ef786bd29..c176054b3aed0 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -15,21 +15,23 @@ use middle::ty_fold::TypeFolder; use middle::typeck::astconv::AstConv; use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{structurally_resolved_type}; +use middle::typeck::check::regionmanip; use middle::typeck::check::writeback; use middle::typeck::infer::fixup_err_to_string; use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; use middle::typeck::infer; -use middle::typeck::{vtable_origin, vtable_res, vtable_param_res}; -use middle::typeck::{vtable_static, vtable_param, vtable_error}; -use middle::typeck::{param_index}; -use middle::typeck::MethodCall; -use middle::typeck::TypeAndSubsts; +use middle::typeck::{MethodCall, TypeAndSubsts}; +use middle::typeck::{param_index, vtable_error, vtable_origin, vtable_param}; +use middle::typeck::{vtable_param_res, vtable_res, vtable_static}; +use middle::typeck::{vtable_unboxed_closure}; use middle::subst; use middle::subst::{Subst, VecPerParamSpace}; use util::common::indenter; +use util::nodemap::DefIdMap; use util::ppaux; use util::ppaux::Repr; +use std::cell::RefCell; use std::rc::Rc; use std::collections::HashSet; use syntax::ast; @@ -69,6 +71,7 @@ use syntax::visit::Visitor; pub struct VtableContext<'a> { pub infcx: &'a infer::InferCtxt<'a>, pub param_env: &'a ty::ParameterEnvironment, + pub unboxed_closure_types: &'a RefCell>, } impl<'a> VtableContext<'a> { @@ -203,11 +206,10 @@ fn relate_trait_refs(vcx: &VtableContext, !ty::trait_ref_contains_error(&r_exp_trait_ref) { let tcx = vcx.tcx(); - tcx.sess.span_err(span, - format!("expected {}, but found {} ({})", - ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref), - ppaux::trait_ref_to_string(tcx, &r_act_trait_ref), - ty::type_err_to_str(tcx, err)).as_slice()); + span_err!(tcx.sess, span, E0095, "expected {}, but found {} ({})", + ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref), + ppaux::trait_ref_to_string(tcx, &r_act_trait_ref), + ty::type_err_to_str(tcx, err)); } } } @@ -248,10 +250,13 @@ fn lookup_vtable(vcx: &VtableContext, ty::ty_param(ParamTy {space, idx: n, ..}) => { let env_bounds = &vcx.param_env.bounds; let type_param_bounds = &env_bounds.get(space, n).trait_bounds; - lookup_vtable_from_bounds(vcx, span, + lookup_vtable_from_bounds(vcx, + span, type_param_bounds.as_slice(), - param_index { space: space, - index: n }, + param_index { + space: space, + index: n, + }, trait_ref.clone()) } @@ -297,6 +302,75 @@ fn lookup_vtable_from_bounds(vcx: &VtableContext, ret } +fn search_for_unboxed_closure_vtable(vcx: &VtableContext, + span: Span, + ty: ty::t, + trait_ref: Rc) + -> Option { + let tcx = vcx.tcx(); + let closure_def_id = match ty::get(ty).sty { + ty::ty_unboxed_closure(closure_def_id) => closure_def_id, + _ => return None, + }; + + let fn_traits = [ + tcx.lang_items.fn_trait(), + tcx.lang_items.fn_mut_trait(), + tcx.lang_items.fn_once_trait() + ]; + for fn_trait in fn_traits.iter() { + match *fn_trait { + Some(ref fn_trait) if *fn_trait == trait_ref.def_id => {} + _ => continue, + }; + + // Check to see whether the argument and return types match. + let unboxed_closure_types = tcx.unboxed_closure_types.borrow(); + let closure_type = match unboxed_closure_types.find(&closure_def_id) { + Some(closure_type) => (*closure_type).clone(), + None => { + // Try the inherited unboxed closure type map. + let unboxed_closure_types = vcx.unboxed_closure_types + .borrow(); + match unboxed_closure_types.find(&closure_def_id) { + Some(closure_type) => (*closure_type).clone(), + None => { + tcx.sess.span_bug(span, + "didn't find unboxed closure type \ + in tcx map or inh map") + } + } + } + }; + + // FIXME(pcwalton): This is a bogus thing to do, but + // it'll do for now until we get the new trait-bound + // region skolemization working. + let (_, new_signature) = + regionmanip::replace_late_bound_regions_in_fn_sig( + tcx, + &closure_type.sig, + |br| { + vcx.infcx.next_region_var(infer::LateBoundRegion(span, + br)) + }); + + let arguments_tuple = *new_signature.inputs.get(0); + let corresponding_trait_ref = Rc::new(ty::TraitRef { + def_id: trait_ref.def_id, + substs: subst::Substs::new_trait( + vec![arguments_tuple, new_signature.output], + Vec::new(), + ty) + }); + + relate_trait_refs(vcx, span, corresponding_trait_ref, trait_ref); + return Some(vtable_unboxed_closure(closure_def_id)) + } + + None +} + fn search_for_vtable(vcx: &VtableContext, span: Span, ty: ty::t, @@ -306,6 +380,18 @@ fn search_for_vtable(vcx: &VtableContext, debug!("nrc - search_for_vtable"); let tcx = vcx.tcx(); + // First, check to see whether this is a call to the `call` method of an + // unboxed closure. If so, and the arguments match, we're done. + match search_for_unboxed_closure_vtable(vcx, + span, + ty, + trait_ref.clone()) { + Some(vtable_origin) => return Some(vtable_origin), + None => {} + } + + // Nope. Continue. + let mut found = Vec::new(); let mut impls_seen = HashSet::new(); @@ -449,7 +535,8 @@ fn search_for_vtable(vcx: &VtableContext, 1 => return Some(found.get(0).clone()), _ => { if !is_early { - vcx.tcx().sess.span_err(span, "multiple applicable methods in scope"); + span_err!(vcx.tcx().sess, span, E0096, + "multiple applicable methods in scope"); } return Some(found.get(0).clone()); } @@ -544,9 +631,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { if !mutability_allowed(mt.mutbl, mutbl) => { match ty::get(ty).sty { ty::ty_trait(..) => { - fcx.tcx() - .sess - .span_err(ex.span, "types differ in mutability"); + span_err!(fcx.tcx().sess, ex.span, E0097, "types differ in mutability"); } _ => {} } @@ -622,11 +707,9 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { (&ty::ty_uniq(ty), _) => { match ty::get(ty).sty { ty::ty_trait(..) => { - fcx.ccx.tcx.sess.span_err( - ex.span, - format!("can only cast an boxed pointer \ - to a boxed object, not a {}", - ty::ty_sort_string(fcx.tcx(), src_ty)).as_slice()); + span_err!(fcx.ccx.tcx.sess, ex.span, E0098, + "can only cast an boxed pointer to a boxed object, not a {}", + ty::ty_sort_string(fcx.tcx(), src_ty)); } _ => {} } @@ -635,11 +718,9 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { (&ty::ty_rptr(_, ty::mt{ty, ..}), _) => { match ty::get(ty).sty { ty::ty_trait(..) => { - fcx.ccx.tcx.sess.span_err( - ex.span, - format!("can only cast an &-pointer \ - to an &-object, not a {}", - ty::ty_sort_string(fcx.tcx(), src_ty)).as_slice()); + span_err!(fcx.ccx.tcx.sess, ex.span, E0099, + "can only cast an &-pointer to an &-object, not a {}", + ty::ty_sort_string(fcx.tcx(), src_ty)); } _ => {} } @@ -799,7 +880,12 @@ pub fn resolve_impl(tcx: &ty::ctxt, debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx)); let infcx = &infer::new_infer_ctxt(tcx); - let vcx = VtableContext { infcx: infcx, param_env: ¶m_env }; + let unboxed_closure_types = RefCell::new(DefIdMap::new()); + let vcx = VtableContext { + infcx: infcx, + param_env: ¶m_env, + unboxed_closure_types: &unboxed_closure_types, + }; // Resolve the vtables for the trait reference on the impl. This // serves many purposes, best explained by example. Imagine we have: @@ -847,9 +933,11 @@ pub fn resolve_impl(tcx: &ty::ctxt, pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId, substs: &subst::Substs) -> vtable_res { let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics; + let unboxed_closure_types = RefCell::new(DefIdMap::new()); let vcx = VtableContext { infcx: &infer::new_infer_ctxt(tcx), - param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id) + param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id), + unboxed_closure_types: &unboxed_closure_types, }; lookup_vtables(&vcx, diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 59b65fdbec790..c3e7d06f3f896 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -30,7 +30,7 @@ use util::ppaux::Repr; use std::cell::Cell; use syntax::ast; -use syntax::codemap::Span; +use syntax::codemap::{DUMMY_SP, Span}; use syntax::print::pprust::pat_to_string; use syntax::visit; use syntax::visit::Visitor; @@ -43,6 +43,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) { let mut wbcx = WritebackCx::new(fcx); wbcx.visit_expr(e, ()); wbcx.visit_upvar_borrow_map(); + wbcx.visit_unboxed_closure_types(); } pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, @@ -61,6 +62,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, } } wbcx.visit_upvar_borrow_map(); + wbcx.visit_unboxed_closure_types(); } pub fn resolve_impl_res(infcx: &infer::InferCtxt, @@ -130,7 +132,9 @@ impl<'cx> Visitor<()> for WritebackCx<'cx> { MethodCall::expr(e.id)); match e.node { - ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => { + ast::ExprFnBlock(ref decl, _) | + ast::ExprProc(ref decl, _) | + ast::ExprUnboxedFn(ref decl, _) => { for input in decl.inputs.iter() { let _ = self.visit_node_id(ResolvingExpr(e.span), input.id); @@ -201,6 +205,26 @@ impl<'cx> WritebackCx<'cx> { } } + fn visit_unboxed_closure_types(&self) { + if self.fcx.writeback_errors.get() { + return + } + + for (def_id, closure_ty) in self.fcx + .inh + .unboxed_closure_types + .borrow() + .iter() { + let closure_ty = self.resolve(closure_ty, + ResolvingUnboxedClosure(*def_id)); + self.fcx + .tcx() + .unboxed_closure_types + .borrow_mut() + .insert(*def_id, closure_ty); + } + } + fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) { // Resolve any borrowings for the node with id `id` self.visit_adjustments(reason, id); @@ -237,9 +261,8 @@ impl<'cx> WritebackCx<'cx> { Some(&def::DefStruct(_)) => { } _ => { - self.tcx().sess.span_err( - reason.span(self.tcx()), - "cannot coerce non-statically resolved bare fn") + span_err!(self.tcx().sess, reason.span(self.tcx()), E0100, + "cannot coerce non-statically resolved bare fn"); } } @@ -332,6 +355,7 @@ enum ResolveReason { ResolvingPattern(Span), ResolvingUpvar(ty::UpvarId), ResolvingImplRes(Span), + ResolvingUnboxedClosure(ast::DefId), } impl ResolveReason { @@ -344,6 +368,13 @@ impl ResolveReason { ty::expr_span(tcx, upvar_id.closure_expr_id) } ResolvingImplRes(s) => s, + ResolvingUnboxedClosure(did) => { + if did.krate == ast::LOCAL_CRATE { + ty::expr_span(tcx, did.node) + } else { + DUMMY_SP + } + } } } } @@ -399,47 +430,41 @@ impl<'cx> Resolver<'cx> { if !self.tcx.sess.has_errors() { match self.reason { ResolvingExpr(span) => { - self.tcx.sess.span_err( - span, - format!("cannot determine a type for \ - this expression: {}", - infer::fixup_err_to_string(e)).as_slice()) + span_err!(self.tcx.sess, span, E0101, + "cannot determine a type for this expression: {}", + infer::fixup_err_to_string(e)); } ResolvingLocal(span) => { - self.tcx.sess.span_err( - span, - format!("cannot determine a type for \ - this local variable: {}", - infer::fixup_err_to_string(e)).as_slice()) + span_err!(self.tcx.sess, span, E0102, + "cannot determine a type for this local variable: {}", + infer::fixup_err_to_string(e)); } ResolvingPattern(span) => { - self.tcx.sess.span_err( - span, - format!("cannot determine a type for \ - this pattern binding: {}", - infer::fixup_err_to_string(e)).as_slice()) + span_err!(self.tcx.sess, span, E0103, + "cannot determine a type for this pattern binding: {}", + infer::fixup_err_to_string(e)); } ResolvingUpvar(upvar_id) => { let span = self.reason.span(self.tcx); - self.tcx.sess.span_err( - span, - format!("cannot resolve lifetime for \ - captured variable `{}`: {}", - ty::local_var_name_str( - self.tcx, - upvar_id.var_id).get().to_string(), - infer::fixup_err_to_string(e)).as_slice()); + span_err!(self.tcx.sess, span, E0104, + "cannot resolve lifetime for captured variable `{}`: {}", + ty::local_var_name_str(self.tcx, upvar_id.var_id).get().to_string(), + infer::fixup_err_to_string(e)); } ResolvingImplRes(span) => { - self.tcx - .sess - .span_err(span, - "cannot determine a type for impl \ - supertrait"); + span_err!(self.tcx.sess, span, E0105, + "cannot determine a type for impl supertrait"); + } + + ResolvingUnboxedClosure(_) => { + let span = self.reason.span(self.tcx); + self.tcx.sess.span_err(span, + "cannot determine a type for this \ + unboxed closure") } } } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index b9bf8e37dead8..fe140cf2c97c2 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -25,7 +25,8 @@ use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil}; use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; -use middle::ty::{ty_uint, ty_uniq, ty_bare_fn, ty_closure}; +use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn}; +use middle::ty::{ty_closure}; use middle::ty::type_is_ty_var; use middle::subst::Subst; use middle::ty; @@ -75,7 +76,7 @@ fn get_base_type(inference_context: &InferCtxt, } match get(resolved_type).sty { - ty_enum(..) | ty_struct(..) => { + ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => { debug!("(getting base type) found base type"); Some(resolved_type) } @@ -111,7 +112,8 @@ fn type_is_defined_in_local_crate(tcx: &ty::ctxt, original_type: t) -> bool { ty::walk_ty(original_type, |t| { match get(t).sty { ty_enum(def_id, _) | - ty_struct(def_id, _) => { + ty_struct(def_id, _) | + ty_unboxed_closure(def_id) => { if def_id.krate == ast::LOCAL_CRATE { found_nominal = true; } @@ -154,7 +156,8 @@ fn get_base_type_def_id(inference_context: &InferCtxt, Some(base_type) => { match get(base_type).sty { ty_enum(def_id, _) | - ty_struct(def_id, _) => { + ty_struct(def_id, _) | + ty_unboxed_closure(def_id) => { Some(def_id) } ty_rptr(_, ty::mt {ty, ..}) | ty_uniq(ty) => match ty::get(ty).sty { @@ -221,10 +224,10 @@ impl<'a> visit::Visitor<()> for PrivilegedScopeVisitor<'a> { if !self.cc.ast_type_is_defined_in_local_crate(&**ast_ty) { // This is an error. let session = &self.cc.crate_context.tcx.sess; - session.span_err(item.span, - "cannot associate methods with a type outside the \ - crate the type is defined in; define and implement \ - a trait or new type instead"); + span_err!(session, item.span, E0116, + "cannot associate methods with a type outside the \ + crate the type is defined in; define and implement \ + a trait or new type instead"); } } ItemImpl(_, Some(ref trait_ref), _, _) => { @@ -241,9 +244,9 @@ impl<'a> visit::Visitor<()> for PrivilegedScopeVisitor<'a> { if trait_def_id.krate != LOCAL_CRATE { let session = &self.cc.crate_context.tcx.sess; - session.span_err(item.span, - "cannot provide an extension implementation \ - where both trait and type are not defined in this crate"); + span_err!(session, item.span, E0117, + "cannot provide an extension implementation \ + where both trait and type are not defined in this crate"); } } @@ -299,9 +302,9 @@ impl<'a> CoherenceChecker<'a> { self_type.ty) { None => { let session = &self.crate_context.tcx.sess; - session.span_err(item.span, - "no base type found for inherent implementation; \ - implement a trait or new type instead"); + span_err!(session, item.span, E0118, + "no base type found for inherent implementation; \ + implement a trait or new type instead"); } Some(_) => { // Nothing to do. @@ -438,22 +441,18 @@ impl<'a> CoherenceChecker<'a> { if self.polytypes_unify(polytype_a.clone(), polytype_b) { let session = &self.crate_context.tcx.sess; - session.span_err( - self.span_of_impl(impl_a), - format!("conflicting implementations for trait `{}`", - ty::item_path_str( - self.crate_context.tcx, - trait_def_id)).as_slice()); + span_err!(session, self.span_of_impl(impl_a), E0119, + "conflicting implementations for trait `{}`", + ty::item_path_str(self.crate_context.tcx, trait_def_id)); if impl_b.krate == LOCAL_CRATE { - session.span_note(self.span_of_impl(impl_b), - "note conflicting implementation here"); + span_note!(session, self.span_of_impl(impl_b), + "note conflicting implementation here"); } else { let crate_store = &self.crate_context.tcx.sess.cstore; let cdata = crate_store.get_crate_data(impl_b.krate); - session.note( - format!("conflicting implementation in crate \ - `{}`", - cdata.name).as_slice()); + span_note!(session, self.span_of_impl(impl_a), + "conflicting implementation in crate `{}`", + cdata.name); } } } @@ -691,7 +690,8 @@ impl<'a> CoherenceChecker<'a> { let self_type = self.get_self_type_for_implementation(impl_did); match ty::get(self_type.ty).sty { ty::ty_enum(type_def_id, _) | - ty::ty_struct(type_def_id, _) => { + ty::ty_struct(type_def_id, _) | + ty::ty_unboxed_closure(type_def_id) => { tcx.destructor_for_type.borrow_mut().insert(type_def_id, method_def_id); tcx.destructors.borrow_mut().insert(method_def_id); @@ -702,10 +702,8 @@ impl<'a> CoherenceChecker<'a> { { match tcx.map.find(impl_did.node) { Some(ast_map::NodeItem(item)) => { - tcx.sess.span_err((*item).span, - "the Drop trait may \ - only be implemented \ - on structures"); + span_err!(tcx.sess, item.span, E0120, + "the Drop trait may only be implemented on structures"); } _ => { tcx.sess.bug("didn't find impl in ast \ diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 7a39dd5b5ab82..780faddb88639 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -40,11 +40,14 @@ use middle::subst::{Substs}; use middle::ty::{ImplContainer, MethodContainer, TraitContainer}; use middle::ty::{Polytype}; use middle::ty; +use middle::ty_fold::TypeFolder; use middle::typeck::astconv::{AstConv, ty_of_arg}; use middle::typeck::astconv::{ast_ty_to_ty}; use middle::typeck::astconv; +use middle::typeck::infer; use middle::typeck::rscope::*; use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; +use middle::typeck; use util::ppaux; use util::ppaux::Repr; @@ -57,8 +60,7 @@ use syntax::ast::{StaticRegionTyParamBound, OtherRegionTyParamBound}; use syntax::ast::{TraitTyParamBound, UnboxedFnTyParamBound}; use syntax::ast; use syntax::ast_map; -use syntax::ast_util; -use syntax::ast_util::{local_def, method_ident, split_trait_methods}; +use syntax::ast_util::{local_def, split_trait_methods, PostExpansionMethod}; use syntax::codemap::Span; use syntax::codemap; use syntax::owned_slice::OwnedSlice; @@ -138,9 +140,8 @@ impl<'a> AstConv for CrateCtxt<'a> { } fn ty_infer(&self, span: Span) -> ty::t { - self.tcx.sess.span_err(span, "the type placeholder `_` is not \ - allowed within types on item \ - signatures."); + span_err!(self.tcx.sess, span, E0121, + "the type placeholder `_` is not allowed within types on item signatures."); ty::mk_err() } } @@ -206,23 +207,35 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, let ty_method = Rc::new(match m { &ast::Required(ref m) => { ty_method_of_trait_method( - ccx, trait_id, &trait_def.generics, - &m.id, &m.ident, &m.explicit_self, - &m.generics, &m.fn_style, &*m.decl) + ccx, + trait_id, + &trait_def.generics, + &m.id, + &m.ident, + &m.explicit_self, + m.abi, + &m.generics, + &m.fn_style, + &*m.decl) } &ast::Provided(ref m) => { ty_method_of_trait_method( - ccx, trait_id, &trait_def.generics, - &m.id, &ast_util::method_ident(&**m), - ast_util::method_explicit_self(&**m), - ast_util::method_generics(&**m), - &ast_util::method_fn_style(&**m), - ast_util::method_fn_decl(&**m)) + ccx, + trait_id, + &trait_def.generics, + &m.id, + &m.pe_ident(), + m.pe_explicit_self(), + m.pe_abi(), + m.pe_generics(), + &m.pe_fn_style(), + &*m.pe_fn_decl()) } }); - if ty_method.explicit_self == ast::SelfStatic { + if ty_method.explicit_self == + ty::StaticExplicitSelfCategory { make_static_method_ty(ccx, &*ty_method); } @@ -266,13 +279,21 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, m_id: &ast::NodeId, m_ident: &ast::Ident, m_explicit_self: &ast::ExplicitSelf, + m_abi: abi::Abi, m_generics: &ast::Generics, m_fn_style: &ast::FnStyle, - m_decl: &ast::FnDecl) -> ty::Method - { + m_decl: &ast::FnDecl) + -> ty::Method { let trait_self_ty = ty::mk_self_type(this.tcx, local_def(trait_id)); - let fty = astconv::ty_of_method(this, *m_id, *m_fn_style, trait_self_ty, - *m_explicit_self, m_decl); + + let (fty, explicit_self_category) = + astconv::ty_of_method(this, + *m_id, + *m_fn_style, + trait_self_ty, + *m_explicit_self, + m_decl, + m_abi); let ty_generics = ty_generics_for_fn_or_method(this, m_generics, @@ -281,7 +302,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, *m_ident, ty_generics, fty, - m_explicit_self.node, + explicit_self_category, // assume public, because this is only invoked on trait methods ast::Public, local_def(*m_id), @@ -334,7 +355,7 @@ fn convert_methods(ccx: &CrateCtxt, let tcx = ccx.tcx; let mut seen_methods = HashSet::new(); for m in ms.iter() { - if !seen_methods.insert(ast_util::method_ident(&**m).repr(tcx)) { + if !seen_methods.insert(m.pe_ident().repr(ccx.tcx)) { tcx.sess.span_err(m.span, "duplicate method in trait impl"); } @@ -346,9 +367,9 @@ fn convert_methods(ccx: &CrateCtxt, rcvr_visibility)); let fty = ty::mk_bare_fn(tcx, mty.fty.clone()); debug!("method {} (id {}) has type {}", - method_ident(&**m).repr(tcx), + m.pe_ident().repr(ccx.tcx), m.id, - fty.repr(tcx)); + fty.repr(ccx.tcx)); tcx.tcache.borrow_mut().insert( local_def(m.id), Polytype { @@ -367,26 +388,43 @@ fn convert_methods(ccx: &CrateCtxt, untransformed_rcvr_ty: ty::t, rcvr_ty_generics: &ty::Generics, rcvr_visibility: ast::Visibility) - -> ty::Method - { - let fty = astconv::ty_of_method(ccx, m.id, ast_util::method_fn_style(&*m), - untransformed_rcvr_ty, - *ast_util::method_explicit_self(&*m), - ast_util::method_fn_decl(&*m)); + -> ty::Method { + // FIXME(pcwalton): Hack until we have syntax in stage0 for snapshots. + let real_abi = match container { + ty::TraitContainer(trait_id) => { + if ccx.tcx.lang_items.fn_trait() == Some(trait_id) || + ccx.tcx.lang_items.fn_mut_trait() == Some(trait_id) || + ccx.tcx.lang_items.fn_once_trait() == Some(trait_id) { + abi::RustCall + } else { + m.pe_abi() + } + } + _ => m.pe_abi(), + }; + + let (fty, explicit_self_category) = + astconv::ty_of_method(ccx, + m.id, + m.pe_fn_style(), + untransformed_rcvr_ty, + *m.pe_explicit_self(), + &*m.pe_fn_decl(), + real_abi); // if the method specifies a visibility, use that, otherwise // inherit the visibility from the impl (so `foo` in `pub impl // { fn foo(); }` is public, but private in `priv impl { fn // foo(); }`). - let method_vis = ast_util::method_vis(&*m).inherit_from(rcvr_visibility); + let method_vis = m.pe_vis().inherit_from(rcvr_visibility); let m_ty_generics = - ty_generics_for_fn_or_method(ccx, ast_util::method_generics(&*m), + ty_generics_for_fn_or_method(ccx, m.pe_generics(), (*rcvr_ty_generics).clone()); - ty::Method::new(ast_util::method_ident(&*m), + ty::Method::new(m.pe_ident(), m_ty_generics, fty, - ast_util::method_explicit_self(&*m).node, + explicit_self_category, method_vis, local_def(m.id), container, @@ -400,10 +438,8 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, thing: &'static str) { for ty_param in generics.ty_params.iter() { if ty_param.bounds.len() > 0 { - ccx.tcx.sess.span_err( - span, - format!("trait bounds are not allowed in {} definitions", - thing).as_slice()); + span_err!(ccx.tcx.sess, span, E0122, + "trait bounds are not allowed in {} definitions", thing); } } } @@ -414,8 +450,8 @@ fn ensure_generics_abi(ccx: &CrateCtxt, generics: &ast::Generics) { if generics.ty_params.len() > 0 && !(abi == abi::Rust || abi == abi::RustIntrinsic) { - ccx.tcx.sess.span_err(span, - "foreign functions may not use type parameters"); + span_err!(ccx.tcx.sess, span, E0123, + "foreign functions may not use type parameters"); } } @@ -455,6 +491,13 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { it.vis }; + for method in ms.iter() { + check_method_self_type(ccx, + &BindingRscope::new(method.id), + selfty, + method.pe_explicit_self()) + } + convert_methods(ccx, ImplContainer(local_def(it.id)), ms.as_slice(), @@ -469,6 +512,28 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { ast::ItemTrait(_, _, _, ref trait_methods) => { let trait_def = trait_def_of_item(ccx, it); + for trait_method in trait_methods.iter() { + let self_type = ty::mk_param(ccx.tcx, + subst::SelfSpace, + 0, + local_def(it.id)); + match *trait_method { + ast::Required(ref type_method) => { + let rscope = BindingRscope::new(type_method.id); + check_method_self_type(ccx, + &rscope, + self_type, + &type_method.explicit_self) + } + ast::Provided(ref method) => { + check_method_self_type(ccx, + &BindingRscope::new(method.id), + self_type, + method.pe_explicit_self()) + } + } + } + // Run convert_methods on the provided methods. let (_, provided_methods) = split_trait_methods(trait_methods.as_slice()); @@ -539,12 +604,10 @@ pub fn convert_struct(ccx: &CrateCtxt, if result.name != special_idents::unnamed_field.name { let dup = match seen_fields.find(&result.name) { Some(prev_span) => { - tcx.sess.span_err( - f.span, - format!("field `{}` is already declared", - token::get_name(result.name)).as_slice()); - tcx.sess.span_note(*prev_span, - "previously declared here"); + span_err!(tcx.sess, f.span, E0124, + "field `{}` is already declared", + token::get_name(result.name)); + span_note!(tcx.sess, *prev_span, "previously declared here"); true }, None => false, @@ -573,9 +636,9 @@ pub fn convert_struct(ccx: &CrateCtxt, Some(ast_map::NodeItem(i)) => match i.node { ast::ItemStruct(struct_def, _) => { if !struct_def.is_virtual { - tcx.sess.span_err(t.span, - "struct inheritance is only \ - allowed from virtual structs"); + span_err!(tcx.sess, t.span, E0126, + "struct inheritance is only \ + allowed from virtual structs"); } }, _ => {}, @@ -794,8 +857,8 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { { // This means a trait inherited from the same // supertrait more than once. - tcx.sess.span_err(sp, "duplicate supertrait in \ - trait declaration"); + span_err!(tcx.sess, sp, E0127, + "duplicate supertrait in trait declaration"); break; } else { ty_trait_refs.push(trait_ref); @@ -1061,10 +1124,9 @@ fn ty_generics(ccx: &CrateCtxt, ty::walk_ty(ty, |t| { match ty::get(t).sty { ty::ty_param(p) => if p.idx > cur_idx { - ccx.tcx.sess.span_err( - path.span, - "type parameters with a default cannot use \ - forward declared identifiers") + span_err!(ccx.tcx.sess, path.span, E0128, + "type parameters with a default cannot use \ + forward declared identifiers"); }, _ => {} } @@ -1171,12 +1233,11 @@ fn ty_generics(ccx: &CrateCtxt, |trait_ref| { let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id); if trait_def.bounds.contains_elem(ty::BoundSized) { - tcx.sess.span_err(span, - format!("incompatible bounds on type parameter {}, \ - bound {} does not allow unsized type", - token::get_ident(ident), - ppaux::trait_ref_to_string(tcx, - &*trait_ref)).as_slice()); + span_err!(tcx.sess, span, E0129, + "incompatible bounds on type parameter {}, \ + bound {} does not allow unsized type", + token::get_ident(ident), + ppaux::trait_ref_to_string(tcx, &*trait_ref)); } true }); @@ -1195,8 +1256,10 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, match (*i).pat.node { ast::PatIdent(_, _, _) => (), ast::PatWild => (), - _ => ccx.tcx.sess.span_err((*i).pat.span, - "patterns aren't allowed in foreign function declarations") + _ => { + span_err!(ccx.tcx.sess, (*i).pat.span, E0130, + "patterns aren't allowed in foreign function declarations"); + } } } @@ -1245,3 +1308,36 @@ pub fn mk_item_substs(ccx: &CrateCtxt, subst::Substs::new(types, regions) } + +/// Verifies that the explicit self type of a method matches the impl or +/// trait. +fn check_method_self_type( + crate_context: &CrateCtxt, + rs: &RS, + required_type: ty::t, + explicit_self: &ast::ExplicitSelf) { + match explicit_self.node { + ast::SelfExplicit(ref ast_type, _) => { + let typ = crate_context.to_ty(rs, &**ast_type); + let base_type = match ty::get(typ).sty { + ty::ty_rptr(_, tm) => tm.ty, + ty::ty_uniq(typ) => typ, + _ => typ, + }; + let infcx = infer::new_infer_ctxt(crate_context.tcx); + drop(typeck::require_same_types(crate_context.tcx, + Some(&infcx), + false, + explicit_self.span, + base_type, + required_type, + || { + format!("mismatched self type: expected `{}`", + ppaux::ty_to_string(crate_context.tcx, required_type)) + })); + infcx.resolve_regions_and_report_errors(); + } + _ => {} + } +} + diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index f8efb3c38c200..03890250f7701 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -76,7 +76,6 @@ use util::common::indenter; use util::ppaux::Repr; use syntax::abi; -use syntax::ast::MutImmutable; use syntax::ast; // Note: Coerce is not actually a combiner, in that it does not @@ -248,12 +247,7 @@ impl<'f> Coerce<'f> { let r_borrow = self.get_ref().infcx.next_region_var(coercion); let inner_ty = match *sty_a { - ty::ty_box(typ) | ty::ty_uniq(typ) => { - if mt_b.mutbl == ast::MutMutable { - return Err(ty::terr_mutability) - } - typ - } + ty::ty_box(_) | ty::ty_uniq(_) => return Err(ty::terr_mismatch), ty::ty_rptr(_, mt_a) => mt_a.ty, _ => { return self.subtype(a, b); @@ -280,23 +274,9 @@ impl<'f> Coerce<'f> { b.repr(self.get_ref().infcx.tcx)); match *sty_a { - ty::ty_uniq(t) => match ty::get(t).sty { - ty::ty_str => {} - _ => return self.subtype(a, b), - }, - _ => { - return self.subtype(a, b); - } - }; - - let coercion = Coercion(self.get_ref().trace.clone()); - let r_a = self.get_ref().infcx.next_region_var(coercion); - let a_borrowed = ty::mk_str_slice(self.get_ref().infcx.tcx, r_a, ast::MutImmutable); - if_ok!(self.subtype(a_borrowed, b)); - Ok(Some(AutoDerefRef(AutoDerefRef { - autoderefs: 0, - autoref: Some(AutoBorrowVec(r_a, MutImmutable)) - }))) + ty::ty_uniq(_) => return Err(ty::terr_mismatch), + _ => return self.subtype(a, b), + } } pub fn coerce_borrowed_vector(&self, @@ -313,7 +293,8 @@ impl<'f> Coerce<'f> { let coercion = Coercion(self.get_ref().trace.clone()); let r_borrow = self.get_ref().infcx.next_region_var(coercion); let ty_inner = match *sty_a { - ty::ty_uniq(t) | ty::ty_ptr(ty::mt{ty: t, ..}) | + ty::ty_uniq(_) => return Err(ty::terr_mismatch), + ty::ty_ptr(ty::mt{ty: t, ..}) | ty::ty_rptr(_, ty::mt{ty: t, ..}) => match ty::get(t).sty { ty::ty_vec(mt, None) => mt.ty, _ => { diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 1e33b1d5d0ebd..1aae97d3d83e9 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -111,7 +111,11 @@ pub trait Combine { b_subst: &subst::Substs) -> cres { - let variances = ty::item_variances(self.infcx().tcx, item_def_id); + let variances = if self.infcx().tcx.variance_computed.get() { + Some(ty::item_variances(self.infcx().tcx, item_def_id)) + } else { + None + }; let mut substs = subst::Substs::empty(); for &space in subst::ParamSpace::all().iter() { @@ -121,7 +125,18 @@ pub trait Combine { let a_regions = a_subst.regions().get_slice(space); let b_regions = b_subst.regions().get_slice(space); - let r_variances = variances.regions.get_slice(space); + + let mut invariance = Vec::new(); + let r_variances = match variances { + Some(ref variances) => variances.regions.get_slice(space), + None => { + for _ in a_regions.iter() { + invariance.push(ty::Invariant); + } + invariance.as_slice() + } + }; + let regions = if_ok!(relate_region_params(self, item_def_id, r_variances, @@ -208,12 +223,14 @@ pub trait Combine { let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness)); let bounds = if_ok!(self.bounds(a.bounds, b.bounds)); let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig)); + let abi = if_ok!(self.abi(a.abi, b.abi)); Ok(ty::ClosureTy { fn_style: fn_style, onceness: onceness, store: store, bounds: bounds, - sig: sig + sig: sig, + abi: abi, }) } @@ -475,6 +492,11 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { Ok(ty::mk_struct(tcx, a_id, substs)) } + (&ty::ty_unboxed_closure(a_id), &ty::ty_unboxed_closure(b_id)) + if a_id == b_id => { + Ok(ty::mk_unboxed_closure(tcx, a_id)) + } + (&ty::ty_box(a_inner), &ty::ty_box(b_inner)) => { this.tys(a_inner, b_inner).and_then(|typ| Ok(ty::mk_box(tcx, typ))) } @@ -537,7 +559,7 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { } (&ty::ty_closure(ref a_fty), &ty::ty_closure(ref b_fty)) => { - this.closure_tys(*a_fty, *b_fty).and_then(|fty| { + this.closure_tys(&**a_fty, &**b_fty).and_then(|fty| { Ok(ty::mk_closure(tcx, fty)) }) } diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index bdd6d96f394a2..8be1700b635b4 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -84,7 +84,7 @@ use std::string::String; use syntax::ast; use syntax::ast_map; use syntax::ast_util; -use syntax::ast_util::name_to_dummy_lifetime; +use syntax::ast_util::{name_to_dummy_lifetime, PostExpansionMethod}; use syntax::owned_slice::OwnedSlice; use syntax::codemap; use syntax::parse::token; @@ -700,11 +700,8 @@ impl<'a> ErrorReporting for InferCtxt<'a> { } } ast_map::NodeMethod(ref m) => { - Some((ast_util::method_fn_decl(&**m), - ast_util::method_generics(&**m), - ast_util::method_fn_style(&**m), - ast_util::method_ident(&**m), - Some(ast_util::method_explicit_self(&**m).node), m.span)) + Some((m.pe_fn_decl(), m.pe_generics(), m.pe_fn_style(), + m.pe_ident(), Some(m.pe_explicit_self().node), m.span)) }, _ => None }, @@ -1455,7 +1452,7 @@ fn lifetimes_in_scope(tcx: &ty::ctxt, _ => None }, ast_map::NodeMethod(m) => { - taken.push_all(ast_util::method_generics(&*m).lifetimes.as_slice()); + taken.push_all(m.pe_generics().lifetimes.as_slice()); Some(m.id) }, _ => None diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 16e758df9dbbd..30fffc42a3f97 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -30,8 +30,8 @@ use middle::ty_fold::TypeFolder; use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig; use middle::typeck::infer::coercion::Coerce; use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys}; -use middle::typeck::infer::region_inference::{RegionVarBindings, - RegionSnapshot}; +use middle::typeck::infer::region_inference::{RegionSnapshot}; +use middle::typeck::infer::region_inference::{RegionVarBindings}; use middle::typeck::infer::resolve::{resolver}; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::lub::Lub; diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 28240686dc358..d17553e9c39b3 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -13,16 +13,15 @@ use middle::ty; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; -use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound, - ReLateBound}; -use middle::ty::{ReScope, ReVar, ReSkolemized, BrFresh}; +use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; +use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; use middle::typeck::infer::cres; use middle::typeck::infer::{RegionVariableOrigin, SubregionOrigin, TypeTrace}; use middle::typeck::infer; use middle::graph; use middle::graph::{Direction, NodeIndex}; use util::common::indenter; -use util::ppaux::{Repr}; +use util::ppaux::Repr; use std::cell::{Cell, RefCell}; use std::uint; @@ -318,6 +317,11 @@ impl<'a> RegionVarBindings<'a> { origin.repr(self.tcx)); match (sub, sup) { + (ReEarlyBound(..), ReEarlyBound(..)) => { + // This case is used only to make sure that explicitly-specified + // `Self` types match the real self type in implementations. + self.add_constraint(ConstrainRegSubReg(sub, sup), origin); + } (ReEarlyBound(..), _) | (ReLateBound(..), _) | (_, ReEarlyBound(..)) | diff --git a/src/librustc/middle/typeck/infer/test.rs b/src/librustc/middle/typeck/infer/test.rs index c06e40fce14f9..c8f6836b20596 100644 --- a/src/librustc/middle/typeck/infer/test.rs +++ b/src/librustc/middle/typeck/infer/test.rs @@ -95,7 +95,7 @@ impl Emitter for ExpectErrorEmitter { } fn errors(msgs: &[&str]) -> (Box, uint) { - let v = Vec::from_fn(msgs.len(), |i| msgs[i].to_owned()); + let v = msgs.iter().map(|m| m.to_string()).collect(); (box ExpectErrorEmitter { messages: v } as Box, msgs.len()) } @@ -114,7 +114,7 @@ fn test_env(_test_name: &str, let sess = session::build_session_(options, None, span_diagnostic_handler); let krate_config = Vec::new(); - let input = driver::StrInput(source_string.to_owned()); + let input = driver::StrInput(source_string.to_string()); let krate = driver::phase_1_parse_input(&sess, krate_config, &input); let (krate, ast_map) = driver::phase_2_configure_and_expand(&sess, krate, "test") @@ -174,7 +174,7 @@ impl<'a> Env<'a> { assert!(idx < names.len()); for item in m.items.iter() { if item.ident.user_string(this.tcx) == names[idx] { - return search(this, *item, idx+1, names); + return search(this, &**item, idx+1, names); } } return None; diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index ad6864ba48792..4000807ec1b8e 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -97,6 +97,9 @@ pub enum MethodOrigin { // fully statically resolved method MethodStatic(ast::DefId), + // fully statically resolved unboxed closure invocation + MethodStaticUnboxedClosure(ast::DefId), + // method invoked on a type parameter with a bounded trait MethodParam(MethodParam), @@ -232,6 +235,12 @@ pub enum vtable_origin { */ vtable_param(param_index, uint), + /* + Vtable automatically generated for an unboxed closure. The def ID is the + ID of the closure expression. + */ + vtable_unboxed_closure(ast::DefId), + /* Asked to determine the vtable for ty_err. This is the value used for the vtables of `Self` in a virtual call like `foo.bar()` @@ -256,6 +265,10 @@ impl Repr for vtable_origin { format!("vtable_param({:?}, {:?})", x, y) } + vtable_unboxed_closure(def_id) => { + format!("vtable_unboxed_closure({})", def_id) + } + vtable_error => { format!("vtable_error") } @@ -359,9 +372,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt, match it.node { ast::ItemFn(_, _, _, ref ps, _) if ps.is_parameterized() => { - tcx.sess.span_err( - main_span, - "main function is not allowed to have type parameters"); + span_err!(ccx.tcx.sess, main_span, E0131, + "main function is not allowed to have type parameters"); return; } _ => () @@ -408,9 +420,8 @@ fn check_start_fn_ty(ccx: &CrateCtxt, match it.node { ast::ItemFn(_,_,_,ref ps,_) if ps.is_parameterized() => { - tcx.sess.span_err( - start_span, - "start function is not allowed to have type parameters"); + span_err!(tcx.sess, start_span, E0132, + "start function is not allowed to have type parameters"); return; } _ => () diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index 2abbd916d7627..cdb691073cd36 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -64,10 +64,24 @@ impl RegionScope for BindingRscope { fn anon_regions(&self, _: Span, count: uint) - -> Result , ()> { + -> Result, ()> { let idx = self.anon_bindings.get(); self.anon_bindings.set(idx + count); Ok(Vec::from_fn(count, |i| ty::ReLateBound(self.binder_id, ty::BrAnon(idx + i)))) } } + +/// A scope in which we generate one specific region. This occurs after the +/// `->` (i.e. in the return type) of function signatures. +pub struct ImpliedSingleRscope { + pub region: ty::Region, +} + +impl RegionScope for ImpliedSingleRscope { + fn anon_regions(&self, _: Span, count: uint) + -> Result,()> { + Ok(Vec::from_elem(count, self.region.clone())) + } +} + diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 8b5d16620b0f5..d230b08096641 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -214,6 +214,7 @@ pub fn infer_variance(tcx: &ty::ctxt, let terms_cx = determine_parameters_to_be_inferred(tcx, &mut arena, krate); let constraints_cx = add_constraints_from_crate(terms_cx, krate); solve_constraints(constraints_cx); + tcx.variance_computed.set(true); } /************************************************************************** @@ -714,7 +715,7 @@ impl<'a> ConstraintContext<'a> { match ty::get(ty).sty { ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | - ty::ty_float(_) | ty::ty_str => { + ty::ty_float(_) | ty::ty_str | ty::ty_unboxed_closure(..) => { /* leaf type -- noop */ } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6526943955c92..c3986d01d3da5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -14,13 +14,14 @@ use middle::subst; use middle::subst::{VecPerParamSpace,Subst}; use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{BoundRegion, BrAnon, BrNamed}; -use middle::ty::{BrFresh, ctxt}; +use middle::ty::{ReEarlyBound, BrFresh, ctxt}; use middle::ty::{mt, t, ParamTy}; use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure}; use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup}; use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer}; +use middle::ty::{ty_unboxed_closure}; use middle::ty; use middle::typeck; use middle::typeck::infer; @@ -130,9 +131,13 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) ReEmpty => { ("the empty lifetime".to_string(), None) } + ReEarlyBound(_, _, _, name) => { + (format!("{}", token::get_name(name)), None) + } + // I believe these cases should not occur (except when debugging, // perhaps) - ty::ReInfer(_) | ty::ReEarlyBound(..) | ty::ReLateBound(..) => { + ty::ReInfer(_) | ty::ReLateBound(..) => { (format!("lifetime {:?}", region), None) } }; @@ -370,7 +375,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { format!("({})", strs.connect(",")) } ty_closure(ref f) => { - closure_to_string(cx, *f) + closure_to_string(cx, &**f) } ty_bare_fn(ref f) => { bare_fn_to_string(cx, f.fn_style, f.abi, None, &f.sig) @@ -410,6 +415,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { bound_str) } ty_str => "str".to_string(), + ty_unboxed_closure(..) => "closure".to_string(), ty_vec(ref mt, sz) => { match sz { Some(n) => { @@ -421,6 +427,19 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { } } +pub fn explicit_self_category_to_str(category: &ty::ExplicitSelfCategory) + -> &'static str { + match *category { + ty::StaticExplicitSelfCategory => "static", + ty::ByValueExplicitSelfCategory => "self", + ty::ByReferenceExplicitSelfCategory(_, ast::MutMutable) => { + "&mut self" + } + ty::ByReferenceExplicitSelfCategory(_, ast::MutImmutable) => "&self", + ty::ByBoxExplicitSelfCategory => "Box", + } +} + pub fn parameterized(cx: &ctxt, base: &str, substs: &subst::Substs, @@ -861,6 +880,9 @@ impl Repr for typeck::MethodOrigin { &typeck::MethodStatic(def_id) => { format!("MethodStatic({})", def_id.repr(tcx)) } + &typeck::MethodStaticUnboxedClosure(def_id) => { + format!("MethodStaticUnboxedClosure({})", def_id.repr(tcx)) + } &typeck::MethodParam(ref p) => { p.repr(tcx) } @@ -1083,3 +1105,10 @@ impl Repr for region_inference::VarValue { } } } + +impl Repr for ty::ExplicitSelfCategory { + fn repr(&self, _: &ctxt) -> String { + explicit_self_category_to_str(self).to_string() + } +} + diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 8ec74f4d6efcc..5db6c72975587 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -21,7 +21,6 @@ //! one that doesn't; the one that doesn't might get decent parallel //! build speedups. -#![crate_id = "rustc_back#0.11.0-pre"] #![crate_name = "rustc_back"] #![experimental] #![comment = "The Rust compiler minimal-dependency dumping-ground"] @@ -33,7 +32,6 @@ html_root_url = "http://doc.rust-lang.org/")] #![feature(globs, phase, macro_rules)] -#![allow(unused_attribute)] // NOTE: remove after stage0 #[phase(plugin, link)] extern crate log; diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 66bc8c740c47f..cb9519b1eb815 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -239,6 +239,7 @@ mod svh_visitor { SawExprWhile, SawExprMatch, SawExprFnBlock, + SawExprUnboxedFn, SawExprProc, SawExprBlock, SawExprAssign, @@ -270,6 +271,7 @@ mod svh_visitor { ExprLoop(_, id) => SawExprLoop(id.map(content)), ExprMatch(..) => SawExprMatch, ExprFnBlock(..) => SawExprFnBlock, + ExprUnboxedFn(..) => SawExprUnboxedFn, ExprProc(..) => SawExprProc, ExprBlock(..) => SawExprBlock, ExprAssign(..) => SawExprAssign, diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 9ee8fa98c7499..215ae444b6920 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -13,7 +13,6 @@ #![allow(non_snake_case_functions)] #![allow(dead_code)] -#![crate_id = "rustc_llvm#0.11.0"] #![crate_name = "rustc_llvm"] #![experimental] #![license = "MIT/ASL2"] @@ -25,7 +24,6 @@ #![feature(globs)] #![feature(link_args)] -#![allow(unused_attribute)] // NOTE: remove after stage0 extern crate libc; @@ -1944,6 +1942,14 @@ pub fn mk_section_iter(llof: ObjectFileRef) -> SectionIter { } } +/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun. +pub fn get_param(llfn: ValueRef, index: c_uint) -> ValueRef { + unsafe { + assert!(index < LLVMCountParams(llfn)); + LLVMGetParam(llfn, index) + } +} + // FIXME #15460 - create a public function that actually calls our // static LLVM symbols. Otherwise the linker will just throw llvm // away. We're just calling lots of stuff until we transitively get diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2e3bb2eef7d9d..9f5df205aa4c3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -14,6 +14,7 @@ use syntax; use syntax::ast; use syntax::ast_util; +use syntax::ast_util::PostExpansionMethod; use syntax::attr; use syntax::attr::{AttributeMethods, AttrMetaMethods}; use syntax::codemap::Pos; @@ -393,7 +394,7 @@ impl Clean for doctree::Module { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub enum Attribute { Word(String), List(String, Vec ), @@ -446,7 +447,7 @@ impl<'a> attr::AttrMetaMethods for &'a Attribute { fn meta_item_list<'a>(&'a self) -> Option<&'a [Gc]> { None } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct TyParam { pub name: String, pub did: ast::DefId, @@ -478,7 +479,7 @@ impl Clean for ty::TypeParameterDef { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub enum TyParamBound { RegionBound, TraitBound(Type) @@ -637,7 +638,7 @@ impl Clean> for ty::Region { } // maybe use a Generic enum and use ~[Generic]? -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct Generics { pub lifetimes: Vec, pub type_params: Vec, @@ -695,30 +696,30 @@ pub struct Method { impl Clean for ast::Method { fn clean(&self) -> Item { - let fn_decl = ast_util::method_fn_decl(self); - let inputs = match ast_util::method_explicit_self(self).node { - ast::SelfStatic => fn_decl.inputs.as_slice(), - _ => fn_decl.inputs.slice_from(1) + let all_inputs = &self.pe_fn_decl().inputs; + let inputs = match self.pe_explicit_self().node { + ast::SelfStatic => all_inputs.as_slice(), + _ => all_inputs.slice_from(1) }; let decl = FnDecl { inputs: Arguments { values: inputs.iter().map(|x| x.clean()).collect(), }, - output: (fn_decl.output.clean()), - cf: fn_decl.cf.clean(), + output: (self.pe_fn_decl().output.clean()), + cf: self.pe_fn_decl().cf.clean(), attrs: Vec::new() }; Item { - name: Some(ast_util::method_ident(self).clean()), + name: Some(self.pe_ident().clean()), attrs: self.attrs.clean().move_iter().collect(), source: self.span.clean(), def_id: ast_util::local_def(self.id), - visibility: ast_util::method_vis(self).clean(), + visibility: self.pe_vis().clean(), stability: get_stability(ast_util::local_def(self.id)), inner: MethodItem(Method { - generics: ast_util::method_generics(self).clean(), - self_: ast_util::method_explicit_self(self).node.clean(), - fn_style: ast_util::method_fn_style(self).clone(), + generics: self.pe_generics().clean(), + self_: self.pe_explicit_self().node.clean(), + fn_style: self.pe_fn_style().clone(), decl: decl, }), } @@ -770,6 +771,7 @@ pub enum SelfTy { SelfValue, SelfBorrowed(Option, Mutability), SelfOwned, + SelfExplicit(Type), } impl Clean for ast::ExplicitSelf_ { @@ -778,7 +780,10 @@ impl Clean for ast::ExplicitSelf_ { ast::SelfStatic => SelfStatic, ast::SelfValue(_) => SelfValue, ast::SelfUniq(_) => SelfOwned, - ast::SelfRegion(lt, mt, _) => SelfBorrowed(lt.clean(), mt.clean()), + ast::SelfRegion(lt, mt, _) => { + SelfBorrowed(lt.clean(), mt.clean()) + } + ast::SelfExplicit(typ, _) => SelfExplicit(typ.clean()), } } } @@ -808,7 +813,7 @@ impl Clean for doctree::Function { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct ClosureDecl { pub lifetimes: Vec, pub decl: FnDecl, @@ -832,7 +837,7 @@ impl Clean for ast::ClosureTy { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct FnDecl { pub inputs: Arguments, pub output: Type, @@ -840,7 +845,7 @@ pub struct FnDecl { pub attrs: Vec, } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct Arguments { pub values: Vec, } @@ -887,7 +892,7 @@ impl<'a> Clean for (ast::DefId, &'a ty::FnSig) { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct Argument { pub type_: Type, pub name: String, @@ -904,7 +909,7 @@ impl Clean for ast::Arg { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub enum RetStyle { NoReturn, Return @@ -990,22 +995,28 @@ impl Clean for ty::Method { fn clean(&self) -> Item { let cx = get_cx(); let (self_, sig) = match self.explicit_self { - ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()), + ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(), self.fty.sig.clone()), s => { let sig = ty::FnSig { inputs: Vec::from_slice(self.fty.sig.inputs.slice_from(1)), ..self.fty.sig.clone() }; let s = match s { - ast::SelfRegion(..) => { - match ty::get(*self.fty.sig.inputs.get(0)).sty { + ty::ByReferenceExplicitSelfCategory(..) => { + match ty::get(self.fty.sig.inputs[0]).sty { ty::ty_rptr(r, mt) => { SelfBorrowed(r.clean(), mt.mutbl.clean()) } - _ => s.clean(), + _ => { + // FIXME(pcwalton): This is wrong. + SelfStatic + } } } - s => s.clean(), + _ => { + // FIXME(pcwalton): This is wrong. + SelfStatic + } }; (s, sig) } @@ -1031,7 +1042,7 @@ impl Clean for ty::Method { /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original /// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly /// it does not preserve mutability or boxes. -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub enum Type { /// structs/enums/traits (anything that'd be an ast::TyPath) ResolvedPath { @@ -1290,6 +1301,8 @@ impl Clean for ty::t { } } + ty::ty_unboxed_closure(..) => Primitive(Unit), // FIXME(pcwalton) + ty::ty_infer(..) => fail!("ty_infer"), ty::ty_err => fail!("ty_err"), } @@ -1549,7 +1562,7 @@ impl Clean for syntax::codemap::Span { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct Path { pub global: bool, pub segments: Vec, @@ -1564,7 +1577,7 @@ impl Clean for ast::Path { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct PathSegment { pub name: String, pub lifetimes: Vec, @@ -1630,7 +1643,7 @@ impl Clean for doctree::Typedef { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, PartialEq)] pub struct BareFunctionDecl { pub fn_style: ast::FnStyle, pub generics: Generics, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index c549469dcdeaa..d0f9b37cc4ce4 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -210,7 +210,7 @@ fn path(w: &mut fmt::Formatter, path: &clean::Path, print_all: bool, let loc = current_location_key.get().unwrap(); let cache = cache_key.get().unwrap(); let abs_root = root(&**cache, loc.as_slice()); - let rel_root = match path.segments.get(0).name.as_slice() { + let rel_root = match path.segments[0].name.as_slice() { "self" => Some("./".to_string()), _ => None, }; @@ -500,6 +500,9 @@ impl<'a> fmt::Show for Method<'a> { args.push_str(format!("&{}self", MutableSpace(mtbl)).as_slice()); } + clean::SelfExplicit(ref typ) => { + args.push_str(format!("self: {}", *typ).as_slice()); + } } for (i, input) in d.inputs.values.iter().enumerate() { if i > 0 || args.len() > 0 { args.push_str(", "); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 244fada5b9ada..eed058878e082 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -551,7 +551,7 @@ fn write_shared(cx: &Context, } mydst.push(format!("{}.{}.js", remote_item_type.to_static_str(), - *remote_path.get(remote_path.len() - 1))); + remote_path[remote_path.len() - 1])); let all_implementors = try!(collect(&mydst, krate.name.as_slice(), "implementors")); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2cbac090835ed..245dc9a0a34e5 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -167,7 +167,7 @@ pub fn main_args(args: &[String]) -> int { println!("only one input file may be specified"); return 1; } - let input = matches.free.get(0).as_slice(); + let input = matches.free[0].as_slice(); let libs = matches.opt_strs("L").iter().map(|s| Path::new(s.as_slice())).collect(); diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index da271be4768e3..f9bc59888ae3b 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -75,7 +75,7 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches, "invalid markdown file: expecting initial line with `% ...TITLE...`"); return 5; } - let title = metadata.get(0).as_slice(); + let title = metadata[0].as_slice(); reset_headers(); diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 5145a4f254eea..cc5bc5cb7c170 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -339,7 +339,7 @@ pub fn unindent(s: &str) -> String { }); if lines.len() >= 1 { - let mut unindented = vec![ lines.get(0).trim().to_string() ]; + let mut unindented = vec![ lines[0].trim().to_string() ]; unindented.push_all(lines.tail().iter().map(|&line| { if line.is_whitespace() { line.to_string() diff --git a/src/librustrt/c_str.rs b/src/librustrt/c_str.rs index 396d51f4fcb13..0f2fcaff31036 100644 --- a/src/librustrt/c_str.rs +++ b/src/librustrt/c_str.rs @@ -778,11 +778,11 @@ mod tests { c_ = Some(c.clone()); c.clone(); // force a copy, reading the memory - c.as_bytes().to_owned(); + c.as_bytes().to_vec(); }); let c_ = c_.unwrap(); // force a copy, reading the memory - c_.as_bytes().to_owned(); + c_.as_bytes().to_vec(); } #[test] diff --git a/src/librustrt/local_data.rs b/src/librustrt/local_data.rs index ace53478d0a03..7434951d3ee91 100644 --- a/src/librustrt/local_data.rs +++ b/src/librustrt/local_data.rs @@ -94,7 +94,7 @@ pub type Map = Vec>; type TLSValue = Box; // Gets the map from the runtime. Lazily initialises if not done so already. -unsafe fn get_local_map() -> Option<&mut Map> { +unsafe fn get_local_map<'a>() -> Option<&'a mut Map> { if !Local::exists(None::) { return None } let task: *mut Task = Local::unsafe_borrow(); diff --git a/src/librustrt/rtio.rs b/src/librustrt/rtio.rs index 343b911fb83f3..81a033e4c987e 100644 --- a/src/librustrt/rtio.rs +++ b/src/librustrt/rtio.rs @@ -134,7 +134,7 @@ impl<'a> Drop for LocalIo<'a> { impl<'a> LocalIo<'a> { /// Returns the local I/O: either the local scheduler's I/O services or /// the native I/O services. - pub fn borrow() -> Option { + pub fn borrow() -> Option> { // FIXME(#11053): bad // // This is currently very unsafely implemented. We don't actually diff --git a/src/librustuv/file.rs b/src/librustuv/file.rs index 26ba601f73ec1..f42f42d211160 100644 --- a/src/librustuv/file.rs +++ b/src/librustuv/file.rs @@ -469,7 +469,7 @@ mod test { use super::super::Loop; use super::super::local_loop; - fn l() -> &mut Loop { &mut local_loop().loop_ } + fn l() -> &'static mut Loop { &mut local_loop().loop_ } #[test] fn file_test_full_simple_sync() { diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index f7301abef51f2..a56904c9ef4db 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -74,51 +74,102 @@ When using `ToJson` the `Encodable` trait implementation is not mandatory. ## Using Autoserialization -Create a struct called TestStruct1 and serialize and deserialize it to and from JSON -using the serialization API, using the derived serialization code. +Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the +serialization API, using the derived serialization code. ```rust extern crate serialize; use serialize::json; -#[deriving(Decodable, Encodable)] //generate Decodable, Encodable impl. -pub struct TestStruct1 { +// Automatically generate `Decodable` and `Encodable` trait implementations +#[deriving(Decodable, Encodable)] +pub struct TestStruct { data_int: u8, data_str: String, data_vector: Vec, } fn main() { - let object = TestStruct1 - {data_int: 1, data_str:"toto".to_string(), data_vector:vec![2,3,4,5]}; + let object = TestStruct { + data_int: 1, + data_str: "toto".to_string(), + data_vector: vec![2,3,4,5], + }; // Serialize using `json::encode` let encoded = json::encode(&object); // Deserialize using `json::decode` - let decoded: TestStruct1 = json::decode(encoded.as_slice()).unwrap(); + let decoded: TestStruct = json::decode(encoded.as_slice()).unwrap(); } ``` -## Using `ToJson` +## Using the `ToJson` trait + +The examples above use the `ToJson` trait to generate the JSON string, which required +for custom mappings. + +### Simple example of `ToJson` usage + +```rust +extern crate serialize; +use serialize::json::ToJson; +use serialize::json; + +// A custom data structure +struct ComplexNum { + a: f64, + b: f64, +} + +// JSON value representation +impl ToJson for ComplexNum { + fn to_json(&self) -> json::Json { + json::String(format!("{}+{}i", self.a, self.b)) + } +} -This example uses the `ToJson` trait to generate the JSON string. +// Only generate `Encodable` trait implementation +#[deriving(Encodable)] +pub struct ComplexNumRecord { + uid: u8, + dsc: String, + val: json::Json, +} + +fn main() { + let num = ComplexNum { a: 0.0001, b: 12.539 }; + let data: String = json::encode(&ComplexNumRecord{ + uid: 1, + dsc: "test".to_string(), + val: num.to_json(), + }); + println!("data: {}", data); + // data: {"uid":1,"dsc":"test","val":"0.0001+12.539j"}; +} +``` + +### Verbose example of `ToJson` usage ```rust +extern crate serialize; use std::collections::TreeMap; use serialize::json::ToJson; use serialize::json; +// Only generate `Decodable` trait implementation #[deriving(Decodable)] -pub struct TestStruct1 { +pub struct TestStruct { data_int: u8, data_str: String, data_vector: Vec, } -impl ToJson for TestStruct1 { - fn to_json( &self ) -> json::Json { +// Specify encoding method manually +impl ToJson for TestStruct { + fn to_json(&self) -> json::Json { let mut d = TreeMap::new(); + // All standard types implement `to_json()`, so use it d.insert("data_int".to_string(), self.data_int.to_json()); d.insert("data_str".to_string(), self.data_str.to_json()); d.insert("data_vector".to_string(), self.data_vector.to_json()); @@ -128,12 +179,16 @@ impl ToJson for TestStruct1 { fn main() { // Serialize using `ToJson` - let test2 = TestStruct1 {data_int: 1, data_str:"toto".to_string(), data_vector:vec![2,3,4,5]}; - let tjson: json::Json = test2.to_json(); - let json_str: String = tjson.to_string(); + let input_data = TestStruct { + data_int: 1, + data_str: "toto".to_string(), + data_vector: vec![2,3,4,5], + }; + let json_obj: json::Json = input_data.to_json(); + let json_str: String = json_obj.to_string(); // Deserialize like before - let decoded: TestStruct1 = json::decode(json_str.as_slice()).unwrap(); + let decoded: TestStruct = json::decode(json_str.as_slice()).unwrap(); } ``` @@ -1015,7 +1070,7 @@ impl Stack { /// lower indices are at the bottom of the stack while higher indices are /// at the top. pub fn get<'l>(&'l self, idx: uint) -> StackElement<'l> { - match *self.stack.get(idx) { + match self.stack[idx] { InternalIndex(i) => { Index(i) } InternalKey(start, size) => { Key(str::from_utf8( @@ -2740,6 +2795,7 @@ mod tests { } } #[test] + #[ignore] // FIXME(#15763) fn test_decode_errors_struct() { check_err::("[]", ExpectedError("Object".to_string(), "[]".to_string())); check_err::("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}", diff --git a/src/libstd/collections/hashmap.rs b/src/libstd/collections/hashmap.rs index 098e87243b69c..14027bc1f544f 100644 --- a/src/libstd/collections/hashmap.rs +++ b/src/libstd/collections/hashmap.rs @@ -1484,49 +1484,76 @@ pub type SetMoveItems = /// An implementation of a hash set using the underlying representation of a /// HashMap where the value is (). As with the `HashMap` type, a `HashSet` /// requires that the elements implement the `Eq` and `Hash` traits. +/// +/// # Example +/// +/// ```rust +/// use std::collections::HashSet; +/// +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashSet<&str>` in this example). +/// let mut books = HashSet::new(); +/// +/// // Add some books. +/// books.insert("A Dance With Dragons"); +/// books.insert("To Kill a Mockingbird"); +/// books.insert("The Odyssey"); +/// books.insert("The Great Gatsby"); +/// +/// // Check for a specific one. +/// if !books.contains(&("The Winds of Winter")) { +/// println!("We have {} books, but The Winds of Winter ain't one.", +/// books.len()); +/// } +/// +/// // Remove a book. +/// books.remove(&"The Odyssey"); +/// +/// // Iterate over everything. +/// for book in books.iter() { +/// println!("{}", *book); +/// } +/// ``` +/// +/// The easiest way to use `HashSet` with a custom type is to derive +/// `Eq` and `Hash`. We must also derive `PartialEq`, this will in the +/// future be implied by `Eq`. +/// +/// ```rust +/// use std::collections::HashSet; +/// +/// #[deriving(Hash, Eq, PartialEq, Show)] +/// struct Viking<'a> { +/// name: &'a str, +/// power: uint, +/// } +/// +/// let mut vikings = HashSet::new(); +/// +/// vikings.insert(Viking { name: "Einar", power: 9u }); +/// vikings.insert(Viking { name: "Einar", power: 9u }); +/// vikings.insert(Viking { name: "Olaf", power: 4u }); +/// vikings.insert(Viking { name: "Harald", power: 8u }); +/// +/// // Use derived implementation to print the vikings. +/// for x in vikings.iter() { +/// println!("{}", x); +/// } +/// ``` #[deriving(Clone)] pub struct HashSet { map: HashMap } -impl, S, H: Hasher> PartialEq for HashSet { - fn eq(&self, other: &HashSet) -> bool { - if self.len() != other.len() { return false; } - - self.iter().all(|key| other.contains(key)) - } -} - -impl, S, H: Hasher> Eq for HashSet {} - -impl, S, H: Hasher> Collection for HashSet { - fn len(&self) -> uint { self.map.len() } -} - -impl, S, H: Hasher> Mutable for HashSet { - fn clear(&mut self) { self.map.clear() } -} - -impl, S, H: Hasher> Set for HashSet { - fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } - - fn is_disjoint(&self, other: &HashSet) -> bool { - self.iter().all(|v| !other.contains(v)) - } - - fn is_subset(&self, other: &HashSet) -> bool { - self.iter().all(|v| other.contains(v)) - } -} - -impl, S, H: Hasher> MutableSet for HashSet { - fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } - - fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } -} - impl HashSet { - /// Create an empty HashSet + /// Create an empty HashSet. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// ``` #[inline] pub fn new() -> HashSet { HashSet::with_capacity(INITIAL_CAPACITY) @@ -1534,6 +1561,13 @@ impl HashSet { /// Create an empty HashSet with space for at least `n` elements in /// the hash table. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// let mut set: HashSet = HashSet::with_capacity(10); + /// ``` #[inline] pub fn with_capacity(capacity: uint) -> HashSet { HashSet { map: HashMap::with_capacity(capacity) } @@ -1545,6 +1579,17 @@ impl, S, H: Hasher> HashSet { /// keys. /// /// The hash set is also created with the default initial capacity. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// use std::hash::sip::SipHasher; + /// + /// let h = SipHasher::new(); + /// let mut set = HashSet::with_hasher(h); + /// set.insert(2u); + /// ``` #[inline] pub fn with_hasher(hasher: H) -> HashSet { HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher) @@ -1557,24 +1602,97 @@ impl, S, H: Hasher> HashSet { /// is designed to allow `HashSet`s to be resistant to attacks that /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// use std::hash::sip::SipHasher; + /// + /// let h = SipHasher::new(); + /// let mut set = HashSet::with_capacity_and_hasher(10u, h); + /// set.insert(1i); + /// ``` #[inline] pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashSet { HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } } /// Reserve space for at least `n` elements in the hash table. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.reserve(10); + /// ``` pub fn reserve(&mut self, n: uint) { self.map.reserve(n) } /// Returns true if the hash set contains a value equivalent to the /// given query value. + /// + /// # Example + /// + /// This is a slightly silly example where we define the number's + /// parity as the equivilance class. It is important that the + /// values hash the same, which is why we implement `Hash`. + /// + /// ```rust + /// use std::collections::HashSet; + /// use std::hash::Hash; + /// use std::hash::sip::SipState; + /// + /// #[deriving(Eq, PartialEq)] + /// struct EvenOrOdd { + /// num: uint + /// }; + /// + /// impl Hash for EvenOrOdd { + /// fn hash(&self, state: &mut SipState) { + /// let parity = self.num % 2; + /// parity.hash(state); + /// } + /// } + /// + /// impl Equiv for EvenOrOdd { + /// fn equiv(&self, other: &EvenOrOdd) -> bool { + /// self.num % 2 == other.num % 2 + /// } + /// } + /// + /// let mut set = HashSet::new(); + /// set.insert(EvenOrOdd { num: 3u }); + /// + /// assert!(set.contains_equiv(&EvenOrOdd { num: 3u })); + /// assert!(set.contains_equiv(&EvenOrOdd { num: 5u })); + /// assert!(!set.contains_equiv(&EvenOrOdd { num: 4u })); + /// assert!(!set.contains_equiv(&EvenOrOdd { num: 2u })); + /// + /// ``` pub fn contains_equiv + Equiv>(&self, value: &Q) -> bool { self.map.contains_key_equiv(value) } /// An iterator visiting all elements in arbitrary order. /// Iterator element type is &'a T. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.insert("a"); + /// set.insert("b"); + /// + /// // Will print in an arbitrary order. + /// for x in set.iter() { + /// println!("{}", x); + /// } + /// ``` pub fn iter<'a>(&'a self) -> SetItems<'a, T> { self.map.keys() } @@ -1582,11 +1700,51 @@ impl, S, H: Hasher> HashSet { /// Creates a consuming iterator, that is, one that moves each value out /// of the set in arbitrary order. The set cannot be used after calling /// this. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// set.insert("a".to_string()); + /// set.insert("b".to_string()); + /// + /// // Not possible to collect to a Vec with a regular `.iter()`. + /// let v: Vec = set.move_iter().collect(); + /// + /// // Will print in an arbitrary order. + /// for x in v.iter() { + /// println!("{}", x); + /// } + /// ``` pub fn move_iter(self) -> SetMoveItems { self.map.move_iter().map(|(k, _)| k) } - /// Visit the values representing the difference + /// Visit the values representing the difference. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Can be seen as `a - b`. + /// for x in a.difference(&b) { + /// println!("{}", x); // Print 1 + /// } + /// + /// let diff: HashSet = a.difference(&b).map(|&x| x).collect(); + /// assert_eq!(diff, [1i].iter().map(|&x| x).collect()); + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else: + /// let diff: HashSet = b.difference(&a).map(|&x| x).collect(); + /// assert_eq!(diff, [4i].iter().map(|&x| x).collect()); + /// ``` pub fn difference<'a>(&'a self, other: &'a HashSet) -> SetAlgebraItems<'a, T, H> { Repeat::new(other).zip(self.iter()) .filter_map(|(other, elt)| { @@ -1594,13 +1752,50 @@ impl, S, H: Hasher> HashSet { }) } - /// Visit the values representing the symmetric difference + /// Visit the values representing the symmetric difference. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Print 1, 4 in arbitrary order. + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// + /// let diff1: HashSet = a.symmetric_difference(&b).map(|&x| x).collect(); + /// let diff2: HashSet = b.symmetric_difference(&a).map(|&x| x).collect(); + /// + /// assert_eq!(diff1, diff2); + /// assert_eq!(diff1, [1i, 4].iter().map(|&x| x).collect()); + /// ``` pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) -> Chain, SetAlgebraItems<'a, T, H>> { self.difference(other).chain(other.difference(self)) } - /// Visit the values representing the intersection + /// Visit the values representing the intersection. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Print 2, 3 in arbitrary order. + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// + /// let diff: HashSet = a.intersection(&b).map(|&x| x).collect(); + /// assert_eq!(diff, [2i, 3].iter().map(|&x| x).collect()); + /// ``` pub fn intersection<'a>(&'a self, other: &'a HashSet) -> SetAlgebraItems<'a, T, H> { Repeat::new(other).zip(self.iter()) @@ -1609,13 +1804,67 @@ impl, S, H: Hasher> HashSet { }) } - /// Visit the values representing the union + /// Visit the values representing the union. + /// + /// # Example + /// + /// ```rust + /// use std::collections::HashSet; + /// + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Print 1, 2, 3, 4 in arbitrary order. + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// + /// let diff: HashSet = a.union(&b).map(|&x| x).collect(); + /// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect()); + /// ``` pub fn union<'a>(&'a self, other: &'a HashSet) -> Chain, SetAlgebraItems<'a, T, H>> { self.iter().chain(other.difference(self)) } } +impl, S, H: Hasher> PartialEq for HashSet { + fn eq(&self, other: &HashSet) -> bool { + if self.len() != other.len() { return false; } + + self.iter().all(|key| other.contains(key)) + } +} + +impl, S, H: Hasher> Eq for HashSet {} + +impl, S, H: Hasher> Collection for HashSet { + fn len(&self) -> uint { self.map.len() } +} + +impl, S, H: Hasher> Mutable for HashSet { + fn clear(&mut self) { self.map.clear() } +} + +impl, S, H: Hasher> Set for HashSet { + fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } + + fn is_disjoint(&self, other: &HashSet) -> bool { + self.iter().all(|v| !other.contains(v)) + } + + fn is_subset(&self, other: &HashSet) -> bool { + self.iter().all(|v| other.contains(v)) + } +} + +impl, S, H: Hasher> MutableSet for HashSet { + fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } + + fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } +} + + impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{")); diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 0ffaadef0a130..a9b9a907a2642 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -226,19 +226,24 @@ impl Rng for TaskRng { } } -/// Generate a random value using the task-local random number -/// generator. +/// Generates a random value using the task-local random number generator. /// -/// # Example +/// `random()` can generate various types of random things, and so may require +/// type hinting to generate the specific type you want. +/// +/// # Examples /// /// ```rust -/// use std::rand::random; +/// use std::rand; +/// +/// let x = rand::random(); +/// println!("{}", 2u * x); +/// +/// let y = rand::random::(); +/// println!("{}", y); /// -/// if random() { -/// let x = random(); -/// println!("{}", 2u * x); -/// } else { -/// println!("{}", random::()); +/// if rand::random() { // generates a boolean +/// println!("Better lucky than good!"); /// } /// ``` #[inline] diff --git a/src/libsync/comm/mod.rs b/src/libsync/comm/mod.rs index e9a303634fe37..2aec39521255e 100644 --- a/src/libsync/comm/mod.rs +++ b/src/libsync/comm/mod.rs @@ -2098,4 +2098,23 @@ mod sync_tests { }); assert_eq!(rx.recv(), 1); } #[ignore(reason = "flaky on libnative")]) + + test!(fn issue_15761() { + fn repro() { + let (tx1, rx1) = sync_channel::<()>(3); + let (tx2, rx2) = sync_channel::<()>(3); + + spawn(proc() { + rx1.recv(); + tx2.try_send(()).unwrap(); + }); + + tx1.try_send(()).unwrap(); + rx2.recv(); + } + + for _ in range(0u, 100) { + repro() + } + }) } diff --git a/src/libsync/comm/sync.rs b/src/libsync/comm/sync.rs index cc3c2197c13f0..1d5a7d6ed9f58 100644 --- a/src/libsync/comm/sync.rs +++ b/src/libsync/comm/sync.rs @@ -218,9 +218,15 @@ impl Packet { } } else { // If the buffer has some space and the capacity isn't 0, then we - // just enqueue the data for later retrieval. + // just enqueue the data for later retrieval, ensuring to wake up + // any blocked receiver if there is one. assert!(state.buf.size() < state.buf.cap()); state.buf.enqueue(t); + match mem::replace(&mut state.blocker, NoneBlocked) { + BlockedReceiver(task) => wakeup(task, guard), + NoneBlocked => {} + BlockedSender(..) => unreachable!(), + } Ok(()) } } diff --git a/src/libsync/mpmc_bounded_queue.rs b/src/libsync/mpmc_bounded_queue.rs index b700d57bc033d..7343838f19e61 100644 --- a/src/libsync/mpmc_bounded_queue.rs +++ b/src/libsync/mpmc_bounded_queue.rs @@ -90,7 +90,7 @@ impl State { let mask = self.mask; let mut pos = self.enqueue_pos.load(Relaxed); loop { - let node = self.buffer.get(pos & mask); + let node = &self.buffer[pos & mask]; let seq = unsafe { (*node.get()).sequence.load(Acquire) }; let diff: int = seq as int - pos as int; @@ -118,7 +118,7 @@ impl State { let mask = self.mask; let mut pos = self.dequeue_pos.load(Relaxed); loop { - let node = self.buffer.get(pos & mask); + let node = &self.buffer[pos & mask]; let seq = unsafe { (*node.get()).sequence.load(Acquire) }; let diff: int = seq as int - (pos + 1) as int; if diff == 0 { diff --git a/src/libsync/raw.rs b/src/libsync/raw.rs index 26cc0b2c6a23c..d056566bb9a97 100644 --- a/src/libsync/raw.rs +++ b/src/libsync/raw.rs @@ -243,7 +243,7 @@ impl<'a> Condvar<'a> { } // Create waiter nobe, and enqueue ourself to // be woken up by a signaller. - wait_end = Some(state.blocked.get(condvar_id).wait_end()); + wait_end = Some(state.blocked[condvar_id].wait_end()); } else { out_of_bounds = Some(state.blocked.len()); } @@ -281,7 +281,7 @@ impl<'a> Condvar<'a> { let mut result = false; self.sem.with(|state| { if condvar_id < state.blocked.len() { - result = state.blocked.get(condvar_id).signal(); + result = state.blocked[condvar_id].signal(); } else { out_of_bounds = Some(state.blocked.len()); } diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 8b01002831b7e..6f80938362049 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -30,6 +30,7 @@ pub enum Abi { C, System, RustIntrinsic, + RustCall, } #[allow(non_camel_case_types)] @@ -85,6 +86,7 @@ static AbiDatas: &'static [AbiData] = &[ AbiData {abi: C, name: "C", abi_arch: AllArch}, AbiData {abi: System, name: "system", abi_arch: AllArch}, AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch}, + AbiData {abi: RustCall, name: "rust-call", abi_arch: RustArch}, ]; /// Returns the ABI with the given name (if any). diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 857cb4c0162ce..394d4a825167d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -503,6 +503,7 @@ pub enum Expr_ { ExprMatch(Gc, Vec), ExprFnBlock(P, P), ExprProc(P, P), + ExprUnboxedFn(P, P), ExprBlock(P), ExprAssign(Gc, Gc), @@ -690,6 +691,7 @@ pub struct TypeMethod { pub ident: Ident, pub attrs: Vec, pub fn_style: FnStyle, + pub abi: Abi, pub decl: P, pub generics: Generics, pub explicit_self: ExplicitSelf, @@ -949,12 +951,14 @@ pub enum RetStyle { pub enum ExplicitSelf_ { /// No self SelfStatic, - /// `self + /// `self` SelfValue(Ident), /// `&'lt self`, `&'lt mut self` SelfRegion(Option, Mutability, Ident), /// `~self` - SelfUniq(Ident) + SelfUniq(Ident), + /// `self: TYPE` + SelfExplicit(P, Ident), } pub type ExplicitSelf = Spanned; @@ -964,13 +968,20 @@ pub struct Method { pub attrs: Vec, pub id: NodeId, pub span: Span, - pub node: Method_ + pub node: Method_, } #[deriving(PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Method_ { /// Represents a method declaration - MethDecl(Ident, Generics, ExplicitSelf, FnStyle, P, P, Visibility), + MethDecl(Ident, + Generics, + Abi, + ExplicitSelf, + FnStyle, + P, + P, + Visibility), /// Represents a macro in method position MethMac(Mac), } diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs index 1280b884f117a..a522f80554327 100644 --- a/src/libsyntax/ast_map/blocks.rs +++ b/src/libsyntax/ast_map/blocks.rs @@ -26,7 +26,7 @@ use ast::{P, Block, FnDecl, NodeId}; use ast; use ast_map::{Node}; use ast_map; -use ast_util; +use ast_util::PostExpansionMethod; use codemap::Span; use visit; @@ -152,13 +152,13 @@ impl FnLikeNode { pub fn body<'a>(&'a self) -> P { self.handle(|i: ItemFnParts| i.body, - |m: &'a ast::Method| ast_util::method_body(m), + |m: &'a ast::Method| m.pe_body(), |c: ClosureParts| c.body) } pub fn decl<'a>(&'a self) -> P { self.handle(|i: ItemFnParts| i.decl, - |m: &'a ast::Method| ast_util::method_fn_decl(m), + |m: &'a ast::Method| m.pe_fn_decl(), |c: ClosureParts| c.decl) } @@ -182,7 +182,7 @@ impl FnLikeNode { visit::FkFnBlock }; let method = |m: &'a ast::Method| { - visit::FkMethod(ast_util::method_ident(m), ast_util::method_generics(m), m) + visit::FkMethod(m.pe_ident(), m.pe_generics(), m) }; self.handle(item, method, closure) } diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 50e487b63db1f..c77f7db1c6da0 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -320,13 +320,15 @@ impl Map { } NodeForeignItem(i) => PathName(i.ident.name), NodeMethod(m) => match m.node { - MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name), + MethDecl(ident, _, _, _, _, _, _, _) => PathName(ident.name), MethMac(_) => fail!("no path elem for {:?}", node) }, NodeTraitMethod(tm) => match *tm { Required(ref m) => PathName(m.ident.name), Provided(m) => match m.node { - MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name), + MethDecl(ident, _, _, _, _, _, _, _) => { + PathName(ident.name) + } MethMac(_) => fail!("no path elem for {:?}", node), } }, @@ -709,7 +711,7 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String { format!("foreign item {} (id={})", path_str, id) } Some(NodeMethod(m)) => match m.node { - MethDecl(ident, _, _, _, _, _, _) => + MethDecl(ident, _, _, _, _, _, _, _) => format!("method {} in {} (id={})", token::get_ident(ident), map.path_to_string(id), id), diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index a18d8a81ef47f..3b4f6a6e0f85f 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use abi::Abi; use ast::*; use ast; use ast_util; @@ -249,7 +250,14 @@ pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod { Required(ref m) => (*m).clone(), Provided(m) => { match m.node { - MethDecl(ident, ref generics, explicit_self, fn_style, decl, _, vis) => { + MethDecl(ident, + ref generics, + abi, + explicit_self, + fn_style, + decl, + _, + vis) => { TypeMethod { ident: ident, attrs: m.attrs.clone(), @@ -260,6 +268,7 @@ pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod { id: m.id, span: m.span, vis: vis, + abi: abi, } }, MethMac(_) => fail!("expected non-macro method declaration") @@ -742,16 +751,25 @@ pub fn static_has_significant_address(mutbl: ast::Mutability, inline == InlineNever || inline == InlineNone } - /// Macro invocations are guaranteed not to occur after expansion is complete. -/// extracting fields of a method requires a dynamic check to make sure that it's -/// not a macro invocation, though this check is guaranteed to succeed, assuming +/// Extracting fields of a method requires a dynamic check to make sure that it's +/// not a macro invocation. This check is guaranteed to succeed, assuming /// that the invocations are indeed gone. -macro_rules! method_field_extractor { - ($fn_name:ident, $field_ty:ty, $field_pat:pat, $result:ident) => { - /// Returns the ident of a Method. To be used after expansion is complete - pub fn $fn_name<'a>(method: &'a ast::Method) -> $field_ty { - match method.node { +pub trait PostExpansionMethod { + fn pe_ident(&self) -> ast::Ident; + fn pe_generics<'a>(&'a self) -> &'a ast::Generics; + fn pe_abi(&self) -> Abi; + fn pe_explicit_self<'a>(&'a self) -> &'a ast::ExplicitSelf; + fn pe_fn_style(&self) -> ast::FnStyle; + fn pe_fn_decl(&self) -> P; + fn pe_body(&self) -> P; + fn pe_vis(&self) -> ast::Visibility; +} + +macro_rules! mf_method{ + ($meth_name:ident, $field_ty:ty, $field_pat:pat, $result:ident) => { + fn $meth_name<'a>(&'a self) -> $field_ty { + match self.node { $field_pat => $result, MethMac(_) => { fail!("expected an AST without macro invocations"); @@ -761,18 +779,19 @@ macro_rules! method_field_extractor { } } -// Note: this is unhygienic in the lifetime 'a. In order to fix this, we'd have to -// add :lifetime as a macro argument type, so that the 'a could be supplied by the macro -// invocation. -pub method_field_extractor!(method_ident,ast::Ident,MethDecl(ident,_,_,_,_,_,_),ident) -pub method_field_extractor!(method_generics,&'a ast::Generics, - MethDecl(_,ref generics,_,_,_,_,_),generics) -pub method_field_extractor!(method_explicit_self,&'a ast::ExplicitSelf, - MethDecl(_,_,ref explicit_self,_,_,_,_),explicit_self) -pub method_field_extractor!(method_fn_style,ast::FnStyle,MethDecl(_,_,_,fn_style,_,_,_),fn_style) -pub method_field_extractor!(method_fn_decl,P,MethDecl(_,_,_,_,decl,_,_),decl) -pub method_field_extractor!(method_body,P,MethDecl(_,_,_,_,_,body,_),body) -pub method_field_extractor!(method_vis,ast::Visibility,MethDecl(_,_,_,_,_,_,vis),vis) + +impl PostExpansionMethod for Method { + mf_method!(pe_ident,ast::Ident,MethDecl(ident,_,_,_,_,_,_,_),ident) + mf_method!(pe_generics,&'a ast::Generics, + MethDecl(_,ref generics,_,_,_,_,_,_),generics) + mf_method!(pe_abi,Abi,MethDecl(_,_,abi,_,_,_,_,_),abi) + mf_method!(pe_explicit_self,&'a ast::ExplicitSelf, + MethDecl(_,_,_,ref explicit_self,_,_,_,_),explicit_self) + mf_method!(pe_fn_style,ast::FnStyle,MethDecl(_,_,_,_,fn_style,_,_,_),fn_style) + mf_method!(pe_fn_decl,P,MethDecl(_,_,_,_,_,decl,_,_),decl) + mf_method!(pe_body,P,MethDecl(_,_,_,_,_,_,body,_),body) + mf_method!(pe_vis,ast::Visibility,MethDecl(_,_,_,_,_,_,_,vis),vis) +} #[cfg(test)] mod test { @@ -799,4 +818,3 @@ mod test { .iter().map(ident_to_segment).collect::>().as_slice())); } } - diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index b4af7205c4206..c344168b62a28 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -10,58 +10,32 @@ #![macro_escape] -// NOTE: remove after next snapshot -#[cfg(stage0)] -#[macro_export] -macro_rules! __register_diagnostic( - ($code:tt, $description:tt) => (); - ($code:tt) => () -) - #[macro_export] macro_rules! register_diagnostic( ($code:tt, $description:tt) => (__register_diagnostic!($code, $description)); ($code:tt) => (__register_diagnostic!($code)) ) -// NOTE: remove after next snapshot -#[cfg(stage0)] -#[macro_export] -macro_rules! __build_diagnostic_array( - ($name:ident) => { - pub static $name: [(&'static str, &'static str), ..0] = []; - } -) - -// NOTE: remove after next snapshot -#[cfg(stage0)] -#[macro_export] -macro_rules! __diagnostic_used( - ($code:ident) => { - () - } -) - #[macro_export] macro_rules! span_err( - ($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({ + ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); - ($session).span_err_with_code($span, format!($($arg),*).as_slice(), stringify!($code)) + $session.span_err_with_code($span, format!($($message)*).as_slice(), stringify!($code)) }) ) #[macro_export] macro_rules! span_warn( - ($session:expr, $span:expr, $code:ident, $($arg:expr),*) => ({ + ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ __diagnostic_used!($code); - ($session).span_warn_with_code($span, format!($($arg),*).as_slice(), stringify!($code)) + $session.span_warn_with_code($span, format!($($message)*).as_slice(), stringify!($code)) }) ) #[macro_export] macro_rules! span_note( - ($session:expr, $span:expr, $($arg:expr),*) => ({ - ($session).span_note($span, format!($($arg),*).as_slice()) + ($session:expr, $span:expr, $($message:tt)*) => ({ + ($session).span_note($span, format!($($message)*).as_slice()) }) ) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 56484c4ba59df..49bd3697884c7 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -371,6 +371,9 @@ pub fn syntax_expander_table() -> SyntaxEnv { syntax_expanders.insert(intern("quote_ty"), builtin_normal_expander( ext::quote::expand_quote_ty)); + syntax_expanders.insert(intern("quote_method"), + builtin_normal_expander( + ext::quote::expand_quote_method)); syntax_expanders.insert(intern("quote_item"), builtin_normal_expander( ext::quote::expand_quote_item)); diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 46efdccadec80..871f277a2da28 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -183,6 +183,8 @@ use std::cell::RefCell; use std::gc::{Gc, GC}; +use abi::Abi; +use abi; use ast; use ast::{P, EnumDef, Expr, Ident, Generics, StructDef}; use ast_util; @@ -477,9 +479,13 @@ impl<'a> TraitDef<'a> { nonself_args.as_slice()) }; - method_def.create_method(cx, self, - type_ident, generics, - explicit_self, tys, + method_def.create_method(cx, + self, + type_ident, + generics, + abi::Rust, + explicit_self, + tys, body) }).collect(); @@ -513,9 +519,13 @@ impl<'a> TraitDef<'a> { nonself_args.as_slice()) }; - method_def.create_method(cx, self, - type_ident, generics, - explicit_self, tys, + method_def.create_method(cx, + self, + type_ident, + generics, + abi::Rust, + explicit_self, + tys, body) }).collect(); @@ -622,9 +632,11 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef, type_ident: Ident, generics: &Generics, + abi: Abi, explicit_self: ast::ExplicitSelf, arg_types: Vec<(Ident, P)> , - body: Gc) -> Gc { + body: Gc) + -> Gc { // create the generics that aren't for Self let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); @@ -653,6 +665,7 @@ impl<'a> MethodDef<'a> { span: trait_.span, node: ast::MethDecl(method_ident, fn_generics, + abi, explicit_self, ast::NormalFn, fn_decl, @@ -954,7 +967,9 @@ impl<'a> MethodDef<'a> { // expressions for referencing every field of every // Self arg, assuming all are instances of VariantK. // Build up code associated with such a case. - let substructure = EnumMatching(index, variant, field_tuples); + let substructure = EnumMatching(index, + &*variant, + field_tuples); let arm_expr = self.call_substructure_method( cx, trait_, type_ident, self_args, nonself_args, &substructure); diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index f6a39d7b2e6c1..06eb92e1b271b 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -25,8 +25,6 @@ use std::gc::Gc; /// The types of pointers pub enum PtrTy<'a> { - /// ~ - Send, /// &'lifetime mut Borrowed(Option<&'a str>, ast::Mutability), } @@ -138,9 +136,6 @@ impl<'a> Ty<'a> { Ptr(ref ty, ref ptr) => { let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); match *ptr { - Send => { - cx.ty_uniq(span, raw_ty) - } Borrowed(ref lt, mutbl) => { let lt = mk_lifetime(cx, span, lt); cx.ty_rptr(span, raw_ty, lt, mutbl) @@ -260,7 +255,6 @@ pub fn get_explicit_self(cx: &ExtCtxt, span: Span, self_ptr: &Option) let self_ty = respan( span, match *ptr { - Send => ast::SelfUniq(special_idents::self_), Borrowed(ref lt, mutbl) => { let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name)); ast::SelfRegion(lt, mutbl, special_idents::self_) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 58689389769c9..fdb698441fc0c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -166,14 +166,14 @@ pub fn expand_expr(e: Gc, fld: &mut MacroExpander) -> Gc { ast::ExprFnBlock(fn_decl, block) => { let (rewritten_fn_decl, rewritten_block) - = expand_and_rename_fn_decl_and_block(fn_decl, block, fld); + = expand_and_rename_fn_decl_and_block(&*fn_decl, block, fld); let new_node = ast::ExprFnBlock(rewritten_fn_decl, rewritten_block); box(GC) ast::Expr{id:e.id, node: new_node, span: fld.new_span(e.span)} } ast::ExprProc(fn_decl, block) => { let (rewritten_fn_decl, rewritten_block) - = expand_and_rename_fn_decl_and_block(fn_decl, block, fld); + = expand_and_rename_fn_decl_and_block(&*fn_decl, block, fld); let new_node = ast::ExprProc(rewritten_fn_decl, rewritten_block); box(GC) ast::Expr{id:e.id, node: new_node, span: fld.new_span(e.span)} } @@ -422,7 +422,7 @@ fn expand_item_underscore(item: &ast::Item_, fld: &mut MacroExpander) -> ast::It match *item { ast::ItemFn(decl, fn_style, abi, ref generics, body) => { let (rewritten_fn_decl, rewritten_body) - = expand_and_rename_fn_decl_and_block(decl,body,fld); + = expand_and_rename_fn_decl_and_block(&*decl, body, fld); let expanded_generics = fold::fold_generics(generics,fld); ast::ItemFn(rewritten_fn_decl, fn_style, abi, expanded_generics, rewritten_body) } @@ -572,7 +572,9 @@ fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector> { }; let expanded_stmt = match expand_mac_invoc(mac,&s.span, |r|{r.make_stmt()}, - |sts,mrk|{mark_stmt(sts,mrk)}, + |sts,mrk| { + mark_stmt(&*sts,mrk) + }, fld) { Some(stmt) => stmt, None => { @@ -628,7 +630,7 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander) // names, as well... but that should be okay, as long as // the new names are gensyms for the old ones. // generate fresh names, push them to a new pending list - let idents = pattern_bindings(expanded_pat); + let idents = pattern_bindings(&*expanded_pat); let mut new_pending_renames = idents.iter().map(|ident| (*ident, fresh_name(ident))).collect(); // rewrite the pattern using the new names (the old @@ -677,7 +679,7 @@ fn expand_arm(arm: &ast::Arm, fld: &mut MacroExpander) -> ast::Arm { // all of the pats must have the same set of bindings, so use the // first one to extract them and generate new names: let first_pat = expanded_pats.get(0); - let idents = pattern_bindings(*first_pat); + let idents = pattern_bindings(&**first_pat); let new_renames = idents.iter().map(|id| (*id,fresh_name(id))).collect(); // apply the renaming, but only to the PatIdents: @@ -732,7 +734,7 @@ fn pattern_bindings(pat : &ast::Pat) -> Vec { fn fn_decl_arg_bindings(fn_decl: &ast::FnDecl) -> Vec { let mut pat_idents = PatIdentFinder{ident_accumulator:Vec::new()}; for arg in fn_decl.inputs.iter() { - pat_idents.visit_pat(arg.pat,()); + pat_idents.visit_pat(&*arg.pat, ()); } pat_idents.ident_accumulator } @@ -908,15 +910,23 @@ impl<'a> Folder for PatIdentRenamer<'a> { fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> SmallVector> { let id = fld.new_id(m.id); match m.node { - ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => { + ast::MethDecl(ident, + ref generics, + abi, + ref explicit_self, + fn_style, + decl, + body, + vis) => { let (rewritten_fn_decl, rewritten_body) - = expand_and_rename_fn_decl_and_block(decl,body,fld); + = expand_and_rename_fn_decl_and_block(&*decl,body,fld); SmallVector::one(box(GC) ast::Method { attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(), id: id, span: fld.new_span(m.span), node: ast::MethDecl(fld.fold_ident(ident), fold_generics(generics, fld), + abi, fld.fold_explicit_self(explicit_self), fn_style, rewritten_fn_decl, @@ -951,12 +961,12 @@ fn expand_and_rename_fn_decl_and_block(fn_decl: &ast::FnDecl, block: Gc (Gc, Gc) { let expanded_decl = fld.fold_fn_decl(fn_decl); - let idents = fn_decl_arg_bindings(expanded_decl); + let idents = fn_decl_arg_bindings(&*expanded_decl); let renames = idents.iter().map(|id : &ast::Ident| (*id,fresh_name(id))).collect(); // first, a renamer for the PatIdents, for the fn_decl: let mut rename_pat_fld = PatIdentRenamer{renames: &renames}; - let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(expanded_decl); + let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(&*expanded_decl); // now, a renamer for *all* idents, for the body: let mut rename_fld = IdentRenamer{renames: &renames}; let rewritten_body = fld.fold_block(rename_fld.fold_block(block)); @@ -999,7 +1009,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { } fn fold_method(&mut self, method: Gc) -> SmallVector> { - expand_method(method, self) + expand_method(&*method, self) } fn new_span(&mut self, span: Span) -> Span { @@ -1544,7 +1554,7 @@ mod test { fn run_renaming_test(t: &RenamingTest, test_idx: uint) { let invalid_name = token::special_idents::invalid.name; let (teststr, bound_connections, bound_ident_check) = match *t { - (ref str,ref conns, bic) => (str.to_owned(), conns.clone(), bic) + (ref str,ref conns, bic) => (str.to_string(), conns.clone(), bic) }; let cr = expand_crate_str(teststr.to_string()); let bindings = crate_bindings(&cr); @@ -1660,7 +1670,7 @@ foo_module!() fn pat_idents(){ let pat = string_to_pat( "(a,Foo{x:c @ (b,9),y:Bar(4,d)})".to_string()); - let idents = pattern_bindings(pat); + let idents = pattern_bindings(&*pat); assert_eq!(idents, strs_to_idents(vec!("a","c","b","d"))); } diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 786fd953f8901..4b245f2c9fd48 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -215,12 +215,21 @@ impl<'a, 'b> Context<'a, 'b> { } } + fn describe_num_args(&self) -> String { + match self.args.len() { + 0 => "no arguments given".to_string(), + 1 => "there is 1 argument".to_string(), + x => format!("there are {} arguments", x), + } + } + fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) { match arg { Exact(arg) => { if self.args.len() <= arg { - let msg = format!("invalid reference to argument `{}` (there \ - are {} arguments)", arg, self.args.len()); + let msg = format!("invalid reference to argument `{}` ({:s})", + arg, self.describe_num_args()); + self.ecx.span_err(self.fmtsp, msg.as_slice()); return; } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 696d62838ba79..a7ede6f742d9f 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -54,9 +54,10 @@ pub mod rt { } } - impl ToTokens for Vec { - fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - (*self).clone() + impl ToTokens for Vec { + fn to_tokens(&self, cx: &ExtCtxt) -> Vec { + let a = self.iter().flat_map(|t| t.to_tokens(cx).move_iter()); + FromIterator::from_iter(a) } } @@ -67,6 +68,15 @@ pub mod rt { } } + impl ToTokens for Option { + fn to_tokens(&self, cx: &ExtCtxt) -> Vec { + match self { + &Some(ref t) => t.to_tokens(cx), + &None => Vec::new(), + } + } + } + /* Should be (when bugs in default methods are fixed): trait ToSource : ToTokens { @@ -133,11 +143,18 @@ pub mod rt { impl_to_source!(ast::Arg, arg_to_string) impl_to_source!(Generics, generics_to_string) impl_to_source!(Gc, item_to_string) + impl_to_source!(Gc, method_to_string) impl_to_source!(Gc, expr_to_string) impl_to_source!(Gc, pat_to_string) impl_to_source_slice!(ast::Ty, ", ") impl_to_source_slice!(Gc, "\n\n") + impl ToSource for ast::Attribute_ { + fn to_source(&self) -> String { + pprust::attribute_to_string(&dummy_spanned(*self)) + } + } + impl<'a> ToSource for &'a str { fn to_source(&self) -> String { let lit = dummy_spanned(ast::LitStr( @@ -222,6 +239,7 @@ pub mod rt { impl_to_tokens!(ast::Ident) impl_to_tokens!(Gc) impl_to_tokens!(Gc) + impl_to_tokens!(Gc) impl_to_tokens_lifetime!(&'a [Gc]) impl_to_tokens!(ast::Ty) impl_to_tokens_lifetime!(&'a [ast::Ty]) @@ -229,6 +247,7 @@ pub mod rt { impl_to_tokens!(Gc) impl_to_tokens!(ast::Block) impl_to_tokens!(ast::Arg) + impl_to_tokens!(ast::Attribute_) impl_to_tokens_lifetime!(&'a str) impl_to_tokens!(()) impl_to_tokens!(char) @@ -336,6 +355,16 @@ pub fn expand_quote_ty(cx: &mut ExtCtxt, base::MacExpr::new(expanded) } +pub fn expand_quote_method(cx: &mut ExtCtxt, + sp: Span, + tts: &[ast::TokenTree]) + -> Box { + let e_param_colons = cx.expr_none(sp); + let expanded = expand_parse_call(cx, sp, "parse_method", + vec!(e_param_colons), tts); + base::MacExpr::new(expanded) +} + pub fn expand_quote_stmt(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fd786192cb48c..5417991c9df19 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -344,6 +344,7 @@ pub trait Folder { SelfRegion(ref lifetime, m, id) => { SelfRegion(fold_opt_lifetime(lifetime, self), m, id) } + SelfExplicit(ref typ, id) => SelfExplicit(self.fold_ty(*typ), id), } } @@ -471,7 +472,7 @@ fn fold_interpolated(nt : &token::Nonterminal, fld: &mut T) -> token: .expect_one("expected fold to produce exactly one item")), token::NtBlock(block) => token::NtBlock(fld.fold_block(block)), token::NtStmt(stmt) => - token::NtStmt(fld.fold_stmt(stmt) + token::NtStmt(fld.fold_stmt(&*stmt) // this is probably okay, because the only folds likely // to peek inside interpolated nodes will be renamings/markings, // which map single items to single items @@ -482,8 +483,8 @@ fn fold_interpolated(nt : &token::Nonterminal, fld: &mut T) -> token: token::NtIdent(ref id, is_mod_name) => token::NtIdent(box fld.fold_ident(**id),is_mod_name), token::NtMeta(meta_item) => token::NtMeta(fold_meta_item_(meta_item,fld)), - token::NtPath(ref path) => token::NtPath(box fld.fold_path(*path)), - token::NtTT(tt) => token::NtTT(box (GC) fold_tt(tt,fld)), + token::NtPath(ref path) => token::NtPath(box fld.fold_path(&**path)), + token::NtTT(tt) => token::NtTT(box (GC) fold_tt(&*tt,fld)), // it looks to me like we can leave out the matchers: token::NtMatchers(matchers) _ => (*nt).clone() } @@ -726,6 +727,7 @@ pub fn noop_fold_type_method(m: &TypeMethod, fld: &mut T) -> TypeMeth ident: fld.fold_ident(m.ident), attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(), fn_style: m.fn_style, + abi: m.abi, decl: fld.fold_fn_decl(&*m.decl), generics: fold_generics(&m.generics, fld), explicit_self: fld.fold_explicit_self(&m.explicit_self), @@ -817,9 +819,17 @@ pub fn noop_fold_method(m: &Method, folder: &mut T) -> SmallVector { + MethDecl(ident, + ref generics, + abi, + ref explicit_self, + fn_style, + decl, + body, + vis) => { MethDecl(folder.fold_ident(ident), fold_generics(generics, folder), + abi, folder.fold_explicit_self(explicit_self), fn_style, folder.fold_fn_decl(&*decl), @@ -947,7 +957,11 @@ pub fn noop_fold_expr(e: Gc, folder: &mut T) -> Gc { ExprProc(folder.fold_fn_decl(&**decl), folder.fold_block(body.clone())) } - ExprBlock(ref blk) => ExprBlock(folder.fold_block(blk.clone())), + ExprUnboxedFn(ref decl, ref body) => { + ExprUnboxedFn(folder.fold_fn_decl(&**decl), + folder.fold_block(*body)) + } + ExprBlock(ref blk) => ExprBlock(folder.fold_block(*blk)), ExprAssign(el, er) => { ExprAssign(folder.fold_expr(el), folder.fold_expr(er)) } diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index cadae7ef12f80..ba401d313d87f 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -76,7 +76,7 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> { ), ObsoleteManagedExpr => ( "`@` notation for a managed pointer allocation", - "use the `box(GC)` oeprator instead of `@`" + "use the `box(GC)` operator instead of `@`" ), }; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e0c94dffb5cae..394288bd9f29b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -25,7 +25,7 @@ use ast::{ExprBreak, ExprCall, ExprCast}; use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex}; use ast::{ExprLit, ExprLoop, ExprMac}; use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc}; -use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary}; +use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn}; use ast::{ExprVec, ExprVstore, ExprVstoreSlice}; use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl}; use ast::{ExprVstoreUniq, Once, Many}; @@ -45,7 +45,7 @@ use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; use ast::{StructVariantKind, BiSub}; use ast::StrStyle; -use ast::{SelfRegion, SelfStatic, SelfUniq, SelfValue}; +use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfUniq, SelfValue}; use ast::{TokenTree, TraitMethod, TraitRef, TTDelim, TTSeq, TTTok}; use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox}; use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn}; @@ -59,6 +59,7 @@ use ast::Visibility; use ast; use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec}; use ast_util; +use attr; use codemap::{Span, BytePos, Spanned, spanned, mk_sp}; use codemap; use parse; @@ -502,7 +503,9 @@ impl<'a> Parser<'a> { inedible: &[token::Token]) { debug!("commit_stmt {:?}", s); let _s = s; // unused, but future checks might want to inspect `s`. - if self.last_token.as_ref().map_or(false, |t| is_ident_or_path(*t)) { + if self.last_token + .as_ref() + .map_or(false, |t| is_ident_or_path(&**t)) { let expected = edible.iter().map(|x| (*x).clone()).collect::>() .append(inedible.as_slice()); self.check_for_erroneous_unit_struct_expecting( @@ -1215,6 +1218,16 @@ impl<'a> Parser<'a> { // NB: at the moment, trait methods are public by default; this // could change. let vis = p.parse_visibility(); + let abi = if p.eat_keyword(keywords::Extern) { + p.parse_opt_abi().unwrap_or(abi::C) + } else if attr::contains_name(attrs.as_slice(), + "rust_call_abi_hack") { + // FIXME(stage0, pcwalton): Remove this awful hack after a + // snapshot, and change to `extern "rust-call" fn`. + abi::RustCall + } else { + abi::Rust + }; let style = p.parse_fn_style(); let ident = p.parse_ident(); @@ -1237,6 +1250,7 @@ impl<'a> Parser<'a> { fn_style: style, decl: d, generics: generics, + abi: abi, explicit_self: explicit_self, id: ast::DUMMY_NODE_ID, span: mk_sp(lo, hi), @@ -1252,7 +1266,14 @@ impl<'a> Parser<'a> { attrs: attrs, id: ast::DUMMY_NODE_ID, span: mk_sp(lo, hi), - node: ast::MethDecl(ident, generics, explicit_self, style, d, body, vis) + node: ast::MethDecl(ident, + generics, + abi, + explicit_self, + style, + d, + body, + vis) }) } @@ -2618,51 +2639,11 @@ impl<'a> Parser<'a> { self.mk_expr(lo, hi, ExprIf(cond, thn, els)) } - /// `|args| { ... }` or `{ ...}` like in `do` expressions - pub fn parse_lambda_block_expr(&mut self) -> Gc { - self.parse_lambda_expr_( - |p| { - match p.token { - token::BINOP(token::OR) | token::OROR => { - p.parse_fn_block_decl() - } - _ => { - // No argument list - `do foo {` - P(FnDecl { - inputs: Vec::new(), - output: P(Ty { - id: ast::DUMMY_NODE_ID, - node: TyInfer, - span: p.span - }), - cf: Return, - variadic: false - }) - } - } - }, - |p| { - let blk = p.parse_block(); - p.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)) - }) - } - - /// `|args| expr` + // `|args| expr` pub fn parse_lambda_expr(&mut self) -> Gc { - self.parse_lambda_expr_(|p| p.parse_fn_block_decl(), - |p| p.parse_expr()) - } - - /// parse something of the form |args| expr - /// this is used both in parsing a lambda expr - /// and in parsing a block expr as e.g. in for... - pub fn parse_lambda_expr_(&mut self, - parse_decl: |&mut Parser| -> P, - parse_body: |&mut Parser| -> Gc) - -> Gc { let lo = self.span.lo; - let decl = parse_decl(self); - let body = parse_body(self); + let (decl, is_unboxed) = self.parse_fn_block_decl(); + let body = self.parse_expr(); let fakeblock = P(ast::Block { view_items: Vec::new(), stmts: Vec::new(), @@ -2672,7 +2653,11 @@ impl<'a> Parser<'a> { span: body.span, }); - return self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock)); + if is_unboxed { + self.mk_expr(lo, body.span.hi, ExprUnboxedFn(decl, fakeblock)) + } else { + self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock)) + } } pub fn parse_else_expr(&mut self) -> Gc { @@ -3843,7 +3828,15 @@ impl<'a> Parser<'a> { } } token::IDENT(..) if self.is_self_ident() => { - SelfValue(self.expect_self_ident()) + let self_ident = self.expect_self_ident(); + + // Determine whether this is the fully explicit form, `self: + // TYPE`. + if self.eat(&token::COLON) { + SelfExplicit(self.parse_ty(false), self_ident) + } else { + SelfValue(self_ident) + } } token::BINOP(token::STAR) => { // Possibly "*self" or "*mut self" -- not supported. Try to avoid @@ -3851,7 +3844,9 @@ impl<'a> Parser<'a> { self.bump(); let _mutability = if Parser::token_is_mutability(&self.token) { self.parse_mutability() - } else { MutImmutable }; + } else { + MutImmutable + }; if self.is_self_ident() { let span = self.span; self.span_err(span, "cannot pass self by unsafe pointer"); @@ -3863,7 +3858,15 @@ impl<'a> Parser<'a> { _ if Parser::token_is_mutability(&self.token) && self.look_ahead(1, |t| token::is_keyword(keywords::Self, t)) => { mutbl_self = self.parse_mutability(); - SelfValue(self.expect_self_ident()) + let self_ident = self.expect_self_ident(); + + // Determine whether this is the fully explicit form, `self: + // TYPE`. + if self.eat(&token::COLON) { + SelfExplicit(self.parse_ty(false), self_ident) + } else { + SelfValue(self_ident) + } } _ if Parser::token_is_mutability(&self.token) && self.look_ahead(1, |t| *t == token::TILDE) && @@ -3914,8 +3917,8 @@ impl<'a> Parser<'a> { } SelfValue(id) => parse_remaining_arguments!(id), SelfRegion(_,_,id) => parse_remaining_arguments!(id), - SelfUniq(id) => parse_remaining_arguments!(id) - + SelfUniq(id) => parse_remaining_arguments!(id), + SelfExplicit(_,id) => parse_remaining_arguments!(id), }; @@ -3935,18 +3938,30 @@ impl<'a> Parser<'a> { (spanned(lo, hi, explicit_self), fn_decl) } - /// Parse the |arg, arg| header on a lambda - fn parse_fn_block_decl(&mut self) -> P { - let inputs_captures = { + // parse the |arg, arg| header on a lambda + fn parse_fn_block_decl(&mut self) -> (P, bool) { + let (is_unboxed, inputs_captures) = { if self.eat(&token::OROR) { - Vec::new() + (false, Vec::new()) } else { - self.parse_unspanned_seq( - &token::BINOP(token::OR), + self.expect(&token::BINOP(token::OR)); + let is_unboxed = self.token == token::BINOP(token::AND) && + self.look_ahead(1, |t| { + token::is_keyword(keywords::Mut, t) + }) && + self.look_ahead(2, |t| *t == token::COLON); + if is_unboxed { + self.bump(); + self.bump(); + self.bump(); + } + let args = self.parse_seq_to_before_end( &token::BINOP(token::OR), seq_sep_trailing_disallowed(token::COMMA), |p| p.parse_fn_block_arg() - ) + ); + self.bump(); + (is_unboxed, args) } }; let output = if self.eat(&token::RARROW) { @@ -3959,12 +3974,12 @@ impl<'a> Parser<'a> { }) }; - P(FnDecl { + (P(FnDecl { inputs: inputs_captures, output: output, cf: Return, variadic: false - }) + }), is_unboxed) } /// Parses the `(arg, arg) -> return_type` header on a procedure. @@ -4059,6 +4074,11 @@ impl<'a> Parser<'a> { (ast::MethMac(m), self.span.hi, attrs) } else { let visa = self.parse_visibility(); + let abi = if self.eat_keyword(keywords::Extern) { + self.parse_opt_abi().unwrap_or(abi::C) + } else { + abi::Rust + }; let fn_style = self.parse_fn_style(); let ident = self.parse_ident(); let generics = self.parse_generics(); @@ -4067,7 +4087,14 @@ impl<'a> Parser<'a> { }); let (inner_attrs, body) = self.parse_inner_attrs_and_block(); let new_attrs = attrs.append(inner_attrs.as_slice()); - (ast::MethDecl(ident, generics, explicit_self, fn_style, decl, body, visa), + (ast::MethDecl(ident, + generics, + abi, + explicit_self, + fn_style, + decl, + body, + visa), body.span.hi, new_attrs) } }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d524622f8ecf5..dd96118ea49ee 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -188,7 +188,7 @@ pub fn method_to_string(p: &ast::Method) -> String { } pub fn fn_block_to_string(p: &ast::FnDecl) -> String { - to_string(|s| s.print_fn_block_args(p)) + to_string(|s| s.print_fn_block_args(p, false)) } pub fn path_to_string(p: &ast::Path) -> String { @@ -259,7 +259,8 @@ fn needs_parentheses(expr: &ast::Expr) -> bool { match expr.node { ast::ExprAssign(..) | ast::ExprBinary(..) | ast::ExprFnBlock(..) | ast::ExprProc(..) | - ast::ExprAssignOp(..) | ast::ExprCast(..) => true, + ast::ExprUnboxedFn(..) | ast::ExprAssignOp(..) | + ast::ExprCast(..) => true, _ => false, } } @@ -1004,9 +1005,20 @@ impl<'a> State<'a> { try!(self.maybe_print_comment(meth.span.lo)); try!(self.print_outer_attributes(meth.attrs.as_slice())); match meth.node { - ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => { - try!(self.print_fn(&*decl, Some(fn_style), abi::Rust, - ident, generics, Some(explicit_self.node), + ast::MethDecl(ident, + ref generics, + abi, + ref explicit_self, + fn_style, + decl, + body, + vis) => { + try!(self.print_fn(&*decl, + Some(fn_style), + abi, + ident, + generics, + Some(explicit_self.node), vis)); try!(word(&mut self.s, " ")); self.print_block_with_attrs(&*body, meth.attrs.as_slice()) @@ -1446,7 +1458,37 @@ impl<'a> State<'a> { // we are inside. // // if !decl.inputs.is_empty() { - try!(self.print_fn_block_args(&**decl)); + try!(self.print_fn_block_args(&**decl, false)); + try!(space(&mut self.s)); + // } + + if !body.stmts.is_empty() || !body.expr.is_some() { + try!(self.print_block_unclosed(&**body)); + } else { + // we extract the block, so as not to create another set of boxes + match body.expr.unwrap().node { + ast::ExprBlock(blk) => { + try!(self.print_block_unclosed(&*blk)); + } + _ => { + // this is a bare expression + try!(self.print_expr(&*body.expr.unwrap())); + try!(self.end()); // need to close a box + } + } + } + // a box will be closed by print_expr, but we didn't want an overall + // wrapper so we closed the corresponding opening. so create an + // empty box to satisfy the close. + try!(self.ibox(0)); + } + ast::ExprUnboxedFn(ref decl, ref body) => { + // in do/for blocks we don't want to show an empty + // argument list, but at this point we don't know which + // we are inside. + // + // if !decl.inputs.is_empty() { + try!(self.print_fn_block_args(&**decl, true)); try!(space(&mut self.s)); // } @@ -1859,6 +1901,11 @@ impl<'a> State<'a> { try!(self.print_mutability(m)); try!(word(&mut self.s, "self")); } + ast::SelfExplicit(ref typ, _) => { + try!(word(&mut self.s, "self")); + try!(self.word_space(":")); + try!(self.print_type(&**typ)); + } } return Ok(true); } @@ -1934,8 +1981,13 @@ impl<'a> State<'a> { } pub fn print_fn_block_args(&mut self, - decl: &ast::FnDecl) -> IoResult<()> { + decl: &ast::FnDecl, + is_unboxed: bool) + -> IoResult<()> { try!(word(&mut self.s, "|")); + if is_unboxed { + try!(self.word_space("&mut:")); + } try!(self.print_fn_args(decl, None)); try!(word(&mut self.s, "|")); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 795f19d0cfb06..d5fb75a4d695d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -215,6 +215,7 @@ pub fn walk_explicit_self>(visitor: &mut V, SelfRegion(ref lifetime, _, _) => { visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime, env) } + SelfExplicit(ref typ, _) => visitor.visit_ty(&**typ, env.clone()), } } @@ -561,11 +562,11 @@ pub fn walk_method_helper>(visitor: &mut V, method: &Method, env: E) { match method.node { - MethDecl(ident, ref generics, _, _, decl, body, _) => { + MethDecl(ident, ref generics, _, _, _, decl, body, _) => { visitor.visit_ident(method.span, ident, env.clone()); visitor.visit_fn(&FkMethod(ident, generics, method), - decl, - body, + &*decl, + &*body, method.span, method.id, env.clone()); @@ -593,7 +594,7 @@ pub fn walk_fn>(visitor: &mut V, FkMethod(_, generics, method) => { visitor.visit_generics(generics, env.clone()); match method.node { - MethDecl(_, _, ref explicit_self, _, _, _, _) => + MethDecl(_, _, _, ref explicit_self, _, _, _, _) => visitor.visit_explicit_self(explicit_self, env.clone()), MethMac(ref mac) => visitor.visit_mac(mac, env.clone()) @@ -789,6 +790,14 @@ pub fn walk_expr>(visitor: &mut V, expression: &Expr, en expression.id, env.clone()) } + ExprUnboxedFn(ref function_declaration, ref body) => { + visitor.visit_fn(&FkFnBlock, + &**function_declaration, + &**body, + expression.span, + expression.id, + env.clone()) + } ExprProc(ref function_declaration, ref body) => { visitor.visit_fn(&FkFnBlock, &**function_declaration, diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs index 139f1113aaf94..db76e78d1617c 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/libterm/terminfo/parm.rs @@ -512,13 +512,13 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result ,String> { assert!(!s.is_empty(), "string conversion produced empty result"); match op { FormatDigit => { - if flags.space && !(*s.get(0) == '-' as u8 || - *s.get(0) == '+' as u8) { + if flags.space && !(s[0] == '-' as u8 || + s[0] == '+' as u8) { s.unshift(' ' as u8); } } FormatOctal => { - if flags.alternate && *s.get(0) != '0' as u8 { + if flags.alternate && s[0] != '0' as u8 { s.unshift('0' as u8); } } diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs index 7ad14d7975493..ebec59924e8f3 100644 --- a/src/libterm/terminfo/searcher.rs +++ b/src/libterm/terminfo/searcher.rs @@ -79,7 +79,7 @@ pub fn get_dbpath_for_term(term: &str) -> Option> { pub fn open(term: &str) -> Result { match get_dbpath_for_term(term) { Some(x) => { - match File::open(x) { + match File::open(&*x) { Ok(file) => Ok(file), Err(e) => Err(format!("error opening file: {}", e)), } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index a857bc7535d9c..15c5fa6b75a5a 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -373,7 +373,7 @@ pub fn parse_opts(args: &[String]) -> Option { if matches.opt_present("h") { usage(args[0].as_slice()); return None; } let filter = if matches.free.len() > 0 { - let s = matches.free.get(0).as_slice(); + let s = matches.free[0].as_slice(); match Regex::new(s) { Ok(re) => Some(re), Err(e) => return Some(Err(format!("could not parse /{}/: {}", s, e))) diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 5169652116532..d8f628e2196f5 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -175,7 +175,7 @@ impl<'a,T: FloatMath + FromPrimitive> Stats for &'a [T] { // This inner loop applies `hi`/`lo` summation to each // partial so that the list of partial sums remains exact. for i in range(0, partials.len()) { - let mut y = *partials.get(i); + let mut y = partials[i]; if num::abs(x) < num::abs(y) { mem::swap(&mut x, &mut y); } diff --git a/src/libunicode/lib.rs b/src/libunicode/lib.rs index 13e54ed3c977b..c923799e812ff 100644 --- a/src/libunicode/lib.rs +++ b/src/libunicode/lib.rs @@ -29,7 +29,6 @@ html_root_url = "http://doc.rust-lang.org/", html_playground_url = "http://play.rust-lang.org/")] #![no_std] -#![allow(unused_attribute)] // NOTE: remove after stage0 extern crate core; diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index 233743175b503..aa13ae82e76d9 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -398,8 +398,8 @@ impl Uuid { match group_lens.len() { // Single group, no hyphens 1 => { - if *group_lens.get(0) != 32 { - return Err(ErrorInvalidLength(*group_lens.get(0))); + if group_lens[0] != 32 { + return Err(ErrorInvalidLength(group_lens[0])); } }, // Five groups, hyphens in between each diff --git a/src/snapshots.txt b/src/snapshots.txt index c0c7015e31a77..623f8f8bcc00d 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2014-07-17 9fc8394 + freebsd-x86_64 5a4b645e2b42ae06224cc679d4a43b3d89be1482 + linux-i386 a5e1bb723020ac35173d49600e76b0935e257a6a + linux-x86_64 1a2407df17442d93d1c34c916269a345658045d7 + macos-i386 6648fa88e41ad7c0991a085366e36d56005873ca + macos-x86_64 71b2d1dfd0abe1052908dc091e098ed22cf272c6 + winnt-i386 c26f0a713c5fadf99cce935f60dce0ea403fb411 + S 2014-07-09 8ddd286 freebsd-x86_64 de0c39057f409b69e5ddb888ba3e20b90d63f5db linux-i386 28bef31f2a017e1998256d0c2b2e0a0c9221451b diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs index b63aa18b75d34..b0090c63969ab 100644 --- a/src/test/auxiliary/lint_stability.rs +++ b/src/test/auxiliary/lint_stability.rs @@ -10,6 +10,9 @@ #![crate_id="lint_stability#0.1"] #![crate_type = "lib"] +#![feature(macro_rules)] +#![macro_escape] + #[deprecated] pub fn deprecated() {} #[deprecated="text"] @@ -173,3 +176,8 @@ pub struct StableTupleStruct(pub int); pub struct FrozenTupleStruct(pub int); #[locked] pub struct LockedTupleStruct(pub int); + +#[macro_export] +macro_rules! macro_test( + () => (deprecated()); +) diff --git a/src/test/auxiliary/overloaded_autoderef_xc.rs b/src/test/auxiliary/overloaded_autoderef_xc.rs index dbb978a0b4ed9..26d61e166f26b 100644 --- a/src/test/auxiliary/overloaded_autoderef_xc.rs +++ b/src/test/auxiliary/overloaded_autoderef_xc.rs @@ -15,17 +15,17 @@ struct DerefWithHelper { } trait Helper { - fn helper_borrow<'a>(&'a self) -> &'a T; + fn helper_borrow(&self) -> &T; } impl Helper for Option { - fn helper_borrow<'a>(&'a self) -> &'a T { + fn helper_borrow(&self) -> &T { self.as_ref().unwrap() } } impl> Deref for DerefWithHelper { - fn deref<'a>(&'a self) -> &'a T { + fn deref(&self) -> &T { self.helper.helper_borrow() } } diff --git a/src/test/auxiliary/use_from_trait_xc.rs b/src/test/auxiliary/use_from_trait_xc.rs index 19e53fcc61aa3..8c547c2800204 100644 --- a/src/test/auxiliary/use_from_trait_xc.rs +++ b/src/test/auxiliary/use_from_trait_xc.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +pub use self::sub::Bar; + pub trait Trait { fn foo(); } @@ -17,3 +19,11 @@ struct Foo; impl Foo { pub fn new() {} } + +mod sub { + pub struct Bar; + + impl Bar { + pub fn new() {} + } +} diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index b3deb88543ed4..143175e558b6d 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -72,7 +72,7 @@ fn sort_and_fmt(mm: &HashMap , uint>, total: uint) -> String { // given a map, search for the frequency of a pattern fn find(mm: &HashMap , uint>, key: String) -> uint { - let key = key.to_owned().into_ascii().as_slice().to_lower().into_string(); + let key = key.into_ascii().as_slice().to_lower().into_string(); match mm.find_equiv(&key.as_bytes()) { option::None => { return 0u; } option::Some(&num) => { return num; } @@ -179,7 +179,7 @@ fn main() { let mut proc_mode = false; for line in rdr.lines() { - let line = line.unwrap().as_slice().trim().to_owned(); + let line = line.unwrap().as_slice().trim().to_string(); if line.len() == 0u { continue; } diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index fe0744e5e7c37..b31b524cf9b45 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -156,7 +156,7 @@ impl Table { } } - fn iter<'a>(&'a self) -> Items<'a> { + fn iter(&self) -> Items { Items { cur: None, items: self.items.iter() } } } diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index 2d98668496cdb..b0e23983192f2 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -64,7 +64,7 @@ fn mandelbrot(w: uint, mut out: W) -> io::IoResult<()> { let chunk_size = h / WORKERS; // Account for remainders in workload division, e.g. 1000 / 16 = 62.5 - let first_chunk_size = if h % WORKERS != 0 { + let last_chunk_size = if h % WORKERS != 0 { chunk_size + h % WORKERS } else { chunk_size @@ -87,8 +87,8 @@ fn mandelbrot(w: uint, mut out: W) -> io::IoResult<()> { let mut is = Vec::with_capacity(w / WORKERS); let start = i * chunk_size; - let end = if i == 0 { - first_chunk_size + let end = if i == (WORKERS - 1) { + start + last_chunk_size } else { (i + 1) * chunk_size }; diff --git a/src/test/bench/shootout-regex-dna.rs b/src/test/bench/shootout-regex-dna.rs index bdf6862d0b133..8908b5b87ed3c 100644 --- a/src/test/bench/shootout-regex-dna.rs +++ b/src/test/bench/shootout-regex-dna.rs @@ -109,7 +109,7 @@ fn main() { let (mut variant_strs, mut counts) = (vec!(), vec!()); for variant in variants.move_iter() { let seq_arc_copy = seq_arc.clone(); - variant_strs.push(variant.to_string().to_owned()); + variant_strs.push(variant.to_string()); counts.push(Future::spawn(proc() { count_matches(seq_arc_copy.as_slice(), &variant) })); diff --git a/src/test/compile-fail/borrowck-bad-nested-calls-free.rs b/src/test/compile-fail/borrowck-bad-nested-calls-free.rs index fd96b750fc16c..ab2fc6c67b401 100644 --- a/src/test/compile-fail/borrowck-bad-nested-calls-free.rs +++ b/src/test/compile-fail/borrowck-bad-nested-calls-free.rs @@ -30,7 +30,7 @@ fn implicit() { // evaluated, but it gets freed when evaluating the second // argument! add( - a, + &*a, rewrite(&mut a)); //~ ERROR cannot borrow } diff --git a/src/test/compile-fail/borrowck-bad-nested-calls-move.rs b/src/test/compile-fail/borrowck-bad-nested-calls-move.rs index d1ab70e4aedcc..708eed0d113bd 100644 --- a/src/test/compile-fail/borrowck-bad-nested-calls-move.rs +++ b/src/test/compile-fail/borrowck-bad-nested-calls-move.rs @@ -30,7 +30,7 @@ fn implicit() { // evaluated, but it gets moved when evaluating the second // argument! add( - a, + &*a, a); //~ ERROR cannot move } diff --git a/src/test/compile-fail/borrowck-borrow-from-temporary.rs b/src/test/compile-fail/borrowck-borrow-from-temporary.rs index a2f5e28de3bdf..784bd1e8ae45d 100644 --- a/src/test/compile-fail/borrowck-borrow-from-temporary.rs +++ b/src/test/compile-fail/borrowck-borrow-from-temporary.rs @@ -13,7 +13,7 @@ struct Foo(int); -fn foo() -> &int { +fn foo<'a>() -> &'a int { let &Foo(ref x) = &Foo(3); //~ ERROR borrowed value does not live long enough x } diff --git a/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs b/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs index 34b9c31fdd82f..7175194355b0a 100644 --- a/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs +++ b/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs @@ -12,7 +12,7 @@ // other `&mut` pointers. trait Foo { - fn f1<'a>(&'a mut self) -> &'a (); + fn f1(&mut self) -> &(); fn f2(&mut self); } diff --git a/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref-mut.rs b/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref-mut.rs index 1e04a3568c350..05bc0d1e13b2d 100644 --- a/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref-mut.rs +++ b/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref-mut.rs @@ -18,13 +18,13 @@ struct Own { } impl Deref for Own { - fn deref<'a>(&'a self) -> &'a T { + fn deref(&self) -> &T { unsafe { &*self.value } } } impl DerefMut for Own { - fn deref_mut<'a>(&'a mut self) -> &'a mut T { + fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.value } } } @@ -44,11 +44,11 @@ impl Point { self.y = y; } - fn x_ref<'a>(&'a self) -> &'a int { + fn x_ref(&self) -> &int { &self.x } - fn y_mut<'a>(&'a mut self) -> &'a mut int { + fn y_mut(&mut self) -> &mut int { &mut self.y } } @@ -65,19 +65,19 @@ fn deref_mut_field2(mut x: Own) { let _i = &mut x.y; } -fn deref_extend_field<'a>(x: &'a Own) -> &'a int { +fn deref_extend_field(x: &Own) -> &int { &x.y } -fn deref_extend_mut_field1<'a>(x: &'a Own) -> &'a mut int { +fn deref_extend_mut_field1(x: &Own) -> &mut int { &mut x.y //~ ERROR cannot borrow } -fn deref_extend_mut_field2<'a>(x: &'a mut Own) -> &'a mut int { +fn deref_extend_mut_field2(x: &mut Own) -> &mut int { &mut x.y } -fn deref_extend_mut_field3<'a>(x: &'a mut Own) { +fn deref_extend_mut_field3(x: &mut Own) { // Hmm, this is unfortunate, because with box it would work, // but it's presently the expected outcome. See `deref_extend_mut_field4` // for the workaround. @@ -124,15 +124,15 @@ fn deref_mut_method2(mut x: Own) { x.set(0, 0); } -fn deref_extend_method<'a>(x: &'a Own) -> &'a int { +fn deref_extend_method(x: &Own) -> &int { x.x_ref() } -fn deref_extend_mut_method1<'a>(x: &'a Own) -> &'a mut int { +fn deref_extend_mut_method1(x: &Own) -> &mut int { x.y_mut() //~ ERROR cannot borrow } -fn deref_extend_mut_method2<'a>(x: &'a mut Own) -> &'a mut int { +fn deref_extend_mut_method2(x: &mut Own) -> &mut int { x.y_mut() } diff --git a/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref.rs b/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref.rs index 30aed76a4ebdb..5aaefd0173990 100644 --- a/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref.rs +++ b/src/test/compile-fail/borrowck-borrow-overloaded-auto-deref.rs @@ -18,7 +18,7 @@ struct Rc { } impl Deref for Rc { - fn deref<'a>(&'a self) -> &'a T { + fn deref(&self) -> &T { unsafe { &*self.value } } } @@ -38,11 +38,11 @@ impl Point { self.y = y; } - fn x_ref<'a>(&'a self) -> &'a int { + fn x_ref(&self) -> &int { &self.x } - fn y_mut<'a>(&'a mut self) -> &'a mut int { + fn y_mut(&mut self) -> &mut int { &mut self.y } } @@ -59,15 +59,15 @@ fn deref_mut_field2(mut x: Rc) { let _i = &mut x.y; //~ ERROR cannot borrow } -fn deref_extend_field<'a>(x: &'a Rc) -> &'a int { +fn deref_extend_field(x: &Rc) -> &int { &x.y } -fn deref_extend_mut_field1<'a>(x: &'a Rc) -> &'a mut int { +fn deref_extend_mut_field1(x: &Rc) -> &mut int { &mut x.y //~ ERROR cannot borrow } -fn deref_extend_mut_field2<'a>(x: &'a mut Rc) -> &'a mut int { +fn deref_extend_mut_field2(x: &mut Rc) -> &mut int { &mut x.y //~ ERROR cannot borrow } @@ -95,15 +95,15 @@ fn deref_mut_method2(mut x: Rc) { x.set(0, 0); //~ ERROR cannot borrow } -fn deref_extend_method<'a>(x: &'a Rc) -> &'a int { +fn deref_extend_method(x: &Rc) -> &int { x.x_ref() } -fn deref_extend_mut_method1<'a>(x: &'a Rc) -> &'a mut int { +fn deref_extend_mut_method1(x: &Rc) -> &mut int { x.y_mut() //~ ERROR cannot borrow } -fn deref_extend_mut_method2<'a>(x: &'a mut Rc) -> &'a mut int { +fn deref_extend_mut_method2(x: &mut Rc) -> &mut int { x.y_mut() //~ ERROR cannot borrow } diff --git a/src/test/compile-fail/borrowck-closures-use-after-free.rs b/src/test/compile-fail/borrowck-closures-use-after-free.rs index ec31160f0d535..735d9ece9b1a5 100644 --- a/src/test/compile-fail/borrowck-closures-use-after-free.rs +++ b/src/test/compile-fail/borrowck-closures-use-after-free.rs @@ -28,5 +28,5 @@ fn main() { let test = |foo: &Foo| { ptr = box Foo { x: ptr.x + 1 }; }; - test(ptr); //~ ERROR cannot borrow `*ptr` + test(&*ptr); //~ ERROR cannot borrow `*ptr` } diff --git a/src/test/compile-fail/borrowck-lend-flow-loop.rs b/src/test/compile-fail/borrowck-lend-flow-loop.rs index 561d8c679a1a4..12e1240d10d63 100644 --- a/src/test/compile-fail/borrowck-lend-flow-loop.rs +++ b/src/test/compile-fail/borrowck-lend-flow-loop.rs @@ -31,7 +31,7 @@ fn loop_overarching_alias_mut() { let mut x = &mut v; **x += 1; loop { - borrow(v); //~ ERROR cannot borrow + borrow(&*v); //~ ERROR cannot borrow } } @@ -41,7 +41,7 @@ fn block_overarching_alias_mut() { let mut v = box 3; let mut x = &mut v; for _ in range(0i, 3) { - borrow(v); //~ ERROR cannot borrow + borrow(&*v); //~ ERROR cannot borrow } *x = box 5; } @@ -105,7 +105,7 @@ fn while_aliased_mut_cond(cond: bool, cond2: bool) { let mut x = &mut w; while cond { **x += 1; - borrow(v); //~ ERROR cannot borrow + borrow(&*v); //~ ERROR cannot borrow if cond2 { x = &mut v; //~ ERROR cannot borrow } diff --git a/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs b/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs index c11a08b254f1c..bfa890ada9f19 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs @@ -14,7 +14,7 @@ fn borrow(v: &int, f: |x: &int|) { fn box_imm() { let mut v = box 3; - borrow(v, + borrow(&*v, |w| { //~ ERROR cannot borrow `v` as mutable v = box 4; assert_eq!(*v, 3); diff --git a/src/test/compile-fail/borrowck-managed-pointer-deref-scope.rs b/src/test/compile-fail/borrowck-managed-pointer-deref-scope.rs index 30430e00ef342..9e6bafa1eba7c 100644 --- a/src/test/compile-fail/borrowck-managed-pointer-deref-scope.rs +++ b/src/test/compile-fail/borrowck-managed-pointer-deref-scope.rs @@ -15,7 +15,7 @@ use std::gc::{GC, Gc}; -fn foo<'a>(x: &'a Gc) -> &'a int { +fn foo(x: &Gc) -> &int { match x { &ref y => { &**y // Do not expect an error here diff --git a/src/test/compile-fail/borrowck-object-lifetime.rs b/src/test/compile-fail/borrowck-object-lifetime.rs index 9466a78588c45..c55a5a30538d8 100644 --- a/src/test/compile-fail/borrowck-object-lifetime.rs +++ b/src/test/compile-fail/borrowck-object-lifetime.rs @@ -10,14 +10,14 @@ trait Foo { - fn borrowed<'a>(&'a self) -> &'a (); + fn borrowed(&self) -> &(); } -fn borrowed_receiver<'a>(x: &'a Foo) -> &'a () { +fn borrowed_receiver(x: &Foo) -> &() { x.borrowed() } -fn owned_receiver(x: Box) -> &() { +fn owned_receiver(x: Box) -> &'static () { x.borrowed() //~ ERROR `*x` does not live long enough } diff --git a/src/test/compile-fail/borrowck-overloaded-call.rs b/src/test/compile-fail/borrowck-overloaded-call.rs index 349a20313fa8c..f134c2aa09bd5 100644 --- a/src/test/compile-fail/borrowck-overloaded-call.rs +++ b/src/test/compile-fail/borrowck-overloaded-call.rs @@ -18,7 +18,7 @@ struct SFn { } impl Fn<(int,),int> for SFn { - fn call(&self, (z,): (int,)) -> int { + extern "rust-call" fn call(&self, (z,): (int,)) -> int { self.x * self.y * z } } @@ -29,7 +29,7 @@ struct SFnMut { } impl FnMut<(int,),int> for SFnMut { - fn call_mut(&mut self, (z,): (int,)) -> int { + extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int { self.x * self.y * z } } @@ -39,7 +39,7 @@ struct SFnOnce { } impl FnOnce<(String,),uint> for SFnOnce { - fn call_once(self, (z,): (String,)) -> uint { + extern "rust-call" fn call_once(self, (z,): (String,)) -> uint { self.x.len() + z.len() } } diff --git a/src/test/compile-fail/borrowck-overloaded-index-2.rs b/src/test/compile-fail/borrowck-overloaded-index-2.rs index 1e3144a931fbf..6d2eae8bc1e12 100644 --- a/src/test/compile-fail/borrowck-overloaded-index-2.rs +++ b/src/test/compile-fail/borrowck-overloaded-index-2.rs @@ -13,7 +13,7 @@ struct MyVec { } impl Index for MyVec { - fn index<'a>(&'a self, &i: &uint) -> &'a T { + fn index(&self, &i: &uint) -> &T { self.data.get(i) } } diff --git a/src/test/compile-fail/borrowck-preserve-box-in-field.rs b/src/test/compile-fail/borrowck-preserve-box-in-field.rs index 1ea4a98c45bee..b9dc795358083 100644 --- a/src/test/compile-fail/borrowck-preserve-box-in-field.rs +++ b/src/test/compile-fail/borrowck-preserve-box-in-field.rs @@ -25,7 +25,7 @@ struct F { f: Box } pub fn main() { let mut x = box(GC) F {f: box 3}; - borrow(x.f, |b_x| { + borrow(&*x.f, |b_x| { //~^ ERROR cannot borrow `x` as mutable because `*x.f` is also borrowed as immutable assert_eq!(*b_x, 3); assert_eq!(&(*x.f) as *const int, &(*b_x) as *const int); diff --git a/src/test/compile-fail/borrowck-preserve-box-in-uniq.rs b/src/test/compile-fail/borrowck-preserve-box-in-uniq.rs index 979791ad763f5..38c80f293ef24 100644 --- a/src/test/compile-fail/borrowck-preserve-box-in-uniq.rs +++ b/src/test/compile-fail/borrowck-preserve-box-in-uniq.rs @@ -25,7 +25,7 @@ struct F { f: Box } pub fn main() { let mut x = box box(GC) F{f: box 3}; - borrow(x.f, |b_x| { + borrow(&*x.f, |b_x| { //~^ ERROR cannot borrow `x` as mutable because `*x.f` is also borrowed as immutable assert_eq!(*b_x, 3); assert_eq!(&(*x.f) as *const int, &(*b_x) as *const int); diff --git a/src/test/compile-fail/borrowck-preserve-box.rs b/src/test/compile-fail/borrowck-preserve-box.rs index 9eadb62c3a059..d838851e922ca 100644 --- a/src/test/compile-fail/borrowck-preserve-box.rs +++ b/src/test/compile-fail/borrowck-preserve-box.rs @@ -23,7 +23,7 @@ fn borrow(x: &int, f: |x: &int|) { pub fn main() { let mut x = box(GC) 3; - borrow(x, |b_x| { + borrow(&*x, |b_x| { //~^ ERROR cannot borrow `x` as mutable because `*x` is also borrowed as immutable assert_eq!(*b_x, 3); assert_eq!(&(*x) as *const int, &(*b_x) as *const int); diff --git a/src/test/compile-fail/borrowck-preserve-expl-deref.rs b/src/test/compile-fail/borrowck-preserve-expl-deref.rs index 066bb53cdc4d3..d00bded2d79ca 100644 --- a/src/test/compile-fail/borrowck-preserve-expl-deref.rs +++ b/src/test/compile-fail/borrowck-preserve-expl-deref.rs @@ -25,7 +25,7 @@ struct F { f: Box } pub fn main() { let mut x = box(GC) F {f: box 3}; - borrow((*x).f, |b_x| { + borrow(&*(*x).f, |b_x| { //~^ ERROR cannot borrow `x` as mutable because `*x.f` is also borrowed as immutable assert_eq!(*b_x, 3); assert_eq!(&(*x.f) as *const int, &(*b_x) as *const int); diff --git a/src/test/compile-fail/borrowck-uniq-via-lend.rs b/src/test/compile-fail/borrowck-uniq-via-lend.rs index 5a129956487c9..9785b6a8f69a3 100644 --- a/src/test/compile-fail/borrowck-uniq-via-lend.rs +++ b/src/test/compile-fail/borrowck-uniq-via-lend.rs @@ -13,13 +13,13 @@ fn borrow(_v: &int) {} fn local() { let mut v = box 3i; - borrow(v); + borrow(&*v); } fn local_rec() { struct F { f: Box } let mut v = F {f: box 3}; - borrow(v.f); + borrow(&*v.f); } fn local_recs() { @@ -27,26 +27,26 @@ fn local_recs() { struct G { g: H } struct H { h: Box } let mut v = F {f: G {g: H {h: box 3}}}; - borrow(v.f.g.h); + borrow(&*v.f.g.h); } fn aliased_imm() { let mut v = box 3i; let _w = &v; - borrow(v); + borrow(&*v); } fn aliased_mut() { let mut v = box 3i; let _w = &mut v; - borrow(v); //~ ERROR cannot borrow `*v` + borrow(&*v); //~ ERROR cannot borrow `*v` } fn aliased_other() { let mut v = box 3i; let mut w = box 4i; let _x = &mut w; - borrow(v); + borrow(&*v); } fn aliased_other_reassign() { @@ -54,7 +54,7 @@ fn aliased_other_reassign() { let mut w = box 4i; let mut _x = &mut w; _x = &mut v; - borrow(v); //~ ERROR cannot borrow `*v` + borrow(&*v); //~ ERROR cannot borrow `*v` } fn main() { diff --git a/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs index 3da284175541d..53ebaa38fddba 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn a() -> &[int] { +fn a<'a>() -> &'a [int] { let vec = vec!(1, 2, 3, 4); let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough let tail = match vec { @@ -18,7 +18,7 @@ fn a() -> &[int] { tail } -fn b() -> &[int] { +fn b<'a>() -> &'a [int] { let vec = vec!(1, 2, 3, 4); let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough let init = match vec { @@ -28,7 +28,7 @@ fn b() -> &[int] { init } -fn c() -> &[int] { +fn c<'a>() -> &'a [int] { let vec = vec!(1, 2, 3, 4); let vec: &[int] = vec.as_slice(); //~ ERROR does not live long enough let slice = match vec { diff --git a/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs index 26dc853859c92..57a276bec81bc 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn a() -> &int { +fn a<'a>() -> &'a int { let vec = vec!(1, 2, 3, 4); let vec: &[int] = vec.as_slice(); //~ ERROR `vec` does not live long enough let tail = match vec { diff --git a/src/test/compile-fail/cleanup-rvalue-scopes-cf.rs b/src/test/compile-fail/cleanup-rvalue-scopes-cf.rs index 01c6256173f03..b79f4507d4673 100644 --- a/src/test/compile-fail/cleanup-rvalue-scopes-cf.rs +++ b/src/test/compile-fail/cleanup-rvalue-scopes-cf.rs @@ -24,12 +24,12 @@ fn AddFlags(bits: u64) -> AddFlags { AddFlags { bits: bits } } -fn arg<'a>(x: &'a AddFlags) -> &'a AddFlags { +fn arg(x: &AddFlags) -> &AddFlags { x } impl AddFlags { - fn get<'a>(&'a self) -> &'a AddFlags { + fn get(&self) -> &AddFlags { self } } diff --git a/src/test/compile-fail/crate-name-mismatch.rs b/src/test/compile-fail/crate-name-mismatch.rs new file mode 100644 index 0000000000000..589c0beb76059 --- /dev/null +++ b/src/test/compile-fail/crate-name-mismatch.rs @@ -0,0 +1,16 @@ +// Copyright 2014 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. + +// compile-flags: --crate-name foo + +#![crate_name = "bar"] +//~^ ERROR: --crate-name and #[crate_name] are required to match, but `foo` != `bar` + +fn main() {} diff --git a/src/test/compile-fail/drop-with-active-borrows-2.rs b/src/test/compile-fail/drop-with-active-borrows-2.rs index 2700ceff68a07..1cbd6292e9907 100644 --- a/src/test/compile-fail/drop-with-active-borrows-2.rs +++ b/src/test/compile-fail/drop-with-active-borrows-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn read_lines_borrowed() -> Vec<&str> { +fn read_lines_borrowed<'a>() -> Vec<&'a str> { let raw_lines: Vec = vec!("foo ".to_string(), " bar".to_string()); raw_lines.iter().map(|l| l.as_slice().trim()).collect() //~^ ERROR `raw_lines` does not live long enough diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs new file mode 100644 index 0000000000000..285792e26b1bf --- /dev/null +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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. + +struct Foo<'a,'b> { + x: &'a int, + y: &'b int, +} + +impl<'a,'b> Foo<'a,'b> { + // The number of errors is related to the way invariance works. + fn bar(self: Foo<'b,'a>) {} + //~^ ERROR mismatched types: expected `Foo<'a,'b>` but found `Foo<'b,'a>` + //~^^ ERROR mismatched types: expected `Foo<'a,'b>` but found `Foo<'b,'a>` + //~^^^ ERROR mismatched types: expected `Foo<'b,'a>` but found `Foo<'a,'b>` + //~^^^^ ERROR mismatched types: expected `Foo<'b,'a>` but found `Foo<'a,'b>` +} + +fn main() {} + diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs index 84735ec78ce7e..6829b1e2721a7 100644 --- a/src/test/compile-fail/ifmt-bad-arg.rs +++ b/src/test/compile-fail/ifmt-bad-arg.rs @@ -29,6 +29,21 @@ fn main() { format!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument format!("", foo=1, 2); //~ ERROR: positional arguments cannot follow + // bad number of arguments, see #15780 + + format!("{0}"); + //~^ ERROR invalid reference to argument `0` (no arguments given) + + format!("{0} {1}", 1); + //~^ ERROR invalid reference to argument `1` (there is 1 argument) + + format!("{0} {1} {2}", 1, 2); + //~^ ERROR invalid reference to argument `2` (there are 2 arguments) + + format!("{0} {1}"); + //~^ ERROR invalid reference to argument `0` (no arguments given) + //~^^ ERROR invalid reference to argument `1` (no arguments given) + // bad syntax of the format string format!("{"); //~ ERROR: expected `}` but string was terminated diff --git a/src/test/compile-fail/infinite-autoderef.rs b/src/test/compile-fail/infinite-autoderef.rs index b41797d0042fa..e4c6fa7d47f4a 100644 --- a/src/test/compile-fail/infinite-autoderef.rs +++ b/src/test/compile-fail/infinite-autoderef.rs @@ -15,7 +15,7 @@ use std::ops::Deref; struct Foo; impl Deref for Foo { - fn deref<'a>(&'a self) -> &'a Foo { + fn deref(&self) -> &Foo { self } } diff --git a/src/test/compile-fail/issue-11192.rs b/src/test/compile-fail/issue-11192.rs index e7fa8300bcb69..18a00d15eafe3 100644 --- a/src/test/compile-fail/issue-11192.rs +++ b/src/test/compile-fail/issue-11192.rs @@ -25,7 +25,7 @@ fn main() { ptr = box Foo { x: ptr.x + 1 }; println!("access {}", foo.x); }; - test(ptr); + test(&*ptr); //~^ ERROR: cannot borrow `*ptr` as immutable } diff --git a/src/test/compile-fail/issue-11681.rs b/src/test/compile-fail/issue-11681.rs index dad503e88e1b9..71f1d5dcc9af4 100644 --- a/src/test/compile-fail/issue-11681.rs +++ b/src/test/compile-fail/issue-11681.rs @@ -18,7 +18,7 @@ impl Drop for Test { fn drop (&mut self) {} } -fn createTest() -> &Test { +fn createTest<'a>() -> &'a Test { let testValue = &Test; //~ ERROR borrowed value does not live long enough return testValue; } diff --git a/src/test/compile-fail/issue-3154.rs b/src/test/compile-fail/issue-3154.rs index dcb705856d997..141bf2b42791b 100644 --- a/src/test/compile-fail/issue-3154.rs +++ b/src/test/compile-fail/issue-3154.rs @@ -12,7 +12,7 @@ struct thing<'a, Q> { x: &'a Q } -fn thing(x: &Q) -> thing { +fn thing<'a,Q>(x: &Q) -> thing<'a,Q> { thing{ x: x } //~ ERROR cannot infer } diff --git a/src/test/compile-fail/issue-4972.rs b/src/test/compile-fail/issue-4972.rs index edd6932aec6f0..d684d1b376b8f 100644 --- a/src/test/compile-fail/issue-4972.rs +++ b/src/test/compile-fail/issue-4972.rs @@ -15,7 +15,7 @@ pub enum TraitWrapper { A(Box), } -fn get_tw_map<'lt>(tw: &'lt TraitWrapper) -> &'lt MyTrait { +fn get_tw_map(tw: &TraitWrapper) -> &MyTrait { match *tw { A(box ref map) => map, //~ ERROR cannot be dereferenced } diff --git a/src/test/compile-fail/issue-5153.rs b/src/test/compile-fail/issue-5153.rs index f8c1a91464271..57a158d2438dd 100644 --- a/src/test/compile-fail/issue-5153.rs +++ b/src/test/compile-fail/issue-5153.rs @@ -11,11 +11,11 @@ // error-pattern: type `&Foo` does not implement any method in scope named `foo` trait Foo { - fn foo(~self); + fn foo(self: Box); } impl Foo for int { - fn foo(~self) { } + fn foo(self: Box) { } } fn main() { diff --git a/src/test/compile-fail/isuue-12470.rs b/src/test/compile-fail/isuue-12470.rs index 18bfb7abe6c86..bf13b7ebbdbbe 100644 --- a/src/test/compile-fail/isuue-12470.rs +++ b/src/test/compile-fail/isuue-12470.rs @@ -31,9 +31,9 @@ fn make_a<'a>(p: &'a X) -> A<'a> { A { p: p } } -fn make_make_a() -> A { +fn make_make_a<'a>() -> A<'a> { let b: Box = box B {i:1}; - let bb: &B = b; //~ ERROR does not live long enough + let bb: &B = &*b; //~ ERROR does not live long enough make_a(bb) } diff --git a/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs b/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs new file mode 100644 index 0000000000000..aef3f7a40b555 --- /dev/null +++ b/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs @@ -0,0 +1,32 @@ +// Copyright 2014 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. + +// Lifetime annotation needed because we have no arguments. +fn f() -> &int { //~ ERROR missing lifetime specifier + fail!() +} + +// Lifetime annotation needed because we have two by-reference parameters. +fn g(_: &int, _: &int) -> &int { //~ ERROR missing lifetime specifier + fail!() +} + +struct Foo<'a> { + x: &'a int, +} + +// Lifetime annotation needed because we have two lifetimes: one as a parameter +// and one on the reference. +fn h(_: &Foo) -> &int { //~ ERROR missing lifetime specifier + fail!() +} + +fn main() {} + diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index 3328a5d23e62e..ef5a45fcf70ae 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength struct Foo<'x> { bar: int } -fn foo1(x: &Foo) -> &int { +fn foo1<'a>(x: &Foo) -> &'a int { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn foo1<'a>(x: &'a Foo) -> &'a int &x.bar //~ ERROR: cannot infer } @@ -21,34 +21,28 @@ fn foo2<'a, 'b>(x: &'a Foo) -> &'b int { &x.bar //~ ERROR: cannot infer } -fn foo3(x: &Foo) -> (&int, &int) { +fn foo3<'a>(x: &Foo) -> (&'a int, &'a int) { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn foo3<'a>(x: &'a Foo) -> (&'a int, &'a int) (&x.bar, &x.bar) //~ ERROR: cannot infer //~^ ERROR: cannot infer } -fn foo4<'a, 'b>(x: &'a Foo) -> (&'b int, &'a int, &int) { +fn foo4<'a, 'b>(x: &'a Foo) -> (&'b int, &'a int, &'b int) { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn foo4<'a>(x: &'a Foo) -> (&'a int, &'a int, &'a int) (&x.bar, &x.bar, &x.bar) //~ ERROR: cannot infer //~^ ERROR: cannot infer } -fn foo5(x: &int) -> &int { -//~^ NOTE: consider using an explicit lifetime parameter as shown: fn foo5<'a>(x: &'a int) -> &'a int - x //~ ERROR: mismatched types - //~^ ERROR: cannot infer -} - struct Bar<'x, 'y, 'z> { bar: &'y int, baz: int } -fn bar1(x: &Bar) -> (&int, &int, &int) { -//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'a, 'b, 'c, 'd>(x: &'d Bar<'b, 'a, 'c>) -> (&'a int, &'d int, &'d int) +fn bar1<'a>(x: &Bar) -> (&'a int, &'a int, &'a int) { +//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a int, &'a int, &'a int) (x.bar, &x.baz, &x.baz) //~ ERROR: mismatched types //~^ ERROR: cannot infer //~^^ ERROR: cannot infer } -fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&int, &int, &int) { -//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'d, 'a, 'b, 'c>(x: &'d Bar<'a, 'b, 'c>) -> (&'b int, &'d int, &'d int) +fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a int, &'a int, &'a int) { +//~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a int, &'a int, &'a int) (x.bar, &x.baz, &x.baz) //~ ERROR: mismatched types //~^ ERROR: cannot infer //~^^ ERROR: cannot infer @@ -56,13 +50,9 @@ fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&int, &int, &int) { struct Cat<'x, T> { cat: &'x int, t: T } struct Dog<'y> { dog: &'y int } -fn cat<'x>(x: Cat<'x, Dog>) -> &int { -//~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat<'a, 'x>(x: Cat<'x, Dog<'a>>) -> &'a int - x.t.dog //~ ERROR: mismatched types -} -fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &int { -//~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'y int +fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'x int { +//~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat2<'x>(x: Cat<'x, Dog<'x>>) -> &'x int x.t.dog //~ ERROR: mismatched types } @@ -70,16 +60,11 @@ struct Baz<'x> { bar: &'x int } -impl<'x> Baz<'x> { - fn baz1(&self) -> &int { - //~^ NOTE: consider using an explicit lifetime parameter as shown: fn baz1(&self) -> &'x int - self.bar //~ ERROR: mismatched types - } -} impl<'a> Baz<'a> { - fn baz2(&self, x: &int) -> (&int, &int) { - //~^ NOTE: consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &'b int) -> (&'a int, &'b int) + fn baz2<'b>(&self, x: &int) -> (&'b int, &'b int) { + // The lifetime that gets assigned to `x` seems somewhat random. + // I have disabled this test for the time being. --pcwalton (self.bar, x) //~ ERROR: cannot infer //~^ ERROR: mismatched types //~^^ ERROR: mismatched types diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 5d06ad79c9bdf..3a9380befbcb4 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -11,13 +11,14 @@ // aux-build:lint_stability.rs // aux-build:inherited_stability.rs -#![feature(globs)] +#![feature(globs, phase)] #![deny(unstable)] #![deny(deprecated)] #![deny(experimental)] #![allow(dead_code)] mod cross_crate { + #[phase(plugin, link)] extern crate lint_stability; use self::lint_stability::*; @@ -76,7 +77,6 @@ mod cross_crate { foo.method_locked_text(); foo.trait_locked_text(); - let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item let _ = ExperimentalStruct { i: 0 }; //~ ERROR use of experimental item let _ = UnstableStruct { i: 0 }; //~ ERROR use of unstable item @@ -108,6 +108,13 @@ mod cross_crate { let _ = StableTupleStruct (1); let _ = FrozenTupleStruct (1); let _ = LockedTupleStruct (1); + + // At the moment, the following just checks that the stability + // level of expanded code does not trigger the + // lint. Eventually, we will want to lint the contents of the + // macro in the module *defining* it. Also, stability levels + // on macros themselves are not yet linted. + macro_test!(); } fn test_method_param(foo: F) { diff --git a/src/test/compile-fail/lint-unused-mut-self.rs b/src/test/compile-fail/lint-unused-mut-self.rs index 84c484a91e2c4..fc19a1ba06f9b 100644 --- a/src/test/compile-fail/lint-unused-mut-self.rs +++ b/src/test/compile-fail/lint-unused-mut-self.rs @@ -16,7 +16,7 @@ struct Foo; impl Foo { fn foo(mut self) {} //~ ERROR: variable does not need to be mutable - fn bar(mut ~self) {} //~ ERROR: variable does not need to be mutable + fn bar(mut self: Box) {} //~ ERROR: variable does not need to be mutable } fn main() {} diff --git a/src/test/compile-fail/match-arm-statics.rs b/src/test/compile-fail/match-arm-statics.rs new file mode 100644 index 0000000000000..69cb626b75a46 --- /dev/null +++ b/src/test/compile-fail/match-arm-statics.rs @@ -0,0 +1,108 @@ +// Copyright 2014 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. + +struct NewBool(bool); + +enum Direction { + North, + East, + South, + West +} + +static TRUE_TRUE: (bool, bool) = (true, true); + +fn nonexhaustive_1() { + match (true, false) { + //~^ ERROR non-exhaustive patterns: `(true, false)` not covered + TRUE_TRUE => (), + (false, false) => (), + (false, true) => () + } +} + +fn unreachable_1() { + match (true, false) { + TRUE_TRUE => (), + (false, false) => (), + (false, true) => (), + (true, false) => (), + (true, true) => () + //~^ ERROR unreachable pattern + } +} + +static NONE: Option = None; +static EAST: Direction = East; + +fn nonexhaustive_2() { + match Some(Some(North)) { + //~^ ERROR non-exhaustive patterns: `Some(Some(West))` not covered + Some(NONE) => (), + Some(Some(North)) => (), + Some(Some(EAST)) => (), + Some(Some(South)) => (), + None => () + } +} + +fn unreachable_2() { + match Some(Some(North)) { + Some(NONE) => (), + Some(Some(North)) => (), + Some(Some(EAST)) => (), + Some(Some(South)) => (), + Some(Some(West)) => (), + Some(Some(East)) => (), + //~^ ERROR unreachable pattern + None => () + } +} + +static NEW_FALSE: NewBool = NewBool(false); +struct Foo { + bar: Option, + baz: NewBool +} + +static STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE }; + +fn nonexhaustive_3() { + match (Foo { bar: Some(North), baz: NewBool(true) }) { + //~^ ERROR non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` + Foo { bar: None, baz: NewBool(true) } => (), + Foo { bar: _, baz: NEW_FALSE } => (), + Foo { bar: Some(West), baz: NewBool(true) } => (), + Foo { bar: Some(South), .. } => (), + Foo { bar: Some(EAST), .. } => () + } +} + +fn unreachable_3() { + match (Foo { bar: Some(EAST), baz: NewBool(true) }) { + Foo { bar: None, baz: NewBool(true) } => (), + Foo { bar: _, baz: NEW_FALSE } => (), + Foo { bar: Some(West), baz: NewBool(true) } => (), + Foo { bar: Some(South), .. } => (), + Foo { bar: Some(EAST), .. } => (), + Foo { bar: Some(North), baz: NewBool(true) } => (), + Foo { bar: Some(EAST), baz: NewBool(false) } => () + //~^ ERROR unreachable pattern + } +} + +fn main() { + nonexhaustive_1(); + nonexhaustive_2(); + nonexhaustive_3(); + unreachable_1(); + unreachable_2(); + unreachable_3(); +} diff --git a/src/test/compile-fail/multiple-main-2.rs b/src/test/compile-fail/multiple-main-2.rs index 723aefb91cb9c..e3dbc67b7a9ef 100644 --- a/src/test/compile-fail/multiple-main-2.rs +++ b/src/test/compile-fail/multiple-main-2.rs @@ -13,5 +13,5 @@ fn bar() { } #[main] -fn foo() { //~ ERROR multiple 'main' functions +fn foo() { //~ ERROR multiple functions with a #[main] attribute } diff --git a/src/test/compile-fail/multiple-main-3.rs b/src/test/compile-fail/multiple-main-3.rs index 36da3e6e84a22..58cc148568ee6 100644 --- a/src/test/compile-fail/multiple-main-3.rs +++ b/src/test/compile-fail/multiple-main-3.rs @@ -14,6 +14,6 @@ fn main1() { mod foo { #[main] - fn main2() { //~ ERROR multiple 'main' functions + fn main2() { //~ ERROR multiple functions with a #[main] attribute } } diff --git a/src/test/compile-fail/object-pointer-types.rs b/src/test/compile-fail/object-pointer-types.rs index 8868ddd4dfa30..84e7f98a40dc2 100644 --- a/src/test/compile-fail/object-pointer-types.rs +++ b/src/test/compile-fail/object-pointer-types.rs @@ -13,7 +13,7 @@ trait Foo { fn borrowed(&self); fn borrowed_mut(&mut self); - fn owned(~self); + fn owned(self: Box); } fn borrowed_receiver(x: &Foo) { diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index 3c03c87475720..cc01c0b3c9f1c 100644 --- a/src/test/compile-fail/overloaded-calls-bad.rs +++ b/src/test/compile-fail/overloaded-calls-bad.rs @@ -18,7 +18,7 @@ struct S { } impl FnMut<(int,),int> for S { - fn call_mut(&mut self, (z,): (int,)) -> int { + extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int { self.x * self.y * z } } diff --git a/src/test/compile-fail/overloaded-calls-nontuple.rs b/src/test/compile-fail/overloaded-calls-nontuple.rs index 9bbc4ab3ba3b3..ee2fe3522470a 100644 --- a/src/test/compile-fail/overloaded-calls-nontuple.rs +++ b/src/test/compile-fail/overloaded-calls-nontuple.rs @@ -18,7 +18,7 @@ struct S { } impl FnMut for S { - fn call_mut(&mut self, z: int) -> int { + extern "rust-call" fn call_mut(&mut self, z: int) -> int { self.x + self.y + z } } diff --git a/src/test/compile-fail/regions-creating-enums.rs b/src/test/compile-fail/regions-creating-enums.rs index 4fd3cd2704437..ed3ce1fd0f077 100644 --- a/src/test/compile-fail/regions-creating-enums.rs +++ b/src/test/compile-fail/regions-creating-enums.rs @@ -27,7 +27,7 @@ fn compute(x: &ast) -> uint { } } -fn map_nums(x: &ast, f: |uint| -> uint) -> &ast { +fn map_nums<'a,'b>(x: &ast, f: |uint| -> uint) -> &'a ast<'b> { match *x { num(x) => { return &num(f(x)); //~ ERROR borrowed value does not live long enough diff --git a/src/test/compile-fail/regions-creating-enums4.rs b/src/test/compile-fail/regions-creating-enums4.rs index 0cd5a97596045..082ba0f0cf103 100644 --- a/src/test/compile-fail/regions-creating-enums4.rs +++ b/src/test/compile-fail/regions-creating-enums4.rs @@ -13,7 +13,7 @@ enum ast<'a> { add(&'a ast<'a>, &'a ast<'a>) } -fn mk_add_bad2<'a>(x: &'a ast<'a>, y: &'a ast<'a>, z: &ast) -> ast { +fn mk_add_bad2<'a,'b>(x: &'a ast<'a>, y: &'a ast<'a>, z: &ast) -> ast<'b> { add(x, y) //~ ERROR cannot infer } diff --git a/src/test/compile-fail/regions-fn-subtyping-return-static.rs b/src/test/compile-fail/regions-fn-subtyping-return-static.rs index c03040fe0f211..2d20634cdc41d 100644 --- a/src/test/compile-fail/regions-fn-subtyping-return-static.rs +++ b/src/test/compile-fail/regions-fn-subtyping-return-static.rs @@ -40,7 +40,7 @@ fn bar<'a,'b>(x: &'a S) -> &'b S { } // Meets F, but not G. -fn baz<'a>(x: &'a S) -> &'a S { +fn baz(x: &S) -> &S { fail!() } diff --git a/src/test/compile-fail/regions-fn-subtyping.rs b/src/test/compile-fail/regions-fn-subtyping.rs index 0cbd37a3b9a5e..30b33e82a4b79 100644 --- a/src/test/compile-fail/regions-fn-subtyping.rs +++ b/src/test/compile-fail/regions-fn-subtyping.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn of() -> |T| { fail!(); } +fn of<'a,T>() -> |T|:'a { fail!(); } fn subtype(x: |T|) { fail!(); } fn test_fn<'x,'y,'z,T>(_x: &'x T, _y: &'y T, _z: &'z T) { diff --git a/src/test/compile-fail/regions-infer-at-fn-not-param.rs b/src/test/compile-fail/regions-infer-at-fn-not-param.rs index 4c883656d61a5..e5444aadc1ca6 100644 --- a/src/test/compile-fail/regions-infer-at-fn-not-param.rs +++ b/src/test/compile-fail/regions-infer-at-fn-not-param.rs @@ -20,7 +20,7 @@ struct not_parameterized2 { g: ||: 'static } -fn take1(p: parameterized1) -> parameterized1 { p } +fn take1<'a>(p: parameterized1) -> parameterized1<'a> { p } //~^ ERROR mismatched types //~^^ ERROR cannot infer diff --git a/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs b/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs index 77988d1867952..b00ceec028782 100644 --- a/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs +++ b/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs @@ -21,8 +21,8 @@ fn x_coord<'r>(p: &'r point) -> &'r int { return &p.x; } -fn foo(p: Gc) -> &int { - let xc = x_coord(p); //~ ERROR `*p` does not live long enough +fn foo<'a>(p: Gc) -> &'a int { + let xc = x_coord(&*p); //~ ERROR `*p` does not live long enough assert_eq!(*xc, 3); return xc; } diff --git a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs b/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs index 0aff58c34cc23..ce6a51e8fb5e7 100644 --- a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs +++ b/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs @@ -12,7 +12,7 @@ use std::gc::Gc; -fn borrow<'r, T>(x: &'r T) -> &'r T {x} +fn borrow(x: &T) -> &T {x} fn foo(cond: || -> bool, make_box: || -> Gc) { let mut y: ∫ @@ -21,7 +21,7 @@ fn foo(cond: || -> bool, make_box: || -> Gc) { // Here we complain because the resulting region // of this borrow is the fn body as a whole. - y = borrow(x); //~ ERROR `*x` does not live long enough + y = borrow(&*x); //~ ERROR `*x` does not live long enough assert_eq!(*x, *y); if cond() { break; } diff --git a/src/test/compile-fail/regions-infer-not-param.rs b/src/test/compile-fail/regions-infer-not-param.rs index 86f98d5cc3515..cadf66c328686 100644 --- a/src/test/compile-fail/regions-infer-not-param.rs +++ b/src/test/compile-fail/regions-infer-not-param.rs @@ -22,12 +22,12 @@ struct indirect2<'a> { g: |direct<'a>|: 'static } -fn take_direct(p: direct) -> direct { p } //~ ERROR mismatched types +fn take_direct<'a,'b>(p: direct<'a>) -> direct<'b> { p } //~ ERROR mismatched types //~^ ERROR cannot infer fn take_indirect1(p: indirect1) -> indirect1 { p } -fn take_indirect2(p: indirect2) -> indirect2 { p } //~ ERROR mismatched types +fn take_indirect2<'a,'b>(p: indirect2<'a>) -> indirect2<'b> { p } //~ ERROR mismatched types //~^ ERROR cannot infer fn main() {} diff --git a/src/test/compile-fail/regions-lifetime-of-struct-or-enum-variant.rs b/src/test/compile-fail/regions-lifetime-of-struct-or-enum-variant.rs index c266952f08f08..27e2f5582f5a4 100644 --- a/src/test/compile-fail/regions-lifetime-of-struct-or-enum-variant.rs +++ b/src/test/compile-fail/regions-lifetime-of-struct-or-enum-variant.rs @@ -18,12 +18,12 @@ enum MyEnum { Variant1 } -fn structLifetime() -> &Test { +fn structLifetime<'a>() -> &'a Test { let testValue = &Test; //~ ERROR borrowed value does not live long enough testValue } -fn variantLifetime() -> &MyEnum { +fn variantLifetime<'a>() -> &'a MyEnum { let testValue = &Variant1; //~ ERROR borrowed value does not live long enough testValue } diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs index c20764e0728d1..f9983bcf80172 100644 --- a/src/test/compile-fail/regions-ret-borrowed.rs +++ b/src/test/compile-fail/regions-ret-borrowed.rs @@ -19,7 +19,7 @@ fn with(f: |x: &int| -> R) -> R { f(&3) } -fn return_it() -> &int { +fn return_it<'a>() -> &'a int { with(|o| o) //~ ERROR mismatched types //~^ ERROR lifetime of return value does not outlive the function call //~^^ ERROR cannot infer diff --git a/src/test/compile-fail/regions-ret.rs b/src/test/compile-fail/regions-ret.rs index eccffb4051e23..4986771c79397 100644 --- a/src/test/compile-fail/regions-ret.rs +++ b/src/test/compile-fail/regions-ret.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f<'a>(_x : &'a int) -> &'a int { +fn f(_x: &int) -> &int { return &3; //~ ERROR borrowed value does not live long enough } diff --git a/src/test/compile-fail/regions-trait-variance.rs b/src/test/compile-fail/regions-trait-variance.rs index 62e6a404838c2..53cfd4e032497 100644 --- a/src/test/compile-fail/regions-trait-variance.rs +++ b/src/test/compile-fail/regions-trait-variance.rs @@ -34,15 +34,15 @@ struct A<'r> { p: &'r X } -fn make_a<'r>(p:&'r X) -> A<'r> { +fn make_a(p:&X) -> A { A{p:p} } -fn make_make_a() -> A { +fn make_make_a<'a>() -> A<'a> { let b: Box = box B { i: 1, }; - let bb: &B = b; //~ ERROR `*b` does not live long enough + let bb: &B = &*b; //~ ERROR `*b` does not live long enough make_a(bb) } diff --git a/src/test/compile-fail/static-mut-not-pat.rs b/src/test/compile-fail/static-mut-not-pat.rs index c410e85655258..b3e93daccab8d 100644 --- a/src/test/compile-fail/static-mut-not-pat.rs +++ b/src/test/compile-fail/static-mut-not-pat.rs @@ -20,7 +20,34 @@ fn main() { // instead of spitting out a custom error about some identifier collisions // (we should allow shadowing) match 4i { - a => {} - _ => {} //~ ERROR: unreachable pattern + a => {} //~ ERROR mutable static variables cannot be referenced in a pattern + _ => {} + } +} + +struct NewBool(bool); +enum Direction { + North, + East, + South, + West +} +static NEW_FALSE: NewBool = NewBool(false); +struct Foo { + bar: Option, + baz: NewBool +} + +static mut STATIC_MUT_FOO: Foo = Foo { bar: Some(West), baz: NEW_FALSE }; + +fn mutable_statics() { + match (Foo { bar: Some(North), baz: NewBool(true) }) { + Foo { bar: None, baz: NewBool(true) } => (), + STATIC_MUT_FOO => (), + //~^ ERROR mutable static variables cannot be referenced in a pattern + Foo { bar: Some(South), .. } => (), + Foo { bar: Some(EAST), .. } => (), + Foo { bar: Some(North), baz: NewBool(true) } => (), + Foo { bar: Some(EAST), baz: NewBool(false) } => () } } diff --git a/src/test/compile-fail/struct-field-assignability.rs b/src/test/compile-fail/struct-field-assignability.rs index b6ce848a7d8fb..bfa8f402a82db 100644 --- a/src/test/compile-fail/struct-field-assignability.rs +++ b/src/test/compile-fail/struct-field-assignability.rs @@ -1,3 +1,5 @@ +// ignore-test + // Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. @@ -17,6 +19,6 @@ struct Foo<'a> { } pub fn main() { - let f = Foo { x: box(GC) 3 }; //~ ERROR borrowed value does not live long enough + let f = Foo { x: &*(box(GC) 3) }; //~ ERROR borrowed value does not live long enough assert_eq!(*f.x, 3); } diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs new file mode 100644 index 0000000000000..e5bad7e31b81e --- /dev/null +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -0,0 +1,49 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::owned::Box; + +struct Foo { + f: int, +} + +impl Foo { + fn foo(self: int, x: int) -> int { //~ ERROR mismatched self type +//~^ ERROR not a valid type for `self` + self.f + x + } +} + +struct Bar { + f: T, +} + +impl Bar { + fn foo(self: Bar, x: int) -> int { //~ ERROR mismatched self type +//~^ ERROR not a valid type for `self` + x + } + fn bar(self: &Bar, x: int) -> int { //~ ERROR mismatched self type +//~^ ERROR not a valid type for `self` + x + } +} + +fn main() { + let foo = box Foo { + f: 1, + }; + println!("{}", foo.foo(2)); + let bar = box Bar { + f: 1, + }; + println!("{} {}", bar.foo(2), bar.bar(2)); +} + diff --git a/src/test/compile-fail/unboxed-closures-type-mismatch.rs b/src/test/compile-fail/unboxed-closures-type-mismatch.rs new file mode 100644 index 0000000000000..09f13b7738694 --- /dev/null +++ b/src/test/compile-fail/unboxed-closures-type-mismatch.rs @@ -0,0 +1,19 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +pub fn main() { + let mut f = |&mut: x: int, y: int| -> int { x + y }; + let z = f.call_mut((1u, 2)); //~ ERROR mismatched types + println!("{}", z); +} diff --git a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs new file mode 100644 index 0000000000000..2ee632b9093c8 --- /dev/null +++ b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs @@ -0,0 +1,25 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +fn call_it>(y: int, mut f: F) -> int { + f.call_mut((2, y)) +} + +pub fn main() { + let f = |&mut: x: uint, y: int| -> int { (x as int) + y }; + let z = call_it(3, f); //~ ERROR expected core::ops::FnMut + //~^ ERROR expected core::ops::FnMut + println!("{}", z); +} + diff --git a/src/test/compile-fail/use-from-trait-xc.rs b/src/test/compile-fail/use-from-trait-xc.rs index 8e197b901e610..cea85955d3795 100644 --- a/src/test/compile-fail/use-from-trait-xc.rs +++ b/src/test/compile-fail/use-from-trait-xc.rs @@ -18,4 +18,7 @@ use use_from_trait_xc::Trait::foo; use use_from_trait_xc::Foo::new; //~^ ERROR unresolved import `use_from_trait_xc::Foo::new`. Cannot import from a trait or type imple +use use_from_trait_xc::Bar::new; +//~^ ERROR unresolved import `use_from_trait_xc::Bar::new`. Cannot import from a trait or type + fn main() {} diff --git a/src/test/debuginfo/basic-types.rs b/src/test/debuginfo/basic-types.rs index ae554cafb507c..67f77014c9fa9 100644 --- a/src/test/debuginfo/basic-types.rs +++ b/src/test/debuginfo/basic-types.rs @@ -17,6 +17,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -49,6 +52,42 @@ // gdb-command:print f64 // gdb-check:$14 = 3.5 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run +// lldb-command:print b +// lldb-check:[...]$0 = false +// lldb-command:print i +// lldb-check:[...]$1 = -1 + +// NOTE: LLDB does not support 32bit chars +// d ebugger:print (uint)(c) +// c heck:$3 = 97 + +// lldb-command:print i8 +// lldb-check:[...]$2 = 'D' +// lldb-command:print i16 +// lldb-check:[...]$3 = -16 +// lldb-command:print i32 +// lldb-check:[...]$4 = -32 +// lldb-command:print i64 +// lldb-check:[...]$5 = -64 +// lldb-command:print u +// lldb-check:[...]$6 = 1 +// lldb-command:print u8 +// lldb-check:[...]$7 = 'd' +// lldb-command:print u16 +// lldb-check:[...]$8 = 16 +// lldb-command:print u32 +// lldb-check:[...]$9 = 32 +// lldb-command:print u64 +// lldb-check:[...]$10 = 64 +// lldb-command:print f32 +// lldb-check:[...]$11 = 2.5 +// lldb-command:print f64 +// lldb-check:[...]$12 = 3.5 + #![allow(unused_variable)] fn main() { @@ -66,7 +105,7 @@ fn main() { let u64: u64 = 64; let f32: f32 = 2.5; let f64: f64 = 3.5; - _zzz(); + _zzz(); // #break } fn _zzz() {()} diff --git a/src/test/debuginfo/borrowed-basic.rs b/src/test/debuginfo/borrowed-basic.rs index d511e5ed20f8e..84610b3c74051 100644 --- a/src/test/debuginfo/borrowed-basic.rs +++ b/src/test/debuginfo/borrowed-basic.rs @@ -14,6 +14,9 @@ // its numerical value. // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -59,6 +62,53 @@ // gdb-command:print *f64_ref // gdb-check:$14 = 3.5 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run +// lldb-command:print *bool_ref +// lldb-check:[...]$0 = true + +// lldb-command:print *int_ref +// lldb-check:[...]$1 = -1 + +// NOTE: lldb doesn't support 32bit chars at the moment +// d ebugger:print *char_ref +// c heck:[...]$x = 97 + +// lldb-command:print *i8_ref +// lldb-check:[...]$2 = 'D' + +// lldb-command:print *i16_ref +// lldb-check:[...]$3 = -16 + +// lldb-command:print *i32_ref +// lldb-check:[...]$4 = -32 + +// lldb-command:print *i64_ref +// lldb-check:[...]$5 = -64 + +// lldb-command:print *uint_ref +// lldb-check:[...]$6 = 1 + +// lldb-command:print *u8_ref +// lldb-check:[...]$7 = 'd' + +// lldb-command:print *u16_ref +// lldb-check:[...]$8 = 16 + +// lldb-command:print *u32_ref +// lldb-check:[...]$9 = 32 + +// lldb-command:print *u64_ref +// lldb-check:[...]$10 = 64 + +// lldb-command:print *f32_ref +// lldb-check:[...]$11 = 2.5 + +// lldb-command:print *f64_ref +// lldb-check:[...]$12 = 3.5 + #![allow(unused_variable)] fn main() { @@ -103,7 +153,8 @@ fn main() { let f64_val: f64 = 3.5; let f64_ref: &f64 = &f64_val; - zzz(); + + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/borrowed-c-style-enum.rs b/src/test/debuginfo/borrowed-c-style-enum.rs index 9ab7e0701cc99..2270cfb6d215d 100644 --- a/src/test/debuginfo/borrowed-c-style-enum.rs +++ b/src/test/debuginfo/borrowed-c-style-enum.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -24,6 +27,20 @@ // gdb-command:print *the_c_ref // gdb-check:$3 = TheC + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print *the_a_ref +// lldb-check:[...]$0 = TheA + +// lldb-command:print *the_b_ref +// lldb-check:[...]$1 = TheB + +// lldb-command:print *the_c_ref +// lldb-check:[...]$2 = TheC + #![allow(unused_variable)] enum ABC { TheA, TheB, TheC } @@ -38,7 +55,7 @@ fn main() { let the_c = TheC; let the_c_ref: &ABC = &the_c; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/borrowed-enum.rs b/src/test/debuginfo/borrowed-enum.rs index a377d68a33d8c..b6f5096c726a5 100644 --- a/src/test/debuginfo/borrowed-enum.rs +++ b/src/test/debuginfo/borrowed-enum.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -24,6 +27,18 @@ // gdb-command:print *univariant_ref // gdb-check:$3 = {{4820353753753434}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print *the_a_ref +// lldb-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 } +// lldb-command:print *the_b_ref +// lldb-check:[...]$1 = TheB(0, 286331153, 286331153) +// lldb-command:print *univariant_ref +// lldb-check:[...]$2 = TheOnlyCase(4820353753753434) + #![allow(unused_variable)] #![feature(struct_variant)] @@ -59,7 +74,7 @@ fn main() { let univariant = TheOnlyCase(4820353753753434); let univariant_ref: &Univariant = &univariant; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/borrowed-managed-basic.rs b/src/test/debuginfo/borrowed-managed-basic.rs index 0f81e530fdd36..8e924a46d9aaa 100644 --- a/src/test/debuginfo/borrowed-managed-basic.rs +++ b/src/test/debuginfo/borrowed-managed-basic.rs @@ -16,6 +16,9 @@ // its numerical value. // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -61,53 +64,104 @@ // gdb-command:print *f64_ref // gdb-check:$14 = 3.5 + +// === LLDB TESTS ================================================================================== + +// lldb-command:type format add -f decimal char +// lldb-command:type format add -f decimal 'unsigned char' +// lldb-command:run + +// lldb-command:print *bool_ref +// lldb-check:[...]$0 = true + +// lldb-command:print *int_ref +// lldb-check:[...]$1 = -1 + +// LLDB can't handle 32bit chars yet +// d ebugger:print *char_ref +// c heck:[...]$x = 97 + +// lldb-command:print *i8_ref +// lldb-check:[...]$2 = 68 + +// lldb-command:print *i16_ref +// lldb-check:[...]$3 = -16 + +// lldb-command:print *i32_ref +// lldb-check:[...]$4 = -32 + +// lldb-command:print *i64_ref +// lldb-check:[...]$5 = -64 + +// lldb-command:print *uint_ref +// lldb-check:[...]$6 = 1 + +// lldb-command:print *u8_ref +// lldb-check:[...]$7 = 100 + +// lldb-command:print *u16_ref +// lldb-check:[...]$8 = 16 + +// lldb-command:print *u32_ref +// lldb-check:[...]$9 = 32 + +// lldb-command:print *u64_ref +// lldb-check:[...]$10 = 64 + +// lldb-command:print *f32_ref +// lldb-check:[...]$11 = 2.5 + +// lldb-command:print *f64_ref +// lldb-check:[...]$12 = 3.5 + #![allow(unused_variable)] use std::gc::{Gc, GC}; fn main() { let bool_box: Gc = box(GC) true; - let bool_ref: &bool = bool_box; + let bool_ref: &bool = &*bool_box; let int_box: Gc = box(GC) -1; - let int_ref: &int = int_box; + let int_ref: &int = &*int_box; let char_box: Gc = box(GC) 'a'; - let char_ref: &char = char_box; + let char_ref: &char = &*char_box; let i8_box: Gc = box(GC) 68; - let i8_ref: &i8 = i8_box; + let i8_ref: &i8 = &*i8_box; let i16_box: Gc = box(GC) -16; - let i16_ref: &i16 = i16_box; + let i16_ref: &i16 = &*i16_box; let i32_box: Gc = box(GC) -32; - let i32_ref: &i32 = i32_box; + let i32_ref: &i32 = &*i32_box; let i64_box: Gc = box(GC) -64; - let i64_ref: &i64 = i64_box; + let i64_ref: &i64 = &*i64_box; let uint_box: Gc = box(GC) 1; - let uint_ref: &uint = uint_box; + let uint_ref: &uint = &*uint_box; let u8_box: Gc = box(GC) 100; - let u8_ref: &u8 = u8_box; + let u8_ref: &u8 = &*u8_box; let u16_box: Gc = box(GC) 16; - let u16_ref: &u16 = u16_box; + let u16_ref: &u16 = &*u16_box; let u32_box: Gc = box(GC) 32; - let u32_ref: &u32 = u32_box; + let u32_ref: &u32 = &*u32_box; let u64_box: Gc = box(GC) 64; - let u64_ref: &u64 = u64_box; + let u64_ref: &u64 = &*u64_box; let f32_box: Gc = box(GC) 2.5; - let f32_ref: &f32 = f32_box; + let f32_ref: &f32 = &*f32_box; let f64_box: Gc = box(GC) 3.5; - let f64_ref: &f64 = f64_box; - zzz(); + let f64_ref: &f64 = &*f64_box; + + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/borrowed-struct.rs b/src/test/debuginfo/borrowed-struct.rs index 98b66098862b5..ed56c19869f22 100644 --- a/src/test/debuginfo/borrowed-struct.rs +++ b/src/test/debuginfo/borrowed-struct.rs @@ -9,8 +9,10 @@ // except according to those terms. // ignore-android: FIXME(#10381) - // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -45,6 +47,41 @@ // gdb-command:print *unique_val_interior_ref_2 // gdb-check:$10 = 26.5 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print *stack_val_ref +// lldb-check:[...]$0 = SomeStruct { x: 10, y: 23.5 } + +// lldb-command:print *stack_val_interior_ref_1 +// lldb-check:[...]$1 = 10 + +// lldb-command:print *stack_val_interior_ref_2 +// lldb-check:[...]$2 = 23.5 + +// lldb-command:print *ref_to_unnamed +// lldb-check:[...]$3 = SomeStruct { x: 11, y: 24.5 } + +// lldb-command:print *managed_val_ref +// lldb-check:[...]$4 = SomeStruct { x: 12, y: 25.5 } + +// lldb-command:print *managed_val_interior_ref_1 +// lldb-check:[...]$5 = 12 + +// lldb-command:print *managed_val_interior_ref_2 +// lldb-check:[...]$6 = 25.5 + +// lldb-command:print *unique_val_ref +// lldb-check:[...]$7 = SomeStruct { x: 13, y: 26.5 } + +// lldb-command:print *unique_val_interior_ref_1 +// lldb-check:[...]$8 = 13 + +// lldb-command:print *unique_val_interior_ref_2 +// lldb-check:[...]$9 = 26.5 + #![feature(managed_boxes)] #![allow(unused_variable)] @@ -63,16 +100,16 @@ fn main() { let ref_to_unnamed: &SomeStruct = &SomeStruct { x: 11, y: 24.5 }; let managed_val = box(GC) SomeStruct { x: 12, y: 25.5 }; - let managed_val_ref: &SomeStruct = managed_val; + let managed_val_ref: &SomeStruct = &*managed_val; let managed_val_interior_ref_1: &int = &managed_val.x; let managed_val_interior_ref_2: &f64 = &managed_val.y; let unique_val = box SomeStruct { x: 13, y: 26.5 }; - let unique_val_ref: &SomeStruct = unique_val; + let unique_val_ref: &SomeStruct = &*unique_val; let unique_val_interior_ref_1: &int = &unique_val.x; let unique_val_interior_ref_2: &f64 = &unique_val.y; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/borrowed-tuple.rs b/src/test/debuginfo/borrowed-tuple.rs index b88161e4a0b30..583906b7b3070 100644 --- a/src/test/debuginfo/borrowed-tuple.rs +++ b/src/test/debuginfo/borrowed-tuple.rs @@ -13,6 +13,9 @@ #![feature(managed_boxes)] // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -29,6 +32,24 @@ // gdb-command:print *unique_val_ref // gdb-check:$4 = {-17, -22} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print *stack_val_ref +// lldb-check:[...]$0 = (-14, -19) + +// lldb-command:print *ref_to_unnamed +// lldb-check:[...]$1 = (-15, -20) + +// lldb-command:print *managed_val_ref +// lldb-check:[...]$2 = (-16, -21) + +// lldb-command:print *unique_val_ref +// lldb-check:[...]$3 = (-17, -22) + + #![allow(unused_variable)] use std::gc::{Gc, GC}; @@ -39,12 +60,12 @@ fn main() { let ref_to_unnamed: &(i16, f32) = &(-15, -20f32); let managed_val: Gc<(i16, f32)> = box(GC) (-16, -21f32); - let managed_val_ref: &(i16, f32) = managed_val; + let managed_val_ref: &(i16, f32) = &*managed_val; let unique_val: Box<(i16, f32)> = box() (-17, -22f32); - let unique_val_ref: &(i16, f32) = unique_val; + let unique_val_ref: &(i16, f32) = &*unique_val; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/borrowed-unique-basic.rs b/src/test/debuginfo/borrowed-unique-basic.rs index 6e8fa62ed26c8..4a5df78b5c61e 100644 --- a/src/test/debuginfo/borrowed-unique-basic.rs +++ b/src/test/debuginfo/borrowed-unique-basic.rs @@ -14,6 +14,9 @@ // its numerical value. // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -59,52 +62,102 @@ // gdb-command:print *f64_ref // gdb-check:$14 = 3.5 + +// === LLDB TESTS ================================================================================== + +// lldb-command:type format add -f decimal char +// lldb-command:type format add -f decimal 'unsigned char' +// lldb-command:run + +// lldb-command:print *bool_ref +// lldb-check:[...]$0 = true + +// lldb-command:print *int_ref +// lldb-check:[...]$1 = -1 + +// d ebugger:print *char_ref +// c heck:[...]$3 = 97 + +// lldb-command:print *i8_ref +// lldb-check:[...]$2 = 68 + +// lldb-command:print *i16_ref +// lldb-check:[...]$3 = -16 + +// lldb-command:print *i32_ref +// lldb-check:[...]$4 = -32 + +// lldb-command:print *i64_ref +// lldb-check:[...]$5 = -64 + +// lldb-command:print *uint_ref +// lldb-check:[...]$6 = 1 + +// lldb-command:print *u8_ref +// lldb-check:[...]$7 = 100 + +// lldb-command:print *u16_ref +// lldb-check:[...]$8 = 16 + +// lldb-command:print *u32_ref +// lldb-check:[...]$9 = 32 + +// lldb-command:print *u64_ref +// lldb-check:[...]$10 = 64 + +// lldb-command:print *f32_ref +// lldb-check:[...]$11 = 2.5 + +// lldb-command:print *f64_ref +// lldb-check:[...]$12 = 3.5 + #![allow(unused_variable)] fn main() { let bool_box: Box = box true; - let bool_ref: &bool = bool_box; + let bool_ref: &bool = &*bool_box; let int_box: Box = box -1; - let int_ref: &int = int_box; + let int_ref: &int = &*int_box; let char_box: Box = box 'a'; - let char_ref: &char = char_box; + let char_ref: &char = &*char_box; let i8_box: Box = box 68; - let i8_ref: &i8 = i8_box; + let i8_ref: &i8 = &*i8_box; let i16_box: Box = box -16; - let i16_ref: &i16 = i16_box; + let i16_ref: &i16 = &*i16_box; let i32_box: Box = box -32; - let i32_ref: &i32 = i32_box; + let i32_ref: &i32 = &*i32_box; let i64_box: Box = box -64; - let i64_ref: &i64 = i64_box; + let i64_ref: &i64 = &*i64_box; let uint_box: Box = box 1; - let uint_ref: &uint = uint_box; + let uint_ref: &uint = &*uint_box; let u8_box: Box = box 100; - let u8_ref: &u8 = u8_box; + let u8_ref: &u8 = &*u8_box; let u16_box: Box = box 16; - let u16_ref: &u16 = u16_box; + let u16_ref: &u16 = &*u16_box; let u32_box: Box = box 32; - let u32_ref: &u32 = u32_box; + let u32_ref: &u32 = &*u32_box; let u64_box: Box = box 64; - let u64_ref: &u64 = u64_box; + let u64_ref: &u64 = &*u64_box; let f32_box: Box = box 2.5; - let f32_ref: &f32 = f32_box; + let f32_ref: &f32 = &*f32_box; let f64_box: Box = box 3.5; - let f64_ref: &f64 = f64_box; - zzz(); + let f64_ref: &f64 = &*f64_box; + + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/box.rs b/src/test/debuginfo/box.rs index dcfe1804510ad..5b799b25bbfc4 100644 --- a/src/test/debuginfo/box.rs +++ b/src/test/debuginfo/box.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz // gdb-command:run @@ -24,6 +27,19 @@ // gdb-command:print d->val // gdb-check:$4 = false + +// === LLDB TESTS ================================================================================== + +// lldb-command:run +// lldb-command:print *a +// lldb-check:[...]$0 = 1 +// lldb-command:print *b +// lldb-check:[...]$1 = (2, 3.5) +// lldb-command:print c->val +// lldb-check:[...]$2 = 4 +// lldb-command:print d->val +// lldb-check:[...]$3 = false + #![feature(managed_boxes)] #![allow(unused_variable)] @@ -34,7 +50,8 @@ fn main() { let b = box() (2i, 3.5f64); let c = box(GC) 4i; let d = box(GC) false; - _zzz(); + + zzz(); // #break } -fn _zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/boxed-struct.rs b/src/test/debuginfo/boxed-struct.rs index f583016b93f39..0e958545fb3c0 100644 --- a/src/test/debuginfo/boxed-struct.rs +++ b/src/test/debuginfo/boxed-struct.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -27,6 +30,23 @@ // gdb-command:print managed_dtor->val // gdb-check:$4 = {x = 33, y = 333, z = 3333, w = 33333} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print *unique +// lldb-check:[...]$0 = StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 } + +// lldb-command:print managed->val +// lldb-check:[...]$1 = StructWithSomePadding { x: 88, y: 888, z: 8888, w: 88888 } + +// lldb-command:print *unique_dtor +// lldb-check:[...]$2 = StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 } + +// lldb-command:print managed_dtor->val +// lldb-check:[...]$3 = StructWithDestructor { x: 33, y: 333, z: 3333, w: 33333 } + #![feature(managed_boxes)] #![allow(unused_variable)] @@ -58,7 +78,7 @@ fn main() { let unique_dtor = box StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }; let managed_dtor = box(GC) StructWithDestructor { x: 33, y: 333, z: 3333, w: 33333 }; - zzz(); + zzz(); // #break } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/by-value-non-immediate-argument.rs b/src/test/debuginfo/by-value-non-immediate-argument.rs index 873e062352107..2e1c4c79af0b3 100644 --- a/src/test/debuginfo/by-value-non-immediate-argument.rs +++ b/src/test/debuginfo/by-value-non-immediate-argument.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -43,6 +46,35 @@ // gdb-check:$7 = {{Case1, x = 0, y = 8970181431921507452}, {Case1, 0, 2088533116, 2088533116}} // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print s +// lldb-check:[...]$0 = Struct { a: 1, b: 2.5 } +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$1 = Struct { a: 3, b: 4.5 } +// lldb-command:print y +// lldb-check:[...]$2 = 5 +// lldb-command:print z +// lldb-check:[...]$3 = 6.5 +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$4 = (7, 8, 9.5, 10.5) +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$5 = Newtype(11.5, 12.5, 13, 14) +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$6 = Case1 { x: 0, y: 8970181431921507452 } +// lldb-command:continue + #![feature(struct_variant)] #[deriving(Clone)] @@ -58,21 +90,21 @@ struct StructStruct { } fn fun(s: Struct) { - zzz(); + zzz(); // #break } fn fun_fun(StructStruct { a: x, b: Struct { a: y, b: z } }: StructStruct) { - zzz(); + zzz(); // #break } fn tup(a: (int, uint, f64, f64)) { - zzz(); + zzz(); // #break } struct Newtype(f64, f64, int, uint); fn new_type(a: Newtype) { - zzz(); + zzz(); // #break } // The first element is to ensure proper alignment, irrespective of the machines word size. Since @@ -84,7 +116,7 @@ enum Enum { } fn by_val_enum(x: Enum) { - zzz(); + zzz(); // #break } fn main() { @@ -100,4 +132,4 @@ fn main() { by_val_enum(Case1 { x: 0, y: 8970181431921507452 }); } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs b/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs index 0da2d44d5ae50..4d6064c185b4c 100644 --- a/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs +++ b/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs @@ -13,6 +13,9 @@ #![feature(managed_boxes)] // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -36,6 +39,27 @@ // gdb-check:$4 = 8888 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print self +// lldb-check:[...]$0 = 1111 +// lldb-command:continue + +// lldb-command:print self +// lldb-check:[...]$1 = Struct { x: 2222, y: 3333 } +// lldb-command:continue + +// lldb-command:print self +// lldb-check:[...]$2 = (4444.5, 5555, 6666, 7777.5) +// lldb-command:continue + +// lldb-command:print self->val +// lldb-check:[...]$3 = 8888 +// lldb-command:continue + use std::gc::{Gc, GC}; trait Trait { @@ -44,7 +68,7 @@ trait Trait { impl Trait for int { fn method(self) -> int { - zzz(); + zzz(); // #break self } } @@ -56,21 +80,21 @@ struct Struct { impl Trait for Struct { fn method(self) -> Struct { - zzz(); + zzz(); // #break self } } impl Trait for (f64, int, int, f64) { fn method(self) -> (f64, int, int, f64) { - zzz(); + zzz(); // #break self } } impl Trait for Gc { fn method(self) -> Gc { - zzz(); + zzz(); // #break self } } @@ -82,4 +106,4 @@ fn main() { let _ = (box(GC) 8888).method(); } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/c-style-enum-in-composite.rs b/src/test/debuginfo/c-style-enum-in-composite.rs index 3e76bf1987b98..f73517282907f 100644 --- a/src/test/debuginfo/c-style-enum-in-composite.rs +++ b/src/test/debuginfo/c-style-enum-in-composite.rs @@ -8,9 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -36,6 +40,31 @@ // gdb-command:print struct_with_drop // gdb-check:$7 = {{a = OneHundred, b = Vienna}, 9} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print tuple_interior_padding +// lldb-check:[...]$0 = (0, OneHundred) + +// lldb-command:print tuple_padding_at_end +// lldb-check:[...]$1 = ((1, OneThousand), 2) +// lldb-command:print tuple_different_enums +// lldb-check:[...]$2 = (OneThousand, MountainView, OneMillion, Vienna) + +// lldb-command:print padded_struct +// lldb-check:[...]$3 = PaddedStruct { a: 3, b: OneMillion, c: 4, d: Toronto, e: 5 } + +// lldb-command:print packed_struct +// lldb-check:[...]$4 = PackedStruct { a: 6, b: OneHundred, c: 7, d: Vienna, e: 8 } + +// lldb-command:print non_padded_struct +// lldb-check:[...]$5 = NonPaddedStruct { a: OneMillion, b: MountainView, c: OneThousand, d: Toronto } + +// lldb-command:print struct_with_drop +// lldb-check:[...]$6 = (StructWithDrop { a: OneHundred, b: Vienna }, 9) + #![allow(unused_variable)] enum AnEnum { @@ -115,7 +144,7 @@ fn main() { let struct_with_drop = (StructWithDrop { a: OneHundred, b: Vienna }, 9_i64); - zzz(); + zzz(); // #break } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs index 19f8398f1a94b..da30363f271d0 100644 --- a/src/test/debuginfo/c-style-enum.rs +++ b/src/test/debuginfo/c-style-enum.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:print 'c-style-enum::SINGLE_VARIANT' @@ -71,6 +74,32 @@ // gdb-command:print 'c-style-enum::MANUAL_THREE' // gdb-check:$18 = OneMillion + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print auto_one +// lldb-check:[...]$0 = One + +// lldb-command:print auto_two +// lldb-check:[...]$1 = Two + +// lldb-command:print auto_three +// lldb-check:[...]$2 = Three + +// lldb-command:print manual_one_hundred +// lldb-check:[...]$3 = OneHundred + +// lldb-command:print manual_one_thousand +// lldb-check:[...]$4 = OneThousand + +// lldb-command:print manual_one_million +// lldb-check:[...]$5 = OneMillion + +// lldb-command:print single_variant +// lldb-check:[...]$6 = TheOnlyVariant + #![allow(unused_variable)] #![allow(dead_code)] @@ -120,11 +149,11 @@ fn main() { MANUAL_THREE = OneMillion; }; - zzz(); + zzz(); // #break let a = SINGLE_VARIANT; let a = unsafe { AUTO_ONE }; let a = unsafe { MANUAL_ONE }; } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/closure-in-generic-function.rs b/src/test/debuginfo/closure-in-generic-function.rs index cc241040f2bd2..67601221e7a46 100644 --- a/src/test/debuginfo/closure-in-generic-function.rs +++ b/src/test/debuginfo/closure-in-generic-function.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -28,10 +31,27 @@ // gdb-check:$4 = 110 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print x +// lldb-check:[...]$0 = 0.5 +// lldb-command:print y +// lldb-check:[...]$1 = 10 +// lldb-command:continue + +// lldb-command:print *x +// lldb-check:[...]$2 = 29 +// lldb-command:print *y +// lldb-check:[...]$3 = 110 +// lldb-command:continue + fn some_generic_fun(a: T1, b: T2) -> (T2, T1) { let closure = |x, y| { - zzz(); + zzz(); // #break (y, x) }; @@ -43,4 +63,4 @@ fn main() { some_generic_fun(&29i, box 110i); } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/destructured-fn-argument.rs b/src/test/debuginfo/destructured-fn-argument.rs index 697703034f6e3..48d14a46c83f1 100644 --- a/src/test/debuginfo/destructured-fn-argument.rs +++ b/src/test/debuginfo/destructured-fn-argument.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -181,6 +184,154 @@ // gdb-check:$49 = 62 // gdb-command:continue + +// === LLDB TESTS ================================================================================== +// lldb-command:run + +// lldb-command:print a +// lldb-check:[...]$0 = 1 +// lldb-command:print b +// lldb-check:[...]$1 = false +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$2 = 2 +// lldb-command:print b +// lldb-check:[...]$3 = 3 +// lldb-command:print c +// lldb-check:[...]$4 = 4 +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$5 = 5 +// lldb-command:print b +// lldb-check:[...]$6 = (6, 7) +// lldb-command:continue + +// lldb-command:print h +// lldb-check:[...]$7 = 8 +// lldb-command:print i +// lldb-check:[...]$8 = Struct { a: 9, b: 10 } +// lldb-command:print j +// lldb-check:[...]$9 = 11 +// lldb-command:continue + +// lldb-command:print k +// lldb-check:[...]$10 = 12 +// lldb-command:print l +// lldb-check:[...]$11 = 13 +// lldb-command:continue + +// lldb-command:print m +// lldb-check:[...]$12 = 14 +// lldb-command:print n +// lldb-check:[...]$13 = 16 +// lldb-command:continue + +// lldb-command:print o +// lldb-check:[...]$14 = 18 +// lldb-command:continue + +// lldb-command:print p +// lldb-check:[...]$15 = 19 +// lldb-command:print q +// lldb-check:[...]$16 = 20 +// lldb-command:print r +// lldb-check:[...]$17 = Struct { a: 21, b: 22 } +// lldb-command:continue + +// lldb-command:print s +// lldb-check:[...]$18 = 24 +// lldb-command:print t +// lldb-check:[...]$19 = 23 +// lldb-command:continue + +// lldb-command:print u +// lldb-check:[...]$20 = 25 +// lldb-command:print v +// lldb-check:[...]$21 = 26 +// lldb-command:print w +// lldb-check:[...]$22 = 27 +// lldb-command:print x +// lldb-check:[...]$23 = 28 +// lldb-command:print y +// lldb-check:[...]$24 = 29 +// lldb-command:print z +// lldb-check:[...]$25 = 30 +// lldb-command:print ae +// lldb-check:[...]$26 = 31 +// lldb-command:print oe +// lldb-check:[...]$27 = 32 +// lldb-command:print ue +// lldb-check:[...]$28 = 33 +// lldb-command:continue + +// lldb-command:print aa +// lldb-check:[...]$29 = (34, 35) +// lldb-command:continue + +// lldb-command:print bb +// lldb-check:[...]$30 = (36, 37) +// lldb-command:continue + +// lldb-command:print cc +// lldb-check:[...]$31 = 38 +// lldb-command:continue + +// lldb-command:print dd +// lldb-check:[...]$32 = (40, 41, 42) +// lldb-command:continue + +// lldb-command:print *ee +// lldb-check:[...]$33 = (43, 44, 45) +// lldb-command:continue + +// lldb-command:print *ff +// lldb-check:[...]$34 = 46 +// lldb-command:print gg +// lldb-check:[...]$35 = (47, 48) +// lldb-command:continue + +// lldb-command:print *hh +// lldb-check:[...]$36 = 50 +// lldb-command:continue + +// lldb-command:print ii +// lldb-check:[...]$37 = 51 +// lldb-command:continue + +// lldb-command:print *jj +// lldb-check:[...]$38 = 52 +// lldb-command:continue + +// lldb-command:print kk +// lldb-check:[...]$39 = 53 +// lldb-command:print ll +// lldb-check:[...]$40 = 54 +// lldb-command:continue + +// lldb-command:print mm +// lldb-check:[...]$41 = 55 +// lldb-command:print *nn +// lldb-check:[...]$42 = 56 +// lldb-command:continue + +// lldb-command:print oo +// lldb-check:[...]$43 = 57 +// lldb-command:print pp +// lldb-check:[...]$44 = 58 +// lldb-command:print qq +// lldb-check:[...]$45 = 59 +// lldb-command:continue + +// lldb-command:print rr +// lldb-check:[...]$46 = 60 +// lldb-command:print ss +// lldb-check:[...]$47 = 61 +// lldb-command:print tt +// lldb-check:[...]$48 = 62 +// lldb-command:continue + #![allow(unused_variable)] @@ -197,93 +348,93 @@ struct TupleStruct (f64, int); fn simple_tuple((a, b): (int, bool)) { - zzz(); + zzz(); // #break } fn nested_tuple((a, (b, c)): (int, (u16, u16))) { - zzz(); + zzz(); // #break } fn destructure_only_first_level((a, b): (int, (u32, u32))) { - zzz(); + zzz(); // #break } fn struct_as_tuple_element((h, i, j): (i16, Struct, i16)) { - zzz(); + zzz(); // #break } fn struct_pattern(Struct { a: k, b: l }: Struct) { - zzz(); + zzz(); // #break } fn ignored_tuple_element((m, _, n): (int, u16, i32)) { - zzz(); + zzz(); // #break } fn ignored_struct_field(Struct { b: o, .. }: Struct) { - zzz(); + zzz(); // #break } fn one_struct_destructured_one_not((Struct { a: p, b: q }, r): (Struct, Struct)) { - zzz(); + zzz(); // #break } fn different_order_of_struct_fields(Struct { b: s, a: t }: Struct ) { - zzz(); + zzz(); // #break } fn complex_nesting(((u, v ), ((w, (x, Struct { a: y, b: z})), Struct { a: ae, b: oe }), ue ): ((i16, i32), ((i64, (i32, Struct, )), Struct ), u16)) { - zzz(); + zzz(); // #break } fn managed_box(&aa: &(int, int)) { - zzz(); + zzz(); // #break } fn borrowed_pointer(&bb: &(int, int)) { - zzz(); + zzz(); // #break } fn contained_borrowed_pointer((&cc, _): (&int, int)) { - zzz(); + zzz(); // #break } fn unique_pointer(box dd: Box<(int, int, int)>) { - zzz(); + zzz(); // #break } fn ref_binding(ref ee: (int, int, int)) { - zzz(); + zzz(); // #break } fn ref_binding_in_tuple((ref ff, gg): (int, (int, int))) { - zzz(); + zzz(); // #break } fn ref_binding_in_struct(Struct { b: ref hh, .. }: Struct) { - zzz(); + zzz(); // #break } fn univariant_enum(Unit(ii): Univariant) { - zzz(); + zzz(); // #break } fn univariant_enum_with_ref_binding(Unit(ref jj): Univariant) { - zzz(); + zzz(); // #break } fn tuple_struct(TupleStruct(kk, ll): TupleStruct) { - zzz(); + zzz(); // #break } fn tuple_struct_with_ref_binding(TupleStruct(mm, ref nn): TupleStruct) { - zzz(); + zzz(); // #break } fn multiple_arguments((oo, pp): (int, int), qq : int) { - zzz(); + zzz(); // #break } fn main() { @@ -311,11 +462,10 @@ fn main() { multiple_arguments((57, 58), 59); fn nested_function(rr: int, (ss, tt): (int, int)) { - zzz(); + zzz(); // #break } nested_function(60, (61, 62)); } - -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/destructured-local.rs b/src/test/debuginfo/destructured-local.rs index d91d98f43050f..837a6dc062227 100644 --- a/src/test/debuginfo/destructured-local.rs +++ b/src/test/debuginfo/destructured-local.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -125,6 +128,122 @@ // gdb-command:print *nn // gdb-check:$43 = 56 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print a +// lldb-check:[...]$0 = 1 +// lldb-command:print b +// lldb-check:[...]$1 = false + +// lldb-command:print c +// lldb-check:[...]$2 = 2 +// lldb-command:print d +// lldb-check:[...]$3 = 3 +// lldb-command:print e +// lldb-check:[...]$4 = 4 + +// lldb-command:print f +// lldb-check:[...]$5 = 5 +// lldb-command:print g +// lldb-check:[...]$6 = (6, 7) + +// lldb-command:print h +// lldb-check:[...]$7 = 8 +// lldb-command:print i +// lldb-check:[...]$8 = Struct { a: 9, b: 10 } +// lldb-command:print j +// lldb-check:[...]$9 = 11 + +// lldb-command:print k +// lldb-check:[...]$10 = 12 +// lldb-command:print l +// lldb-check:[...]$11 = 13 + +// lldb-command:print m +// lldb-check:[...]$12 = 14 +// lldb-command:print n +// lldb-check:[...]$13 = 16 + +// lldb-command:print o +// lldb-check:[...]$14 = 18 + +// lldb-command:print p +// lldb-check:[...]$15 = 19 +// lldb-command:print q +// lldb-check:[...]$16 = 20 +// lldb-command:print r +// lldb-check:[...]$17 = Struct { a: 21, b: 22 } + +// lldb-command:print s +// lldb-check:[...]$18 = 24 +// lldb-command:print t +// lldb-check:[...]$19 = 23 + +// lldb-command:print u +// lldb-check:[...]$20 = 25 +// lldb-command:print v +// lldb-check:[...]$21 = 26 +// lldb-command:print w +// lldb-check:[...]$22 = 27 +// lldb-command:print x +// lldb-check:[...]$23 = 28 +// lldb-command:print y +// lldb-check:[...]$24 = 29 +// lldb-command:print z +// lldb-check:[...]$25 = 30 +// lldb-command:print ae +// lldb-check:[...]$26 = 31 +// lldb-command:print oe +// lldb-check:[...]$27 = 32 +// lldb-command:print ue +// lldb-check:[...]$28 = 33 + +// lldb-command:print aa +// lldb-check:[...]$29 = (34, 35) + +// lldb-command:print bb +// lldb-check:[...]$30 = (36, 37) + +// lldb-command:print cc +// lldb-check:[...]$31 = 38 + +// lldb-command:print dd +// lldb-check:[...]$32 = (40, 41, 42) + +// lldb-command:print *ee +// lldb-check:[...]$33 = (43, 44, 45) + +// lldb-command:print *ff +// lldb-check:[...]$34 = 46 + +// lldb-command:print gg +// lldb-check:[...]$35 = (47, 48) + +// lldb-command:print *hh +// lldb-check:[...]$36 = 50 + +// lldb-command:print ii +// lldb-check:[...]$37 = 51 + +// lldb-command:print *jj +// lldb-check:[...]$38 = 52 + +// lldb-command:print kk +// lldb-check:[...]$39 = 53 + +// lldb-command:print ll +// lldb-check:[...]$40 = 54 + +// lldb-command:print mm +// lldb-check:[...]$41 = 55 + +// lldb-command:print *nn +// lldb-check:[...]$42 = 56 + + #![allow(unused_variable)] struct Struct { @@ -204,7 +323,7 @@ fn main() { // tuple struct with ref binding let &TupleStruct(mm, ref nn) = &TupleStruct(55.0, 56); - zzz(); + zzz(); // #break } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/evec-in-struct.rs b/src/test/debuginfo/evec-in-struct.rs index 913038c44be26..b5ce865a4aaa2 100644 --- a/src/test/debuginfo/evec-in-struct.rs +++ b/src/test/debuginfo/evec-in-struct.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz // gdb-command:run @@ -30,6 +33,25 @@ // gdb-command:print struct_padded_at_end // gdb-check:$5 = {x = {22, 23}, y = {24, 25}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print no_padding1 +// lldb-check:[...]$0 = NoPadding1 { x: [0, 1, 2], y: -3, z: [4.5, 5.5] } +// lldb-command:print no_padding2 +// lldb-check:[...]$1 = NoPadding2 { x: [6, 7, 8], y: [[9, 10], [11, 12]] } + +// lldb-command:print struct_internal_padding +// lldb-check:[...]$2 = StructInternalPadding { x: [13, 14], y: [15, 16] } + +// lldb-command:print single_vec +// lldb-check:[...]$3 = SingleVec { x: [17, 18, 19, 20, 21] } + +// lldb-command:print struct_padded_at_end +// lldb-check:[...]$4 = StructPaddedAtEnd { x: [22, 23], y: [24, 25] } + #![allow(unused_variable)] struct NoPadding1 { @@ -84,7 +106,7 @@ fn main() { y: [24, 25] }; - zzz(); + zzz(); // #break } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs index 535efa0b84efc..640e04cf71c11 100644 --- a/src/test/debuginfo/function-arg-initialization.rs +++ b/src/test/debuginfo/function-arg-initialization.rs @@ -18,18 +18,19 @@ // compile-flags:-g // gdb-command:set print pretty off -// gdb-command:break function-arg-initialization.rs:139 -// gdb-command:break function-arg-initialization.rs:154 -// gdb-command:break function-arg-initialization.rs:158 -// gdb-command:break function-arg-initialization.rs:162 -// gdb-command:break function-arg-initialization.rs:166 -// gdb-command:break function-arg-initialization.rs:170 -// gdb-command:break function-arg-initialization.rs:174 -// gdb-command:break function-arg-initialization.rs:178 -// gdb-command:break function-arg-initialization.rs:182 -// gdb-command:break function-arg-initialization.rs:190 -// gdb-command:break function-arg-initialization.rs:197 - +// gdb-command:break function-arg-initialization.rs:243 +// gdb-command:break function-arg-initialization.rs:258 +// gdb-command:break function-arg-initialization.rs:262 +// gdb-command:break function-arg-initialization.rs:266 +// gdb-command:break function-arg-initialization.rs:270 +// gdb-command:break function-arg-initialization.rs:274 +// gdb-command:break function-arg-initialization.rs:278 +// gdb-command:break function-arg-initialization.rs:282 +// gdb-command:break function-arg-initialization.rs:286 +// gdb-command:break function-arg-initialization.rs:294 +// gdb-command:break function-arg-initialization.rs:301 + +// === GDB TESTS =================================================================================== // gdb-command:run @@ -130,13 +131,116 @@ // gdb-check:$32 = 45 // gdb-command:continue -#![allow(unused_variable)] +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// IMMEDIATE ARGS +// lldb-command:print a +// lldb-check:[...]$0 = 1 +// lldb-command:print b +// lldb-check:[...]$1 = true +// lldb-command:print c +// lldb-check:[...]$2 = 2.5 +// lldb-command:continue + +// NON IMMEDIATE ARGS +// lldb-command:print a +// lldb-check:[...]$3 = BigStruct { a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10 } +// lldb-command:print b +// lldb-check:[...]$4 = BigStruct { a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18 } +// lldb-command:continue + +// BINDING +// lldb-command:print a +// lldb-check:[...]$5 = 19 +// lldb-command:print b +// lldb-check:[...]$6 = 20 +// lldb-command:print c +// lldb-check:[...]$7 = 21.5 +// lldb-command:continue + +// ASSIGNMENT +// lldb-command:print a +// lldb-check:[...]$8 = 22 +// lldb-command:print b +// lldb-check:[...]$9 = 23 +// lldb-command:print c +// lldb-check:[...]$10 = 24.5 +// lldb-command:continue + +// FUNCTION CALL +// lldb-command:print x +// lldb-check:[...]$11 = 25 +// lldb-command:print y +// lldb-check:[...]$12 = 26 +// lldb-command:print z +// lldb-check:[...]$13 = 27.5 +// lldb-command:continue + +// EXPR +// lldb-command:print x +// lldb-check:[...]$14 = 28 +// lldb-command:print y +// lldb-check:[...]$15 = 29 +// lldb-command:print z +// lldb-check:[...]$16 = 30.5 +// lldb-command:continue + +// RETURN EXPR +// lldb-command:print x +// lldb-check:[...]$17 = 31 +// lldb-command:print y +// lldb-check:[...]$18 = 32 +// lldb-command:print z +// lldb-check:[...]$19 = 33.5 +// lldb-command:continue + +// ARITHMETIC EXPR +// lldb-command:print x +// lldb-check:[...]$20 = 34 +// lldb-command:print y +// lldb-check:[...]$21 = 35 +// lldb-command:print z +// lldb-check:[...]$22 = 36.5 +// lldb-command:continue + +// IF EXPR +// lldb-command:print x +// lldb-check:[...]$23 = 37 +// lldb-command:print y +// lldb-check:[...]$24 = 38 +// lldb-command:print z +// lldb-check:[...]$25 = 39.5 +// lldb-command:continue + +// WHILE EXPR +// lldb-command:print x +// lldb-check:[...]$26 = 40 +// lldb-command:print y +// lldb-check:[...]$27 = 41 +// lldb-command:print z +// lldb-check:[...]$28 = 42 +// lldb-command:continue + +// LOOP EXPR +// lldb-command:print x +// lldb-check:[...]$29 = 43 +// lldb-command:print y +// lldb-check:[...]$30 = 44 +// lldb-command:print z +// lldb-check:[...]$31 = 45 +// lldb-command:continue + + + +#![allow(unused_variable)] fn immediate_args(a: int, b: bool, c: f64) { - () + () // #break } struct BigStruct { @@ -151,35 +255,35 @@ struct BigStruct { } fn non_immediate_args(a: BigStruct, b: BigStruct) { - () + () // #break } fn binding(a: i64, b: u64, c: f64) { - let x = 0i; + let x = 0i; // #break } fn assignment(mut a: u64, b: u64, c: f64) { - a = b; + a = b; // #break } fn function_call(x: u64, y: u64, z: f64) { - std::io::stdio::print("Hi!") + std::io::stdio::print("Hi!") // #break } fn identifier(x: u64, y: u64, z: f64) -> u64 { - x + x // #break } fn return_expr(x: u64, y: u64, z: f64) -> u64 { - return x; + return x; // #break } fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 { - x + y + x + y // #break } fn if_expr(x: u64, y: u64, z: f64) -> u64 { - if x + y < 1000 { + if x + y < 1000 { // #break x } else { y @@ -187,14 +291,14 @@ fn if_expr(x: u64, y: u64, z: f64) -> u64 { } fn while_expr(mut x: u64, y: u64, z: u64) -> u64 { - while x + y < 1000 { + while x + y > 1000 { // #break x += z } return x; } fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 { - loop { + loop { // #break x += z; if x + y > 1000 { diff --git a/src/test/debuginfo/function-arguments.rs b/src/test/debuginfo/function-arguments.rs index e65b9a2519d60..69bd5ae1d6c30 100644 --- a/src/test/debuginfo/function-arguments.rs +++ b/src/test/debuginfo/function-arguments.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -28,21 +31,38 @@ // gdb-command:print b // gdb-check:$4 = 3000 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print x +// lldb-check:[...]$0 = 111102 +// lldb-command:print y +// lldb-check:[...]$1 = true +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$2 = 2000 +// lldb-command:print b +// lldb-check:[...]$3 = 3000 +// lldb-command:continue + fn main() { fun(111102, true); nested(2000, 3000); fn nested(a: i32, b: i64) -> (i32, i64) { - zzz(); + zzz(); // #break (a, b) } } fn fun(x: int, y: bool) -> (int, bool) { - zzz(); + zzz(); // #break (x, y) } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/function-prologue-stepping-no-split-stack.rs b/src/test/debuginfo/function-prologue-stepping-no-split-stack.rs index 0160a6f1879db..05e2c5eb6c7ca 100644 --- a/src/test/debuginfo/function-prologue-stepping-no-split-stack.rs +++ b/src/test/debuginfo/function-prologue-stepping-no-split-stack.rs @@ -14,9 +14,13 @@ // beginning of a function. Functions with the #[no_split_stack] attribute have the same prologue as // regular C functions compiled with GCC or Clang and therefore are better handled by GDB. As a // consequence, and as opposed to regular Rust functions, we can set the breakpoints via the -// function name (and don't have to fall back on using line numbers). +// function name (and don't have to fall back on using line numbers). For LLDB this shouldn't make +// a difference because it can handle both cases. // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak immediate_args // gdb-command:rbreak binding @@ -127,6 +131,119 @@ // gdb-check:$32 = 45 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:breakpoint set --name immediate_args +// lldb-command:breakpoint set --name non_immediate_args +// lldb-command:breakpoint set --name binding +// lldb-command:breakpoint set --name assignment +// lldb-command:breakpoint set --name function_call +// lldb-command:breakpoint set --name identifier +// lldb-command:breakpoint set --name return_expr +// lldb-command:breakpoint set --name arithmetic_expr +// lldb-command:breakpoint set --name if_expr +// lldb-command:breakpoint set --name while_expr +// lldb-command:breakpoint set --name loop_expr +// lldb-command:run + +// IMMEDIATE ARGS +// lldb-command:print a +// lldb-check:[...]$0 = 1 +// lldb-command:print b +// lldb-check:[...]$1 = true +// lldb-command:print c +// lldb-check:[...]$2 = 2.5 +// lldb-command:continue + +// NON IMMEDIATE ARGS +// lldb-command:print a +// lldb-check:[...]$3 = BigStruct { a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10 } +// lldb-command:print b +// lldb-check:[...]$4 = BigStruct { a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18 } +// lldb-command:continue + +// BINDING +// lldb-command:print a +// lldb-check:[...]$5 = 19 +// lldb-command:print b +// lldb-check:[...]$6 = 20 +// lldb-command:print c +// lldb-check:[...]$7 = 21.5 +// lldb-command:continue + +// ASSIGNMENT +// lldb-command:print a +// lldb-check:[...]$8 = 22 +// lldb-command:print b +// lldb-check:[...]$9 = 23 +// lldb-command:print c +// lldb-check:[...]$10 = 24.5 +// lldb-command:continue + +// FUNCTION CALL +// lldb-command:print x +// lldb-check:[...]$11 = 25 +// lldb-command:print y +// lldb-check:[...]$12 = 26 +// lldb-command:print z +// lldb-check:[...]$13 = 27.5 +// lldb-command:continue + +// EXPR +// lldb-command:print x +// lldb-check:[...]$14 = 28 +// lldb-command:print y +// lldb-check:[...]$15 = 29 +// lldb-command:print z +// lldb-check:[...]$16 = 30.5 +// lldb-command:continue + +// RETURN EXPR +// lldb-command:print x +// lldb-check:[...]$17 = 31 +// lldb-command:print y +// lldb-check:[...]$18 = 32 +// lldb-command:print z +// lldb-check:[...]$19 = 33.5 +// lldb-command:continue + +// ARITHMETIC EXPR +// lldb-command:print x +// lldb-check:[...]$20 = 34 +// lldb-command:print y +// lldb-check:[...]$21 = 35 +// lldb-command:print z +// lldb-check:[...]$22 = 36.5 +// lldb-command:continue + +// IF EXPR +// lldb-command:print x +// lldb-check:[...]$23 = 37 +// lldb-command:print y +// lldb-check:[...]$24 = 38 +// lldb-command:print z +// lldb-check:[...]$25 = 39.5 +// lldb-command:continue + +// WHILE EXPR +// lldb-command:print x +// lldb-check:[...]$26 = 40 +// lldb-command:print y +// lldb-check:[...]$27 = 41 +// lldb-command:print z +// lldb-check:[...]$28 = 42 +// lldb-command:continue + +// LOOP EXPR +// lldb-command:print x +// lldb-check:[...]$29 = 43 +// lldb-command:print y +// lldb-check:[...]$30 = 44 +// lldb-command:print z +// lldb-check:[...]$31 = 45 +// lldb-command:continue + #![allow(unused_variable)] #[no_split_stack] diff --git a/src/test/debuginfo/function-prologue-stepping-regular.rs b/src/test/debuginfo/function-prologue-stepping-regular.rs new file mode 100644 index 0000000000000..7cb9c6bba5227 --- /dev/null +++ b/src/test/debuginfo/function-prologue-stepping-regular.rs @@ -0,0 +1,232 @@ +// Copyright 2013-2014 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. + +// This test case checks if function arguments already have the correct value when breaking at the +// beginning of a function. + +// ignore-gdb +// compile-flags:-g + +// lldb-command:breakpoint set --name immediate_args +// lldb-command:breakpoint set --name non_immediate_args +// lldb-command:breakpoint set --name binding +// lldb-command:breakpoint set --name assignment +// lldb-command:breakpoint set --name function_call +// lldb-command:breakpoint set --name identifier +// lldb-command:breakpoint set --name return_expr +// lldb-command:breakpoint set --name arithmetic_expr +// lldb-command:breakpoint set --name if_expr +// lldb-command:breakpoint set --name while_expr +// lldb-command:breakpoint set --name loop_expr +// lldb-command:run + +// IMMEDIATE ARGS +// lldb-command:print a +// lldb-check:[...]$0 = 1 +// lldb-command:print b +// lldb-check:[...]$1 = true +// lldb-command:print c +// lldb-check:[...]$2 = 2.5 +// lldb-command:continue + +// NON IMMEDIATE ARGS +// lldb-command:print a +// lldb-check:[...]$3 = BigStruct { a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10 } +// lldb-command:print b +// lldb-check:[...]$4 = BigStruct { a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18 } +// lldb-command:continue + +// BINDING +// lldb-command:print a +// lldb-check:[...]$5 = 19 +// lldb-command:print b +// lldb-check:[...]$6 = 20 +// lldb-command:print c +// lldb-check:[...]$7 = 21.5 +// lldb-command:continue + +// ASSIGNMENT +// lldb-command:print a +// lldb-check:[...]$8 = 22 +// lldb-command:print b +// lldb-check:[...]$9 = 23 +// lldb-command:print c +// lldb-check:[...]$10 = 24.5 +// lldb-command:continue + +// FUNCTION CALL +// lldb-command:print x +// lldb-check:[...]$11 = 25 +// lldb-command:print y +// lldb-check:[...]$12 = 26 +// lldb-command:print z +// lldb-check:[...]$13 = 27.5 +// lldb-command:continue + +// EXPR +// lldb-command:print x +// lldb-check:[...]$14 = 28 +// lldb-command:print y +// lldb-check:[...]$15 = 29 +// lldb-command:print z +// lldb-check:[...]$16 = 30.5 +// lldb-command:continue + +// RETURN EXPR +// lldb-command:print x +// lldb-check:[...]$17 = 31 +// lldb-command:print y +// lldb-check:[...]$18 = 32 +// lldb-command:print z +// lldb-check:[...]$19 = 33.5 +// lldb-command:continue + +// ARITHMETIC EXPR +// lldb-command:print x +// lldb-check:[...]$20 = 34 +// lldb-command:print y +// lldb-check:[...]$21 = 35 +// lldb-command:print z +// lldb-check:[...]$22 = 36.5 +// lldb-command:continue + +// IF EXPR +// lldb-command:print x +// lldb-check:[...]$23 = 37 +// lldb-command:print y +// lldb-check:[...]$24 = 38 +// lldb-command:print z +// lldb-check:[...]$25 = 39.5 +// lldb-command:continue + +// WHILE EXPR +// lldb-command:print x +// lldb-check:[...]$26 = 40 +// lldb-command:print y +// lldb-check:[...]$27 = 41 +// lldb-command:print z +// lldb-check:[...]$28 = 42 +// lldb-command:continue + +// LOOP EXPR +// lldb-command:print x +// lldb-check:[...]$29 = 43 +// lldb-command:print y +// lldb-check:[...]$30 = 44 +// lldb-command:print z +// lldb-check:[...]$31 = 45 +// lldb-command:continue + +#![allow(unused_variable)] + +fn immediate_args(a: int, b: bool, c: f64) { + () +} + +struct BigStruct { + a: u64, + b: u64, + c: u64, + d: u64, + e: u64, + f: u64, + g: u64, + h: u64 +} + +fn non_immediate_args(a: BigStruct, b: BigStruct) { + () +} + +fn binding(a: i64, b: u64, c: f64) { + let x = 0i; +} + +fn assignment(mut a: u64, b: u64, c: f64) { + a = b; +} + +fn function_call(x: u64, y: u64, z: f64) { + std::io::stdio::print("Hi!") +} + +fn identifier(x: u64, y: u64, z: f64) -> u64 { + x +} + +fn return_expr(x: u64, y: u64, z: f64) -> u64 { + return x; +} + +fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 { + x + y +} + +fn if_expr(x: u64, y: u64, z: f64) -> u64 { + if x + y < 1000 { + x + } else { + y + } +} + +fn while_expr(mut x: u64, y: u64, z: u64) -> u64 { + while x + y < 1000 { + x += z + } + return x; +} + +fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 { + loop { + x += z; + + if x + y > 1000 { + return x; + } + } +} + +fn main() { + immediate_args(1, true, 2.5); + + non_immediate_args( + BigStruct { + a: 3, + b: 4, + c: 5, + d: 6, + e: 7, + f: 8, + g: 9, + h: 10 + }, + BigStruct { + a: 11, + b: 12, + c: 13, + d: 14, + e: 15, + f: 16, + g: 17, + h: 18 + } + ); + + binding(19, 20, 21.5); + assignment(22, 23, 24.5); + function_call(25, 26, 27.5); + identifier(28, 29, 30.5); + return_expr(31, 32, 33.5); + arithmetic_expr(34, 35, 36.5); + if_expr(37, 38, 39.5); + while_expr(40, 41, 42); + loop_expr(43, 44, 45); +} diff --git a/src/test/debuginfo/generic-function.rs b/src/test/debuginfo/generic-function.rs index 1777c168d9b9a..c3996929e7c79 100644 --- a/src/test/debuginfo/generic-function.rs +++ b/src/test/debuginfo/generic-function.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -41,6 +44,36 @@ // gdb-check:$9 = {{5, {a = 6, b = 7.5}}, {{a = 6, b = 7.5}, 5}} // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print *t0 +// lldb-check:[...]$0 = 1 +// lldb-command:print *t1 +// lldb-check:[...]$1 = 2.5 +// lldb-command:print ret +// lldb-check:[...]$2 = ((1, 2.5), (2.5, 1)) +// lldb-command:continue + +// lldb-command:print *t0 +// lldb-check:[...]$3 = 3.5 +// lldb-command:print *t1 +// lldb-check:[...]$4 = 4 +// lldb-command:print ret +// lldb-check:[...]$5 = ((3.5, 4), (4, 3.5)) +// lldb-command:continue + +// lldb-command:print *t0 +// lldb-check:[...]$6 = 5 +// lldb-command:print *t1 +// lldb-check:[...]$7 = Struct { a: 6, b: 7.5 } +// lldb-command:print ret +// lldb-check:[...]$8 = ((5, Struct { a: 6, b: 7.5 }), (Struct { a: 6, b: 7.5 }, 5)) +// lldb-command:continue + + #[deriving(Clone)] struct Struct { a: int, @@ -49,7 +82,7 @@ struct Struct { fn dup_tup(t0: &T0, t1: &T1) -> ((T0, T1), (T1, T0)) { let ret = ((t0.clone(), t1.clone()), (t1.clone(), t0.clone())); - zzz(); + zzz(); // #break ret } diff --git a/src/test/debuginfo/generic-functions-nested.rs b/src/test/debuginfo/generic-functions-nested.rs index 1805405dc1ef5..2546c2c233954 100644 --- a/src/test/debuginfo/generic-functions-nested.rs +++ b/src/test/debuginfo/generic-functions-nested.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -42,12 +45,41 @@ // gdb-check:$8 = 2.5 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print x +// lldb-check:[...]$0 = -1 +// lldb-command:print y +// lldb-check:[...]$1 = 1 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$2 = -1 +// lldb-command:print y +// lldb-check:[...]$3 = 2.5 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$4 = -2.5 +// lldb-command:print y +// lldb-check:[...]$5 = 1 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$6 = -2.5 +// lldb-command:print y +// lldb-check:[...]$7 = 2.5 +// lldb-command:continue + fn outer(a: TA) { inner(a.clone(), 1i); inner(a.clone(), 2.5f64); fn inner(x: TX, y: TY) { - zzz(); + zzz(); // #break } } @@ -56,4 +88,4 @@ fn main() { outer(-2.5f64); } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/generic-method-on-generic-struct.rs b/src/test/debuginfo/generic-method-on-generic-struct.rs index 9ed1c0175a91b..2e43dcdeb498e 100644 --- a/src/test/debuginfo/generic-method-on-generic-struct.rs +++ b/src/test/debuginfo/generic-method-on-generic-struct.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -20,8 +23,8 @@ // gdb-check:$1 = {x = {8888, -8888}} // gdb-command:print arg1 // gdb-check:$2 = -1 -// gdb-command:print/d arg2 -// gdb-check:$3 = -2 +// gdb-command:print arg2 +// gdb-check:$3 = 2 // gdb-command:continue // STACK BY VAL @@ -64,6 +67,57 @@ // gdb-check:$15 = -10.5 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// STACK BY REF +// lldb-command:print *self +// lldb-check:[...]$0 = Struct<(u32, i32)> { x: (8888, -8888) } +// lldb-command:print arg1 +// lldb-check:[...]$1 = -1 +// lldb-command:print arg2 +// lldb-check:[...]$2 = 2 +// lldb-command:continue + +// STACK BY VAL +// lldb-command:print self +// lldb-check:[...]$3 = Struct<(u32, i32)> { x: (8888, -8888) } +// lldb-command:print arg1 +// lldb-check:[...]$4 = -3 +// lldb-command:print arg2 +// lldb-check:[...]$5 = -4 +// lldb-command:continue + +// OWNED BY REF +// lldb-command:print *self +// lldb-check:[...]$6 = Struct { x: 1234.5 } +// lldb-command:print arg1 +// lldb-check:[...]$7 = -5 +// lldb-command:print arg2 +// lldb-check:[...]$8 = -6 +// lldb-command:continue + +// OWNED BY VAL +// lldb-command:print self +// lldb-check:[...]$9 = Struct { x: 1234.5 } +// lldb-command:print arg1 +// lldb-check:[...]$10 = -7 +// lldb-command:print arg2 +// lldb-check:[...]$11 = -8 +// lldb-command:continue + +// OWNED MOVED +// lldb-command:print *self +// lldb-check:[...]$12 = Struct { x: 1234.5 } +// lldb-command:print arg1 +// lldb-check:[...]$13 = -9 +// lldb-command:print arg2 +// lldb-check:[...]$14 = -10.5 +// lldb-command:continue + + struct Struct { x: T } @@ -71,24 +125,24 @@ struct Struct { impl Struct { fn self_by_ref(&self, arg1: int, arg2: T2) -> int { - zzz(); + zzz(); // #break arg1 } fn self_by_val(self, arg1: int, arg2: T2) -> int { - zzz(); + zzz(); // #break arg1 } - fn self_owned(~self, arg1: int, arg2: T2) -> int { - zzz(); + fn self_owned(self: Box>, arg1: int, arg2: T2) -> int { + zzz(); // #break arg1 } } fn main() { let stack = Struct { x: (8888_u32, -8888_i32) }; - let _ = stack.self_by_ref(-1, -2_i8); + let _ = stack.self_by_ref(-1, 2_u16); let _ = stack.self_by_val(-3, -4_i16); let owned = box Struct { x: 1234.5f64 }; diff --git a/src/test/debuginfo/generic-struct.rs b/src/test/debuginfo/generic-struct.rs index a2c5a0973fca4..65ccb1314add3 100644 --- a/src/test/debuginfo/generic-struct.rs +++ b/src/test/debuginfo/generic-struct.rs @@ -8,9 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -24,6 +28,20 @@ // gdb-command:print float_int_float // gdb-check:$4 = {key = 6.5, value = {key = 7, value = 8.5}} +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print int_int +// lldb-check:[...]$0 = AGenericStruct { key: 0, value: 1 } +// lldb-command:print int_float +// lldb-check:[...]$1 = AGenericStruct { key: 2, value: 3.5 } +// lldb-command:print float_int +// lldb-check:[...]$2 = AGenericStruct { key: 4.5, value: 5 } + +// lldb-command:print float_int_float +// lldb-check:[...]$3 = AGenericStruct> { key: 6.5, value: AGenericStruct { key: 7, value: 8.5 } } + struct AGenericStruct { key: TKey, value: TValue @@ -39,7 +57,7 @@ fn main() { value: AGenericStruct { key: 7i, value: 8.5f64 }, }; - zzz(); + zzz(); // #break } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/generic-tuple-style-enum.rs b/src/test/debuginfo/generic-tuple-style-enum.rs index 07f7546068ca9..8638ae3b49d89 100644 --- a/src/test/debuginfo/generic-tuple-style-enum.rs +++ b/src/test/debuginfo/generic-tuple-style-enum.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print union on // gdb-command:rbreak zzz // gdb-command:run @@ -30,6 +33,23 @@ // gdb-check:$4 = {{-1}} +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print case1 +// lldb-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868) + +// lldb-command:print case2 +// lldb-check:[...]$1 = Case2(0, 286331153, 286331153) + +// lldb-command:print case3 +// lldb-check:[...]$2 = Case3(0, 6438275382588823897) + +// lldb-command:print univariant +// lldb-check:[...]$3 = TheOnlyCase(-1) + + // NOTE: This is a copy of the non-generic test case. The `Txx` type parameters have to be // substituted with something of size `xx` bits and the same alignment as an integer type of the // same size. @@ -73,7 +93,7 @@ fn main() { let univariant = TheOnlyCase(-1_i64); - zzz(); + zzz(); // #break } -fn zzz() {()} +fn zzz() { () } diff --git a/src/test/debuginfo/include_string.rs b/src/test/debuginfo/include_string.rs index 977e304a32ec2..ed9767c78f3f6 100644 --- a/src/test/debuginfo/include_string.rs +++ b/src/test/debuginfo/include_string.rs @@ -15,13 +15,27 @@ // gdb-command:run // gdb-command:finish // gdb-command:print string1.length -// gdb-check:$1 = 49 +// gdb-check:$1 = 48 // gdb-command:print string2.length // gdb-check:$2 = 49 // gdb-command:print string3.length -// gdb-check:$3 = 49 +// gdb-check:$3 = 50 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print string1.length +// lldb-check:[...]$0 = 48 +// lldb-command:print string2.length +// lldb-check:[...]$1 = 49 +// lldb-command:print string3.length +// lldb-check:[...]$2 = 50 + +// lldb-command:continue + #![allow(unused_variable)] // This test case makes sure that debug info does not ICE when include_str is @@ -31,7 +45,8 @@ fn main() { let string1 = include_str!("text-to-include-1.txt"); let string2 = include_str!("text-to-include-2.txt"); let string3 = include_str!("text-to-include-3.txt"); - zzz(); + + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/lexical-scope-in-for-loop.rs b/src/test/debuginfo/lexical-scope-in-for-loop.rs index 0fb823a74cc72..13cae3252d804 100644 --- a/src/test/debuginfo/lexical-scope-in-for-loop.rs +++ b/src/test/debuginfo/lexical-scope-in-for-loop.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -53,6 +56,43 @@ // gdb-check:$7 = 1000000 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// FIRST ITERATION +// lldb-command:print x +// lldb-check:[...]$0 = 1 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$1 = -1 +// lldb-command:continue + +// SECOND ITERATION +// lldb-command:print x +// lldb-check:[...]$2 = 2 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$3 = -2 +// lldb-command:continue + +// THIRD ITERATION +// lldb-command:print x +// lldb-check:[...]$4 = 3 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$5 = -3 +// lldb-command:continue + +// AFTER LOOP +// lldb-command:print x +// lldb-check:[...]$6 = 1000000 +// lldb-command:continue + fn main() { let range = [1i, 2, 3]; @@ -60,16 +100,16 @@ fn main() { let x = 1000000i; // wan meeeljen doollaars! for &x in range.iter() { - zzz(); + zzz(); // #break sentinel(); let x = -1i * x; - zzz(); + zzz(); // #break sentinel(); } - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/lexical-scope-in-if.rs b/src/test/debuginfo/lexical-scope-in-if.rs index 6018e62af0078..ce30886c7d375 100644 --- a/src/test/debuginfo/lexical-scope-in-if.rs +++ b/src/test/debuginfo/lexical-scope-in-if.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -78,47 +81,109 @@ // gdb-check:$16 = -1 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// BEFORE if +// lldb-command:print x +// lldb-check:[...]$0 = 999 +// lldb-command:print y +// lldb-check:[...]$1 = -1 +// lldb-command:continue + +// AT BEGINNING of 'then' block +// lldb-command:print x +// lldb-check:[...]$2 = 999 +// lldb-command:print y +// lldb-check:[...]$3 = -1 +// lldb-command:continue + +// AFTER 1st redeclaration of 'x' +// lldb-command:print x +// lldb-check:[...]$4 = 1001 +// lldb-command:print y +// lldb-check:[...]$5 = -1 +// lldb-command:continue + +// AFTER 2st redeclaration of 'x' +// lldb-command:print x +// lldb-check:[...]$6 = 1002 +// lldb-command:print y +// lldb-check:[...]$7 = 1003 +// lldb-command:continue + +// AFTER 1st if expression +// lldb-command:print x +// lldb-check:[...]$8 = 999 +// lldb-command:print y +// lldb-check:[...]$9 = -1 +// lldb-command:continue + +// BEGINNING of else branch +// lldb-command:print x +// lldb-check:[...]$10 = 999 +// lldb-command:print y +// lldb-check:[...]$11 = -1 +// lldb-command:continue + +// BEGINNING of else branch +// lldb-command:print x +// lldb-check:[...]$12 = 1004 +// lldb-command:print y +// lldb-check:[...]$13 = 1005 +// lldb-command:continue + +// BEGINNING of else branch +// lldb-command:print x +// lldb-check:[...]$14 = 999 +// lldb-command:print y +// lldb-check:[...]$15 = -1 +// lldb-command:continue + + fn main() { let x = 999i; let y = -1i; - zzz(); + zzz(); // #break sentinel(); if x < 1000 { - zzz(); + zzz(); // #break sentinel(); let x = 1001i; - zzz(); + zzz(); // #break sentinel(); let x = 1002i; let y = 1003i; - zzz(); + zzz(); // #break sentinel(); } else { unreachable!(); } - zzz(); + zzz(); // #break sentinel(); if x > 1000 { unreachable!(); } else { - zzz(); + zzz(); // #break sentinel(); let x = 1004i; let y = 1005i; - zzz(); + zzz(); // #break sentinel(); } - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/lexical-scope-in-match.rs b/src/test/debuginfo/lexical-scope-in-match.rs index 7bec677e4b100..78e9b278e53a9 100644 --- a/src/test/debuginfo/lexical-scope-in-match.rs +++ b/src/test/debuginfo/lexical-scope-in-match.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -74,6 +77,64 @@ // gdb-check:$18 = 232 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print shadowed +// lldb-check:[...]$0 = 231 +// lldb-command:print not_shadowed +// lldb-check:[...]$1 = 232 +// lldb-command:continue + +// lldb-command:print shadowed +// lldb-check:[...]$2 = 233 +// lldb-command:print not_shadowed +// lldb-check:[...]$3 = 232 +// lldb-command:print local_to_arm +// lldb-check:[...]$4 = 234 +// lldb-command:continue + +// lldb-command:print shadowed +// lldb-check:[...]$5 = 236 +// lldb-command:print not_shadowed +// lldb-check:[...]$6 = 232 +// lldb-command:continue + +// lldb-command:print shadowed +// lldb-check:[...]$7 = 237 +// lldb-command:print not_shadowed +// lldb-check:[...]$8 = 232 +// lldb-command:print local_to_arm +// lldb-check:[...]$9 = 238 +// lldb-command:continue + +// lldb-command:print shadowed +// lldb-check:[...]$10 = 239 +// lldb-command:print not_shadowed +// lldb-check:[...]$11 = 232 +// lldb-command:continue + +// lldb-command:print shadowed +// lldb-check:[...]$12 = 241 +// lldb-command:print not_shadowed +// lldb-check:[...]$13 = 232 +// lldb-command:continue + +// lldb-command:print shadowed +// lldb-check:[...]$14 = 243 +// lldb-command:print *local_to_arm +// lldb-check:[...]$15 = 244 +// lldb-command:continue + +// lldb-command:print shadowed +// lldb-check:[...]$16 = 231 +// lldb-command:print not_shadowed +// lldb-check:[...]$17 = 232 +// lldb-command:continue + + struct Struct { x: int, y: int @@ -84,13 +145,13 @@ fn main() { let shadowed = 231i; let not_shadowed = 232i; - zzz(); + zzz(); // #break sentinel(); match (233i, 234i) { (shadowed, local_to_arm) => { - zzz(); + zzz(); // #break sentinel(); } } @@ -99,7 +160,7 @@ fn main() { // with literal (235, shadowed) => { - zzz(); + zzz(); // #break sentinel(); } _ => {} @@ -108,7 +169,7 @@ fn main() { match (Struct { x: 237, y: 238 }) { Struct { x: shadowed, y: local_to_arm } => { - zzz(); + zzz(); // #break sentinel(); } } @@ -117,7 +178,7 @@ fn main() { // ignored field Struct { x: shadowed, .. } => { - zzz(); + zzz(); // #break sentinel(); } } @@ -126,7 +187,7 @@ fn main() { // with literal Struct { x: shadowed, y: 242 } => { - zzz(); + zzz(); // #break sentinel(); } _ => {} @@ -135,12 +196,12 @@ fn main() { match (243i, 244i) { (shadowed, ref local_to_arm) => { - zzz(); + zzz(); // #break sentinel(); } } - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/lexical-scope-in-stack-closure.rs b/src/test/debuginfo/lexical-scope-in-stack-closure.rs index 0168eaa86c2d1..aca6cc06abddb 100644 --- a/src/test/debuginfo/lexical-scope-in-stack-closure.rs +++ b/src/test/debuginfo/lexical-scope-in-stack-closure.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -44,34 +47,63 @@ // gdb-check:$6 = false // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print x +// lldb-check:[...]$0 = false +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$1 = false +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$2 = 1000 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$3 = 2.5 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$4 = true +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$5 = false +// lldb-command:continue + fn main() { let x = false; - zzz(); + zzz(); // #break sentinel(); let stack_closure: |int| = |x| { - zzz(); + zzz(); // #break sentinel(); let x = 2.5f64; - zzz(); + zzz(); // #break sentinel(); let x = true; - zzz(); + zzz(); // #break sentinel(); }; - zzz(); + zzz(); // #break sentinel(); stack_closure(1000); - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/lexical-scope-in-unconditional-loop.rs b/src/test/debuginfo/lexical-scope-in-unconditional-loop.rs index 48edd7ae12a09..3096dfbd2a6e2 100644 --- a/src/test/debuginfo/lexical-scope-in-unconditional-loop.rs +++ b/src/test/debuginfo/lexical-scope-in-unconditional-loop.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -82,6 +85,66 @@ // gdb-check:$13 = 2 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// FIRST ITERATION +// lldb-command:print x +// lldb-check:[...]$0 = 0 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$1 = 1 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$2 = 101 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$3 = 101 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$4 = -987 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$5 = 101 +// lldb-command:continue + + +// SECOND ITERATION +// lldb-command:print x +// lldb-check:[...]$6 = 1 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$7 = 2 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$8 = 102 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$9 = 102 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$10 = -987 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$11 = 102 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$12 = 2 +// lldb-command:continue + fn main() { let mut x = 0i; @@ -91,35 +154,35 @@ fn main() { break; } - zzz(); + zzz(); // #break sentinel(); x += 1; - zzz(); + zzz(); // #break sentinel(); // Shadow x let x = x + 100; - zzz(); + zzz(); // #break sentinel(); // open scope within loop's top level scope { - zzz(); + zzz(); // #break sentinel(); let x = -987i; - zzz(); + zzz(); // #break sentinel(); } // Check that we get the x before the inner scope again - zzz(); + zzz(); // #break sentinel(); } - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/lexical-scope-in-unique-closure.rs b/src/test/debuginfo/lexical-scope-in-unique-closure.rs index ce3b2a530e2c2..590b7238c123a 100644 --- a/src/test/debuginfo/lexical-scope-in-unique-closure.rs +++ b/src/test/debuginfo/lexical-scope-in-unique-closure.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -44,34 +47,63 @@ // gdb-check:$6 = false // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print x +// lldb-check:[...]$0 = false +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$1 = false +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$2 = 1000 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$3 = 2.5 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$4 = true +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$5 = false +// lldb-command:continue + fn main() { let x = false; - zzz(); + zzz(); // #break sentinel(); let unique_closure: proc(int) = proc(x) { - zzz(); + zzz(); // #break sentinel(); let x = 2.5f64; - zzz(); + zzz(); // #break sentinel(); let x = true; - zzz(); + zzz(); // #break sentinel(); }; - zzz(); + zzz(); // #break sentinel(); unique_closure(1000); - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/lexical-scope-in-while.rs b/src/test/debuginfo/lexical-scope-in-while.rs index d726eb6581eb2..b211c11128a7c 100644 --- a/src/test/debuginfo/lexical-scope-in-while.rs +++ b/src/test/debuginfo/lexical-scope-in-while.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -82,40 +85,101 @@ // gdb-check:$13 = 2 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// FIRST ITERATION +// lldb-command:print x +// lldb-check:[...]$0 = 0 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$1 = 1 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$2 = 101 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$3 = 101 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$4 = -987 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$5 = 101 +// lldb-command:continue + + +// SECOND ITERATION +// lldb-command:print x +// lldb-check:[...]$6 = 1 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$7 = 2 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$8 = 102 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$9 = 102 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$10 = -987 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$11 = 102 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$12 = 2 +// lldb-command:continue + + fn main() { let mut x = 0i; while x < 2 { - zzz(); + zzz(); // #break sentinel(); x += 1; - zzz(); + zzz(); // #break sentinel(); // Shadow x let x = x + 100; - zzz(); + zzz(); // #break sentinel(); // open scope within loop's top level scope { - zzz(); + zzz(); // #break sentinel(); let x = -987i; - zzz(); + zzz(); // #break sentinel(); } // Check that we get the x before the inner scope again - zzz(); + zzz(); // #break sentinel(); } - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/lexical-scope-with-macro.rs b/src/test/debuginfo/lexical-scope-with-macro.rs index e55271239d488..27070dd867d0e 100644 --- a/src/test/debuginfo/lexical-scope-with-macro.rs +++ b/src/test/debuginfo/lexical-scope-with-macro.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -65,6 +68,56 @@ // gdb-check:$15 = 400 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print a +// lldb-check:[...]$0 = 10 +// lldb-command:print b +// lldb-check:[...]$1 = 34 +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$2 = 890242 +// lldb-command:print b +// lldb-check:[...]$3 = 34 +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$4 = 10 +// lldb-command:print b +// lldb-check:[...]$5 = 34 +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$6 = 102 +// lldb-command:print b +// lldb-check:[...]$7 = 34 +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$8 = 110 +// lldb-command:print b +// lldb-check:[...]$9 = 34 +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$10 = 10 +// lldb-command:print b +// lldb-check:[...]$11 = 34 +// lldb-command:continue + +// lldb-command:print a +// lldb-check:[...]$12 = 10 +// lldb-command:print b +// lldb-check:[...]$13 = 34 +// lldb-command:print c +// lldb-check:[...]$14 = 400 +// lldb-command:continue + + #![feature(macro_rules)] macro_rules! trivial( @@ -78,7 +131,7 @@ macro_rules! no_new_scope( macro_rules! new_scope( () => ({ let a = 890242i; - zzz(); + zzz(); // #break sentinel(); }) ) @@ -87,12 +140,12 @@ macro_rules! shadow_within_macro( ($e1:expr) => ({ let a = $e1 + 2; - zzz(); + zzz(); // #break sentinel(); let a = $e1 + 10; - zzz(); + zzz(); // #break sentinel(); }) ) @@ -108,22 +161,22 @@ fn main() { let a = trivial!(10i); let b = no_new_scope!(33i); - zzz(); + zzz(); // #break sentinel(); new_scope!(); - zzz(); + zzz(); // #break sentinel(); shadow_within_macro!(100i); - zzz(); + zzz(); // #break sentinel(); let c = dup_expr!(10i * 20); - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/lexical-scopes-in-block-expression.rs b/src/test/debuginfo/lexical-scopes-in-block-expression.rs index 2a9969dc6e903..b5f9622e79a7b 100644 --- a/src/test/debuginfo/lexical-scopes-in-block-expression.rs +++ b/src/test/debuginfo/lexical-scopes-in-block-expression.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -211,6 +214,164 @@ // gdb-check:$57 = 10 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// STRUCT EXPRESSION +// lldb-command:print val +// lldb-check:[...]$0 = -1 +// lldb-command:print ten +// lldb-check:[...]$1 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$2 = 11 +// lldb-command:print ten +// lldb-check:[...]$3 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$4 = -1 +// lldb-command:print ten +// lldb-check:[...]$5 = 10 +// lldb-command:continue + +// FUNCTION CALL +// lldb-command:print val +// lldb-check:[...]$6 = -1 +// lldb-command:print ten +// lldb-check:[...]$7 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$8 = 12 +// lldb-command:print ten +// lldb-check:[...]$9 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$10 = -1 +// lldb-command:print ten +// lldb-check:[...]$11 = 10 +// lldb-command:continue + +// TUPLE EXPRESSION +// lldb-command:print val +// lldb-check:[...]$12 = -1 +// lldb-command:print ten +// lldb-check:[...]$13 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$14 = 13 +// lldb-command:print ten +// lldb-check:[...]$15 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$16 = -1 +// lldb-command:print ten +// lldb-check:[...]$17 = 10 +// lldb-command:continue + +// VEC EXPRESSION +// lldb-command:print val +// lldb-check:[...]$18 = -1 +// lldb-command:print ten +// lldb-check:[...]$19 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$20 = 14 +// lldb-command:print ten +// lldb-check:[...]$21 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$22 = -1 +// lldb-command:print ten +// lldb-check:[...]$23 = 10 +// lldb-command:continue + +// REPEAT VEC EXPRESSION +// lldb-command:print val +// lldb-check:[...]$24 = -1 +// lldb-command:print ten +// lldb-check:[...]$25 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$26 = 15 +// lldb-command:print ten +// lldb-check:[...]$27 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$28 = -1 +// lldb-command:print ten +// lldb-check:[...]$29 = 10 +// lldb-command:continue + +// ASSIGNMENT EXPRESSION +// lldb-command:print val +// lldb-check:[...]$30 = -1 +// lldb-command:print ten +// lldb-check:[...]$31 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$32 = 16 +// lldb-command:print ten +// lldb-check:[...]$33 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$34 = -1 +// lldb-command:print ten +// lldb-check:[...]$35 = 10 +// lldb-command:continue + + +// ARITHMETIC EXPRESSION +// lldb-command:print val +// lldb-check:[...]$36 = -1 +// lldb-command:print ten +// lldb-check:[...]$37 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$38 = 17 +// lldb-command:print ten +// lldb-check:[...]$39 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$40 = -1 +// lldb-command:print ten +// lldb-check:[...]$41 = 10 +// lldb-command:continue + +// INDEX EXPRESSION +// lldb-command:print val +// lldb-check:[...]$42 = -1 +// lldb-command:print ten +// lldb-check:[...]$43 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$44 = 18 +// lldb-command:print ten +// lldb-check:[...]$45 = 10 +// lldb-command:continue + +// lldb-command:print val +// lldb-check:[...]$46 = -1 +// lldb-command:print ten +// lldb-check:[...]$47 = 10 +// lldb-command:continue + #![allow(unused_variable)] #![allow(dead_assignment)] @@ -233,13 +394,13 @@ fn main() { // surrounded by struct expression let point = Point { x: { - zzz(); + zzz(); // #break sentinel(); let val = ten + 1; unsafe {MUT_INT = 1;}; - zzz(); + zzz(); // #break sentinel(); val @@ -247,129 +408,129 @@ fn main() { y: 10 }; - zzz(); + zzz(); // #break sentinel(); // surrounded by function call let _ = a_function({ - zzz(); + zzz(); // #break sentinel(); let val = ten + 2; unsafe {MUT_INT = 2;}; - zzz(); + zzz(); // #break sentinel(); val }); - zzz(); + zzz(); // #break sentinel(); // surrounded by tup let _ = ({ - zzz(); + zzz(); // #break sentinel(); let val = ten + 3; unsafe {MUT_INT = 3;}; - zzz(); + zzz(); // #break sentinel(); val }, 0i); - zzz(); + zzz(); // #break sentinel(); // surrounded by vec let _ = [{ - zzz(); + zzz(); // #break sentinel(); let val = ten + 4; unsafe {MUT_INT = 4;}; - zzz(); + zzz(); // #break sentinel(); val }, 0, 0]; - zzz(); + zzz(); // #break sentinel(); // surrounded by repeat vec let _ = [{ - zzz(); + zzz(); // #break sentinel(); let val = ten + 5; unsafe {MUT_INT = 5;}; - zzz(); + zzz(); // #break sentinel(); val }, ..10]; - zzz(); + zzz(); // #break sentinel(); // assignment expression let mut var = 0; var = { - zzz(); + zzz(); // #break sentinel(); let val = ten + 6; unsafe {MUT_INT = 6;}; - zzz(); + zzz(); // #break sentinel(); val }; - zzz(); + zzz(); // #break sentinel(); // arithmetic expression var = 10 + -{ - zzz(); + zzz(); // #break sentinel(); let val = ten + 7; unsafe {MUT_INT = 7;}; - zzz(); + zzz(); // #break sentinel(); val } * 5; - zzz(); + zzz(); // #break sentinel(); // index expression let a_vector = [10i, ..20]; let _ = a_vector[{ - zzz(); + zzz(); // #break sentinel(); let val = ten + 8; unsafe {MUT_INT = 8;}; - zzz(); + zzz(); // #break sentinel(); val as uint }]; - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/limited-debuginfo.rs b/src/test/debuginfo/limited-debuginfo.rs index 9cda2c45131db..6c71971a0f824 100644 --- a/src/test/debuginfo/limited-debuginfo.rs +++ b/src/test/debuginfo/limited-debuginfo.rs @@ -10,6 +10,8 @@ // ignore-android: FIXME(#10381) +// ignore-lldb + // compile-flags:--debuginfo=1 // Make sure functions have proper names diff --git a/src/test/debuginfo/managed-enum.rs b/src/test/debuginfo/managed-enum.rs index bb236a28a8800..2fd43d3e9ca67 100644 --- a/src/test/debuginfo/managed-enum.rs +++ b/src/test/debuginfo/managed-enum.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -24,6 +27,20 @@ // gdb-command:print univariant->val // gdb-check:$3 = {{-9747455}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print the_a->val +// lldb-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 } + +// lldb-command:print the_b->val +// lldb-check:[...]$1 = TheB(0, 286331153, 286331153) + +// lldb-command:print univariant->val +// lldb-check:[...]$2 = TheOnlyCase(-9747455) + #![allow(unused_variable)] #![feature(struct_variant, managed_boxes)] @@ -62,7 +79,7 @@ fn main() { let univariant = box(GC) TheOnlyCase(-9747455); - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/managed-pointer-within-unique-vec.rs b/src/test/debuginfo/managed-pointer-within-unique-vec.rs index d1f38be1d8947..6abd174b1aa67 100644 --- a/src/test/debuginfo/managed-pointer-within-unique-vec.rs +++ b/src/test/debuginfo/managed-pointer-within-unique-vec.rs @@ -13,6 +13,9 @@ #![feature(managed_boxes)] // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -29,6 +32,24 @@ // gdb-command:print unique.ptr[3]->val // gdb-check:$4 = 13 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print unique.ptr[0]->val +// lldb-check:[...]$0 = 10 + +// lldb-command:print unique.ptr[1]->val +// lldb-check:[...]$1 = 11 + +// lldb-command:print unique.ptr[2]->val +// lldb-check:[...]$2 = 12 + +// lldb-command:print unique.ptr[3]->val +// lldb-check:[...]$3 = 13 + + #![allow(unused_variable)] use std::gc::{Gc, GC}; @@ -37,7 +58,7 @@ fn main() { let unique: Vec> = vec!(box(GC) 10, box(GC) 11, box(GC) 12, box(GC) 13); - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/managed-pointer-within-unique.rs b/src/test/debuginfo/managed-pointer-within-unique.rs index cc18ea64f383e..7f1b32936c819 100644 --- a/src/test/debuginfo/managed-pointer-within-unique.rs +++ b/src/test/debuginfo/managed-pointer-within-unique.rs @@ -13,6 +13,9 @@ #![feature(managed_boxes)] // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz // gdb-command:run @@ -27,6 +30,19 @@ // gdb-command:print managed_within_unique->y->val // gdb-check:$3 = -4 +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print *ordinary_unique +// lldb-check:[...]$0 = (-1, -2) + +// lldb-command:print managed_within_unique->x +// lldb-check:[...]$1 = -3 + +// lldb-command:print managed_within_unique->y->val +// lldb-check:[...]$2 = -4 + #![allow(unused_variable)] use std::gc::{GC, Gc}; @@ -41,7 +57,7 @@ fn main() { let managed_within_unique = box ContainsManaged { x: -3, y: box(GC) -4i }; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/method-on-enum.rs b/src/test/debuginfo/method-on-enum.rs index 1a5fac18a6973..74f4882bd4bf4 100644 --- a/src/test/debuginfo/method-on-enum.rs +++ b/src/test/debuginfo/method-on-enum.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -64,6 +67,56 @@ // gdb-check:$15 = -10 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// STACK BY REF +// lldb-command:print *self +// lldb-check:[...]$0 = Variant2(117901063) +// lldb-command:print arg1 +// lldb-check:[...]$1 = -1 +// lldb-command:print arg2 +// lldb-check:[...]$2 = -2 +// lldb-command:continue + +// STACK BY VAL +// lldb-command:print self +// lldb-check:[...]$3 = Variant2(117901063) +// lldb-command:print arg1 +// lldb-check:[...]$4 = -3 +// lldb-command:print arg2 +// lldb-check:[...]$5 = -4 +// lldb-command:continue + +// OWNED BY REF +// lldb-command:print *self +// lldb-check:[...]$6 = Variant1 { x: 1799, y: 1799 } +// lldb-command:print arg1 +// lldb-check:[...]$7 = -5 +// lldb-command:print arg2 +// lldb-check:[...]$8 = -6 +// lldb-command:continue + +// OWNED BY VAL +// lldb-command:print self +// lldb-check:[...]$9 = Variant1 { x: 1799, y: 1799 } +// lldb-command:print arg1 +// lldb-check:[...]$10 = -7 +// lldb-command:print arg2 +// lldb-check:[...]$11 = -8 +// lldb-command:continue + +// OWNED MOVED +// lldb-command:print *self +// lldb-check:[...]$12 = Variant1 { x: 1799, y: 1799 } +// lldb-command:print arg1 +// lldb-check:[...]$13 = -9 +// lldb-command:print arg2 +// lldb-check:[...]$14 = -10 +// lldb-command:continue + #![feature(struct_variant)] enum Enum { @@ -74,17 +127,17 @@ enum Enum { impl Enum { fn self_by_ref(&self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break arg1 + arg2 } fn self_by_val(self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break arg1 + arg2 } - fn self_owned(~self, arg1: int, arg2: int) -> int { - zzz(); + fn self_owned(self: Box, arg1: int, arg2: int) -> int { + zzz(); // #break arg1 + arg2 } } diff --git a/src/test/debuginfo/method-on-generic-struct.rs b/src/test/debuginfo/method-on-generic-struct.rs index 0bac86b1e66aa..590a821fcb6e1 100644 --- a/src/test/debuginfo/method-on-generic-struct.rs +++ b/src/test/debuginfo/method-on-generic-struct.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -64,6 +67,57 @@ // gdb-check:$15 = -10 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// STACK BY REF +// lldb-command:print *self +// lldb-check:[...]$0 = Struct<(u32, i32)> { x: (8888, -8888) } +// lldb-command:print arg1 +// lldb-check:[...]$1 = -1 +// lldb-command:print arg2 +// lldb-check:[...]$2 = -2 +// lldb-command:continue + +// STACK BY VAL +// lldb-command:print self +// lldb-check:[...]$3 = Struct<(u32, i32)> { x: (8888, -8888) } +// lldb-command:print arg1 +// lldb-check:[...]$4 = -3 +// lldb-command:print arg2 +// lldb-check:[...]$5 = -4 +// lldb-command:continue + +// OWNED BY REF +// lldb-command:print *self +// lldb-check:[...]$6 = Struct { x: 1234.5 } +// lldb-command:print arg1 +// lldb-check:[...]$7 = -5 +// lldb-command:print arg2 +// lldb-check:[...]$8 = -6 +// lldb-command:continue + +// OWNED BY VAL +// lldb-command:print self +// lldb-check:[...]$9 = Struct { x: 1234.5 } +// lldb-command:print arg1 +// lldb-check:[...]$10 = -7 +// lldb-command:print arg2 +// lldb-check:[...]$11 = -8 +// lldb-command:continue + +// OWNED MOVED +// lldb-command:print *self +// lldb-check:[...]$12 = Struct { x: 1234.5 } +// lldb-command:print arg1 +// lldb-check:[...]$13 = -9 +// lldb-command:print arg2 +// lldb-check:[...]$14 = -10 +// lldb-command:continue + + struct Struct { x: T } @@ -71,17 +125,17 @@ struct Struct { impl Struct { fn self_by_ref(&self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break arg1 + arg2 } fn self_by_val(self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break arg1 + arg2 } - fn self_owned(~self, arg1: int, arg2: int) -> int { - zzz(); + fn self_owned(self: Box>, arg1: int, arg2: int) -> int { + zzz(); // #break arg1 + arg2 } } diff --git a/src/test/debuginfo/method-on-struct.rs b/src/test/debuginfo/method-on-struct.rs index 3d7cc96ca171f..5ea89f1548915 100644 --- a/src/test/debuginfo/method-on-struct.rs +++ b/src/test/debuginfo/method-on-struct.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -64,6 +67,56 @@ // gdb-check:$15 = -10 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// STACK BY REF +// lldb-command:print *self +// lldb-check:[...]$0 = Struct { x: 100 } +// lldb-command:print arg1 +// lldb-check:[...]$1 = -1 +// lldb-command:print arg2 +// lldb-check:[...]$2 = -2 +// lldb-command:continue + +// STACK BY VAL +// lldb-command:print self +// lldb-check:[...]$3 = Struct { x: 100 } +// lldb-command:print arg1 +// lldb-check:[...]$4 = -3 +// lldb-command:print arg2 +// lldb-check:[...]$5 = -4 +// lldb-command:continue + +// OWNED BY REF +// lldb-command:print *self +// lldb-check:[...]$6 = Struct { x: 200 } +// lldb-command:print arg1 +// lldb-check:[...]$7 = -5 +// lldb-command:print arg2 +// lldb-check:[...]$8 = -6 +// lldb-command:continue + +// OWNED BY VAL +// lldb-command:print self +// lldb-check:[...]$9 = Struct { x: 200 } +// lldb-command:print arg1 +// lldb-check:[...]$10 = -7 +// lldb-command:print arg2 +// lldb-check:[...]$11 = -8 +// lldb-command:continue + +// OWNED MOVED +// lldb-command:print *self +// lldb-check:[...]$12 = Struct { x: 200 } +// lldb-command:print arg1 +// lldb-check:[...]$13 = -9 +// lldb-command:print arg2 +// lldb-check:[...]$14 = -10 +// lldb-command:continue + struct Struct { x: int } @@ -71,17 +124,17 @@ struct Struct { impl Struct { fn self_by_ref(&self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break self.x + arg1 + arg2 } fn self_by_val(self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break self.x + arg1 + arg2 } - fn self_owned(~self, arg1: int, arg2: int) -> int { - zzz(); + fn self_owned(self: Box, arg1: int, arg2: int) -> int { + zzz(); // #break self.x + arg1 + arg2 } } diff --git a/src/test/debuginfo/method-on-trait.rs b/src/test/debuginfo/method-on-trait.rs index a2b73629a6738..1fc136ac1f695 100644 --- a/src/test/debuginfo/method-on-trait.rs +++ b/src/test/debuginfo/method-on-trait.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -64,6 +67,56 @@ // gdb-check:$15 = -10 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// STACK BY REF +// lldb-command:print *self +// lldb-check:[...]$0 = Struct { x: 100 } +// lldb-command:print arg1 +// lldb-check:[...]$1 = -1 +// lldb-command:print arg2 +// lldb-check:[...]$2 = -2 +// lldb-command:continue + +// STACK BY VAL +// lldb-command:print self +// lldb-check:[...]$3 = Struct { x: 100 } +// lldb-command:print arg1 +// lldb-check:[...]$4 = -3 +// lldb-command:print arg2 +// lldb-check:[...]$5 = -4 +// lldb-command:continue + +// OWNED BY REF +// lldb-command:print *self +// lldb-check:[...]$6 = Struct { x: 200 } +// lldb-command:print arg1 +// lldb-check:[...]$7 = -5 +// lldb-command:print arg2 +// lldb-check:[...]$8 = -6 +// lldb-command:continue + +// OWNED BY VAL +// lldb-command:print self +// lldb-check:[...]$9 = Struct { x: 200 } +// lldb-command:print arg1 +// lldb-check:[...]$10 = -7 +// lldb-command:print arg2 +// lldb-check:[...]$11 = -8 +// lldb-command:continue + +// OWNED MOVED +// lldb-command:print *self +// lldb-check:[...]$12 = Struct { x: 200 } +// lldb-command:print arg1 +// lldb-check:[...]$13 = -9 +// lldb-command:print arg2 +// lldb-check:[...]$14 = -10 +// lldb-command:continue + struct Struct { x: int } @@ -71,23 +124,23 @@ struct Struct { trait Trait { fn self_by_ref(&self, arg1: int, arg2: int) -> int; fn self_by_val(self, arg1: int, arg2: int) -> int; - fn self_owned(~self, arg1: int, arg2: int) -> int; + fn self_owned(self: Box, arg1: int, arg2: int) -> int; } impl Trait for Struct { fn self_by_ref(&self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break self.x + arg1 + arg2 } fn self_by_val(self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break self.x + arg1 + arg2 } - fn self_owned(~self, arg1: int, arg2: int) -> int { - zzz(); + fn self_owned(self: Box, arg1: int, arg2: int) -> int { + zzz(); // #break self.x + arg1 + arg2 } } diff --git a/src/test/debuginfo/method-on-tuple-struct.rs b/src/test/debuginfo/method-on-tuple-struct.rs index fe7271716bb4f..d4051e333c184 100644 --- a/src/test/debuginfo/method-on-tuple-struct.rs +++ b/src/test/debuginfo/method-on-tuple-struct.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -64,22 +67,72 @@ // gdb-check:$15 = -10 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// STACK BY REF +// lldb-command:print *self +// lldb-check:[...]$0 = TupleStruct(100, -100.5) +// lldb-command:print arg1 +// lldb-check:[...]$1 = -1 +// lldb-command:print arg2 +// lldb-check:[...]$2 = -2 +// lldb-command:continue + +// STACK BY VAL +// lldb-command:print self +// lldb-check:[...]$3 = TupleStruct(100, -100.5) +// lldb-command:print arg1 +// lldb-check:[...]$4 = -3 +// lldb-command:print arg2 +// lldb-check:[...]$5 = -4 +// lldb-command:continue + +// OWNED BY REF +// lldb-command:print *self +// lldb-check:[...]$6 = TupleStruct(200, -200.5) +// lldb-command:print arg1 +// lldb-check:[...]$7 = -5 +// lldb-command:print arg2 +// lldb-check:[...]$8 = -6 +// lldb-command:continue + +// OWNED BY VAL +// lldb-command:print self +// lldb-check:[...]$9 = TupleStruct(200, -200.5) +// lldb-command:print arg1 +// lldb-check:[...]$10 = -7 +// lldb-command:print arg2 +// lldb-check:[...]$11 = -8 +// lldb-command:continue + +// OWNED MOVED +// lldb-command:print *self +// lldb-check:[...]$12 = TupleStruct(200, -200.5) +// lldb-command:print arg1 +// lldb-check:[...]$13 = -9 +// lldb-command:print arg2 +// lldb-check:[...]$14 = -10 +// lldb-command:continue + struct TupleStruct(int, f64); impl TupleStruct { fn self_by_ref(&self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break arg1 + arg2 } fn self_by_val(self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break arg1 + arg2 } - fn self_owned(~self, arg1: int, arg2: int) -> int { - zzz(); + fn self_owned(self: Box, arg1: int, arg2: int) -> int { + zzz(); // #break arg1 + arg2 } } diff --git a/src/test/debuginfo/multiple-functions-equal-var-names.rs b/src/test/debuginfo/multiple-functions-equal-var-names.rs index 9e40f03c20162..1d9427a3bfe68 100644 --- a/src/test/debuginfo/multiple-functions-equal-var-names.rs +++ b/src/test/debuginfo/multiple-functions-equal-var-names.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -28,22 +31,38 @@ // gdb-command:print abc // gdb-check:$3 = 30303 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print abc +// lldb-check:[...]$0 = 10101 +// lldb-command:continue + +// lldb-command:print abc +// lldb-check:[...]$1 = 20202 +// lldb-command:continue + +// lldb-command:print abc +// lldb-check:[...]$2 = 30303 + #![allow(unused_variable)] fn function_one() { let abc = 10101i; - zzz(); + zzz(); // #break } fn function_two() { let abc = 20202i; - zzz(); + zzz(); // #break } fn function_three() { let abc = 30303i; - zzz(); + zzz(); // #break } diff --git a/src/test/debuginfo/multiple-functions.rs b/src/test/debuginfo/multiple-functions.rs index ef1c69f9eb8cf..25d9dc0240433 100644 --- a/src/test/debuginfo/multiple-functions.rs +++ b/src/test/debuginfo/multiple-functions.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -28,22 +31,38 @@ // gdb-command:print c // gdb-check:$3 = 30303 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print a +// lldb-check:[...]$0 = 10101 +// lldb-command:continue + +// lldb-command:print b +// lldb-check:[...]$1 = 20202 +// lldb-command:continue + +// lldb-command:print c +// lldb-check:[...]$2 = 30303 + #![allow(unused_variable)] fn function_one() { let a = 10101i; - zzz(); + zzz(); // #break } fn function_two() { let b = 20202i; - zzz(); + zzz(); // #break } fn function_three() { let c = 30303i; - zzz(); + zzz(); // #break } diff --git a/src/test/debuginfo/name-shadowing-and-scope-nesting.rs b/src/test/debuginfo/name-shadowing-and-scope-nesting.rs index 8ee6d434016f0..3462735f6d109 100644 --- a/src/test/debuginfo/name-shadowing-and-scope-nesting.rs +++ b/src/test/debuginfo/name-shadowing-and-scope-nesting.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -56,38 +59,79 @@ // gdb-check:$12 = 20 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print x +// lldb-check:[...]$0 = false +// lldb-command:print y +// lldb-check:[...]$1 = true +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$2 = 10 +// lldb-command:print y +// lldb-check:[...]$3 = true +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$4 = 10.5 +// lldb-command:print y +// lldb-check:[...]$5 = 20 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$6 = true +// lldb-command:print y +// lldb-check:[...]$7 = 2220 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$8 = 203203.5 +// lldb-command:print y +// lldb-check:[...]$9 = 2220 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$10 = 10.5 +// lldb-command:print y +// lldb-check:[...]$11 = 20 +// lldb-command:continue + fn main() { let x = false; let y = true; - zzz(); + zzz(); // #break sentinel(); let x = 10i; - zzz(); + zzz(); // #break sentinel(); let x = 10.5f64; let y = 20i; - zzz(); + zzz(); // #break sentinel(); { let x = true; let y = 2220i; - zzz(); + zzz(); // #break sentinel(); let x = 203203.5f64; - zzz(); + zzz(); // #break sentinel(); } - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/nil-enum.rs b/src/test/debuginfo/nil-enum.rs index 43d82e75c4dda..511786999abf3 100644 --- a/src/test/debuginfo/nil-enum.rs +++ b/src/test/debuginfo/nil-enum.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// LLDB can't handle zero-sized values +// ignore-lldb + // ignore-android: FIXME(#10381) // compile-flags:-g diff --git a/src/test/debuginfo/option-like-enum.rs b/src/test/debuginfo/option-like-enum.rs index de6d6814308d8..f9e2f61564bee 100644 --- a/src/test/debuginfo/option-like-enum.rs +++ b/src/test/debuginfo/option-like-enum.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -25,17 +28,41 @@ // gdb-command:print full // gdb-check:$3 = {RUST$ENCODED$ENUM$1$Empty = {454545, 0x87654321, 9988}} -// gdb-command:print empty->discr +// gdb-command:print empty_gdb->discr // gdb-check:$4 = (int *) 0x0 // gdb-command:print droid // gdb-check:$5 = {RUST$ENCODED$ENUM$2$Void = {id = 675675, range = 10000001, internals = 0x43218765}} -// gdb-command:print void_droid->internals +// gdb-command:print void_droid_gdb->internals // gdb-check:$6 = (int *) 0x0 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print some +// lldb-check:[...]$0 = Some(&0x12345678) + +// lldb-command:print none +// lldb-check:[...]$1 = None + +// lldb-command:print full +// lldb-check:[...]$2 = Full(454545, &0x87654321, 9988) + +// lldb-command:print empty +// lldb-check:[...]$3 = Empty + +// lldb-command:print droid +// lldb-check:[...]$4 = Droid { id: 675675, range: 10000001, internals: &0x43218765 } + +// lldb-command:print void_droid +// lldb-check:[...]$5 = Void + + #![feature(struct_variant)] // If a struct has exactly two variants, one of them is empty, and the other one @@ -77,8 +104,8 @@ fn main() { let full = Full(454545, unsafe { std::mem::transmute(0x87654321u) }, 9988); - let int_val = 0i; - let empty: &MoreFieldsRepr = unsafe { std::mem::transmute(&Empty) }; + let empty = Empty; + let empty_gdb: &MoreFieldsRepr = unsafe { std::mem::transmute(&Empty) }; let droid = Droid { id: 675675, @@ -86,9 +113,10 @@ fn main() { internals: unsafe { std::mem::transmute(0x43218765u) } }; - let void_droid: &NamedFieldsRepr = unsafe { std::mem::transmute(&Void) }; + let void_droid = Void; + let void_droid_gdb: &NamedFieldsRepr = unsafe { std::mem::transmute(&Void) }; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/packed-struct-with-destructor.rs b/src/test/debuginfo/packed-struct-with-destructor.rs index 29087b18d5a96..215d961b71b0e 100644 --- a/src/test/debuginfo/packed-struct-with-destructor.rs +++ b/src/test/debuginfo/packed-struct-with-destructor.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz // gdb-command:run @@ -42,6 +45,36 @@ // gdb-command:print deeplyNested // gdb-check:$8 = {a = {a = 1, b = {x = 2, y = 3, z = 4}, c = 5, d = {x = 6, y = 7, z = 8}}, b = {a = 9, b = {x = 10, y = 11, z = 12}, c = {x = 13, y = 14, z = 15}, d = 16}, c = {a = 17, b = {x = 18, y = 19, z = 20}, c = 21, d = {x = 22, y = 23, z = 24}}, d = {a = 25, b = {x = 26, y = 27, z = 28}, c = 29, d = {x = 30, y = 31, z = 32}}, e = {a = 33, b = {x = 34, y = 35, z = 36}, c = {x = 37, y = 38, z = 39}, d = 40}, f = {a = 41, b = {x = 42, y = 43, z = 44}, c = 45, d = {x = 46, y = 47, z = 48}}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print packed +// lldb-check:[...]$0 = Packed { x: 123, y: 234, z: 345 } + +// lldb-command:print packedInPacked +// lldb-check:[...]$1 = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } } + +// lldb-command:print packedInUnpacked +// lldb-check:[...]$2 = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } } + +// lldb-command:print unpackedInPacked +// lldb-check:[...]$3 = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654 }, c: Unpacked { x: 543, y: 432, z: 321 }, d: 210 } + +// lldb-command:print packedInPackedWithDrop +// lldb-check:[...]$4 = PackedInPackedWithDrop { a: 11, b: Packed { x: 22, y: 33, z: 44 }, c: 55, d: Packed { x: 66, y: 77, z: 88 } } + +// lldb-command:print packedInUnpackedWithDrop +// lldb-check:[...]$5 = PackedInUnpackedWithDrop { a: -11, b: Packed { x: -22, y: -33, z: -44 }, c: -55, d: Packed { x: -66, y: -77, z: -88 } } + +// lldb-command:print unpackedInPackedWithDrop +// lldb-check:[...]$6 = UnpackedInPackedWithDrop { a: 98, b: Unpacked { x: 87, y: 76, z: 65 }, c: Unpacked { x: 54, y: 43, z: 32 }, d: 21 } + +// lldb-command:print deeplyNested +// lldb-check:[...]$7 = DeeplyNested { a: PackedInPacked { a: 1, b: Packed { x: 2, y: 3, z: 4 }, c: 5, d: Packed { x: 6, y: 7, z: 8 } }, b: UnpackedInPackedWithDrop { a: 9, b: Unpacked { x: 10, y: 11, z: 12 }, c: Unpacked { x: 13, y: 14, z: 15 }, d: 16 }, c: PackedInUnpacked { a: 17, b: Packed { x: 18, y: 19, z: 20 }, c: 21, d: Packed { x: 22, y: 23, z: 24 } }, d: PackedInUnpackedWithDrop { a: 25, b: Packed { x: 26, y: 27, z: 28 }, c: 29, d: Packed { x: 30, y: 31, z: 32 } }, e: UnpackedInPacked { a: 33, b: Unpacked { x: 34, y: 35, z: 36 }, c: Unpacked { x: 37, y: 38, z: 39 }, d: 40 }, f: PackedInPackedWithDrop { a: 41, b: Packed { x: 42, y: 43, z: 44 }, c: 45, d: Packed { x: 46, y: 47, z: 48 } } } + + #![allow(unused_variable)] #[packed] @@ -216,7 +249,7 @@ fn main() { } }; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/packed-struct.rs b/src/test/debuginfo/packed-struct.rs index bc8156c73853c..8201afe3a0164 100644 --- a/src/test/debuginfo/packed-struct.rs +++ b/src/test/debuginfo/packed-struct.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz // gdb-command:run @@ -35,6 +38,29 @@ // gdb-command:print sizeof(packedInPacked) // gdb-check:$6 = 40 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print packed +// lldb-check:[...]$0 = Packed { x: 123, y: 234, z: 345 } + +// lldb-command:print packedInPacked +// lldb-check:[...]$1 = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } } + +// lldb-command:print packedInUnpacked +// lldb-check:[...]$2 = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } } + +// lldb-command:print unpackedInPacked +// lldb-check:[...]$3 = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654, w: 543 }, c: Unpacked { x: 432, y: 321, z: 210, w: 109 }, d: -98 } + +// lldb-command:print sizeof(packed) +// lldb-check:[...]$4 = 14 + +// lldb-command:print sizeof(packedInPacked) +// lldb-check:[...]$5 = 40 + #![allow(unused_variable)] #[packed] @@ -101,7 +127,7 @@ fn main() { d: -98 }; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/recursive-enum.rs b/src/test/debuginfo/recursive-enum.rs index 68b6764a5a150..4eb251c60841a 100644 --- a/src/test/debuginfo/recursive-enum.rs +++ b/src/test/debuginfo/recursive-enum.rs @@ -10,6 +10,8 @@ // ignore-android: FIXME(#10381) +// ignore-lldb + // compile-flags:-g // gdb-command:run diff --git a/src/test/debuginfo/recursive-struct.rs b/src/test/debuginfo/recursive-struct.rs index ea0867903b5af..931955ec31738 100644 --- a/src/test/debuginfo/recursive-struct.rs +++ b/src/test/debuginfo/recursive-struct.rs @@ -10,6 +10,7 @@ // ignore-tidy-linelength // ignore-android: FIXME(#10381) +// ignore-lldb #![feature(managed_boxes)] diff --git a/src/test/debuginfo/self-in-default-method.rs b/src/test/debuginfo/self-in-default-method.rs index 45cbcf094f4f5..4268c0adcc396 100644 --- a/src/test/debuginfo/self-in-default-method.rs +++ b/src/test/debuginfo/self-in-default-method.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -64,23 +67,74 @@ // gdb-check:$15 = -10 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// STACK BY REF +// lldb-command:print *self +// lldb-check:[...]$0 = Struct { x: 100 } +// lldb-command:print arg1 +// lldb-check:[...]$1 = -1 +// lldb-command:print arg2 +// lldb-check:[...]$2 = -2 +// lldb-command:continue + +// STACK BY VAL +// lldb-command:print self +// lldb-check:[...]$3 = Struct { x: 100 } +// lldb-command:print arg1 +// lldb-check:[...]$4 = -3 +// lldb-command:print arg2 +// lldb-check:[...]$5 = -4 +// lldb-command:continue + +// OWNED BY REF +// lldb-command:print *self +// lldb-check:[...]$6 = Struct { x: 200 } +// lldb-command:print arg1 +// lldb-check:[...]$7 = -5 +// lldb-command:print arg2 +// lldb-check:[...]$8 = -6 +// lldb-command:continue + +// OWNED BY VAL +// lldb-command:print self +// lldb-check:[...]$9 = Struct { x: 200 } +// lldb-command:print arg1 +// lldb-check:[...]$10 = -7 +// lldb-command:print arg2 +// lldb-check:[...]$11 = -8 +// lldb-command:continue + +// OWNED MOVED +// lldb-command:print *self +// lldb-check:[...]$12 = Struct { x: 200 } +// lldb-command:print arg1 +// lldb-check:[...]$13 = -9 +// lldb-command:print arg2 +// lldb-check:[...]$14 = -10 +// lldb-command:continue + + struct Struct { x: int } trait Trait { fn self_by_ref(&self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break arg1 + arg2 } fn self_by_val(self, arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break arg1 + arg2 } - fn self_owned(~self, arg1: int, arg2: int) -> int { - zzz(); + fn self_owned(self: Box, arg1: int, arg2: int) -> int { + zzz(); // #break arg1 + arg2 } } diff --git a/src/test/debuginfo/self-in-generic-default-method.rs b/src/test/debuginfo/self-in-generic-default-method.rs index 8ab3fd44203aa..35f3dffa0b637 100644 --- a/src/test/debuginfo/self-in-generic-default-method.rs +++ b/src/test/debuginfo/self-in-generic-default-method.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -20,8 +23,8 @@ // gdb-check:$1 = {x = 987} // gdb-command:print arg1 // gdb-check:$2 = -1 -// gdb-command:print/d arg2 -// gdb-check:$3 = -2 +// gdb-command:print arg2 +// gdb-check:$3 = 2 // gdb-command:continue // STACK BY VAL @@ -64,6 +67,57 @@ // gdb-check:$15 = -10.5 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// STACK BY REF +// lldb-command:print *self +// lldb-check:[...]$0 = Struct { x: 987 } +// lldb-command:print arg1 +// lldb-check:[...]$1 = -1 +// lldb-command:print arg2 +// lldb-check:[...]$2 = 2 +// lldb-command:continue + +// STACK BY VAL +// lldb-command:print self +// lldb-check:[...]$3 = Struct { x: 987 } +// lldb-command:print arg1 +// lldb-check:[...]$4 = -3 +// lldb-command:print arg2 +// lldb-check:[...]$5 = -4 +// lldb-command:continue + +// OWNED BY REF +// lldb-command:print *self +// lldb-check:[...]$6 = Struct { x: 879 } +// lldb-command:print arg1 +// lldb-check:[...]$7 = -5 +// lldb-command:print arg2 +// lldb-check:[...]$8 = -6 +// lldb-command:continue + +// OWNED BY VAL +// lldb-command:print self +// lldb-check:[...]$9 = Struct { x: 879 } +// lldb-command:print arg1 +// lldb-check:[...]$10 = -7 +// lldb-command:print arg2 +// lldb-check:[...]$11 = -8 +// lldb-command:continue + +// OWNED MOVED +// lldb-command:print *self +// lldb-check:[...]$12 = Struct { x: 879 } +// lldb-command:print arg1 +// lldb-check:[...]$13 = -9 +// lldb-command:print arg2 +// lldb-check:[...]$14 = -10.5 +// lldb-command:continue + + struct Struct { x: int } @@ -71,17 +125,17 @@ struct Struct { trait Trait { fn self_by_ref(&self, arg1: int, arg2: T) -> int { - zzz(); + zzz(); // #break arg1 } fn self_by_val(self, arg1: int, arg2: T) -> int { - zzz(); + zzz(); // #break arg1 } - fn self_owned(~self, arg1: int, arg2: T) -> int { - zzz(); + fn self_owned(self: Box, arg1: int, arg2: T) -> int { + zzz(); // #break arg1 } } @@ -90,7 +144,7 @@ impl Trait for Struct {} fn main() { let stack = Struct { x: 987 }; - let _ = stack.self_by_ref(-1, -2_i8); + let _ = stack.self_by_ref(-1, 2_u16); let _ = stack.self_by_val(-3, -4_i16); let owned = box Struct { x: 879 }; diff --git a/src/test/debuginfo/shadowed-argument.rs b/src/test/debuginfo/shadowed-argument.rs index c180d6b5bcfe7..7a9c7c3b372f4 100644 --- a/src/test/debuginfo/shadowed-argument.rs +++ b/src/test/debuginfo/shadowed-argument.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -35,19 +38,42 @@ // gdb-check:$6 = 20 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print x +// lldb-check:[...]$0 = false +// lldb-command:print y +// lldb-check:[...]$1 = true +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$2 = 10 +// lldb-command:print y +// lldb-check:[...]$3 = true +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$4 = 10.5 +// lldb-command:print y +// lldb-check:[...]$5 = 20 +// lldb-command:continue + fn a_function(x: bool, y: bool) { - zzz(); + zzz(); // #break sentinel(); let x = 10i; - zzz(); + zzz(); // #break sentinel(); let x = 10.5f64; let y = 20i; - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/shadowed-variable.rs b/src/test/debuginfo/shadowed-variable.rs index 88ef3c4879e90..a43bb5e401730 100644 --- a/src/test/debuginfo/shadowed-variable.rs +++ b/src/test/debuginfo/shadowed-variable.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -35,22 +38,45 @@ // gdb-check:$6 = 20 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print x +// lldb-check:[...]$0 = false +// lldb-command:print y +// lldb-check:[...]$1 = true +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$2 = 10 +// lldb-command:print y +// lldb-check:[...]$3 = true +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$4 = 10.5 +// lldb-command:print y +// lldb-check:[...]$5 = 20 +// lldb-command:continue + fn main() { let x = false; let y = true; - zzz(); + zzz(); // #break sentinel(); let x = 10i; - zzz(); + zzz(); // #break sentinel(); let x = 10.5f64; let y = 20i; - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/simd.rs b/src/test/debuginfo/simd.rs index b84405ee7270e..eee1d0e70ca5f 100644 --- a/src/test/debuginfo/simd.rs +++ b/src/test/debuginfo/simd.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Need a fix for LLDB first... +// ignore-lldb + // ignore-android: FIXME(#10381) // compile-flags:-g diff --git a/src/test/debuginfo/simple-lexical-scope.rs b/src/test/debuginfo/simple-lexical-scope.rs index 107b64131e053..a012ee265d4a9 100644 --- a/src/test/debuginfo/simple-lexical-scope.rs +++ b/src/test/debuginfo/simple-lexical-scope.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -50,36 +53,68 @@ // gdb-command:continue +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print x +// lldb-check:[...]$0 = false +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$1 = false +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$2 = 10 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$3 = 10 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$4 = 10.5 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$5 = 10 +// lldb-command:continue + +// lldb-command:print x +// lldb-check:[...]$6 = false +// lldb-command:continue + fn main() { let x = false; - zzz(); + zzz(); // #break sentinel(); { - zzz(); + zzz(); // #break sentinel(); let x = 10i; - zzz(); + zzz(); // #break sentinel(); { - zzz(); + zzz(); // #break sentinel(); let x = 10.5f64; - zzz(); + zzz(); // #break sentinel(); } - zzz(); + zzz(); // #break sentinel(); } - zzz(); + zzz(); // #break sentinel(); } diff --git a/src/test/debuginfo/simple-struct.rs b/src/test/debuginfo/simple-struct.rs index c1f0e2c1f9ea7..5076673c3a512 100644 --- a/src/test/debuginfo/simple-struct.rs +++ b/src/test/debuginfo/simple-struct.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz @@ -76,6 +79,28 @@ // gdb-check:$19 = {a = 10019, b = -10020, x = -10016, y = -10017.5, z = 10018} +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print no_padding16 +// lldb-check:[...]$0 = NoPadding16 { x: 10000, y: -10001 } + +// lldb-command:print no_padding32 +// lldb-check:[...]$1 = NoPadding32 { x: -10002, y: -10003.5, z: 10004 } + +// lldb-command:print no_padding64 +// lldb-check:[...]$2 = NoPadding64 { x: -10005.5, y: 10006, z: 10007 } + +// lldb-command:print no_padding163264 +// lldb-check:[...]$3 = NoPadding163264 { a: -10008, b: 10009, c: 10010, d: 10011 } + +// lldb-command:print internal_padding +// lldb-check:[...]$4 = InternalPadding { x: 10012, y: -10013 } + +// lldb-command:print padding_at_end +// lldb-check:[...]$5 = PaddingAtEnd { x: -10014, y: 10015 } + #![feature(struct_inherit)]; #![allow(unused_variable)]; #![allow(dead_code)]; @@ -188,7 +213,7 @@ fn main() { PADDING_AT_END.y = 28; } - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/simple-tuple.rs b/src/test/debuginfo/simple-tuple.rs index 9486ab2474eff..29d739d7f183a 100644 --- a/src/test/debuginfo/simple-tuple.rs +++ b/src/test/debuginfo/simple-tuple.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz @@ -69,6 +72,28 @@ // gdb-command:print 'simple-tuple::PADDING_AT_END' // gdb-check:$21 = {116, 117} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print/d noPadding8 +// lldb-check:[...]$0 = (-100, 100) +// lldb-command:print noPadding16 +// lldb-check:[...]$1 = (0, 1, 2) +// lldb-command:print noPadding32 +// lldb-check:[...]$2 = (3, 4.5, 5) +// lldb-command:print noPadding64 +// lldb-check:[...]$3 = (6, 7.5, 8) + +// lldb-command:print internalPadding1 +// lldb-check:[...]$4 = (9, 10) +// lldb-command:print internalPadding2 +// lldb-check:[...]$5 = (11, 12, 13, 14) + +// lldb-command:print paddingAtEnd +// lldb-check:[...]$6 = (15, 16) + #![allow(unused_variable)] #![allow(dead_code)] @@ -107,7 +132,7 @@ fn main() { PADDING_AT_END = (116, 117); } - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/static-method-on-struct-and-enum.rs b/src/test/debuginfo/static-method-on-struct-and-enum.rs index d7d962c07d6de..e5f9651bb8bcf 100644 --- a/src/test/debuginfo/static-method-on-struct-and-enum.rs +++ b/src/test/debuginfo/static-method-on-struct-and-enum.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -32,6 +35,27 @@ // gdb-check:$5 = 5 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// STRUCT +// lldb-command:print arg1 +// lldb-check:[...]$0 = 1 +// lldb-command:print arg2 +// lldb-check:[...]$1 = 2 +// lldb-command:continue + +// ENUM +// lldb-command:print arg1 +// lldb-check:[...]$2 = -3 +// lldb-command:print arg2 +// lldb-check:[...]$3 = 4.5 +// lldb-command:print arg3 +// lldb-check:[...]$4 = 5 +// lldb-command:continue + #![feature(struct_variant)] struct Struct { @@ -41,7 +65,7 @@ struct Struct { impl Struct { fn static_method(arg1: int, arg2: int) -> int { - zzz(); + zzz(); // #break arg1 + arg2 } } @@ -55,7 +79,7 @@ enum Enum { impl Enum { fn static_method(arg1: int, arg2: f64, arg3: uint) -> int { - zzz(); + zzz(); // #break arg1 } } diff --git a/src/test/debuginfo/struct-in-enum.rs b/src/test/debuginfo/struct-in-enum.rs index 0cba56ad320ec..d01119bce0533 100644 --- a/src/test/debuginfo/struct-in-enum.rs +++ b/src/test/debuginfo/struct-in-enum.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print union on // gdb-command:rbreak zzz // gdb-command:run @@ -26,6 +29,19 @@ // gdb-command:print univariant // gdb-check:$3 = {{{x = 123, y = 456, z = 789}}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print case1 +// lldb-check:[...]$0 = Case1(0, Struct { x: 2088533116, y: 2088533116, z: 31868 }) +// lldb-command:print case2 +// lldb-check:[...]$1 = Case2(0, 1229782938247303441, 4369) + +// lldb-command:print univariant +// lldb-check:[...]$2 = TheOnlyCase(Struct { x: 123, y: 456, z: 789 }) + #![allow(unused_variable)] struct Struct { @@ -66,7 +82,7 @@ fn main() { let univariant = TheOnlyCase(Struct { x: 123, y: 456, z: 789 }); - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/struct-in-struct.rs b/src/test/debuginfo/struct-in-struct.rs index e4c3f471880df..3822b80e8650f 100644 --- a/src/test/debuginfo/struct-in-struct.rs +++ b/src/test/debuginfo/struct-in-struct.rs @@ -8,9 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz // gdb-command:run @@ -25,6 +29,35 @@ // gdb-command:print padding_at_end_parent // gdb-check:$3 = {x = {x = 10, y = 11}, y = {x = 12, y = 13}, z = {x = 14, y = 15}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print three_simple_structs +// lldb-check:[...]$0 = ThreeSimpleStructs { x: Simple { x: 1 }, y: Simple { x: 2 }, z: Simple { x: 3 } } + +// lldb-command:print internal_padding_parent +// lldb-check:[...]$1 = InternalPaddingParent { x: InternalPadding { x: 4, y: 5 }, y: InternalPadding { x: 6, y: 7 }, z: InternalPadding { x: 8, y: 9 } } + +// lldb-command:print padding_at_end_parent +// lldb-check:[...]$2 = PaddingAtEndParent { x: PaddingAtEnd { x: 10, y: 11 }, y: PaddingAtEnd { x: 12, y: 13 }, z: PaddingAtEnd { x: 14, y: 15 } } + +// lldb-command:print mixed +// lldb-check:[...]$3 = Mixed { x: PaddingAtEnd { x: 16, y: 17 }, y: InternalPadding { x: 18, y: 19 }, z: Simple { x: 20 }, w: 21 } + +// lldb-command:print bag +// lldb-check:[...]$4 = Bag { x: Simple { x: 22 } } + +// lldb-command:print bag_in_bag +// lldb-check:[...]$5 = BagInBag { x: Bag { x: Simple { x: 23 } } } + +// lldb-command:print tjo +// lldb-check:[...]$6 = ThatsJustOverkill { x: BagInBag { x: Bag { x: Simple { x: 24 } } } } + +// lldb-command:print tree +// lldb-check:[...]$7 = Tree { x: Simple { x: 25 }, y: InternalPaddingParent { x: InternalPadding { x: 26, y: 27 }, y: InternalPadding { x: 28, y: 29 }, z: InternalPadding { x: 30, y: 31 } }, z: BagInBag { x: Bag { x: Simple { x: 32 } } } } + #![allow(unused_variable)] struct Simple { @@ -140,7 +173,7 @@ fn main() { } }; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/struct-style-enum.rs b/src/test/debuginfo/struct-style-enum.rs index 70d4d709d23c8..c3a5abf2d389a 100644 --- a/src/test/debuginfo/struct-style-enum.rs +++ b/src/test/debuginfo/struct-style-enum.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print union on // gdb-command:rbreak zzz // gdb-command:run @@ -29,6 +32,23 @@ // gdb-command:print univariant // gdb-check:$4 = {{a = -1}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print case1 +// lldb-check:[...]$0 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 } + +// lldb-command:print case2 +// lldb-check:[...]$1 = Case2 { a: 0, b: 286331153, c: 286331153 } + +// lldb-command:print case3 +// lldb-check:[...]$2 = Case3 { a: 0, b: 6438275382588823897 } + +// lldb-command:print univariant +// lldb-check:[...]$3 = TheOnlyCase { a: -1 } + #![allow(unused_variable)] #![feature(struct_variant)] @@ -71,7 +91,7 @@ fn main() { let univariant = TheOnlyCase { a: -1 }; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/struct-with-destructor.rs b/src/test/debuginfo/struct-with-destructor.rs index 16fbfc49d08ed..525fcd45cfb06 100644 --- a/src/test/debuginfo/struct-with-destructor.rs +++ b/src/test/debuginfo/struct-with-destructor.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -26,6 +29,22 @@ // gdb-command:print nested // gdb-check:$4 = {a = {a = {x = 7890, y = 9870}}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run +// lldb-command:print simple +// lldb-check:[...]$0 = WithDestructor { x: 10, y: 20 } + +// lldb-command:print noDestructor +// lldb-check:[...]$1 = NoDestructorGuarded { a: NoDestructor { x: 10, y: 20 }, guard: -1 } + +// lldb-command:print withDestructor +// lldb-check:[...]$2 = WithDestructorGuarded { a: WithDestructor { x: 10, y: 20 }, guard: -1 } + +// lldb-command:print nested +// lldb-check:[...]$3 = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } } + #![allow(unused_variable)] struct NoDestructor { @@ -121,7 +140,7 @@ fn main() { // <-------NestedOuter--------> let nested = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } }; - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/text-to-include-1.txt b/src/test/debuginfo/text-to-include-1.txt index 91e2445c4aa9d..ba055272a3fa7 100644 --- a/src/test/debuginfo/text-to-include-1.txt +++ b/src/test/debuginfo/text-to-include-1.txt @@ -1 +1 @@ -some text to include in another file as string 1 +some text to include in another file as string 1 \ No newline at end of file diff --git a/src/test/debuginfo/text-to-include-2.txt b/src/test/debuginfo/text-to-include-2.txt index be6022776c521..a59d2057eb46b 100644 --- a/src/test/debuginfo/text-to-include-2.txt +++ b/src/test/debuginfo/text-to-include-2.txt @@ -1 +1 @@ -some text to include in another file as string 2 +some text to include in another file as string 2. \ No newline at end of file diff --git a/src/test/debuginfo/text-to-include-3.txt b/src/test/debuginfo/text-to-include-3.txt index 0cff667b47ca0..6163f7dd48cd4 100644 --- a/src/test/debuginfo/text-to-include-3.txt +++ b/src/test/debuginfo/text-to-include-3.txt @@ -1 +1 @@ -some text to include in another file as string 3 +some text to include in another file as string 3.. \ No newline at end of file diff --git a/src/test/debuginfo/trait-generic-static-default-method.rs b/src/test/debuginfo/trait-generic-static-default-method.rs index e91cd2f02d488..20747681b6ffa 100644 --- a/src/test/debuginfo/trait-generic-static-default-method.rs +++ b/src/test/debuginfo/trait-generic-static-default-method.rs @@ -11,6 +11,9 @@ // except according to those terms. // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run @@ -29,13 +32,42 @@ // gdb-command:continue +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print no_padding1 +// lldb-check:[...]$0 = { x = (0, 1) y = 2 z = (3, 4, 5) } +// lldb-command:print no_padding2 +// lldb-check:[...]$1 = { x = (6, 7) y = { = (8, 9) = 10 } } + +// lldb-command:print tuple_internal_padding +// lldb-check:[...]$2 = { x = (11, 12) y = (13, 14) } +// lldb-command:print struct_internal_padding +// lldb-check:[...]$3 = { x = (15, 16) y = (17, 18) } +// lldb-command:print both_internally_padded +// lldb-check:[...]$4 = { x = (19, 20, 21) y = (22, 23) } + +// lldb-command:print single_tuple +// lldb-check:[...]$5 = { x = (24, 25, 26) } + +// lldb-command:print tuple_padded_at_end +// lldb-check:[...]$6 = { x = (27, 28) y = (29, 30) } +// lldb-command:print struct_padded_at_end +// lldb-check:[...]$7 = { x = (31, 32) y = (33, 34) } +// lldb-command:print both_padded_at_end +// lldb-check:[...]$8 = { x = (35, 36, 37) y = (38, 39) } + +// lldb-command:print mixed_padding +// lldb-check:[...]$9 = { x = { = (40, 41, 42) = (43, 44) } y = (45, 46, 47, 48) } + struct Struct { x: int } trait Trait { fn generic_static_default_method(arg1: int, arg2: T) -> int { - zzz(); + zzz(); // #break arg1 } } diff --git a/src/test/debuginfo/trait-pointers.rs b/src/test/debuginfo/trait-pointers.rs index e58ed4cea29a7..ca407aef1a45e 100644 --- a/src/test/debuginfo/trait-pointers.rs +++ b/src/test/debuginfo/trait-pointers.rs @@ -10,6 +10,8 @@ // ignore-android: FIXME(#10381) +// ignore-lldb + // compile-flags:-g // gdb-command:run diff --git a/src/test/debuginfo/tuple-in-tuple.rs b/src/test/debuginfo/tuple-in-tuple.rs index 3cc8b4e6486d6..4c4ad51c70bb0 100644 --- a/src/test/debuginfo/tuple-in-tuple.rs +++ b/src/test/debuginfo/tuple-in-tuple.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz // gdb-command:run @@ -33,6 +36,28 @@ // gdb-command:print padding_at_end2 // gdb-check:$7 = {{21, 22}, 23} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print no_padding1 +// lldb-check:[...]$0 = ((0, 1), 2, 3) +// lldb-command:print no_padding2 +// lldb-check:[...]$1 = (4, (5, 6), 7) +// lldb-command:print no_padding3 +// lldb-check:[...]$2 = (8, 9, (10, 11)) + +// lldb-command:print internal_padding1 +// lldb-check:[...]$3 = (12, (13, 14)) +// lldb-command:print internal_padding2 +// lldb-check:[...]$4 = (15, (16, 17)) + +// lldb-command:print padding_at_end1 +// lldb-check:[...]$5 = (18, (19, 20)) +// lldb-command:print padding_at_end2 +// lldb-check:[...]$6 = ((21, 22), 23) + #![allow(unused_variable)] fn main() { @@ -46,7 +71,7 @@ fn main() { let padding_at_end1: (i32, (i32, i16)) = (18, (19, 20)); let padding_at_end2: ((i32, i16), i32) = ((21, 22), 23); - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/tuple-struct.rs b/src/test/debuginfo/tuple-struct.rs index cea063820b867..afcacd46e6653 100644 --- a/src/test/debuginfo/tuple-struct.rs +++ b/src/test/debuginfo/tuple-struct.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz // gdb-command:run @@ -35,6 +38,28 @@ // gdb-check:$6 = {-10014, 10015} +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print no_padding16 +// lldb-check:[...]$0 = NoPadding16(10000, -10001) + +// lldb-command:print no_padding32 +// lldb-check:[...]$1 = NoPadding32(-10002, -10003.5, 10004) + +// lldb-command:print no_padding64 +// lldb-check:[...]$2 = NoPadding64(-10005.5, 10006, 10007) + +// lldb-command:print no_padding163264 +// lldb-check:[...]$3 = NoPadding163264(-10008, 10009, 10010, 10011) + +// lldb-command:print internal_padding +// lldb-check:[...]$4 = InternalPadding(10012, -10013) + +// lldb-command:print padding_at_end +// lldb-check:[...]$5 = PaddingAtEnd(-10014, 10015) + // This test case mainly makes sure that no field names are generated for tuple structs (as opposed // to all fields having the name ""). Otherwise they are handled the same a normal // structs. @@ -55,7 +80,7 @@ fn main() { let internal_padding = InternalPadding(10012, -10013); let padding_at_end = PaddingAtEnd(-10014, 10015); - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/tuple-style-enum.rs b/src/test/debuginfo/tuple-style-enum.rs index 81c72d1688643..7cd0a8f6164e8 100644 --- a/src/test/debuginfo/tuple-style-enum.rs +++ b/src/test/debuginfo/tuple-style-enum.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print union on // gdb-command:rbreak zzz // gdb-command:run @@ -29,6 +32,23 @@ // gdb-command:print univariant // gdb-check:$4 = {{-1}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print case1 +// lldb-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868) + +// lldb-command:print case2 +// lldb-check:[...]$1 = Case2(0, 286331153, 286331153) + +// lldb-command:print case3 +// lldb-check:[...]$2 = Case3(0, 6438275382588823897) + +// lldb-command:print univariant +// lldb-check:[...]$3 = TheOnlyCase(-1) + #![allow(unused_variable)] // The first element is to ensure proper alignment, irrespective of the machines word size. Since @@ -70,7 +90,7 @@ fn main() { let univariant = TheOnlyCase(-1); - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/unique-enum.rs b/src/test/debuginfo/unique-enum.rs index 3949a315adca2..4c945e62abcd8 100644 --- a/src/test/debuginfo/unique-enum.rs +++ b/src/test/debuginfo/unique-enum.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -24,6 +27,20 @@ // gdb-command:print *univariant // gdb-check:$3 = {{123234}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print *the_a +// lldb-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 } + +// lldb-command:print *the_b +// lldb-check:[...]$1 = TheB(0, 286331153, 286331153) + +// lldb-command:print *univariant +// lldb-check:[...]$2 = TheOnlyCase(123234) + #![allow(unused_variable)] #![feature(struct_variant)] @@ -60,7 +77,7 @@ fn main() { let univariant = box TheOnlyCase(123234); - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs index 3328b11228441..b538fcd7d76b8 100644 --- a/src/test/debuginfo/var-captured-in-nested-closure.rs +++ b/src/test/debuginfo/var-captured-in-nested-closure.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -48,6 +51,43 @@ // gdb-check:$14 = 8 // gdb-command:continue + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print variable +// lldb-check:[...]$0 = 1 +// lldb-command:print constant +// lldb-check:[...]$1 = 2 +// lldb-command:print a_struct +// lldb-check:[...]$2 = Struct { a: -3, b: 4.5, c: 5 } +// lldb-command:print *struct_ref +// lldb-check:[...]$3 = Struct { a: -3, b: 4.5, c: 5 } +// lldb-command:print *owned +// lldb-check:[...]$4 = 6 +// lldb-command:print managed->val +// lldb-check:[...]$5 = 7 +// lldb-command:print closure_local +// lldb-check:[...]$6 = 8 +// lldb-command:continue + +// lldb-command:print variable +// lldb-check:[...]$7 = 1 +// lldb-command:print constant +// lldb-check:[...]$8 = 2 +// lldb-command:print a_struct +// lldb-check:[...]$9 = Struct { a: -3, b: 4.5, c: 5 } +// lldb-command:print *struct_ref +// lldb-check:[...]$10 = Struct { a: -3, b: 4.5, c: 5 } +// lldb-command:print *owned +// lldb-check:[...]$11 = 6 +// lldb-command:print managed->val +// lldb-check:[...]$12 = 7 +// lldb-command:print closure_local +// lldb-check:[...]$13 = 8 +// lldb-command:continue + #![feature(managed_boxes)] #![allow(unused_variable)] @@ -77,11 +117,11 @@ fn main() { let closure_local = 8; let nested_closure = || { - zzz(); + zzz(); // #break variable = constant + a_struct.a + struct_ref.a + *owned + *managed + closure_local; }; - zzz(); + zzz(); // #break nested_closure(); }; diff --git a/src/test/debuginfo/var-captured-in-sendable-closure.rs b/src/test/debuginfo/var-captured-in-sendable-closure.rs index 03525a3a034dc..e87c23b96e276 100644 --- a/src/test/debuginfo/var-captured-in-sendable-closure.rs +++ b/src/test/debuginfo/var-captured-in-sendable-closure.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -22,6 +25,18 @@ // gdb-command:print *owned // gdb-check:$3 = 5 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print constant +// lldb-check:[...]$0 = 1 +// lldb-command:print a_struct +// lldb-check:[...]$1 = Struct { a: -2, b: 3.5, c: 4 } +// lldb-command:print *owned +// lldb-check:[...]$2 = 5 + #![allow(unused_variable)] struct Struct { @@ -42,8 +57,8 @@ fn main() { let owned = box 5; let closure: proc() = proc() { - zzz(); - do_something(&constant, &a_struct.a, owned); + zzz(); // #break + do_something(&constant, &a_struct.a, &*owned); }; closure(); diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs index 453ac35463178..3fe17dc83e765 100644 --- a/src/test/debuginfo/var-captured-in-stack-closure.rs +++ b/src/test/debuginfo/var-captured-in-stack-closure.rs @@ -11,6 +11,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:rbreak zzz // gdb-command:run // gdb-command:finish @@ -28,6 +31,24 @@ // gdb-command:print managed->val // gdb-check:$6 = 7 + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print variable +// lldb-check:[...]$0 = 1 +// lldb-command:print constant +// lldb-check:[...]$1 = 2 +// lldb-command:print a_struct +// lldb-check:[...]$2 = Struct { a: -3, b: 4.5, c: 5 } +// lldb-command:print *struct_ref +// lldb-check:[...]$3 = Struct { a: -3, b: 4.5, c: 5 } +// lldb-command:print *owned +// lldb-check:[...]$4 = 6 +// lldb-command:print managed->val +// lldb-check:[...]$5 = 7 + #![feature(managed_boxes)] #![allow(unused_variable)] @@ -54,7 +75,7 @@ fn main() { let managed = box(GC) 7; let closure = || { - zzz(); + zzz(); // #break variable = constant + a_struct.a + struct_ref.a + *owned + *managed; }; diff --git a/src/test/debuginfo/vec-slices.rs b/src/test/debuginfo/vec-slices.rs index 783b198395339..00398fd5c8234 100644 --- a/src/test/debuginfo/vec-slices.rs +++ b/src/test/debuginfo/vec-slices.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz // gdb-command:run @@ -53,6 +56,29 @@ // gdb-command:print *((int64_t[2]*)('vec-slices::MUT_VECT_SLICE'.data_ptr)) // gdb-check:$15 = {64, 65} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print empty +// lldb-check:[...]$0 = &[] + +// lldb-command:print singleton +// lldb-check:[...]$1 = &[1] + +// lldb-command:print multiple +// lldb-check:[...]$2 = &[2, 3, 4, 5] + +// lldb-command:print slice_of_slice +// lldb-check:[...]$3 = &[3, 4] + +// lldb-command:print padded_tuple +// lldb-check:[...]$4 = &[(6, 7), (8, 9)] + +// lldb-command:print padded_struct +// lldb-check:[...]$5 = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }] + #![allow(unused_variable)] struct AStruct { @@ -81,7 +107,7 @@ fn main() { MUT_VECT_SLICE = VECT_SLICE; } - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/debuginfo/vec.rs b/src/test/debuginfo/vec.rs index 155865f415b63..7372a6e7ca019 100644 --- a/src/test/debuginfo/vec.rs +++ b/src/test/debuginfo/vec.rs @@ -12,6 +12,9 @@ // ignore-android: FIXME(#10381) // compile-flags:-g + +// === GDB TESTS =================================================================================== + // gdb-command:set print pretty off // gdb-command:rbreak zzz // gdb-command:run @@ -21,6 +24,13 @@ // gdb-command:print vec::VECT // gdb-check:$2 = {4, 5, 6} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run +// lldb-command:print a +// lldb-check:[...]$0 = [1, 2, 3] + #![allow(unused_variable)] static mut VECT: [i32, ..3] = [1, 2, 3]; @@ -34,7 +44,7 @@ fn main() { VECT[2] = 6; } - zzz(); + zzz(); // #break } fn zzz() {()} diff --git a/src/test/run-make/crate-name-priority/Makefile b/src/test/run-make/crate-name-priority/Makefile index 250602710f57d..2fe5183243361 100644 --- a/src/test/run-make/crate-name-priority/Makefile +++ b/src/test/run-make/crate-name-priority/Makefile @@ -7,7 +7,5 @@ all: rm $(TMPDIR)/$(call BIN,bar) $(RUSTC) foo1.rs rm $(TMPDIR)/$(call BIN,foo) - $(RUSTC) foo1.rs --crate-name bar - rm $(TMPDIR)/$(call BIN,bar) - $(RUSTC) foo1.rs --crate-name bar -o $(TMPDIR)/bar1 + $(RUSTC) foo1.rs -o $(TMPDIR)/bar1 rm $(TMPDIR)/$(call BIN,bar1) diff --git a/src/test/run-make/extra-filename-with-temp-outputs/Makefile b/src/test/run-make/extra-filename-with-temp-outputs/Makefile new file mode 100644 index 0000000000000..28c22a173cca0 --- /dev/null +++ b/src/test/run-make/extra-filename-with-temp-outputs/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +all: + $(RUSTC) -C extra-filename=bar foo.rs -C save-temps + rm $(TMPDIR)/foobar.o + rm $(TMPDIR)/$(call BIN,foobar) diff --git a/src/test/compile-fail/lint-allocation.rs b/src/test/run-make/extra-filename-with-temp-outputs/foo.rs similarity index 67% rename from src/test/compile-fail/lint-allocation.rs rename to src/test/run-make/extra-filename-with-temp-outputs/foo.rs index 1600043acbfbb..8ae3d072362ed 100644 --- a/src/test/compile-fail/lint-allocation.rs +++ b/src/test/run-make/extra-filename-with-temp-outputs/foo.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,10 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(unnecessary_allocation)] - -fn f(_: &int) {} - -fn main() { - f(box 1); //~ ERROR unnecessary allocation, use & instead -} +fn main() {} diff --git a/src/test/run-pass/autoderef-method-on-trait.rs b/src/test/run-pass/autoderef-method-on-trait.rs index e50825a401fc6..f13f598fda28c 100644 --- a/src/test/run-pass/autoderef-method-on-trait.rs +++ b/src/test/run-pass/autoderef-method-on-trait.rs @@ -10,11 +10,11 @@ trait double { - fn double(~self) -> uint; + fn double(self: Box) -> uint; } impl double for uint { - fn double(~self) -> uint { *self * 2u } + fn double(self: Box) -> uint { *self * 2u } } pub fn main() { diff --git a/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs b/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs index 7acd54788a8c2..856ee686db30e 100644 --- a/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs +++ b/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs @@ -10,11 +10,11 @@ trait double { - fn double(~self) -> uint; + fn double(self: Box) -> uint; } impl double for Box { - fn double(~self) -> uint { **self * 2u } + fn double(self: Box>) -> uint { **self * 2u } } pub fn main() { diff --git a/src/test/run-pass/autoderef-method-twice.rs b/src/test/run-pass/autoderef-method-twice.rs index a8b6b6f74f4ff..94da61483eaae 100644 --- a/src/test/run-pass/autoderef-method-twice.rs +++ b/src/test/run-pass/autoderef-method-twice.rs @@ -9,11 +9,11 @@ // except according to those terms. trait double { - fn double(~self) -> uint; + fn double(self: Box) -> uint; } impl double for uint { - fn double(~self) -> uint { *self * 2u } + fn double(self: Box) -> uint { *self * 2u } } pub fn main() { diff --git a/src/test/run-pass/autoderef-method.rs b/src/test/run-pass/autoderef-method.rs index 4c4ebdc94f030..2e9751ce6acfc 100644 --- a/src/test/run-pass/autoderef-method.rs +++ b/src/test/run-pass/autoderef-method.rs @@ -9,11 +9,11 @@ // except according to those terms. trait double { - fn double(~self) -> uint; + fn double(self: Box) -> uint; } impl double for uint { - fn double(~self) -> uint { *self * 2u } + fn double(self: Box) -> uint { *self * 2u } } pub fn main() { diff --git a/src/test/run-pass/bitv-perf-test.rs b/src/test/run-pass/bitv-perf-test.rs index 3823a7033f5a6..281167ff46c86 100644 --- a/src/test/run-pass/bitv-perf-test.rs +++ b/src/test/run-pass/bitv-perf-test.rs @@ -15,7 +15,7 @@ use std::collections::Bitv; fn bitv_test() { let mut v1 = box Bitv::with_capacity(31, false); let v2 = box Bitv::with_capacity(31, true); - v1.union(v2); + v1.union(&*v2); } pub fn main() { diff --git a/src/test/run-pass/borrowck-lend-args.rs b/src/test/run-pass/borrowck-lend-args.rs index 68d1b74e2019b..9b8fa8f9f79b2 100644 --- a/src/test/run-pass/borrowck-lend-args.rs +++ b/src/test/run-pass/borrowck-lend-args.rs @@ -12,15 +12,15 @@ fn borrow(_v: &int) {} fn borrow_from_arg_imm_ref(v: Box) { - borrow(v); + borrow(&*v); } fn borrow_from_arg_mut_ref(v: &mut Box) { - borrow(*v); + borrow(&**v); } fn borrow_from_arg_copy(v: Box) { - borrow(v); + borrow(&*v); } pub fn main() { diff --git a/src/test/run-pass/borrowck-mut-uniq.rs b/src/test/run-pass/borrowck-mut-uniq.rs index c0be4abafbe9a..993ce37a1eca7 100644 --- a/src/test/run-pass/borrowck-mut-uniq.rs +++ b/src/test/run-pass/borrowck-mut-uniq.rs @@ -32,7 +32,7 @@ pub fn main() { add_int(&mut *ints, 22); add_int(&mut *ints, 44); - iter_ints(ints, |i| { + iter_ints(&*ints, |i| { println!("int = {}", *i); true }); diff --git a/src/test/run-pass/borrowck-root-while-cond.rs b/src/test/run-pass/borrowck-root-while-cond.rs index eda8637adc4cf..35cdfb41abca0 100644 --- a/src/test/run-pass/borrowck-root-while-cond.rs +++ b/src/test/run-pass/borrowck-root-while-cond.rs @@ -18,5 +18,5 @@ struct Rec { f: Gc } pub fn main() { let rec = box(GC) Rec {f: box(GC) 22}; - while *borrow(rec.f) == 23 {} + while *borrow(&*rec.f) == 23 {} } diff --git a/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs b/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs index 420ee843766bb..02c7dc38db00f 100644 --- a/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs +++ b/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs @@ -17,7 +17,7 @@ struct Box { } impl Box { - fn get<'a>(&'a self) -> &'a uint { + fn get(&self) -> &uint { &self.x } fn set(&mut self, x: uint) { diff --git a/src/test/run-pass/borrowck-uniq-via-ref.rs b/src/test/run-pass/borrowck-uniq-via-ref.rs index 451f9ccf5bd6d..84bd70c78d487 100644 --- a/src/test/run-pass/borrowck-uniq-via-ref.rs +++ b/src/test/run-pass/borrowck-uniq-via-ref.rs @@ -28,27 +28,27 @@ struct Innermost { fn borrow(_v: &int) {} fn box_mut(v: &mut Box) { - borrow(*v); // OK: &mut -> &imm + borrow(&**v); // OK: &mut -> &imm } fn box_mut_rec(v: &mut Rec) { - borrow(v.f); // OK: &mut -> &imm + borrow(&*v.f); // OK: &mut -> &imm } fn box_mut_recs(v: &mut Outer) { - borrow(v.f.g.h); // OK: &mut -> &imm + borrow(&*v.f.g.h); // OK: &mut -> &imm } fn box_imm(v: &Box) { - borrow(*v); // OK + borrow(&**v); // OK } fn box_imm_rec(v: &Rec) { - borrow(v.f); // OK + borrow(&*v.f); // OK } fn box_imm_recs(v: &Outer) { - borrow(v.f.g.h); // OK + borrow(&*v.f.g.h); // OK } pub fn main() { diff --git a/src/test/run-pass/cci_borrow.rs b/src/test/run-pass/cci_borrow.rs index 324fb428df019..32b4065439f93 100644 --- a/src/test/run-pass/cci_borrow.rs +++ b/src/test/run-pass/cci_borrow.rs @@ -18,7 +18,7 @@ use std::gc::GC; pub fn main() { let p = box(GC) 22u; - let r = foo(p); + let r = foo(&*p); println!("r={}", r); assert_eq!(r, 22u); } diff --git a/src/test/run-pass/class-impl-very-parameterized-trait.rs b/src/test/run-pass/class-impl-very-parameterized-trait.rs index 924625faa1010..dd3a7b86bea83 100644 --- a/src/test/run-pass/class-impl-very-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-very-parameterized-trait.rs @@ -60,7 +60,7 @@ impl Mutable for cat { impl Map for cat { fn contains_key(&self, k: &int) -> bool { *k <= self.meows } - fn find<'a>(&'a self, k: &int) -> Option<&'a T> { + fn find(&self, k: &int) -> Option<&T> { if *k <= self.meows { Some(&self.name) } else { @@ -75,7 +75,7 @@ impl MutableMap for cat { true } - fn find_mut<'a>(&'a mut self, _k: &int) -> Option<&'a mut T> { fail!() } + fn find_mut(&mut self, _k: &int) -> Option<&mut T> { fail!() } fn remove(&mut self, k: &int) -> bool { if self.find(k).is_some() { @@ -91,7 +91,7 @@ impl MutableMap for cat { } impl cat { - pub fn get<'a>(&'a self, k: &int) -> &'a T { + pub fn get(&self, k: &int) -> &T { match self.find(k) { Some(v) => { v } None => { fail!("epic fail"); } diff --git a/src/test/run-pass/cleanup-rvalue-for-scope.rs b/src/test/run-pass/cleanup-rvalue-for-scope.rs index e352fc0be981e..932a5a044ad3e 100644 --- a/src/test/run-pass/cleanup-rvalue-for-scope.rs +++ b/src/test/run-pass/cleanup-rvalue-for-scope.rs @@ -42,7 +42,7 @@ fn check_flags(exp: u64) { } impl AddFlags { - fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags { + fn check_flags(&self, exp: u64) -> &AddFlags { check_flags(exp); self } diff --git a/src/test/run-pass/crate-name-attr-used.rs b/src/test/run-pass/crate-name-attr-used.rs index abc565d31758f..95c7d331264e1 100644 --- a/src/test/run-pass/crate-name-attr-used.rs +++ b/src/test/run-pass/crate-name-attr-used.rs @@ -10,6 +10,6 @@ // compile-flags:--crate-name crate-name-attr-used -F unused-attribute -#![crate_name = "test"] +#![crate_name = "crate-name-attr-used"] fn main() {} diff --git a/src/test/run-pass/explicit-self-objects-uniq.rs b/src/test/run-pass/explicit-self-objects-uniq.rs index 595bb4f6b9e44..e566f218aa8f6 100644 --- a/src/test/run-pass/explicit-self-objects-uniq.rs +++ b/src/test/run-pass/explicit-self-objects-uniq.rs @@ -10,7 +10,7 @@ trait Foo { - fn f(~self); + fn f(self: Box); } struct S { @@ -18,7 +18,7 @@ struct S { } impl Foo for S { - fn f(~self) { + fn f(self: Box) { assert_eq!(self.x, 3); } } diff --git a/src/test/run-pass/explicit-self.rs b/src/test/run-pass/explicit-self.rs index 6c2e17046d3c1..32ac14ab18074 100644 --- a/src/test/run-pass/explicit-self.rs +++ b/src/test/run-pass/explicit-self.rs @@ -57,7 +57,7 @@ fn thing(x: A) -> thing { } impl thing { - pub fn bar(~self) -> int { self.x.a } + pub fn bar(self: Box) -> int { self.x.a } pub fn quux(&self) -> int { self.x.a } pub fn baz<'a>(&'a self) -> &'a A { &self.x } pub fn spam(self) -> int { self.x.a } diff --git a/src/test/run-pass/fn-trait-sugar.rs b/src/test/run-pass/fn-trait-sugar.rs index b0c8d84b6646b..ccb5634f7a290 100644 --- a/src/test/run-pass/fn-trait-sugar.rs +++ b/src/test/run-pass/fn-trait-sugar.rs @@ -16,7 +16,7 @@ use std::ops::FnMut; struct S; impl FnMut<(int,),int> for S { - fn call_mut(&mut self, (x,): (int,)) -> int { + extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int { x * x } } diff --git a/src/test/run-pass/issue-14958.rs b/src/test/run-pass/issue-14958.rs index 045d3cc0458f7..b53c2258736ff 100644 --- a/src/test/run-pass/issue-14958.rs +++ b/src/test/run-pass/issue-14958.rs @@ -15,7 +15,7 @@ trait Foo {} struct Bar; impl<'a> std::ops::Fn<(&'a Foo,), ()> for Bar { - fn call(&self, _: (&'a Foo,)) {} + extern "rust-call" fn call(&self, _: (&'a Foo,)) {} } struct Baz; diff --git a/src/test/run-pass/issue-14959.rs b/src/test/run-pass/issue-14959.rs index 7fbb0657c704b..af0bc78094e5f 100644 --- a/src/test/run-pass/issue-14959.rs +++ b/src/test/run-pass/issue-14959.rs @@ -34,7 +34,7 @@ impl Alloy { } impl<'a, 'b> Fn<(&'b mut Response,),()> for SendFile<'a> { - fn call(&self, (_res,): (&'b mut Response,)) {} + extern "rust-call" fn call(&self, (_res,): (&'b mut Response,)) {} } impl Ingot for HelloWorld { diff --git a/src/test/run-pass/issue-1696.rs b/src/test/run-pass/issue-1696.rs index c05e84b6e69f5..291fab29584dd 100644 --- a/src/test/run-pass/issue-1696.rs +++ b/src/test/run-pass/issue-1696.rs @@ -15,6 +15,6 @@ use std::collections::HashMap; pub fn main() { let mut m = HashMap::new(); - m.insert("foo".as_bytes().to_owned(), "bar".as_bytes().to_owned()); + m.insert(b"foo".to_vec(), b"bar".to_vec()); println!("{:?}", m); } diff --git a/src/test/run-pass/issue-2502.rs b/src/test/run-pass/issue-2502.rs index 91912e00e1809..a62e329f106f5 100644 --- a/src/test/run-pass/issue-2502.rs +++ b/src/test/run-pass/issue-2502.rs @@ -19,7 +19,7 @@ impl<'a> font<'a> { } } -fn font<'r>(fontbuf: &'r Vec ) -> font<'r> { +fn font(fontbuf: &Vec ) -> font { font { fontbuf: fontbuf } diff --git a/src/test/run-pass/issue-2748-a.rs b/src/test/run-pass/issue-2748-a.rs index 455d22fe7f0f5..23e26ca5665c5 100644 --- a/src/test/run-pass/issue-2748-a.rs +++ b/src/test/run-pass/issue-2748-a.rs @@ -12,7 +12,7 @@ struct CMap<'a> { buf: &'a [u8], } -fn CMap<'r>(buf: &'r [u8]) -> CMap<'r> { +fn CMap(buf: &[u8]) -> CMap { CMap { buf: buf } diff --git a/src/test/run-pass/issue-3794.rs b/src/test/run-pass/issue-3794.rs index 00878189627ae..9414a6f2302df 100644 --- a/src/test/run-pass/issue-3794.rs +++ b/src/test/run-pass/issue-3794.rs @@ -34,8 +34,7 @@ fn print_s(s: &S) { pub fn main() { let s: Box = box S { s: 5 }; - print_s(s); + print_s(&*s); let t: Box = s as Box; print_t(t); - } diff --git a/src/test/run-pass/issue-4241.rs b/src/test/run-pass/issue-4241.rs index 3ebc3e6457376..15423121fda6c 100644 --- a/src/test/run-pass/issue-4241.rs +++ b/src/test/run-pass/issue-4241.rs @@ -56,7 +56,7 @@ priv fn parse_list(len: uint, io: @io::Reader) -> Result { } priv fn chop(s: String) -> String { - s.slice(0, s.len() - 1).to_owned() + s.slice(0, s.len() - 1).to_string() } priv fn parse_bulk(io: @io::Reader) -> Result { diff --git a/src/test/run-pass/issue-4464.rs b/src/test/run-pass/issue-4464.rs index 529f8ecc6ebe1..822fda8a18ec8 100644 --- a/src/test/run-pass/issue-4464.rs +++ b/src/test/run-pass/issue-4464.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn broken<'r>(v: &'r [u8], i: uint, j: uint) -> &'r [u8] { v.slice(i, j) } +fn broken(v: &[u8], i: uint, j: uint) -> &[u8] { v.slice(i, j) } pub fn main() {} diff --git a/src/test/run-pass/issue-5708.rs b/src/test/run-pass/issue-5708.rs index 39c8562e4589b..2bb320e556235 100644 --- a/src/test/run-pass/issue-5708.rs +++ b/src/test/run-pass/issue-5708.rs @@ -33,7 +33,7 @@ struct Outer<'a> { } impl<'a> Outer<'a> { - fn new<'r>(inner: &'r Inner) -> Outer<'r> { + fn new(inner: &Inner) -> Outer { Outer { inner: inner } diff --git a/src/test/run-pass/issue-5884.rs b/src/test/run-pass/issue-5884.rs index c99fb7765fb23..2d8f966caf1bf 100644 --- a/src/test/run-pass/issue-5884.rs +++ b/src/test/run-pass/issue-5884.rs @@ -22,7 +22,7 @@ struct Bar<'a> { } fn check(a: Gc) { - let _ic = Bar{ b: a, a: box None }; + let _ic = Bar{ b: &*a, a: box None }; } pub fn main(){} diff --git a/src/test/run-pass/issue-7320.rs b/src/test/run-pass/issue-7320.rs index 99ed4288a7ec1..c7087f8e3a8ca 100644 --- a/src/test/run-pass/issue-7320.rs +++ b/src/test/run-pass/issue-7320.rs @@ -10,7 +10,7 @@ trait Foo { - fn foo(~self) { bar(self as Box); } + fn foo(self: Box) { bar(self as Box); } } fn bar(_b: Box) { } diff --git a/src/test/run-pass/issue-7911.rs b/src/test/run-pass/issue-7911.rs index 75494c47dcef1..d8bb61477a0c8 100644 --- a/src/test/run-pass/issue-7911.rs +++ b/src/test/run-pass/issue-7911.rs @@ -23,17 +23,17 @@ struct Foo { bar: Bar } impl FooBar for Bar {} trait Test { - fn get_immut<'r>(&'r self) -> &'r FooBar; - fn get_mut<'r>(&'r mut self) -> &'r mut FooBar; + fn get_immut(&self) -> &FooBar; + fn get_mut(&mut self) -> &mut FooBar; } macro_rules! generate_test(($type_:path, $slf:ident, $field:expr) => ( impl Test for $type_ { - fn get_immut<'r>(&'r $slf) -> &'r FooBar { + fn get_immut(&$slf) -> &FooBar { &$field as &FooBar } - fn get_mut<'r>(&'r mut $slf) -> &'r mut FooBar { + fn get_mut(&mut $slf) -> &mut FooBar { &mut $field as &mut FooBar } } diff --git a/src/test/run-pass/let-assignability.rs b/src/test/run-pass/let-assignability.rs index 477f3b2acafda..6bea1aebc4588 100644 --- a/src/test/run-pass/let-assignability.rs +++ b/src/test/run-pass/let-assignability.rs @@ -10,7 +10,7 @@ fn f() { let a = box 1; - let b: &int = a; + let b: &int = &*a; println!("{}", b); } diff --git a/src/test/run-pass/match-arm-statics.rs b/src/test/run-pass/match-arm-statics.rs new file mode 100644 index 0000000000000..a8f6d9c391744 --- /dev/null +++ b/src/test/run-pass/match-arm-statics.rs @@ -0,0 +1,156 @@ +// Copyright 2014 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. + +#![feature(struct_variant)] + +struct NewBool(bool); + +enum Direction { + North, + East, + South, + West +} +struct Foo { + bar: Option, + baz: NewBool +} +enum EnumWithStructVariants { + Variant1(bool), + Variant2 { + dir: Direction + } +} + +static TRUE_TRUE: (bool, bool) = (true, true); +static NONE: Option = None; +static EAST: Direction = East; +static NEW_FALSE: NewBool = NewBool(false); +static STATIC_FOO: Foo = Foo { bar: Some(South), baz: NEW_FALSE }; +static VARIANT2_NORTH: EnumWithStructVariants = Variant2 { dir: North }; + +pub mod glfw { + pub struct InputState(uint); + + pub static RELEASE : InputState = InputState(0); + pub static PRESS : InputState = InputState(1); + pub static REPEAT : InputState = InputState(2); +} + +fn issue_6533() { + use glfw; + + fn action_to_str(state: glfw::InputState) -> &'static str { + use glfw::{RELEASE, PRESS, REPEAT}; + match state { + RELEASE => { "Released" } + PRESS => { "Pressed" } + REPEAT => { "Repeated" } + _ => { "Unknown" } + } + } + + assert_eq!(action_to_str(glfw::RELEASE), "Released"); + assert_eq!(action_to_str(glfw::PRESS), "Pressed"); + assert_eq!(action_to_str(glfw::REPEAT), "Repeated"); +} + +fn issue_13626() { + static VAL: [u8, ..1] = [0]; + match [1] { + VAL => unreachable!(), + _ => () + } +} + +fn issue_14576() { + type Foo = (i32, i32); + static ON: Foo = (1, 1); + static OFF: Foo = (0, 0); + + match (1, 1) { + OFF => unreachable!(), + ON => (), + _ => unreachable!() + } + + enum C { D = 3, E = 4 } + static F : C = D; + + assert_eq!(match D { F => 1i, _ => 2, }, 1); +} + +fn issue_13731() { + enum A { A(()) } + static B: A = A(()); + + match A(()) { + B => () + } +} + +fn issue_15393() { + #![allow(dead_code)] + struct Flags { + bits: uint + } + + static FOO: Flags = Flags { bits: 0x01 }; + static BAR: Flags = Flags { bits: 0x02 }; + match (Flags { bits: 0x02 }) { + FOO => unreachable!(), + BAR => (), + _ => unreachable!() + } +} + +fn main() { + assert_eq!(match (true, false) { + TRUE_TRUE => 1i, + (false, false) => 2, + (false, true) => 3, + (true, false) => 4 + }, 4); + + assert_eq!(match Some(Some(North)) { + Some(NONE) => 1i, + Some(Some(North)) => 2, + Some(Some(EAST)) => 3, + Some(Some(South)) => 4, + Some(Some(West)) => 5, + None => 6 + }, 2); + + assert_eq!(match (Foo { bar: Some(West), baz: NewBool(true) }) { + Foo { bar: None, baz: NewBool(true) } => 1i, + Foo { bar: NONE, baz: NEW_FALSE } => 2, + STATIC_FOO => 3, + Foo { bar: _, baz: NEW_FALSE } => 4, + Foo { bar: Some(West), baz: NewBool(true) } => 5, + Foo { bar: Some(South), baz: NewBool(true) } => 6, + Foo { bar: Some(EAST), .. } => 7, + Foo { bar: Some(North), baz: NewBool(true) } => 8 + }, 5); + + assert_eq!(match (Variant2 { dir: North }) { + Variant1(true) => 1i, + Variant1(false) => 2, + Variant2 { dir: West } => 3, + VARIANT2_NORTH => 4, + Variant2 { dir: South } => 5, + Variant2 { dir: East } => 6 + }, 4); + + issue_6533(); + issue_13626(); + issue_13731(); + issue_14576(); + issue_15393(); +} diff --git a/src/test/run-pass/new-box.rs b/src/test/run-pass/new-box.rs index d41896ffb41d0..38f552e9a9846 100644 --- a/src/test/run-pass/new-box.rs +++ b/src/test/run-pass/new-box.rs @@ -10,7 +10,7 @@ fn f(x: Box) { - let y: &int = x; + let y: &int = &*x; println!("{}", *x); println!("{}", *y); } diff --git a/src/test/run-pass/nullable-pointer-iotareduction.rs b/src/test/run-pass/nullable-pointer-iotareduction.rs index 8b26ece176d4d..10c07e6435400 100644 --- a/src/test/run-pass/nullable-pointer-iotareduction.rs +++ b/src/test/run-pass/nullable-pointer-iotareduction.rs @@ -29,7 +29,7 @@ impl E { Nothing(..) => true } } - fn get_ref<'r>(&'r self) -> (int, &'r T) { + fn get_ref(&self) -> (int, &T) { match *self { Nothing(..) => fail!("E::get_ref(Nothing::<{}>)", stringify!(T)), Thing(x, ref y) => (x, y) diff --git a/src/test/run-pass/objects-owned-object-owned-method.rs b/src/test/run-pass/objects-owned-object-owned-method.rs index 540593c43fbfd..14ddc5d660f0c 100644 --- a/src/test/run-pass/objects-owned-object-owned-method.rs +++ b/src/test/run-pass/objects-owned-object-owned-method.rs @@ -14,7 +14,7 @@ trait FooTrait { - fn foo(~self) -> uint; + fn foo(self: Box) -> uint; } struct BarStruct { @@ -22,7 +22,7 @@ struct BarStruct { } impl FooTrait for BarStruct { - fn foo(~self) -> uint { + fn foo(self: Box) -> uint { self.x } } diff --git a/src/test/run-pass/operator-overloading.rs b/src/test/run-pass/operator-overloading.rs index a36d8132b260a..a896d2b06f7bd 100644 --- a/src/test/run-pass/operator-overloading.rs +++ b/src/test/run-pass/operator-overloading.rs @@ -43,7 +43,7 @@ impl ops::Not for Point { } impl ops::Index for Point { - fn index<'a>(&'a self, x: &bool) -> &'a int { + fn index(&self, x: &bool) -> &int { if *x { &self.x } else { diff --git a/src/test/run-pass/overloaded-autoderef-count.rs b/src/test/run-pass/overloaded-autoderef-count.rs index 6fdbd17c21b38..24146c4a6ea6a 100644 --- a/src/test/run-pass/overloaded-autoderef-count.rs +++ b/src/test/run-pass/overloaded-autoderef-count.rs @@ -33,14 +33,14 @@ impl DerefCounter { } impl Deref for DerefCounter { - fn deref<'a>(&'a self) -> &'a T { + fn deref(&self) -> &T { self.count_imm.set(self.count_imm.get() + 1); &self.value } } impl DerefMut for DerefCounter { - fn deref_mut<'a>(&'a mut self) -> &'a mut T { + fn deref_mut(&mut self) -> &mut T { self.count_mut += 1; &mut self.value } diff --git a/src/test/run-pass/overloaded-autoderef-order.rs b/src/test/run-pass/overloaded-autoderef-order.rs index 188c62751bcd9..0a9ac734c26fd 100644 --- a/src/test/run-pass/overloaded-autoderef-order.rs +++ b/src/test/run-pass/overloaded-autoderef-order.rs @@ -22,7 +22,7 @@ impl DerefWrapper { } impl Deref for DerefWrapper { - fn deref<'a>(&'a self) -> &'a Y { + fn deref(&self) -> &Y { &self.y } } @@ -43,7 +43,7 @@ mod priv_test { } impl Deref for DerefWrapperHideX { - fn deref<'a>(&'a self) -> &'a Y { + fn deref(&self) -> &Y { &self.y } } diff --git a/src/test/run-pass/overloaded-autoderef-vtable.rs b/src/test/run-pass/overloaded-autoderef-vtable.rs index 15b5cca9cf83e..f71afb9650743 100644 --- a/src/test/run-pass/overloaded-autoderef-vtable.rs +++ b/src/test/run-pass/overloaded-autoderef-vtable.rs @@ -15,17 +15,17 @@ struct DerefWithHelper { } trait Helper { - fn helper_borrow<'a>(&'a self) -> &'a T; + fn helper_borrow(&self) -> &T; } impl Helper for Option { - fn helper_borrow<'a>(&'a self) -> &'a T { + fn helper_borrow(&self) -> &T { self.as_ref().unwrap() } } impl> Deref for DerefWithHelper { - fn deref<'a>(&'a self) -> &'a T { + fn deref(&self) -> &T { self.helper.helper_borrow() } } diff --git a/src/test/run-pass/overloaded-calls-simple.rs b/src/test/run-pass/overloaded-calls-simple.rs index 33120defedd8d..76c7e60116f80 100644 --- a/src/test/run-pass/overloaded-calls-simple.rs +++ b/src/test/run-pass/overloaded-calls-simple.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(overloaded_calls)] +#![feature(lang_items, overloaded_calls)] use std::ops::{Fn, FnMut, FnOnce}; @@ -18,7 +18,7 @@ struct S1 { } impl FnMut<(int,),int> for S1 { - fn call_mut(&mut self, (z,): (int,)) -> int { + extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int { self.x * self.y * z } } @@ -29,7 +29,7 @@ struct S2 { } impl Fn<(int,),int> for S2 { - fn call(&self, (z,): (int,)) -> int { + extern "rust-call" fn call(&self, (z,): (int,)) -> int { self.x * self.y * z } } @@ -40,7 +40,7 @@ struct S3 { } impl FnOnce<(int,int),int> for S3 { - fn call_once(self, (z,zz): (int,int)) -> int { + extern "rust-call" fn call_once(self, (z,zz): (int,int)) -> int { self.x * self.y * z * zz } } @@ -50,21 +50,21 @@ fn main() { x: 3, y: 3, }; - let ans = s(3); - assert_eq!(ans, 27); + let ans = s.call_mut((3,)); + assert_eq!(ans, 27); let s = S2 { x: 3, y: 3, }; - let ans = s(3); + let ans = s.call((3,)); assert_eq!(ans, 27); let s = S3 { x: 3, y: 3, }; - let ans = s(3, 1); + let ans = s.call_once((3, 1)); assert_eq!(ans, 27); } diff --git a/src/test/run-pass/overloaded-calls-zero-args.rs b/src/test/run-pass/overloaded-calls-zero-args.rs index f8f7df6b49b33..b868c8c96b5fb 100644 --- a/src/test/run-pass/overloaded-calls-zero-args.rs +++ b/src/test/run-pass/overloaded-calls-zero-args.rs @@ -18,7 +18,7 @@ struct S { } impl FnMut<(),int> for S { - fn call_mut(&mut self, (): ()) -> int { + extern "rust-call" fn call_mut(&mut self, (): ()) -> int { self.x * self.y } } diff --git a/src/test/run-pass/overloaded-deref-count.rs b/src/test/run-pass/overloaded-deref-count.rs index 283c76adf0daf..0b5406b8f67d5 100644 --- a/src/test/run-pass/overloaded-deref-count.rs +++ b/src/test/run-pass/overloaded-deref-count.rs @@ -33,14 +33,14 @@ impl DerefCounter { } impl Deref for DerefCounter { - fn deref<'a>(&'a self) -> &'a T { + fn deref(&self) -> &T { self.count_imm.set(self.count_imm.get() + 1); &self.value } } impl DerefMut for DerefCounter { - fn deref_mut<'a>(&'a mut self) -> &'a mut T { + fn deref_mut(&mut self) -> &mut T { self.count_mut += 1; &mut self.value } diff --git a/src/test/run-pass/overloaded-index.rs b/src/test/run-pass/overloaded-index.rs index 9d7c068cccd93..1187e06695070 100644 --- a/src/test/run-pass/overloaded-index.rs +++ b/src/test/run-pass/overloaded-index.rs @@ -14,7 +14,7 @@ struct Foo { } impl Index for Foo { - fn index<'a>(&'a self, z: &int) -> &'a int { + fn index(&self, z: &int) -> &int { if *z == 0 { &self.x } else { @@ -24,7 +24,7 @@ impl Index for Foo { } impl IndexMut for Foo { - fn index_mut<'a>(&'a mut self, z: &int) -> &'a mut int { + fn index_mut(&mut self, z: &int) -> &mut int { if *z == 0 { &mut self.x } else { diff --git a/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs b/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs index 47ae5c13d28cb..bb2885a217785 100644 --- a/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs +++ b/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs @@ -18,7 +18,7 @@ struct Character { pos: Box, } -fn get_x<'r>(x: &'r Character) -> &'r int { +fn get_x(x: &Character) -> &int { // interesting case because the scope of this // borrow of the unique pointer is in fact // larger than the fn itself diff --git a/src/test/run-pass/regions-addr-of-ret.rs b/src/test/run-pass/regions-addr-of-ret.rs index 357d829627da0..a046ba456a6b0 100644 --- a/src/test/run-pass/regions-addr-of-ret.rs +++ b/src/test/run-pass/regions-addr-of-ret.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f<'a>(x : &'a int) -> &'a int { +fn f(x: &int) -> &int { return &*x; } diff --git a/src/test/run-pass/regions-borrow-at.rs b/src/test/run-pass/regions-borrow-at.rs index c6dfbabd448db..74990432d03e0 100644 --- a/src/test/run-pass/regions-borrow-at.rs +++ b/src/test/run-pass/regions-borrow-at.rs @@ -18,7 +18,7 @@ fn foo(x: &uint) -> uint { pub fn main() { let p = box(GC) 22u; - let r = foo(p); + let r = foo(&*p); println!("r={}", r); assert_eq!(r, 22u); } diff --git a/src/test/run-pass/regions-borrow-uniq.rs b/src/test/run-pass/regions-borrow-uniq.rs index 6b35c0768d79a..36f7d88f7d797 100644 --- a/src/test/run-pass/regions-borrow-uniq.rs +++ b/src/test/run-pass/regions-borrow-uniq.rs @@ -14,6 +14,6 @@ fn foo(x: &uint) -> uint { pub fn main() { let p = box 3u; - let r = foo(p); + let r = foo(&*p); assert_eq!(r, 3u); } diff --git a/src/test/run-pass/regions-copy-closure.rs b/src/test/run-pass/regions-copy-closure.rs index 65cecb2d5008b..b4523ce41ce75 100644 --- a/src/test/run-pass/regions-copy-closure.rs +++ b/src/test/run-pass/regions-copy-closure.rs @@ -12,7 +12,7 @@ struct closure_box<'a> { cl: ||: 'a, } -fn box_it<'r>(x: ||: 'r) -> closure_box<'r> { +fn box_it(x: ||) -> closure_box { closure_box {cl: x} } diff --git a/src/test/run-pass/regions-dependent-addr-of.rs b/src/test/run-pass/regions-dependent-addr-of.rs index 400ab462f761f..252c0b5578ac6 100644 --- a/src/test/run-pass/regions-dependent-addr-of.rs +++ b/src/test/run-pass/regions-dependent-addr-of.rs @@ -29,54 +29,54 @@ struct C { f: int } -fn get_v1<'v>(a: &'v A) -> &'v int { +fn get_v1(a: &A) -> &int { // Region inferencer must deduce that &v < L2 < L1 let foo = &a.value; // L1 &foo.v1 // L2 } -fn get_v2<'v>(a: &'v A, i: uint) -> &'v int { +fn get_v2(a: &A, i: uint) -> &int { let foo = &a.value; &foo.v2[i] } -fn get_v3<'v>(a: &'v A, i: uint) -> &'v int { +fn get_v3(a: &A, i: uint) -> &int { let foo = &a.value; foo.v3.get(i) } -fn get_v4<'v>(a: &'v A, _i: uint) -> &'v int { +fn get_v4(a: &A, _i: uint) -> &int { let foo = &a.value; &foo.v4.f } -fn get_v5<'v>(a: &'v A, _i: uint) -> &'v int { +fn get_v5(a: &A, _i: uint) -> &int { let foo = &a.value; &foo.v5.f } -fn get_v6_a<'v>(a: &'v A, _i: uint) -> &'v int { +fn get_v6_a(a: &A, _i: uint) -> &int { match a.value.v6 { Some(ref v) => &v.f, None => fail!() } } -fn get_v6_b<'v>(a: &'v A, _i: uint) -> &'v int { +fn get_v6_b(a: &A, _i: uint) -> &int { match *a { A { value: B { v6: Some(ref v), .. } } => &v.f, _ => fail!() } } -fn get_v6_c<'v>(a: &'v A, _i: uint) -> &'v int { +fn get_v6_c(a: &A, _i: uint) -> &int { match a { &A { value: B { v6: Some(ref v), .. } } => &v.f, _ => fail!() } } -fn get_v5_ref<'v>(a: &'v A, _i: uint) -> &'v int { +fn get_v5_ref(a: &A, _i: uint) -> &int { match &a.value { &B {v5: box C {f: ref v}, ..} => v } diff --git a/src/test/run-pass/regions-dependent-autofn.rs b/src/test/run-pass/regions-dependent-autofn.rs index e9cd7fb49731f..311fd1bcdf2e0 100644 --- a/src/test/run-pass/regions-dependent-autofn.rs +++ b/src/test/run-pass/regions-dependent-autofn.rs @@ -11,9 +11,9 @@ // Test lifetimes are linked properly when we autoslice a vector. // Issue #3148. -fn subslice<'r>(v: ||: 'r) -> ||: 'r { v } +fn subslice(v: ||) -> || { v } -fn both<'r>(v: ||: 'r) -> ||: 'r { +fn both(v: ||) -> || { subslice(subslice(v)) } diff --git a/src/test/run-pass/regions-escape-into-other-fn.rs b/src/test/run-pass/regions-escape-into-other-fn.rs index 695a1b110da4e..46e1aaa3a241b 100644 --- a/src/test/run-pass/regions-escape-into-other-fn.rs +++ b/src/test/run-pass/regions-escape-into-other-fn.rs @@ -12,10 +12,10 @@ use std::gc::GC; -fn foo<'r>(x: &'r uint) -> &'r uint { x } +fn foo(x: &uint) -> &uint { x } fn bar(x: &uint) -> uint { *x } pub fn main() { let p = box(GC) 3u; - assert_eq!(bar(foo(p)), 3); + assert_eq!(bar(foo(&*p)), 3); } diff --git a/src/test/run-pass/regions-infer-borrow-scope-view.rs b/src/test/run-pass/regions-infer-borrow-scope-view.rs index 13200d619d02e..c4e0e3bb4fc11 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-view.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-view.rs @@ -9,7 +9,7 @@ // except according to those terms. -fn view<'r, T>(x: &'r [T]) -> &'r [T] {x} +fn view(x: &[T]) -> &[T] {x} pub fn main() { let v = vec!(1i, 2, 3); diff --git a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs index 8f05531853390..4d4417189c908 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs @@ -10,12 +10,12 @@ use std::gc::GC; -fn borrow<'r, T>(x: &'r T) -> &'r T {x} +fn borrow(x: &T) -> &T {x} pub fn main() { let x = box(GC) 3i; loop { - let y = borrow(x); + let y = borrow(&*x); assert_eq!(*x, *y); break; } diff --git a/src/test/run-pass/regions-infer-borrow-scope.rs b/src/test/run-pass/regions-infer-borrow-scope.rs index c757762245325..65e753ddee12d 100644 --- a/src/test/run-pass/regions-infer-borrow-scope.rs +++ b/src/test/run-pass/regions-infer-borrow-scope.rs @@ -14,12 +14,12 @@ use std::gc::GC; struct Point {x: int, y: int} -fn x_coord<'r>(p: &'r Point) -> &'r int { +fn x_coord(p: &Point) -> &int { return &p.x; } pub fn main() { let p = box(GC) Point {x: 3, y: 4}; - let xc = x_coord(p); + let xc = x_coord(&*p); assert_eq!(*xc, 3); } diff --git a/src/test/run-pass/regions-nullary-variant.rs b/src/test/run-pass/regions-nullary-variant.rs index 784424ad54c8a..845ef4017447c 100644 --- a/src/test/run-pass/regions-nullary-variant.rs +++ b/src/test/run-pass/regions-nullary-variant.rs @@ -12,7 +12,7 @@ enum roption<'a> { a, b(&'a uint) } -fn mk<'r>(cond: bool, ptr: &'r uint) -> roption<'r> { +fn mk(cond: bool, ptr: &uint) -> roption { if cond {a} else {b(ptr)} } diff --git a/src/test/run-pass/regions-params.rs b/src/test/run-pass/regions-params.rs index b83d7af9a11d3..c0e821b8d3854 100644 --- a/src/test/run-pass/regions-params.rs +++ b/src/test/run-pass/regions-params.rs @@ -9,7 +9,7 @@ // except according to those terms. -fn region_identity<'r>(x: &'r uint) -> &'r uint { x } +fn region_identity(x: &uint) -> &uint { x } fn apply(t: T, f: |T| -> T) -> T { f(t) } diff --git a/src/test/run-pass/regions-return-interior-of-option.rs b/src/test/run-pass/regions-return-interior-of-option.rs index d1530c4c7b91a..f6971a8b4ad30 100644 --- a/src/test/run-pass/regions-return-interior-of-option.rs +++ b/src/test/run-pass/regions-return-interior-of-option.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn get<'r, T>(opt: &'r Option) -> &'r T { +fn get(opt: &Option) -> &T { match *opt { Some(ref v) => v, None => fail!("none") diff --git a/src/test/run-pass/regions-static-closure.rs b/src/test/run-pass/regions-static-closure.rs index d91c11dde10e2..f1d2adcaf94d8 100644 --- a/src/test/run-pass/regions-static-closure.rs +++ b/src/test/run-pass/regions-static-closure.rs @@ -12,7 +12,7 @@ struct closure_box<'a> { cl: ||: 'a, } -fn box_it<'r>(x: ||: 'r) -> closure_box<'r> { +fn box_it(x: ||) -> closure_box { closure_box {cl: x} } diff --git a/src/test/run-pass/self-in-mut-slot-default-method.rs b/src/test/run-pass/self-in-mut-slot-default-method.rs index 8ab27cfb4ee23..b4a46f34015a2 100644 --- a/src/test/run-pass/self-in-mut-slot-default-method.rs +++ b/src/test/run-pass/self-in-mut-slot-default-method.rs @@ -19,7 +19,7 @@ trait Changer { self } - fn change_again(mut ~self) -> Box { + fn change_again(mut self: Box) -> Box { self.set_to(45); self } diff --git a/src/test/run-pass/ufcs-explicit-self.rs b/src/test/run-pass/ufcs-explicit-self.rs new file mode 100644 index 0000000000000..9ffb56c516af5 --- /dev/null +++ b/src/test/run-pass/ufcs-explicit-self.rs @@ -0,0 +1,57 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::owned::Box; + +struct Foo { + f: int, +} + +impl Foo { + fn foo(self: Foo, x: int) -> int { + self.f + x + } + fn bar(self: &Foo, x: int) -> int { + self.f + x + } + fn baz(self: Box, x: int) -> int { + self.f + x + } +} + +struct Bar { + f: T, +} + +impl Bar { + fn foo(self: Bar, x: int) -> int { + x + } + fn bar<'a>(self: &'a Bar, x: int) -> int { + x + } + fn baz(self: Bar, x: int) -> int { + x + } +} + +fn main() { + let foo = box Foo { + f: 1, + }; + println!("{} {} {}", foo.foo(2), foo.bar(2), foo.baz(2)); + let bar = box Bar { + f: 1, + }; + println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2)); + let bar: Box> = bar; + println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2)); +} + diff --git a/src/test/run-pass/unboxed-closures-boxed.rs b/src/test/run-pass/unboxed-closures-boxed.rs new file mode 100644 index 0000000000000..c4b990abf7e65 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-boxed.rs @@ -0,0 +1,25 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +fn make_adder(x: int) -> Box> { + (box |&mut: y: int| -> int { x + y }) as Box> +} + +pub fn main() { + let mut adder = make_adder(3); + let z = adder.call_mut((2,)); + println!("{}", z); + assert_eq!(z, 5); +} + diff --git a/src/test/run-pass/unboxed-closures-generic.rs b/src/test/run-pass/unboxed-closures-generic.rs new file mode 100644 index 0000000000000..9d1d81fe259b3 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-generic.rs @@ -0,0 +1,25 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +fn call_it>(y: int, mut f: F) -> int { + f.call_mut((2, y)) +} + +pub fn main() { + let f = |&mut: x: int, y: int| -> int { x + y }; + let z = call_it(3, f); + println!("{}", z); + assert_eq!(z, 5); +} + diff --git a/src/test/run-pass/unboxed-closures-simple.rs b/src/test/run-pass/unboxed-closures-simple.rs new file mode 100644 index 0000000000000..f11096ba5ffc6 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-simple.rs @@ -0,0 +1,19 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +pub fn main() { + let mut f = |&mut: x: int, y: int| -> int { x + y }; + let z = f.call_mut((1, 2)); + assert_eq!(z, 3); +} diff --git a/src/test/run-pass/uniq-self-in-mut-slot.rs b/src/test/run-pass/uniq-self-in-mut-slot.rs index 3700e02051a69..4d7830e1cdca1 100644 --- a/src/test/run-pass/uniq-self-in-mut-slot.rs +++ b/src/test/run-pass/uniq-self-in-mut-slot.rs @@ -14,11 +14,11 @@ struct X { } trait Changer { - fn change(mut ~self) -> Box; + fn change(mut self: Box) -> Box; } impl Changer for X { - fn change(mut ~self) -> Box { + fn change(mut self: Box) -> Box { self.a = 55; self }